Mercurial > hg > graal-jvmci-8
changeset 8418:ba659864f935
Merge.
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Thu, 21 Mar 2013 11:09:19 +0100 |
parents | 7e281cb9ea10 (diff) 2bfb9644dcc2 (current diff) |
children | 11bada5f81a6 182753fdaa7f |
files | |
diffstat | 150 files changed, 11438 insertions(+), 11499 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Thu Mar 21 11:09:19 2013 +0100 @@ -37,10 +37,10 @@ import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*; import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; 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.hotspot.replacements.AESCryptSubstitutions.DecryptBlockStubCall.*; +import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.EncryptBlockStubCall.*; +import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*; +import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -50,8 +50,8 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.amd64.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.amd64.*; public class AMD64HotSpotRuntime extends HotSpotRuntime { @@ -196,10 +196,10 @@ private AMD64ConvertSnippets.Templates convertSnippets; @Override - public void installSnippets(Backend backend, SnippetInstaller installer, Assumptions assumptions) { + public void installReplacements(Backend backend, ReplacementsInstaller installer, Assumptions assumptions) { installer.installSnippets(AMD64ConvertSnippets.class); convertSnippets = new AMD64ConvertSnippets.Templates(this, assumptions, graalRuntime.getTarget()); - super.installSnippets(backend, installer, assumptions); + super.installReplacements(backend, installer, assumptions); } @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu Mar 21 11:09:19 2013 +0100 @@ -142,7 +142,7 @@ if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) { graph = new StructuredGraph(method, entryBCI); } else { - // Compiling an intrinsic graph - must clone the graph + // Compiling method substitution - must clone the graph graph = graph.copy(); } InlinedBytecodes.add(method.getCodeSize());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Thu Mar 21 11:09:19 2013 +0100 @@ -36,7 +36,6 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; /** * Singleton class holding the instance of the {@link GraalRuntime}. @@ -251,7 +250,7 @@ @SuppressWarnings("unchecked") @Override public <T> T getCapability(Class<T> clazz) { - if (clazz == GraalCodeCacheProvider.class || clazz == CodeCacheProvider.class || clazz == MetaAccessProvider.class || clazz == SnippetProvider.class) { + if (clazz == GraalCodeCacheProvider.class || clazz == CodeCacheProvider.class || clazz == MetaAccessProvider.class) { return (T) getRuntime(); } if (clazz == DisassemblerProvider.class || clazz == BytecodeDisassemblerProvider.class) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsInstaller.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,63 @@ +/* + * 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; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.replacements.*; + +/** + * Filters certain method substitutions based on whether there is underlying hardware support for them. + */ +public class HotSpotReplacementsInstaller extends ReplacementsInstaller { + + private final HotSpotVMConfig config; + + public HotSpotReplacementsInstaller(HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) { + super(runtime, assumptions, target); + this.config = runtime.config; + } + + @Override + protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { + if (substituteMethod.getDeclaringClass() == IntegerSubstitutions.class || substituteMethod.getDeclaringClass() == LongSubstitutions.class) { + if (substituteMethod.getName().equals("bitCount")) { + if (!config.usePopCountInstruction) { + return; + } + } + } 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.installMethodSubstitution(originalMethod, substituteMethod); + } +}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSnippetInstaller.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +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; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.snippets.*; -import com.oracle.graal.snippets.*; - -/** - * Filters certain intrinsifications based on whether there is underlying hardware support for them. - */ -public class HotSpotSnippetInstaller extends SnippetInstaller { - - private final HotSpotVMConfig config; - - public HotSpotSnippetInstaller(HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target); - this.config = runtime.config; - } - - @Override - protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { - if (substituteMethod.getDeclaringClass() == IntegerSubstitutions.class || substituteMethod.getDeclaringClass() == LongSubstitutions.class) { - if (substituteMethod.getName().equals("bitCount")) { - if (!config.usePopCountInstruction) { - return; - } - } - } 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.installMethodSubstitution(originalMethod, substituteMethod); - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Mar 21 11:09:19 2013 +0100 @@ -47,7 +47,7 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.printer.*; -import com.oracle.graal.snippets.*; +import com.oracle.graal.replacements.*; /** * Exits from the HotSpot VM into Java code. @@ -136,7 +136,7 @@ if (GraalOptions.Debug) { Debug.enable(); - if (GraalOptions.DebugSnippets) { + if (GraalOptions.DebugReplacements) { DebugEnvironment.initialize(log); } } @@ -144,23 +144,23 @@ // Install intrinsics. final HotSpotRuntime runtime = graalRuntime.getCapability(HotSpotRuntime.class); if (GraalOptions.Intrinsify) { - Debug.scope("InstallSnippets", new Object[]{new DebugDumpScope("InstallSnippets")}, new Runnable() { + Debug.scope("InstallReplacements", new Object[]{new DebugDumpScope("InstallReplacements")}, new Runnable() { @Override public void run() { - // Snippets cannot have speculative optimizations since they have to be valid - // for the entire run of the VM. + // Replacements cannot have speculative optimizations since they have + // to be valid for the entire run of the VM. Assumptions assumptions = new Assumptions(false); - SnippetInstaller installer = new HotSpotSnippetInstaller(runtime, assumptions, runtime.getGraalRuntime().getTarget()); + ReplacementsInstaller installer = new HotSpotReplacementsInstaller(runtime, assumptions, runtime.getGraalRuntime().getTarget()); GraalIntrinsics.installIntrinsics(installer); - runtime.installSnippets(graalRuntime.getBackend(), installer, assumptions); + runtime.installReplacements(graalRuntime.getBackend(), installer, assumptions); } }); } - if (GraalOptions.DebugSnippets) { - phaseTransition("snippets"); + if (GraalOptions.DebugReplacements) { + phaseTransition("replacements"); } // Create compilation queue.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Thu Mar 21 11:09:19 2013 +0100 @@ -29,7 +29,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; +import com.oracle.graal.replacements.*; /** * Represents a field in a HotSpot type.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Mar 21 11:09:19 2013 +0100 @@ -30,11 +30,11 @@ import static com.oracle.graal.api.meta.Value.*; import static com.oracle.graal.graph.UnsafeAccess.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; -import static com.oracle.graal.hotspot.snippets.SystemSubstitutions.*; +import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*; import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*; import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; -import static com.oracle.graal.snippets.Log.*; -import static com.oracle.graal.snippets.MathSubstitutionsX86.*; +import static com.oracle.graal.replacements.Log.*; +import static com.oracle.graal.replacements.MathSubstitutionsX86.*; import java.lang.reflect.*; import java.util.*; @@ -57,7 +57,7 @@ import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.phases.*; -import com.oracle.graal.hotspot.snippets.*; +import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; @@ -69,13 +69,13 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; import com.oracle.graal.printer.*; -import com.oracle.graal.snippets.*; +import com.oracle.graal.replacements.*; import com.oracle.graal.word.*; /** * HotSpot implementation of {@link GraalCodeCacheProvider}. */ -public abstract class HotSpotRuntime implements GraalCodeCacheProvider, SnippetProvider, DisassemblerProvider, BytecodeDisassemblerProvider { +public abstract class HotSpotRuntime implements GraalCodeCacheProvider, DisassemblerProvider, BytecodeDisassemblerProvider { public final HotSpotVMConfig config; @@ -319,7 +319,7 @@ protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig); - public void installSnippets(Backend backend, SnippetInstaller installer, Assumptions assumptions) { + public void installReplacements(Backend backend, ReplacementsInstaller installer, Assumptions assumptions) { if (GraalOptions.IntrinsifyObjectMethods) { installer.installSubstitutions(ObjectSubstitutions.class); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -31,7 +31,7 @@ import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; -import com.oracle.graal.snippets.*; +import com.oracle.graal.replacements.*; /** * Causes the VM to exit with a description of the current Java location and an optional
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,129 @@ +/* + * 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.replacements; + +import static com.oracle.graal.hotspot.replacements.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.replacements.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.word.*; + +/** + * Substitutions for {@code com.sun.crypto.provider.AESCrypt} methods. + */ +@ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt", optional = true) +public class AESCryptSubstitutions { + + 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(); + AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl); + kOffset = UnsafeAccess.unsafe.objectFieldOffset(AESCryptClass.getDeclaredField("K")); + } catch (Exception ex) { + throw new GraalInternalError(ex); + } + } + + @MethodSubstitution(isStatic = false) + static void encryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, true); + } + + @MethodSubstitution(isStatic = false) + static void decryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, false); + } + + private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { + Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset), UNKNOWN_LOCATION).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); + if (encrypt) { + EncryptBlockStubCall.call(inAddr, outAddr, kAddr); + } else { + DecryptBlockStubCall.call(inAddr, outAddr, kAddr); + } + } + + abstract static class CryptBlockStubCall extends FixedWithNextNode implements LIRGenLowerable { + + @Input private final ValueNode in; + @Input private final ValueNode out; + @Input private final ValueNode key; + + private final Descriptor descriptor; + + public CryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key, Descriptor descriptor) { + super(StampFactory.forVoid()); + this.in = in; + this.out = out; + this.key = key; + this.descriptor = descriptor; + } + + @Override + public void generate(LIRGenerator gen) { + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); + gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key)); + } + } + + public static class EncryptBlockStubCall extends CryptBlockStubCall { + + public static final Descriptor ENCRYPT_BLOCK = new Descriptor("encrypt_block", false, void.class, Word.class, Word.class, Word.class); + + public EncryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) { + super(in, out, key, ENCRYPT_BLOCK); + } + + @NodeIntrinsic + public static native void call(Word in, Word out, Word key); + } + + public static class DecryptBlockStubCall extends CryptBlockStubCall { + + public static final Descriptor DECRYPT_BLOCK = new Descriptor("decrypt_block", false, void.class, Word.class, Word.class, Word.class); + + public DecryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) { + super(in, out, key, DECRYPT_BLOCK); + } + + @NodeIntrinsic + public static native void call(Word in, Word out, Word key); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,172 @@ +/* + * 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.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.IterableNodeType; +import com.oracle.graal.loop.phases.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.nodes.*; + +public class ArrayCopyNode extends MacroNode implements Virtualizable, IterableNodeType, Lowerable { + + public ArrayCopyNode(Invoke invoke) { + super(invoke); + } + + private ValueNode getSource() { + return arguments.get(0); + } + + private ValueNode getSourcePosition() { + return arguments.get(1); + } + + private ValueNode getDestination() { + return arguments.get(2); + } + + private ValueNode getDestinationPosition() { + return arguments.get(3); + } + + private ValueNode getLength() { + return arguments.get(4); + } + + private StructuredGraph selectSnippet(LoweringTool tool) { + ResolvedJavaType srcType = getSource().objectStamp().type(); + ResolvedJavaType destType = getDestination().objectStamp().type(); + + if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { + return null; + } + if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType()) || !getDestination().objectStamp().isExactType()) { + return null; + } + Kind componentKind = srcType.getComponentType().getKind(); + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); + return (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); + } + + private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) { + LocalNode lengthLocal = snippetGraph.getLocal(4); + if (lengthLocal != null) { + snippetGraph.replaceFloating(lengthLocal, ConstantNode.forInt(length, snippetGraph)); + } + // the canonicalization before loop unrolling is needed to propagate the length into + // additions, etc. + new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); + new LoopFullUnrollPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); + new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); + } + + private static void replaceSnippetInvokes(StructuredGraph snippetGraph, ResolvedJavaMethod targetMethod, int bci) { + for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) { + if (invoke.methodCallTarget().targetMethod() != targetMethod) { + throw new GraalInternalError("unexpected invoke in arraycopy snippet"); + } + if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) { + InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), bci)); + newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI))); + snippetGraph.replaceFixedWithFixed(invoke, newInvoke); + } else { + assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke; + } + } + } + + @Override + protected StructuredGraph getSnippetGraph(LoweringTool tool) { + if (!GraalOptions.IntrinsifyArrayCopy) { + return null; + } + + StructuredGraph snippetGraph = selectSnippet(tool); + if (snippetGraph == null) { + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet); + snippetGraph = ((StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class)).copy(); + assert snippetGraph != null : "ArrayCopySnippets should be installed"; + + replaceSnippetInvokes(snippetGraph, getTargetMethod(), getBci()); + } else { + assert snippetGraph != null : "ArrayCopySnippets should be installed"; + + if (getLength().isConstant()) { + snippetGraph = snippetGraph.copy(); + unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool); + } + } + return snippetGraph; + } + + private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { + return position >= 0 && position + length <= virtualObject.entryCount(); + } + + private static boolean checkEntryTypes(int srcPos, int length, State srcState, ResolvedJavaType destComponentType) { + if (destComponentType.getKind() == Kind.Object) { + for (int i = 0; i < length; i++) { + if (!destComponentType.isAssignableFrom(srcState.getEntry(srcPos + i).objectStamp().type())) { + return false; + } + } + } + return true; + } + + @Override + public void virtualize(VirtualizerTool tool) { + if (getSourcePosition().isConstant() && getDestinationPosition().isConstant() && getLength().isConstant()) { + int srcPos = getSourcePosition().asConstant().asInt(); + int destPos = getDestinationPosition().asConstant().asInt(); + int length = getLength().asConstant().asInt(); + State srcState = tool.getObjectState(getSource()); + State destState = tool.getObjectState(getDestination()); + + if (srcState != null && srcState.getState() == EscapeState.Virtual && destState != null && destState.getState() == EscapeState.Virtual) { + VirtualObjectNode srcVirtual = srcState.getVirtualObject(); + VirtualObjectNode destVirtual = destState.getVirtualObject(); + if (length < 0 || !checkBounds(srcPos, length, srcVirtual) || !checkBounds(destPos, length, destVirtual)) { + return; + } + if (!checkEntryTypes(srcPos, length, srcState, destVirtual.type().getComponentType())) { + return; + } + for (int i = 0; i < length; i++) { + tool.setVirtualEntry(destState, destPos + i, srcState.getEntry(srcPos + i)); + } + tool.delete(); + if (Debug.isLogEnabled()) { + Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPos, getDestination(), destPos, length); + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +@SuppressWarnings("unused") +public class ArrayCopySnippets implements Snippets { + + private static final EnumMap<Kind, Method> arraycopyMethods = new EnumMap<>(Kind.class); + public static final Method genericArraycopySnippet; + + private static void addArraycopySnippetMethod(Kind kind, Class<?> arrayClass) throws NoSuchMethodException { + arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class)); + } + + static { + try { + addArraycopySnippetMethod(Kind.Byte, byte[].class); + addArraycopySnippetMethod(Kind.Boolean, boolean[].class); + addArraycopySnippetMethod(Kind.Char, char[].class); + addArraycopySnippetMethod(Kind.Short, short[].class); + addArraycopySnippetMethod(Kind.Int, int[].class); + addArraycopySnippetMethod(Kind.Long, long[].class); + addArraycopySnippetMethod(Kind.Float, float[].class); + addArraycopySnippetMethod(Kind.Double, double[].class); + addArraycopySnippetMethod(Kind.Object, Object[].class); + genericArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class); + } catch (SecurityException | NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } + + public static Method getSnippetForKind(Kind kind) { + return arraycopyMethods.get(kind); + } + + private static final Kind VECTOR_KIND = Kind.Long; + private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); + + public static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter("baseKind") Kind baseKind) { + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); + int header = arrayBaseOffset(baseKind); + int elementSize = arrayIndexScale(baseKind); + long byteLength = (long) length * elementSize; + long nonVectorBytes = byteLength % VECTOR_SIZE; + long srcOffset = (long) srcPos * elementSize; + long destOffset = (long) destPos * elementSize; + if (src == dest && srcPos < destPos) { // bad aliased case + probability(NOT_FREQUENT_PROBABILITY); + for (long i = byteLength - elementSize; i >= byteLength - nonVectorBytes; i -= elementSize) { + UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); + } + long vectorLength = byteLength - nonVectorBytes; + for (long i = vectorLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < nonVectorBytes; i += elementSize) { + UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); + } + for (long i = nonVectorBytes; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + public static void checkNonNull(Object obj) { + if (obj == null) { + probability(DEOPT_PATH_PROBABILITY); + checkNPECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + } + + public static int checkArrayType(Word hub) { + int layoutHelper = readLayoutHelper(hub); + if (layoutHelper >= 0) { + probability(DEOPT_PATH_PROBABILITY); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + return layoutHelper; + } + + public static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) { + if (srcPos < 0) { + probability(DEOPT_PATH_PROBABILITY); + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + if (destPos < 0) { + probability(DEOPT_PATH_PROBABILITY); + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + if (length < 0) { + probability(DEOPT_PATH_PROBABILITY); + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + if (srcPos + length > ArrayLengthNode.arrayLength(src)) { + probability(DEOPT_PATH_PROBABILITY); + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + if (destPos + length > ArrayLengthNode.arrayLength(dest)) { + probability(DEOPT_PATH_PROBABILITY); + checkAIOOBECounter.inc(); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + checkSuccessCounter.inc(); + } + + @Snippet + public static void arraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { + byteCounter.inc(); + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + } + + @Snippet + public static void arraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { + booleanCounter.inc(); + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + } + + @Snippet + public static void arraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { + charCounter.inc(); + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Char); + } + + @Snippet + public static void arraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { + shortCounter.inc(); + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Short); + } + + @Snippet + public static void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { + intCounter.inc(); + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Int); + } + + @Snippet + public static void arraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { + floatCounter.inc(); + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Float); + } + + @Snippet + public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { + longCounter.inc(); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); + Kind baseKind = Kind.Long; + int header = arrayBaseOffset(baseKind); + long byteLength = (long) length * arrayIndexScale(baseKind); + long srcOffset = (long) srcPos * arrayIndexScale(baseKind); + long destOffset = (long) destPos * arrayIndexScale(baseKind); + if (src == dest && srcPos < destPos) { // bad aliased case + for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + @Snippet + public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { + doubleCounter.inc(); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); + Kind baseKind = Kind.Double; + int header = arrayBaseOffset(baseKind); + long byteLength = (long) length * arrayIndexScale(baseKind); + long srcOffset = (long) srcPos * arrayIndexScale(baseKind); + long destOffset = (long) destPos * arrayIndexScale(baseKind); + if (src == dest && srcPos < destPos) { // bad aliased case + for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + // Does NOT perform store checks + @Snippet + public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { + objectCounter.inc(); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); + final int scale = arrayIndexScale(Kind.Object); + int header = arrayBaseOffset(Kind.Object); + if (src == dest && srcPos < destPos) { // bad aliased case + long start = (long) (length - 1) * scale; + for (long i = start; i >= 0; i -= scale) { + Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); + DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); + } + } else { + long end = (long) length * scale; + for (long i = 0; i < end; i += scale) { + Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); + DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); + } + } + if (length > 0) { + int cardShift = cardTableShift(); + long cardStart = cardTableStart(); + long dstAddr = GetObjectAddressNode.get(dest); + long start = (dstAddr + header + (long) destPos * scale) >>> cardShift; + long end = (dstAddr + header + ((long) destPos + length - 1) * scale) >>> cardShift; + long count = end - start + 1; + while (count-- > 0) { + DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean); + } + } + } + + @Snippet + public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { + + // loading the hubs also checks for nullness + Word srcHub = loadHub(src); + Word destHub = loadHub(dest); + + int layoutHelper = checkArrayType(srcHub); + if (srcHub.equal(destHub) && src != dest) { + probability(FAST_PATH_PROBABILITY); + + checkLimits(src, srcPos, dest, destPos, length); + + arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); + } else { + genericObjectCallCounter.inc(); + System.arraycopy(src, srcPos, dest, destPos, length); + } + } + + public static void arraycopyInnerloop(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + + Word memory = (Word) Word.fromObject(src); + + Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize); + Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize); + Word destStart = destOffset; + long sizeInBytes = ((long) length) << log2ElementSize; + Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); + + int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE); + Word destNonVectorEnd = destStart.add(nonVectorBytes); + + while (destOffset.belowThan(destNonVectorEnd)) { + destOffset.writeByte(0, srcOffset.readByte(0, UNKNOWN_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(1); + srcOffset = srcOffset.add(1); + } + while (destOffset.belowThan(destEnd)) { + destOffset.writeWord(0, srcOffset.readWord(0, UNKNOWN_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(wordSize()); + srcOffset = srcOffset.add(wordSize()); + } + + if ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) != 0) { + genericPrimitiveCallCounter.inc(); + + } else { + probability(LIKELY_PROBABILITY); + genericObjectExactCallCounter.inc(); + + if (length > 0) { + int cardShift = cardTableShift(); + long cardStart = cardTableStart(); + Word destCardOffset = destStart.unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); + Word destCardEnd = destEnd.subtract(1).unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); + while (destCardOffset.belowOrEqual(destCardEnd)) { + DirectStoreNode.store(destCardOffset.rawValue(), false, Kind.Boolean); + destCardOffset = destCardOffset.add(1); + } + } + } + } + + private static final SnippetCounter.Group checkCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("System.arraycopy checkInputs") : null; + private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess"); + private static final SnippetCounter checkNPECounter = new SnippetCounter(checkCounters, "checkNPE", "checkNPE"); + private static final SnippetCounter checkAIOOBECounter = new SnippetCounter(checkCounters, "checkAIOOBE", "checkAIOOBE"); + + private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("System.arraycopy") : null; + private static final SnippetCounter byteCounter = new SnippetCounter(counters, "byte[]", "arraycopy for byte[] arrays"); + private static final SnippetCounter charCounter = new SnippetCounter(counters, "char[]", "arraycopy for char[] arrays"); + private static final SnippetCounter shortCounter = new SnippetCounter(counters, "short[]", "arraycopy for short[] arrays"); + private static final SnippetCounter intCounter = new SnippetCounter(counters, "int[]", "arraycopy for int[] arrays"); + private static final SnippetCounter booleanCounter = new SnippetCounter(counters, "boolean[]", "arraycopy for boolean[] arrays"); + private static final SnippetCounter longCounter = new SnippetCounter(counters, "long[]", "arraycopy for long[] arrays"); + private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays"); + private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays"); + private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays"); + private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays"); + private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays"); + private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method"); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,233 @@ +/* + * 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.replacements; + +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*; +import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; +import static com.oracle.graal.replacements.SnippetTemplate.*; +import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +/** + * Snippets used for implementing the type test of a checkcast instruction. + * + * The type tests implemented are described in the paper <a + * href="http://dl.acm.org/citation.cfm?id=583821"> Fast subtype checking in the HotSpot JVM</a> by + * Cliff Click and John Rose. + */ +public class CheckCastSnippets implements Snippets { + + @NodeIntrinsic(BreakpointNode.class) + static native void bkpt(Object object, Word hub, Word objectHub); + + // @formatter:off + + /** + * Type test used when the type being tested against is a final type. + */ + @Snippet + public static Object checkcastExact( + @Parameter("object") Object object, + @Parameter("exactHub") Word exactHub, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + probability(NOT_FREQUENT_PROBABILITY); + isNull.inc(); + } else { + Word objectHub = loadHub(object); + if (objectHub.notEqual(exactHub)) { + probability(DEOPT_PATH_PROBABILITY); + exactMiss.inc(); + //bkpt(object, exactHub, objectHub); + DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); + } + exactHit.inc(); + } + return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); + } + + /** + * Type test used when the type being tested against is a restricted primary type. + * + * This test ignores use of hints altogether as the display-based type check only + * involves one extra load where the second load should hit the same cache line as the + * first. + */ + @Snippet + public static Object checkcastPrimary( + @Parameter("hub") Word hub, + @Parameter("object") Object object, + @ConstantParameter("checkNull") boolean checkNull, + @ConstantParameter("superCheckOffset") int superCheckOffset) { + if (checkNull && object == null) { + probability(NOT_FREQUENT_PROBABILITY); + isNull.inc(); + } else { + Word objectHub = loadHub(object); + if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { + probability(DEOPT_PATH_PROBABILITY); + displayMiss.inc(); + DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); + } + displayHit.inc(); + } + return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); + } + + /** + * Type test used when the type being tested against is a restricted secondary type. + */ + @Snippet + public static Object checkcastSecondary( + @Parameter("hub") Word hub, + @Parameter("object") Object object, + @VarargsParameter("hints") Word[] hints, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + probability(NOT_FREQUENT_PROBABILITY); + isNull.inc(); + } else { + Word objectHub = loadHub(object); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hints.length; i++) { + Word hintHub = hints[i]; + if (hintHub.equal(objectHub)) { + hintsHit.inc(); + return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); + } + } + if (!checkSecondarySubType(hub, objectHub)) { + DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); + } + } + return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); + } + + /** + * Type test used when the type being tested against is not known at compile time (e.g. the type test + * in an object array store check). + */ + @Snippet + public static Object checkcastDynamic( + @Parameter("hub") Word hub, + @Parameter("object") Object object, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + probability(NOT_FREQUENT_PROBABILITY); + isNull.inc(); + } else { + Word objectHub = loadHub(object); + if (!checkUnknownSubType(hub, objectHub)) { + DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); + } + } + return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); + } + + // @formatter:on + + public static class Templates extends AbstractTemplates<CheckCastSnippets> { + + private final ResolvedJavaMethod exact; + private final ResolvedJavaMethod primary; + private final ResolvedJavaMethod secondary; + private final ResolvedJavaMethod dynamic; + + public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { + super(runtime, assumptions, target, CheckCastSnippets.class); + exact = snippet("checkcastExact", Object.class, Word.class, boolean.class); + primary = snippet("checkcastPrimary", Word.class, Object.class, boolean.class, int.class); + secondary = snippet("checkcastSecondary", Word.class, Object.class, Word[].class, boolean.class); + dynamic = snippet("checkcastDynamic", Word.class, Object.class, boolean.class); + } + + /** + * Lowers a checkcast node. + */ + public void lower(CheckCastNode checkcast, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) checkcast.graph(); + ValueNode object = checkcast.object(); + final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) checkcast.type(); + TypeCheckHints hintInfo = new TypeCheckHints(checkcast.type(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); + ValueNode hub = ConstantNode.forConstant(type.klass(), runtime, checkcast.graph()); + boolean checkNull = !object.stamp().nonNull(); + Arguments arguments; + Key key; + + assert type != null; + if (hintInfo.exact) { + ConstantNode[] hints = createHints(hintInfo, runtime, graph); + assert hints.length == 1; + key = new Key(exact).add("checkNull", checkNull); + arguments = arguments("object", object).add("exactHub", hints[0]); + } else if (type.isPrimaryType()) { + key = new Key(primary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); + arguments = arguments("hub", hub).add("object", object); + } else { + ConstantNode[] hints = createHints(hintInfo, runtime, graph); + key = new Key(secondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); + arguments = arguments("hub", hub).add("object", object).add("hints", hints); + } + + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, arguments); + template.instantiate(runtime, checkcast, DEFAULT_REPLACER, arguments); + } + + /** + * Lowers a dynamic checkcast node. + */ + public void lower(CheckCastDynamicNode checkcast) { + StructuredGraph graph = (StructuredGraph) checkcast.graph(); + ValueNode hub = checkcast.type(); + ValueNode object = checkcast.object(); + boolean checkNull = !object.stamp().nonNull(); + + Key key = new Key(dynamic).add("checkNull", checkNull); + Arguments arguments = arguments("hub", hub).add("object", object); + + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering dynamic checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, arguments); + template.instantiate(runtime, checkcast, DEFAULT_REPLACER, arguments); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,150 @@ +/* + * 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.replacements; + +import static com.oracle.graal.hotspot.replacements.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.replacements.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Substitutions for {@code com.sun.crypto.provider.CipherBlockChaining} methods. + */ +@ClassSubstitution(className = "com.sun.crypto.provider.CipherBlockChaining", optional = true) +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), UNKNOWN_LOCATION); + if (getAESCryptClass().isInstance(embeddedCipher)) { + crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); + } else { + encrypt(rcvr, in, inOffset, inLength, out, outOffset); + } + } + + private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { + Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), UNKNOWN_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), UNKNOWN_LOCATION).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); + if (encrypt) { + EncryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength); + } else { + DecryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength); + } + + } + + @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), UNKNOWN_LOCATION); + if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { + crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); + } else { + decrypt(rcvr, in, inOffset, inLength, out, outOffset); + } + } + + abstract static class AESCryptStubCall 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; + + private final Descriptor descriptor; + + public AESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength, Descriptor descriptor) { + super(StampFactory.forVoid()); + this.in = in; + this.out = out; + this.key = key; + this.r = r; + this.inLength = inLength; + this.descriptor = descriptor; + } + + @Override + public void generate(LIRGenerator gen) { + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); + gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength)); + } + } + + public static class EncryptAESCryptStubCall extends AESCryptStubCall { + + 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(in, out, key, r, inLength, ENCRYPT); + } + + @NodeIntrinsic + public static native void call(Word in, Word out, Word key, Word r, int inLength); + } + + public static class DecryptAESCryptStubCall extends AESCryptStubCall { + + 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(in, out, key, r, inLength, DECRYPT); + } + + @NodeIntrinsic + public static native void call(Word in, Word out, Word key, Word r, int inLength); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,115 @@ +/* + * 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.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; + +import java.lang.reflect.*; + +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.word.*; + +/** + * Substitutions for {@link java.lang.Class} methods. + */ +@ClassSubstitution(java.lang.Class.class) +public class ClassSubstitutions { + + @MethodSubstitution(isStatic = false) + public static int getModifiers(final Class<?> thisObj) { + Word klass = loadWordFromObject(thisObj, klassOffset()); + if (klass.equal(0)) { + // Class for primitive type + return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; + } else { + return klass.readInt(klassModifierFlagsOffset(), FINAL_LOCATION); + } + } + + @MethodSubstitution(isStatic = false) + public static boolean isInterface(final Class<?> thisObj) { + Word klass = loadWordFromObject(thisObj, klassOffset()); + if (klass.equal(0)) { + return false; + } else { + int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION); + return (accessFlags & Modifier.INTERFACE) != 0; + } + } + + @MethodSubstitution(isStatic = false) + public static boolean isArray(final Class<?> thisObj) { + Word klass = loadWordFromObject(thisObj, klassOffset()); + if (klass.equal(0)) { + return false; + } else { + return (readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0; + } + } + + @MethodSubstitution(isStatic = false) + public static boolean isPrimitive(final Class<?> thisObj) { + Word klass = loadWordFromObject(thisObj, klassOffset()); + return klass.equal(0); + } + + @MethodSubstitution(isStatic = false) + public static Class<?> getSuperclass(final Class<?> thisObj) { + Word klass = loadWordFromObject(thisObj, klassOffset()); + if (klass.notEqual(0)) { + int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION); + if ((accessFlags & Modifier.INTERFACE) == 0) { + if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) { + return Object.class; + } else { + Word superKlass = klass.readWord(klassSuperKlassOffset(), FINAL_LOCATION); + if (superKlass.equal(0)) { + return null; + } else { + return unsafeCast(superKlass.readObject(classMirrorOffset(), FINAL_LOCATION), Class.class, true, true); + } + } + } + } + return null; + } + + @MethodSubstitution(isStatic = false) + public static Class<?> getComponentType(final Class<?> thisObj) { + Word klass = loadWordFromObject(thisObj, klassOffset()); + if (klass.notEqual(0)) { + if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) { + return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset(), FINAL_LOCATION), Class.class, true, true); + } + } + return null; + } + + @MethodSubstitution(isStatic = false) + public static boolean isInstance(final Class<?> thisObj, Object obj) { + return !isPrimitive(thisObj) && ConditionalNode.materializeIsInstance(thisObj, obj); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,550 @@ +/* + * 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.replacements; + +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; +import sun.misc.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +//JaCoCo Exclude + +/** + * A collection of methods used in HotSpot snippets and substitutions. + */ +public class HotSpotSnippetUtils { + + public static final Object ANY_LOCATION = LocationNode.ANY_LOCATION; + public static final Object UNKNOWN_LOCATION = LocationNode.UNKNOWN_LOCATION; + public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION; + + public static HotSpotVMConfig config() { + return HotSpotGraalRuntime.getInstance().getConfig(); + } + + @Fold + public static boolean verifyOops() { + return config().verifyOops; + } + + public static final Object TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop"); + + @Fold + public static int threadTlabTopOffset() { + return config().threadTlabTopOffset; + } + + public static final Object TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd"); + + @Fold + private static int threadTlabEndOffset() { + return config().threadTlabEndOffset; + } + + public static final Object TLAB_START_LOCATION = LocationNode.createLocation("TlabStart"); + + @Fold + private static int threadTlabStartOffset() { + return config().threadTlabStartOffset; + } + + public static Word readTlabTop(Word thread) { + return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION); + } + + public static Word readTlabEnd(Word thread) { + return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION); + } + + public static Word readTlabStart(Word thread) { + return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION); + } + + public static void writeTlabTop(Word thread, Word top) { + thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION); + } + + public static void initializeTlab(Word thread, Word start, Word end) { + thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION); + thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION); + thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION); + } + + @Fold + public static int threadObjectOffset() { + return config().threadObjectOffset; + } + + @Fold + public static int osThreadOffset() { + return config().osThreadOffset; + } + + @Fold + public static int osThreadInterruptedOffset() { + return config().osThreadInterruptedOffset; + } + + @Fold + public static Kind wordKind() { + return HotSpotGraalRuntime.getInstance().getTarget().wordKind; + } + + @Fold + public static Register threadRegister() { + return HotSpotGraalRuntime.getInstance().getRuntime().threadRegister(); + } + + @Fold + public static Register stackPointerRegister() { + return HotSpotGraalRuntime.getInstance().getRuntime().stackPointerRegister(); + } + + @Fold + public static int wordSize() { + return HotSpotGraalRuntime.getInstance().getTarget().wordSize; + } + + @Fold + public static int pageSize() { + return Unsafe.getUnsafe().pageSize(); + } + + public static final Object PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord"); + + @Fold + public static int prototypeMarkWordOffset() { + return config().prototypeMarkWordOffset; + } + + @Fold + public static long arrayPrototypeMarkWord() { + return config().arrayPrototypeMarkWord; + } + + @Fold + public static int klassAccessFlagsOffset() { + return config().klassAccessFlagsOffset; + } + + @Fold + private static int klassLayoutHelperOffset() { + return config().klassLayoutHelperOffset; + } + + public static int readLayoutHelper(Word hub) { + return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION); + } + + @Fold + public static int arrayKlassLayoutHelperIdentifier() { + return config().arrayKlassLayoutHelperIdentifier; + } + + @Fold + public static int arrayKlassComponentMirrorOffset() { + return config().arrayKlassComponentMirrorOffset; + } + + @Fold + public static int klassSuperKlassOffset() { + return config().klassSuperKlassOffset; + } + + public static final Object MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord"); + + @Fold + public static int markOffset() { + return config().markOffset; + } + + public static final Object HUB_LOCATION = LocationNode.createLocation("Hub"); + + @Fold + private static int hubOffset() { + return config().hubOffset; + } + + public static void initializeObjectHeader(Word memory, Word markWord, Word hub) { + memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION); + memory.writeWord(hubOffset(), hub, HUB_LOCATION); + } + + @Fold + public static int unlockedMask() { + return config().unlockedMask; + } + + /** + * Mask for a biasable, locked or unlocked mark word. + * + * <pre> + * +----------------------------------+-+-+ + * | 1|1|1| + * +----------------------------------+-+-+ + * </pre> + * + */ + @Fold + public static int biasedLockMaskInPlace() { + return config().biasedLockMaskInPlace; + } + + @Fold + public static int epochMaskInPlace() { + return config().epochMaskInPlace; + } + + /** + * Pattern for a biasable, unlocked mark word. + * + * <pre> + * +----------------------------------+-+-+ + * | 1|0|1| + * +----------------------------------+-+-+ + * </pre> + * + */ + @Fold + public static int biasedLockPattern() { + return config().biasedLockPattern; + } + + @Fold + public static int ageMaskInPlace() { + return config().ageMaskInPlace; + } + + @Fold + public static int metaspaceArrayLengthOffset() { + return config().metaspaceArrayLengthOffset; + } + + @Fold + public static int metaspaceArrayBaseOffset() { + return config().metaspaceArrayBaseOffset; + } + + @Fold + public static int arrayLengthOffset() { + return config().arrayLengthOffset; + } + + @Fold + public static int arrayBaseOffset(Kind elementKind) { + return HotSpotRuntime.getArrayBaseOffset(elementKind); + } + + @Fold + public static int arrayIndexScale(Kind elementKind) { + return HotSpotRuntime.getArrayIndexScale(elementKind); + } + + @Fold + public static int cardTableShift() { + return config().cardtableShift; + } + + @Fold + public static long cardTableStart() { + return config().cardtableStartAddress; + } + + @Fold + public static int superCheckOffsetOffset() { + return config().superCheckOffsetOffset; + } + + public static final Object SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache"); + + @Fold + public static int secondarySuperCacheOffset() { + return config().secondarySuperCacheOffset; + } + + public static final Object SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers"); + + @Fold + public static int secondarySupersOffset() { + return config().secondarySupersOffset; + } + + public static final Object DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord"); + + @Fold + public static int lockDisplacedMarkOffset() { + return config().basicLockDisplacedHeaderOffset; + } + + @Fold + public static boolean useBiasedLocking() { + return config().useBiasedLocking; + } + + @Fold + static int uninitializedIdentityHashCodeValue() { + return config().uninitializedIdentityHashCodeValue; + } + + @Fold + static int identityHashCodeShift() { + return config().identityHashCodeShift; + } + + /** + * Loads the hub from a object, null checking it first. + */ + public static Word loadHub(Object object) { + return loadHubIntrinsic(object, wordKind()); + } + + public static Object verifyOop(Object object) { + if (verifyOops()) { + VerifyOopStubCall.call(object); + } + return object; + } + + /** + * Gets the value of the stack pointer register as a Word. + */ + public static Word stackPointer() { + return HotSpotSnippetUtils.registerAsWord(stackPointerRegister(), true, false); + } + + /** + * Gets the value of the thread register as a Word. + */ + public static Word thread() { + return HotSpotSnippetUtils.registerAsWord(threadRegister(), true, false); + } + + public static Word loadWordFromObject(Object object, int offset) { + return loadWordFromObjectIntrinsic(object, 0, offset, wordKind()); + } + + @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true) + public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming); + + @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) + private static native Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); + + @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true) + static native Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word); + + @Fold + public static int log2WordSize() { + return CodeUtil.log2(wordSize()); + } + + public static final Object CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState"); + + @Fold + public static int klassStateOffset() { + return config().klassStateOffset; + } + + @Fold + public static int klassStateFullyInitialized() { + return config().klassStateFullyInitialized; + } + + @Fold + public static int klassModifierFlagsOffset() { + return config().klassModifierFlagsOffset; + } + + @Fold + public static int klassOffset() { + return config().klassOffset; + } + + @Fold + public static int classMirrorOffset() { + return config().classMirrorOffset; + } + + @Fold + public static int klassInstanceSizeOffset() { + return config().klassInstanceSizeOffset; + } + + public static final Object HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop"); + + @Fold + public static long heapTopAddress() { + return config().heapTopAddress; + } + + public static final Object HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd"); + + @Fold + public static long heapEndAddress() { + return config().heapEndAddress; + } + + @Fold + public static long tlabIntArrayMarkWord() { + return config().tlabIntArrayMarkWord; + } + + @Fold + public static boolean inlineContiguousAllocationSupported() { + return config().inlineContiguousAllocationSupported; + } + + @Fold + public static int tlabAlignmentReserveInHeapWords() { + return config().tlabAlignmentReserve; + } + + public static final Object TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize"); + + @Fold + public static int threadTlabSizeOffset() { + return config().threadTlabSizeOffset; + } + + public static final Object TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes"); + + @Fold + public static int threadAllocatedBytesOffset() { + return config().threadAllocatedBytesOffset; + } + + public static final Object TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit"); + + @Fold + public static int tlabRefillWasteLimitOffset() { + return config().tlabRefillWasteLimitOffset; + } + + public static final Object TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills"); + + @Fold + public static int tlabNumberOfRefillsOffset() { + return config().tlabNumberOfRefillsOffset; + } + + public static final Object TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste"); + + @Fold + public static int tlabFastRefillWasteOffset() { + return config().tlabFastRefillWasteOffset; + } + + public static final Object TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations"); + + @Fold + public static int tlabSlowAllocationsOffset() { + return config().tlabSlowAllocationsOffset; + } + + @Fold + public static int tlabRefillWasteIncrement() { + return config().tlabRefillWasteIncrement; + } + + @Fold + public static boolean tlabStats() { + return config().tlabStats; + } + + @Fold + public static int layoutHelperOffset() { + return config().layoutHelperOffset; + } + + @Fold + public static int layoutHelperHeaderSizeShift() { + return config().layoutHelperHeaderSizeShift; + } + + @Fold + public static int layoutHelperHeaderSizeMask() { + return config().layoutHelperHeaderSizeMask; + } + + @Fold + public static int layoutHelperLog2ElementSizeShift() { + return config().layoutHelperLog2ElementSizeShift; + } + + @Fold + public static int layoutHelperLog2ElementSizeMask() { + return config().layoutHelperLog2ElementSizeMask; + } + + @Fold + public static int layoutHelperElementTypeShift() { + return config().layoutHelperElementTypeShift; + } + + @Fold + public static int layoutHelperElementTypeMask() { + return config().layoutHelperElementTypeMask; + } + + @Fold + public static int layoutHelperElementTypePrimitiveInPlace() { + return config().layoutHelperElementTypePrimitiveInPlace; + } + + static { + assert arrayIndexScale(Kind.Byte) == 1; + assert arrayIndexScale(Kind.Boolean) == 1; + assert arrayIndexScale(Kind.Char) == 2; + assert arrayIndexScale(Kind.Short) == 2; + assert arrayIndexScale(Kind.Int) == 4; + assert arrayIndexScale(Kind.Long) == 8; + assert arrayIndexScale(Kind.Float) == 4; + assert arrayIndexScale(Kind.Double) == 8; + } + + static int computeHashCode(Object x) { + Word mark = loadWordFromObject(x, markOffset()); + + // this code is independent from biased locking (although it does not look that way) + final Word biasedLock = mark.and(biasedLockMaskInPlace()); + if (biasedLock.equal(Word.unsigned(unlockedMask()))) { + probability(FAST_PATH_PROBABILITY); + int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue(); + if (hash != uninitializedIdentityHashCodeValue()) { + probability(FAST_PATH_PROBABILITY); + return hash; + } + } + + return IdentityHashCodeStubCall.call(x); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,222 @@ +/* + * 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.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*; +import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.SnippetTemplate.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +/** + * Snippets used for implementing the type test of an instanceof instruction. Since instanceof is a + * floating node, it is lowered separately for each of its usages. + * + * The type tests implemented are described in the paper <a + * href="http://dl.acm.org/citation.cfm?id=583821"> Fast subtype checking in the HotSpot JVM</a> by + * Cliff Click and John Rose. + */ +public class InstanceOfSnippets implements Snippets { + + // @formatter:off + + /** + * A test against a final type. + */ + @Snippet + public static Object instanceofExact( + @Parameter("object") Object object, + @Parameter("exactHub") Word exactHub, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + probability(NOT_FREQUENT_PROBABILITY); + isNull.inc(); + return falseValue; + } + Word objectHub = loadHub(object); + if (objectHub.notEqual(exactHub)) { + probability(LIKELY_PROBABILITY); + exactMiss.inc(); + return falseValue; + } + exactHit.inc(); + return trueValue; + } + + /** + * A test against a primary type. + */ + @Snippet + public static Object instanceofPrimary( + @Parameter("hub") Word hub, + @Parameter("object") Object object, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @ConstantParameter("checkNull") boolean checkNull, + @ConstantParameter("superCheckOffset") int superCheckOffset) { + if (checkNull && object == null) { + probability(NOT_FREQUENT_PROBABILITY); + isNull.inc(); + return falseValue; + } + Word objectHub = loadHub(object); + if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { + probability(NOT_LIKELY_PROBABILITY); + displayMiss.inc(); + return falseValue; + } + displayHit.inc(); + return trueValue; + } + + /** + * A test against a restricted secondary type type. + */ + @Snippet + public static Object instanceofSecondary( + @Parameter("hub") Word hub, + @Parameter("object") Object object, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @VarargsParameter("hints") Word[] hints, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + probability(NOT_FREQUENT_PROBABILITY); + isNull.inc(); + return falseValue; + } + Word objectHub = loadHub(object); + // if we get an exact match: succeed immediately + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < hints.length; i++) { + Word hintHub = hints[i]; + if (hintHub.equal(objectHub)) { + probability(NOT_FREQUENT_PROBABILITY); + hintsHit.inc(); + return trueValue; + } + } + if (!checkSecondarySubType(hub, objectHub)) { + return falseValue; + } + return trueValue; + } + + /** + * Type test used when the type being tested against is not known at compile time. + */ + @Snippet + public static Object instanceofDynamic( + @Parameter("mirror") Class mirror, + @Parameter("object") Object object, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + probability(NOT_FREQUENT_PROBABILITY); + isNull.inc(); + return falseValue; + } + + Word hub = loadWordFromObject(mirror, klassOffset()); + Word objectHub = loadHub(object); + if (!checkUnknownSubType(hub, objectHub)) { + return falseValue; + } + return trueValue; + } + + // @formatter:on + + public static class Templates extends InstanceOfSnippetsTemplates<InstanceOfSnippets> { + + private final ResolvedJavaMethod instanceofExact; + private final ResolvedJavaMethod instanceofPrimary; + private final ResolvedJavaMethod instanceofSecondary; + private final ResolvedJavaMethod instanceofDynamic; + + public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { + super(runtime, assumptions, target, InstanceOfSnippets.class); + instanceofExact = snippet("instanceofExact", Object.class, Word.class, Object.class, Object.class, boolean.class); + instanceofPrimary = snippet("instanceofPrimary", Word.class, Object.class, Object.class, Object.class, boolean.class, int.class); + instanceofSecondary = snippet("instanceofSecondary", Word.class, Object.class, Object.class, Object.class, Word[].class, boolean.class); + instanceofDynamic = snippet("instanceofDynamic", Class.class, Object.class, Object.class, Object.class, boolean.class); + } + + @Override + protected KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) { + if (replacer.instanceOf instanceof InstanceOfNode) { + InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf; + ValueNode trueValue = replacer.trueValue; + ValueNode falseValue = replacer.falseValue; + ValueNode object = instanceOf.object(); + TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints); + final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type(); + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph()); + boolean checkNull = !object.stamp().nonNull(); + Arguments arguments; + Key key; + if (hintInfo.exact) { + ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); + assert hints.length == 1; + key = new Key(instanceofExact).add("checkNull", checkNull); + arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue); + } else if (type.isPrimaryType()) { + key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); + arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); + } else { + ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); + key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); + arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue); + } + return new KeyAndArguments(key, arguments); + } else { + assert replacer.instanceOf instanceof InstanceOfDynamicNode; + InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf; + ValueNode trueValue = replacer.trueValue; + ValueNode falseValue = replacer.falseValue; + ValueNode object = instanceOf.object(); + ValueNode mirror = instanceOf.mirror(); + boolean checkNull = !object.stamp().nonNull(); + Key key = new Key(instanceofDynamic).add("checkNull", checkNull); + Arguments arguments = arguments("mirror", mirror).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); + return new KeyAndArguments(key, arguments); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,544 @@ +/* + * 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.replacements; + +import static com.oracle.graal.hotspot.nodes.BeginLockScopeNode.*; +import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; +import static com.oracle.graal.hotspot.nodes.EndLockScopeNode.*; +import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.replacements.SnippetTemplate.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Snippets used for implementing the monitorenter and monitorexit instructions. + * + * The locking algorithm used is described in the paper <a + * href="http://dl.acm.org/citation.cfm?id=1167515.1167496"> Eliminating synchronization-related + * atomic operations with biased locking and bulk rebiasing</a> by Kenneth Russell and David + * Detlefs. + */ +public class MonitorSnippets implements Snippets { + + /** + * Monitor operations on objects whose type contains this substring will be traced. + */ + private static final String TRACE_TYPE_FILTER = System.getProperty("graal.monitors.trace.typeFilter"); + + /** + * Monitor operations in methods whose fully qualified name contains this substring will be + * traced. + */ + private static final String TRACE_METHOD_FILTER = System.getProperty("graal.monitors.trace.methodFilter"); + + public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced"); + + @Snippet + public static void monitorenter(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("trace") boolean trace) { + verifyOop(object); + + if (checkNull && object == null) { + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); + } + + // Load the mark word - this includes a null-check on object + final Word mark = loadWordFromObject(object, markOffset()); + + final Word lock = beginLockScope(false); + + trace(trace, " object: 0x%016lx\n", Word.fromObject(object)); + trace(trace, " lock: 0x%016lx\n", lock); + trace(trace, " mark: 0x%016lx\n", mark); + + incCounter(); + + if (useBiasedLocking()) { + // See whether the lock is currently biased toward our thread and + // whether the epoch is still valid. + // Note that the runtime guarantees sufficient alignment of JavaThread + // pointers to allow age to be placed into low bits. + final Word biasableLockBits = mark.and(biasedLockMaskInPlace()); + + // First check to see whether biasing is enabled for this object + if (biasableLockBits.notEqual(Word.unsigned(biasedLockPattern()))) { + // Biasing not enabled -> fall through to lightweight locking + } else { + probability(FREQUENT_PROBABILITY); + // The bias pattern is present in the object's mark word. Need to check + // whether the bias owner and the epoch are both still current. + Word hub = loadHub(object); + final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); + final Word thread = thread(); + final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace()); + trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord); + trace(trace, " thread: 0x%016lx\n", thread); + trace(trace, " tmp: 0x%016lx\n", tmp); + if (tmp.equal(0)) { + // Object is already biased to current thread -> done + probability(FREQUENT_PROBABILITY); + traceObject(trace, "+lock{bias:existing}", object); + return; + } + + // At this point we know that the mark word has the bias pattern and + // that we are not the bias owner in the current epoch. We need to + // figure out more details about the state of the mark word in order to + // know what operations can be legally performed on the object's + // mark word. + + // If the low three bits in the xor result aren't clear, that means + // the prototype header is no longer biasable and we have to revoke + // the bias on this object. + if (tmp.and(biasedLockMaskInPlace()).equal(0)) { + probability(FREQUENT_PROBABILITY); + // Biasing is still enabled for object's type. See whether the + // epoch of the current bias is still valid, meaning that the epoch + // bits of the mark word are equal to the epoch bits of the + // prototype mark word. (Note that the prototype mark word's epoch bits + // only change at a safepoint.) If not, attempt to rebias the object + // toward the current thread. Note that we must be absolutely sure + // that the current epoch is invalid in order to do this because + // otherwise the manipulations it performs on the mark word are + // illegal. + if (tmp.and(epochMaskInPlace()).equal(0)) { + probability(FREQUENT_PROBABILITY); + // The epoch of the current bias is still valid but we know nothing + // about the owner; it might be set or it might be clear. Try to + // acquire the bias of the object using an atomic operation. If this + // fails we will go in to the runtime to revoke the object's bias. + // Note that we first construct the presumed unbiased header so we + // don't accidentally blow away another thread's valid bias. + Word unbiasedMark = mark.and(biasedLockMaskInPlace() | ageMaskInPlace() | epochMaskInPlace()); + Word biasedMark = unbiasedMark.or(thread); + trace(trace, " unbiasedMark: 0x%016lx\n", unbiasedMark); + trace(trace, " biasedMark: 0x%016lx\n", biasedMark); + if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark)) { + // Object is now biased to current thread -> done + traceObject(trace, "+lock{bias:acquired}", object); + return; + } + // If the biasing toward our thread failed, this means that another thread + // owns the bias and we need to revoke that bias. The revocation will occur + // in the interpreter runtime. + probability(DEOPT_PATH_PROBABILITY); + traceObject(trace, "+lock{stub:revoke}", object); + MonitorEnterStubCall.call(object, lock); + return; + } else { + // At this point we know the epoch has expired, meaning that the + // current bias owner, if any, is actually invalid. Under these + // circumstances _only_, are we allowed to use the current mark word + // value as the comparison value when doing the CAS to acquire the + // bias in the current epoch. In other words, we allow transfer of + // the bias from one thread to another directly in this situation. + Word biasedMark = prototypeMarkWord.or(thread); + trace(trace, " biasedMark: 0x%016lx\n", biasedMark); + if (compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark)) { + // Object is now biased to current thread -> done + traceObject(trace, "+lock{bias:transfer}", object); + return; + } + // If the biasing toward our thread failed, then another thread + // succeeded in biasing it toward itself and we need to revoke that + // bias. The revocation will occur in the runtime in the slow case. + probability(DEOPT_PATH_PROBABILITY); + traceObject(trace, "+lock{stub:epoch-expired}", object); + MonitorEnterStubCall.call(object, lock); + return; + } + } else { + // The prototype mark word doesn't have the bias bit set any + // more, indicating that objects of this data type are not supposed + // to be biased any more. We are going to try to reset the mark of + // this object to the prototype value and fall through to the + // CAS-based locking scheme. Note that if our CAS fails, it means + // that another thread raced us for the privilege of revoking the + // bias of this particular object, so it's okay to continue in the + // normal locking code. + Word result = compareAndSwap(object, markOffset(), mark, prototypeMarkWord, MARK_WORD_LOCATION); + + // Fall through to the normal CAS-based lock, because no matter what + // the result of the above CAS, some thread must have succeeded in + // removing the bias bit from the object's header. + + if (ENABLE_BREAKPOINT) { + bkpt(object, mark, tmp, result); + } + } + } + } + + // Create the unlocked mark word pattern + Word unlockedMark = mark.or(unlockedMask()); + trace(trace, " unlockedMark: 0x%016lx\n", unlockedMark); + + // Copy this unlocked mark word into the lock slot on the stack + lock.writeWord(lockDisplacedMarkOffset(), unlockedMark, DISPLACED_MARK_WORD_LOCATION); + + // Test if the object's mark word is unlocked, and if so, store the + // (address of) the lock slot into the object's mark word. + Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock, MARK_WORD_LOCATION); + if (currentMark.notEqual(unlockedMark)) { + trace(trace, " currentMark: 0x%016lx\n", currentMark); + // The mark word in the object header was not the same. + // Either the object is locked by another thread or is already locked + // by the current thread. The latter is true if the mark word + // is a stack pointer into the current thread's stack, i.e.: + // + // 1) (currentMark & aligned_mask) == 0 + // 2) rsp <= currentMark + // 3) currentMark <= rsp + page_size + // + // These 3 tests can be done by evaluating the following expression: + // + // (currentMark - rsp) & (aligned_mask - page_size) + // + // assuming both the stack pointer and page_size have their least + // significant 2 bits cleared and page_size is a power of 2 + final Word alignedMask = Word.unsigned(wordSize() - 1); + final Word stackPointer = stackPointer(); + if (currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0)) { + // Most likely not a recursive lock, go into a slow runtime call + probability(DEOPT_PATH_PROBABILITY); + traceObject(trace, "+lock{stub:failed-cas}", object); + MonitorEnterStubCall.call(object, lock); + return; + } else { + // Recursively locked => write 0 to the lock slot + lock.writeWord(lockDisplacedMarkOffset(), Word.zero(), DISPLACED_MARK_WORD_LOCATION); + traceObject(trace, "+lock{recursive}", object); + } + } else { + traceObject(trace, "+lock{cas}", object); + } + } + + @Snippet + public static void monitorenterEliminated() { + incCounter(); + beginLockScope(true); + } + + /** + * Calls straight out to the monitorenter stub. + */ + @Snippet + public static void monitorenterStub(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("trace") boolean trace) { + verifyOop(object); + incCounter(); + if (checkNull && object == null) { + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); + } + // BeginLockScope nodes do not read from object so a use of object + // cannot float about the null check above + final Word lock = beginLockScope(false); + traceObject(trace, "+lock{stub}", object); + MonitorEnterStubCall.call(object, lock); + } + + @Snippet + public static void monitorexit(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) { + trace(trace, " object: 0x%016lx\n", Word.fromObject(object)); + if (useBiasedLocking()) { + // Check for biased locking unlock case, which is a no-op + // Note: we do not have to check the thread ID for two reasons. + // First, the interpreter checks for IllegalMonitorStateException at + // a higher level. Second, if the bias was revoked while we held the + // lock, the object could not be rebiased toward another thread, so + // the bias bit would be clear. + final Word mark = loadWordFromObject(object, markOffset()); + trace(trace, " mark: 0x%016lx\n", mark); + if (mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern()))) { + probability(FREQUENT_PROBABILITY); + endLockScope(); + decCounter(); + traceObject(trace, "-lock{bias}", object); + return; + } + } + + final Word lock = CurrentLockNode.currentLock(); + + // Load displaced mark + final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION); + trace(trace, " displacedMark: 0x%016lx\n", displacedMark); + + if (displacedMark.equal(0)) { + // Recursive locking => done + traceObject(trace, "-lock{recursive}", object); + } else { + verifyOop(object); + // Test if object's mark word is pointing to the displaced mark word, and if so, restore + // the displaced mark in the object - if the object's mark word is not pointing to + // the displaced mark word, do unlocking via runtime call. + if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock)) { + // The object's mark word was not pointing to the displaced header, + // we do unlocking via runtime call. + probability(DEOPT_PATH_PROBABILITY); + traceObject(trace, "-lock{stub}", object); + MonitorExitStubCall.call(object); + } else { + traceObject(trace, "-lock{cas}", object); + } + } + endLockScope(); + decCounter(); + } + + /** + * Calls straight out to the monitorexit stub. + */ + @Snippet + public static void monitorexitStub(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) { + verifyOop(object); + traceObject(trace, "-lock{stub}", object); + MonitorExitStubCall.call(object); + endLockScope(); + decCounter(); + } + + @Snippet + public static void monitorexitEliminated() { + endLockScope(); + decCounter(); + } + + private static void traceObject(boolean enabled, String action, Object object) { + if (enabled) { + Log.print(action); + Log.print(' '); + Log.printlnObject(object); + } + } + + private static void trace(boolean enabled, String format, WordBase value) { + if (enabled) { + Log.printf(format, value.rawValue()); + } + } + + /** + * Leaving the breakpoint code in to provide an example of how to use the {@link BreakpointNode} + * intrinsic. + */ + private static final boolean ENABLE_BREAKPOINT = false; + + private static final Object MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter"); + + @NodeIntrinsic(BreakpointNode.class) + static native void bkpt(Object object, Word mark, Word tmp, Word value); + + private static void incCounter() { + if (CHECK_BALANCED_MONITORS) { + final Word counter = MonitorCounterNode.counter(); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION); + } + } + + private static void decCounter() { + if (CHECK_BALANCED_MONITORS) { + final Word counter = MonitorCounterNode.counter(); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION); + } + } + + @Snippet + private static void initCounter() { + final Word counter = MonitorCounterNode.counter(); + counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION); + } + + @Snippet + private static void checkCounter(String errMsg) { + final Word counter = MonitorCounterNode.counter(); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + if (count != 0) { + vmError(errMsg, count); + } + } + + public static class Templates extends AbstractTemplates<MonitorSnippets> { + + private final ResolvedJavaMethod monitorenter; + private final ResolvedJavaMethod monitorexit; + private final ResolvedJavaMethod monitorenterStub; + private final ResolvedJavaMethod monitorexitStub; + private final ResolvedJavaMethod monitorenterEliminated; + private final ResolvedJavaMethod monitorexitEliminated; + private final ResolvedJavaMethod initCounter; + private final ResolvedJavaMethod checkCounter; + private final boolean useFastLocking; + + public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target, boolean useFastLocking) { + super(runtime, assumptions, target, MonitorSnippets.class); + monitorenter = snippet("monitorenter", Object.class, boolean.class, boolean.class); + monitorexit = snippet("monitorexit", Object.class, boolean.class); + monitorenterStub = snippet("monitorenterStub", Object.class, boolean.class, boolean.class); + monitorexitStub = snippet("monitorexitStub", Object.class, boolean.class); + monitorenterEliminated = snippet("monitorenterEliminated"); + monitorexitEliminated = snippet("monitorexitEliminated"); + initCounter = snippet("initCounter"); + checkCounter = snippet("checkCounter", String.class); + this.useFastLocking = useFastLocking; + } + + public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) monitorenterNode.graph(); + + checkBalancedMonitors(graph); + + FrameState stateAfter = monitorenterNode.stateAfter(); + boolean eliminated = monitorenterNode.eliminated(); + ResolvedJavaMethod method = eliminated ? monitorenterEliminated : useFastLocking ? monitorenter : monitorenterStub; + boolean checkNull = !monitorenterNode.object().stamp().nonNull(); + Key key = new Key(method); + if (method != monitorenterEliminated) { + key.add("checkNull", checkNull); + } + if (!eliminated) { + key.add("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); + } + + Arguments arguments = new Arguments(); + if (!eliminated) { + arguments.add("object", monitorenterNode.object()); + } + SnippetTemplate template = cache.get(key, assumptions); + Map<Node, Node> nodes = template.instantiate(runtime, monitorenterNode, DEFAULT_REPLACER, arguments); + for (Node n : nodes.values()) { + if (n instanceof BeginLockScopeNode) { + BeginLockScopeNode begin = (BeginLockScopeNode) n; + begin.setStateAfter(stateAfter); + } + } + } + + public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) monitorexitNode.graph(); + FrameState stateAfter = monitorexitNode.stateAfter(); + boolean eliminated = monitorexitNode.eliminated(); + ResolvedJavaMethod method = eliminated ? monitorexitEliminated : useFastLocking ? monitorexit : monitorexitStub; + Key key = new Key(method); + if (!eliminated) { + key.add("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); + } + Arguments arguments = new Arguments(); + if (!eliminated) { + arguments.add("object", monitorexitNode.object()); + } + SnippetTemplate template = cache.get(key, assumptions); + Map<Node, Node> nodes = template.instantiate(runtime, monitorexitNode, DEFAULT_REPLACER, arguments); + for (Node n : nodes.values()) { + if (n instanceof EndLockScopeNode) { + EndLockScopeNode end = (EndLockScopeNode) n; + end.setStateAfter(stateAfter); + } + } + } + + static boolean isTracingEnabledForType(ValueNode object) { + ResolvedJavaType type = object.objectStamp().type(); + if (TRACE_TYPE_FILTER == null) { + return false; + } else { + if (TRACE_TYPE_FILTER.length() == 0) { + return true; + } + if (type == null) { + return false; + } + return (type.getName().contains(TRACE_TYPE_FILTER)); + } + } + + static boolean isTracingEnabledForMethod(ResolvedJavaMethod method) { + if (TRACE_METHOD_FILTER == null) { + return false; + } else { + if (TRACE_METHOD_FILTER.length() == 0) { + return true; + } + if (method == null) { + return false; + } + return (MetaUtil.format("%H.%n", method).contains(TRACE_METHOD_FILTER)); + } + } + + /** + * If balanced monitor checking is enabled then nodes are inserted at the start and all + * return points of the graph to initialize and check the monitor counter respectively. + */ + private void checkBalancedMonitors(StructuredGraph graph) { + if (CHECK_BALANCED_MONITORS) { + NodeIterable<MonitorCounterNode> nodes = graph.getNodes().filter(MonitorCounterNode.class); + if (nodes.isEmpty()) { + // Only insert the nodes if this is the first monitorenter being lowered. + JavaType returnType = initCounter.getSignature().getReturnType(initCounter.getDeclaringClass()); + MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, initCounter, new ValueNode[0], returnType)); + InvokeNode invoke = graph.add(new InvokeNode(callTarget, 0)); + invoke.setStateAfter(graph.start().stateAfter()); + graph.addAfterFixed(graph.start(), invoke); + StructuredGraph inlineeGraph = (StructuredGraph) initCounter.getCompilerStorage().get(Graph.class); + InliningUtil.inline(invoke, inlineeGraph, false); + + List<ReturnNode> rets = graph.getNodes().filter(ReturnNode.class).snapshot(); + for (ReturnNode ret : rets) { + returnType = checkCounter.getSignature().getReturnType(checkCounter.getDeclaringClass()); + Object msg = ((HotSpotRuntime) runtime).registerGCRoot("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d"); + ConstantNode errMsg = ConstantNode.forObject(msg, runtime, graph); + callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter, new ValueNode[]{errMsg}, returnType)); + invoke = graph.add(new InvokeNode(callTarget, 0)); + List<ValueNode> stack = Collections.emptyList(); + FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false); + invoke.setStateAfter(graph.add(stateAfter)); + graph.addBeforeFixed(ret, invoke); + inlineeGraph = (StructuredGraph) checkCounter.getCompilerStorage().get(Graph.class); + InliningUtil.inline(invoke, inlineeGraph, false); + } + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,386 @@ +/* + * 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.replacements; + +import static com.oracle.graal.api.code.UnsignedMath.*; +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*; +import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; +import static com.oracle.graal.replacements.Snippet.Varargs.*; +import static com.oracle.graal.replacements.SnippetTemplate.*; +import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; +import static com.oracle.graal.replacements.nodes.ExplodeLoopNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +/** + * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY. + */ +public class NewObjectSnippets implements Snippets { + + // @formatter:off + + @Snippet + public static Word allocate(@Parameter("size") int size) { + Word thread = thread(); + Word top = readTlabTop(thread); + Word end = readTlabEnd(thread); + Word newTop = top.add(size); + // this check might lead to problems if the TLAB is within 16GB of the address space end (checked in c++ code) + if (newTop.belowOrEqual(end)) { + probability(FAST_PATH_PROBABILITY); + writeTlabTop(thread, newTop); + return top; + } + return Word.zero(); + } + + @Snippet + public static Object initializeObject( + @Parameter("memory") Word memory, + @Parameter("hub") Word hub, + @Parameter("prototypeMarkWord") Word prototypeMarkWord, + @ConstantParameter("size") int size, + @ConstantParameter("fillContents") boolean fillContents, + @ConstantParameter("locked") boolean locked) { + + Object result; + if (memory.equal(0)) { + new_stub.inc(); + result = NewInstanceStubCall.call(hub); + } else { + probability(FAST_PATH_PROBABILITY); + if (locked) { + formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents); + } else { + formatObject(hub, size, memory, prototypeMarkWord, fillContents); + } + result = memory.toObject(); + } + return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic()); + } + + @Snippet + public static Object initializeArray( + @Parameter("memory") Word memory, + @Parameter("hub") Word hub, + @Parameter("length") int length, + @Parameter("allocationSize") int allocationSize, + @Parameter("prototypeMarkWord") Word prototypeMarkWord, + @ConstantParameter("headerSize") int headerSize, + @ConstantParameter("fillContents") boolean fillContents, + @ConstantParameter("locked") boolean locked) { + if (locked) { + return initializeArray(memory, hub, length, allocationSize, thread().or(biasedLockPattern()), headerSize, fillContents); + } else { + return initializeArray(memory, hub, length, allocationSize, prototypeMarkWord, headerSize, fillContents); + } + } + + private static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, int headerSize, boolean fillContents) { + Object result; + if (memory.equal(0)) { + newarray_stub.inc(); + result = NewArrayStubCall.call(hub, length); + } else { + probability(FAST_PATH_PROBABILITY); + newarray_loopInit.inc(); + formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents); + result = memory.toObject(); + } + return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); + } + + /** + * Maximum array length for which fast path allocation is used. + */ + public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; + + @Snippet + public static Object allocateArrayAndInitialize( + @Parameter("length") int length, + @ConstantParameter("alignment") int alignment, + @ConstantParameter("headerSize") int headerSize, + @ConstantParameter("log2ElementSize") int log2ElementSize, + @ConstantParameter("type") ResolvedJavaType type) { + if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { + probability(DEOPT_PATH_PROBABILITY); + // This handles both negative array sizes and very large array sizes + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + Word memory = TLABAllocateNode.allocateVariableSize(allocationSize); + return InitializeArrayNode.initialize(memory, length, allocationSize, type, true, false); + } + + /** + * Computes the size of the memory chunk allocated for an array. This size accounts for the array + * header size, boy size and any padding after the last element to satisfy object alignment requirements. + * + * @param length the number of elements in the array + * @param alignment the object alignment requirement + * @param headerSize the size of the array header + * @param log2ElementSize log2 of the size of an element in the array + */ + public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) { + int size = (length << log2ElementSize) + headerSize + (alignment - 1); + int mask = ~(alignment - 1); + return size & mask; + } + + /** + * Calls the runtime stub for implementing MULTIANEWARRAY. + */ + @Snippet + public static Object newmultiarray( + @Parameter("hub") Word hub, + @ConstantParameter("rank") int rank, + @VarargsParameter("dimensions") int[] dimensions) { + Word dims = DimensionsNode.allocaDimsArray(rank); + ExplodeLoopNode.explodeLoop(); + for (int i = 0; i < rank; i++) { + dims.writeInt(i * 4, dimensions[i], ANY_LOCATION); + } + return NewMultiArrayStubCall.call(hub, rank, dims); + } + + /** + * Maximum size of an object whose body is initialized by a sequence of + * zero-stores to its fields. Larger objects have their bodies initialized + * in a loop. + */ + private static final int MAX_UNROLLED_OBJECT_ZEROING_SIZE = 10 * wordSize(); + + /** + * Formats some allocated memory with an object header zeroes out the rest. + */ + private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) { + Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord; + initializeObjectHeader(memory, prototypeMarkWord, hub); + if (fillContents) { + if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { + new_seqInit.inc(); + explodeLoop(); + for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { + memory.writeWord(offset, Word.zero(), ANY_LOCATION); + } + } else { + new_loopInit.inc(); + for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { + memory.writeWord(offset, Word.zero(), ANY_LOCATION); + } + } + } + } + + /** + * Formats some allocated memory with an object header zeroes out the rest. + */ + public static void formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { + memory.writeInt(arrayLengthOffset(), length, ANY_LOCATION); + // store hub last as the concurrent garbage collectors assume length is valid if hub field is not null + initializeObjectHeader(memory, prototypeMarkWord, hub); + if (fillContents) { + for (int offset = headerSize; offset < allocationSize; offset += wordSize()) { + memory.writeWord(offset, Word.zero(), ANY_LOCATION); + } + } + } + + // @formatter:on + + public static class Templates extends AbstractTemplates<NewObjectSnippets> { + + private final ResolvedJavaMethod allocate; + private final ResolvedJavaMethod initializeObject; + private final ResolvedJavaMethod initializeArray; + private final ResolvedJavaMethod allocateArrayAndInitialize; + private final ResolvedJavaMethod newmultiarray; + private final TargetDescription target; + private final boolean useTLAB; + + public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target, boolean useTLAB) { + super(runtime, assumptions, target, NewObjectSnippets.class); + this.target = target; + this.useTLAB = useTLAB; + allocate = snippet("allocate", int.class); + initializeObject = snippet("initializeObject", Word.class, Word.class, Word.class, int.class, boolean.class, boolean.class); + initializeArray = snippet("initializeArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); + allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class); + newmultiarray = snippet("newmultiarray", Word.class, int.class, int[].class); + } + + /** + * Lowers a {@link NewInstanceNode}. + */ + @SuppressWarnings("unused") + public void lower(NewInstanceNode newInstanceNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) newInstanceNode.graph(); + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass(); + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); + int size = instanceSize(type); + + ValueNode memory; + if (!useTLAB) { + memory = ConstantNode.defaultForKind(target.wordKind, graph); + } else { + ConstantNode sizeNode = ConstantNode.forInt(size, graph); + TLABAllocateNode tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); + graph.addBeforeFixed(newInstanceNode, tlabAllocateNode); + memory = tlabAllocateNode; + } + InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents(), newInstanceNode.locked())); + graph.replaceFixedWithFixed(newInstanceNode, initializeNode); + } + + /** + * Lowers a {@link NewArrayNode}. + */ + @SuppressWarnings("unused") + public void lower(NewArrayNode newArrayNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) newArrayNode.graph(); + ValueNode lengthNode = newArrayNode.length(); + TLABAllocateNode tlabAllocateNode; + ResolvedJavaType elementType = newArrayNode.elementType(); + ResolvedJavaType arrayType = elementType.getArrayClass(); + Kind elementKind = elementType.getKind(); + final int alignment = target.wordSize; + final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind); + final Integer length = lengthNode.isConstant() ? Integer.valueOf(lengthNode.asConstant().asInt()) : null; + int log2ElementSize = CodeUtil.log2(target.sizeInBytes(elementKind)); + if (!useTLAB) { + ConstantNode zero = ConstantNode.defaultForKind(target.wordKind, graph); + // value for 'size' doesn't matter as it isn't used since a stub call will be made + // anyway + // for both allocation and initialization - it just needs to be non-null + ConstantNode size = ConstantNode.forInt(-1, graph); + InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); + graph.replaceFixedWithFixed(newArrayNode, initializeNode); + } else if (length != null && belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { + // Calculate aligned size + int size = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + ConstantNode sizeNode = ConstantNode.forInt(size, graph); + tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); + graph.addBeforeFixed(newArrayNode, tlabAllocateNode); + InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); + graph.replaceFixedWithFixed(newArrayNode, initializeNode); + } else { + Key key = new Key(allocateArrayAndInitialize).add("alignment", alignment).add("headerSize", headerSize).add("log2ElementSize", log2ElementSize).add("type", arrayType); + Arguments arguments = new Arguments().add("length", lengthNode); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, arguments); + template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, arguments); + } + } + + @SuppressWarnings("unused") + public void lower(TLABAllocateNode tlabAllocateNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) tlabAllocateNode.graph(); + ValueNode size = tlabAllocateNode.size(); + Key key = new Key(allocate); + Arguments arguments = arguments("size", size); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering fastAllocate in %s: node=%s, template=%s, arguments=%s", graph, tlabAllocateNode, template, arguments); + template.instantiate(runtime, tlabAllocateNode, DEFAULT_REPLACER, arguments); + } + + @SuppressWarnings("unused") + public void lower(InitializeObjectNode initializeNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) initializeNode.graph(); + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type(); + assert !type.isArray(); + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); + int size = instanceSize(type); + Key key = new Key(initializeObject).add("size", size).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); + ValueNode memory = initializeNode.memory(); + Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); + template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); + } + + @SuppressWarnings("unused") + public void lower(InitializeArrayNode initializeNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) initializeNode.graph(); + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type(); + ResolvedJavaType elementType = type.getComponentType(); + assert elementType != null; + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); + Kind elementKind = elementType.getKind(); + final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind); + Key key = new Key(initializeArray).add("headerSize", headerSize).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); + ValueNode memory = initializeNode.memory(); + Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()).add("allocationSize", initializeNode.allocationSize()).add("length", + initializeNode.length()); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); + template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); + } + + @SuppressWarnings("unused") + public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) newmultiarrayNode.graph(); + int rank = newmultiarrayNode.dimensionCount(); + ValueNode[] dims = new ValueNode[rank]; + for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) { + dims[i] = newmultiarrayNode.dimension(i); + } + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type(); + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); + Key key = new Key(newmultiarray).add("dimensions", vargargs(new int[rank], StampFactory.forKind(Kind.Int))).add("rank", rank); + Arguments arguments = arguments("dimensions", dims).add("hub", hub); + SnippetTemplate template = cache.get(key, assumptions); + template.instantiate(runtime, newmultiarrayNode, DEFAULT_REPLACER, arguments); + } + + private static int instanceSize(HotSpotResolvedObjectType type) { + int size = type.instanceSize(); + assert (size % wordSize()) == 0; + assert size >= 0; + return size; + } + } + + private static final SnippetCounter.Group countersNew = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewInstance") : null; + private static final SnippetCounter new_seqInit = new SnippetCounter(countersNew, "tlabSeqInit", "TLAB alloc with unrolled zeroing"); + private static final SnippetCounter new_loopInit = new SnippetCounter(countersNew, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); + private static final SnippetCounter new_stub = new SnippetCounter(countersNew, "stub", "alloc and zeroing via stub"); + + private static final SnippetCounter.Group countersNewArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewArray") : null; + private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); + private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewArray, "stub", "alloc and zeroing via stub"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,152 @@ +/* + * 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.replacements; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.nodes.*; + +public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider { + + public ObjectCloneNode(Invoke invoke) { + super(invoke); + } + + @Override + public boolean inferStamp() { + return updateStamp(getObject().stamp()); + } + + private ValueNode getObject() { + return arguments.get(0); + } + + @Override + protected StructuredGraph getSnippetGraph(LoweringTool tool) { + if (!GraalOptions.IntrinsifyObjectClone) { + return null; + } + + ResolvedJavaType type = getObject().objectStamp().type(); + Method method; + /* + * The first condition tests if the parameter is an array, the second condition tests if the + * parameter can be an array. Otherwise, the parameter is known to be a non-array object. + */ + if (type.isArray()) { + method = ObjectCloneSnippets.arrayCloneMethod; + } else if (type == null || type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) { + method = ObjectCloneSnippets.genericCloneMethod; + } else { + method = ObjectCloneSnippets.instanceCloneMethod; + } + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method); + StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); + + assert snippetGraph != null : "ObjectCloneSnippets should be installed"; + return snippetGraph; + } + + private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) { + return metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type); + } + + private static ResolvedJavaType getConcreteType(ObjectStamp stamp, Assumptions assumptions) { + if (stamp.isExactType() || stamp.type() == null) { + return stamp.type(); + } else { + ResolvedJavaType type = stamp.type().findUniqueConcreteSubtype(); + if (type != null) { + assumptions.recordConcreteSubtype(stamp.type(), type); + } + return type; + } + } + + @Override + public void virtualize(VirtualizerTool tool) { + State originalState = tool.getObjectState(getObject()); + if (originalState != null && originalState.getState() == EscapeState.Virtual) { + VirtualObjectNode originalVirtual = originalState.getVirtualObject(); + if (isCloneableType(originalVirtual.type(), tool.getMetaAccessProvider())) { + ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()]; + for (int i = 0; i < newEntryState.length; i++) { + newEntryState[i] = originalState.getEntry(i); + } + VirtualObjectNode newVirtual = originalVirtual.duplicate(); + tool.createVirtualObject(newVirtual, newEntryState, 0); + tool.replaceWithVirtual(newVirtual); + } + } else { + ValueNode obj; + if (originalState != null) { + obj = originalState.getMaterializedValue(); + } else { + obj = tool.getReplacedValue(getObject()); + } + ResolvedJavaType type = getConcreteType(obj.objectStamp(), tool.getAssumptions()); + if (isCloneableType(type, tool.getMetaAccessProvider())) { + if (!type.isArray()) { + VirtualInstanceNode newVirtual = new VirtualInstanceNode(type); + ResolvedJavaField[] fields = newVirtual.getFields(); + + ValueNode[] state = new ValueNode[fields.length]; + final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; + for (int i = 0; i < fields.length; i++) { + state[i] = loads[i] = graph().add(new LoadFieldNode(obj, fields[i])); + } + + final StructuredGraph structuredGraph = (StructuredGraph) graph(); + tool.customAction(new Runnable() { + + public void run() { + for (LoadFieldNode load : loads) { + structuredGraph.addBeforeFixed(ObjectCloneNode.this, load); + } + } + }); + tool.createVirtualObject(newVirtual, state, 0); + tool.replaceWithVirtual(newVirtual); + } + } + } + } + + @Override + public ValueNode length() { + if (getObject() instanceof ArrayLengthProvider) { + return ((ArrayLengthProvider) getObject()).length(); + } else { + return null; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +public class ObjectCloneSnippets implements Snippets { + + public static final Method instanceCloneMethod = getCloneMethod("instanceClone"); + public static final Method arrayCloneMethod = getCloneMethod("arrayClone"); + public static final Method genericCloneMethod = getCloneMethod("genericClone"); + + private static Method getCloneMethod(String name) { + try { + return ObjectCloneSnippets.class.getDeclaredMethod(name, Object.class); + } catch (SecurityException | NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } + + private static Object instanceClone(Object src, Word hub, int layoutHelper) { + int instanceSize = layoutHelper; + Pointer memory = NewObjectSnippets.allocate(instanceSize); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); + Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false); + + memory = Word.fromObject(result); + for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { + memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); + } + + return result; + } + + private static Object arrayClone(Object src, Word hub, int layoutHelper) { + int arrayLength = ArrayLengthNode.arrayLength(src); + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); + + Pointer memory = NewObjectSnippets.allocate(sizeInBytes); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); + Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false); + + memory = Word.fromObject(result); + for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { + memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); + } + return result; + } + + private static Word getAndCheckHub(Object src) { + Word hub = loadHub(src); + if (!(src instanceof Cloneable)) { + probability(DEOPT_PATH_PROBABILITY); + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); + } + return hub; + } + + @Snippet + public static Object instanceClone(Object src) { + instanceCloneCounter.inc(); + Word hub = getAndCheckHub(src); + return instanceClone(src, hub, hub.readInt(layoutHelperOffset(), FINAL_LOCATION)); + } + + @Snippet + public static Object arrayClone(Object src) { + arrayCloneCounter.inc(); + Word hub = getAndCheckHub(src); + int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); + return arrayClone(src, hub, layoutHelper); + } + + @Snippet + public static Object genericClone(Object src) { + genericCloneCounter.inc(); + Word hub = getAndCheckHub(src); + int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); + if (layoutHelper < 0) { + probability(LIKELY_PROBABILITY); + genericArrayCloneCounter.inc(); + return arrayClone(src, hub, layoutHelper); + } else { + genericInstanceCloneCounter.inc(); + return instanceClone(src, hub, layoutHelper); + } + } + + private static final SnippetCounter.Group cloneCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Object.clone") : null; + private static final SnippetCounter instanceCloneCounter = new SnippetCounter(cloneCounters, "instanceClone", "clone snippet for instances"); + private static final SnippetCounter arrayCloneCounter = new SnippetCounter(cloneCounters, "arrayClone", "clone snippet for arrays"); + private static final SnippetCounter genericCloneCounter = new SnippetCounter(cloneCounters, "genericClone", "clone snippet for arrays and instances"); + + private static final SnippetCounter.Group genericCloneCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Object.clone generic snippet") : null; + private static final SnippetCounter genericInstanceCloneCounter = new SnippetCounter(genericCloneCounters, "genericInstanceClone", "generic clone implementation took instance path"); + private static final SnippetCounter genericArrayCloneCounter = new SnippetCounter(genericCloneCounters, "genericArrayClone", "generic clone implementation took array path"); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,52 @@ +/* + * 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.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; + +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.word.*; + +/** + * Substitutions for {@link java.lang.Object} methods. + */ +@ClassSubstitution(java.lang.Object.class) +public class ObjectSubstitutions { + + @MethodSubstitution(isStatic = false) + public static Class<?> getClass(final Object thisObj) { + Word hub = loadHub(thisObj); + return unsafeCast(hub.readObject(Word.signed(classMirrorOffset()), LocationNode.FINAL_LOCATION), Class.class, true, true); + } + + @MethodSubstitution(isStatic = false) + public static int hashCode(final Object thisObj) { + return computeHashCode(thisObj); + } + + @MacroSubstitution(macro = ObjectCloneNode.class, isStatic = false) + public static native Object clone(Object obj); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for {@link java.lang.System} methods. + */ +@ClassSubstitution(java.lang.System.class) +public class SystemSubstitutions { + + public static final Descriptor JAVA_TIME_MILLIS = new Descriptor("javaTimeMillis", false, long.class); + public static final Descriptor JAVA_TIME_NANOS = new Descriptor("javaTimeNanos", false, long.class); + + @MacroSubstitution(macro = ArrayCopyNode.class) + public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); + + @MethodSubstitution + public static long currentTimeMillis() { + return callLong(JAVA_TIME_MILLIS); + } + + @MethodSubstitution + public static long nanoTime() { + return callLong(JAVA_TIME_NANOS); + } + + @MethodSubstitution + public static int identityHashCode(Object x) { + if (x == null) { + probability(NOT_FREQUENT_PROBABILITY); + return 0; + } + + return computeHashCode(x); + } + + @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true) + public static native long callLong(@ConstantNodeParameter Descriptor descriptor); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,57 @@ +/* + * 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.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; + +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.word.*; + +/** + * Substitutions for {@link java.lang.Thread} methods. + */ +@ClassSubstitution(java.lang.Thread.class) +public class ThreadSubstitutions { + + @MethodSubstitution + public static Thread currentThread() { + return CurrentThread.get(); + } + + @MethodSubstitution(isStatic = false) + private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) { + Word rawThread = HotSpotCurrentRawThreadNode.get(); + Thread thread = (Thread) rawThread.readObject(threadObjectOffset(), FINAL_LOCATION); + if (thisObject == thread) { + Word osThread = rawThread.readWord(osThreadOffset(), FINAL_LOCATION); + boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), UNKNOWN_LOCATION) != 0; + if (!interrupted || !clearInterrupted) { + return interrupted; + } + } + + return ThreadIsInterruptedStubCall.call(thisObject, clearInterrupted) != 0; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,125 @@ +/* + * 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.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; + +/** + * Utilities and common code paths used by the type check snippets. + */ +public class TypeCheckSnippetUtils { + + public static final Object TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay"); + + static boolean checkSecondarySubType(Word t, Word s) { + // if (S.cache == T) return true + if (s.readWord(secondarySuperCacheOffset(), SECONDARY_SUPER_CACHE_LOCATION).equal(t)) { + cacheHit.inc(); + return true; + } + + return checkSelfAndSupers(t, s); + } + + static boolean checkUnknownSubType(Word t, Word s) { + // int off = T.offset + int superCheckOffset = t.readInt(superCheckOffsetOffset(), FINAL_LOCATION); + boolean primary = superCheckOffset != secondarySuperCacheOffset(); + + // if (T = S[off]) return true + if (s.readWord(superCheckOffset, TYPE_DISPLAY_LOCATION).equal(t)) { + if (primary) { + cacheHit.inc(); + } else { + displayHit.inc(); + } + return true; + } + + // if (off != &cache) return false + if (primary) { + displayMiss.inc(); + return false; + } + + return checkSelfAndSupers(t, s); + } + + private static boolean checkSelfAndSupers(Word t, Word s) { + // if (T == S) return true + if (s.equal(t)) { + T_equals_S.inc(); + return true; + } + + // if (S.scan_s_s_array(T)) { S.cache = T; return true; } + Word secondarySupers = s.readWord(secondarySupersOffset(), SECONDARY_SUPERS_LOCATION); + int length = secondarySupers.readInt(metaspaceArrayLengthOffset(), FINAL_LOCATION); + for (int i = 0; i < length; i++) { + if (t.equal(loadSecondarySupersElement(secondarySupers, i))) { + probability(NOT_LIKELY_PROBABILITY); + s.writeWord(secondarySuperCacheOffset(), t, SECONDARY_SUPER_CACHE_LOCATION); + secondariesHit.inc(); + return true; + } + } + secondariesMiss.inc(); + return false; + } + + static ConstantNode[] createHints(TypeCheckHints hints, MetaAccessProvider runtime, Graph graph) { + ConstantNode[] hintHubs = new ConstantNode[hints.types.length]; + for (int i = 0; i < hintHubs.length; i++) { + hintHubs[i] = ConstantNode.forConstant(((HotSpotResolvedObjectType) hints.types[i]).klass(), runtime, graph); + } + return hintHubs; + } + + static Word loadSecondarySupersElement(Word metaspaceArray, int index) { + return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize(), FINAL_LOCATION); + } + + private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("TypeCheck") : null; + static final SnippetCounter hintsHit = new SnippetCounter(counters, "hintsHit", "hit a hint type"); + static final SnippetCounter exactHit = new SnippetCounter(counters, "exactHit", "exact type test succeeded"); + static final SnippetCounter exactMiss = new SnippetCounter(counters, "exactMiss", "exact type test failed"); + static final SnippetCounter isNull = new SnippetCounter(counters, "isNull", "object tested was null"); + static final SnippetCounter cacheHit = new SnippetCounter(counters, "cacheHit", "secondary type cache hit"); + static final SnippetCounter secondariesHit = new SnippetCounter(counters, "secondariesHit", "secondaries scan succeeded"); + static final SnippetCounter secondariesMiss = new SnippetCounter(counters, "secondariesMiss", "secondaries scan failed"); + static final SnippetCounter displayHit = new SnippetCounter(counters, "displayHit", "primary type test succeeded"); + static final SnippetCounter displayMiss = new SnippetCounter(counters, "displayMiss", "primary type test failed"); + static final SnippetCounter T_equals_S = new SnippetCounter(counters, "T_equals_S", "object type was equal to secondary type"); + +}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.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.word.*; - -/** - * Substitutions for {@code com.sun.crypto.provider.AESCrypt} methods. - */ -@ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt", optional = true) -public class AESCryptSubstitutions { - - 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(); - AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl); - kOffset = UnsafeAccess.unsafe.objectFieldOffset(AESCryptClass.getDeclaredField("K")); - } catch (Exception ex) { - throw new GraalInternalError(ex); - } - } - - @MethodSubstitution(isStatic = false) - static void encryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, true); - } - - @MethodSubstitution(isStatic = false) - static void decryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, false); - } - - private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { - Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset), UNKNOWN_LOCATION).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); - if (encrypt) { - EncryptBlockStubCall.call(inAddr, outAddr, kAddr); - } else { - DecryptBlockStubCall.call(inAddr, outAddr, kAddr); - } - } - - abstract static class CryptBlockStubCall extends FixedWithNextNode implements LIRGenLowerable { - - @Input private final ValueNode in; - @Input private final ValueNode out; - @Input private final ValueNode key; - - private final Descriptor descriptor; - - public CryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key, Descriptor descriptor) { - super(StampFactory.forVoid()); - this.in = in; - this.out = out; - this.key = key; - this.descriptor = descriptor; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); - gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key)); - } - } - - public static class EncryptBlockStubCall extends CryptBlockStubCall { - - public static final Descriptor ENCRYPT_BLOCK = new Descriptor("encrypt_block", false, void.class, Word.class, Word.class, Word.class); - - public EncryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) { - super(in, out, key, ENCRYPT_BLOCK); - } - - @NodeIntrinsic - public static native void call(Word in, Word out, Word key); - } - - public static class DecryptBlockStubCall extends CryptBlockStubCall { - - public static final Descriptor DECRYPT_BLOCK = new Descriptor("decrypt_block", false, void.class, Word.class, Word.class, Word.class); - - public DecryptBlockStubCall(ValueNode in, ValueNode out, ValueNode key) { - super(in, out, key, DECRYPT_BLOCK); - } - - @NodeIntrinsic - public static native void call(Word in, Word out, Word key); - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +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.snippets; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.IterableNodeType; -import com.oracle.graal.loop.phases.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.snippets.nodes.*; - -public class ArrayCopyNode extends MacroNode implements Virtualizable, IterableNodeType, Lowerable { - - public ArrayCopyNode(Invoke invoke) { - super(invoke); - } - - private ValueNode getSource() { - return arguments.get(0); - } - - private ValueNode getSourcePosition() { - return arguments.get(1); - } - - private ValueNode getDestination() { - return arguments.get(2); - } - - private ValueNode getDestinationPosition() { - return arguments.get(3); - } - - private ValueNode getLength() { - return arguments.get(4); - } - - private StructuredGraph selectSnippet(LoweringTool tool) { - ResolvedJavaType srcType = getSource().objectStamp().type(); - ResolvedJavaType destType = getDestination().objectStamp().type(); - - if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { - return null; - } - if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType()) || !getDestination().objectStamp().isExactType()) { - return null; - } - Kind componentKind = srcType.getComponentType().getKind(); - ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); - return (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); - } - - private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) { - LocalNode lengthLocal = snippetGraph.getLocal(4); - if (lengthLocal != null) { - snippetGraph.replaceFloating(lengthLocal, ConstantNode.forInt(length, snippetGraph)); - } - // the canonicalization before loop unrolling is needed to propagate the length into - // additions, etc. - new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); - new LoopFullUnrollPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); - new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); - } - - private static void replaceSnippetInvokes(StructuredGraph snippetGraph, ResolvedJavaMethod targetMethod, int bci) { - for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) { - if (invoke.methodCallTarget().targetMethod() != targetMethod) { - throw new GraalInternalError("unexpected invoke in arraycopy snippet"); - } - if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) { - InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), bci)); - newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI))); - snippetGraph.replaceFixedWithFixed(invoke, newInvoke); - } else { - assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke; - } - } - } - - @Override - protected StructuredGraph getSnippetGraph(LoweringTool tool) { - if (!GraalOptions.IntrinsifyArrayCopy) { - return null; - } - - StructuredGraph snippetGraph = selectSnippet(tool); - if (snippetGraph == null) { - ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet); - snippetGraph = ((StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class)).copy(); - assert snippetGraph != null : "ArrayCopySnippets should be installed"; - - replaceSnippetInvokes(snippetGraph, getTargetMethod(), getBci()); - } else { - assert snippetGraph != null : "ArrayCopySnippets should be installed"; - - if (getLength().isConstant()) { - snippetGraph = snippetGraph.copy(); - unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool); - } - } - return snippetGraph; - } - - private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { - return position >= 0 && position + length <= virtualObject.entryCount(); - } - - private static boolean checkEntryTypes(int srcPos, int length, State srcState, ResolvedJavaType destComponentType) { - if (destComponentType.getKind() == Kind.Object) { - for (int i = 0; i < length; i++) { - if (!destComponentType.isAssignableFrom(srcState.getEntry(srcPos + i).objectStamp().type())) { - return false; - } - } - } - return true; - } - - @Override - public void virtualize(VirtualizerTool tool) { - if (getSourcePosition().isConstant() && getDestinationPosition().isConstant() && getLength().isConstant()) { - int srcPos = getSourcePosition().asConstant().asInt(); - int destPos = getDestinationPosition().asConstant().asInt(); - int length = getLength().asConstant().asInt(); - State srcState = tool.getObjectState(getSource()); - State destState = tool.getObjectState(getDestination()); - - if (srcState != null && srcState.getState() == EscapeState.Virtual && destState != null && destState.getState() == EscapeState.Virtual) { - VirtualObjectNode srcVirtual = srcState.getVirtualObject(); - VirtualObjectNode destVirtual = destState.getVirtualObject(); - if (length < 0 || !checkBounds(srcPos, length, srcVirtual) || !checkBounds(destPos, length, destVirtual)) { - return; - } - if (!checkEntryTypes(srcPos, length, srcState, destVirtual.type().getComponentType())) { - return; - } - for (int i = 0; i < length; i++) { - tool.setVirtualEntry(destState, destPos + i, srcState.getEntry(srcPos + i)); - } - tool.delete(); - if (Debug.isLogEnabled()) { - Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPos, getDestination(), destPos, length); - } - } - } - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,359 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.nodes.*; -import com.oracle.graal.word.*; - -@SuppressWarnings("unused") -public class ArrayCopySnippets implements SnippetsInterface { - - private static final EnumMap<Kind, Method> arraycopyMethods = new EnumMap<>(Kind.class); - public static final Method genericArraycopySnippet; - - private static void addArraycopySnippetMethod(Kind kind, Class<?> arrayClass) throws NoSuchMethodException { - arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class)); - } - - static { - try { - addArraycopySnippetMethod(Kind.Byte, byte[].class); - addArraycopySnippetMethod(Kind.Boolean, boolean[].class); - addArraycopySnippetMethod(Kind.Char, char[].class); - addArraycopySnippetMethod(Kind.Short, short[].class); - addArraycopySnippetMethod(Kind.Int, int[].class); - addArraycopySnippetMethod(Kind.Long, long[].class); - addArraycopySnippetMethod(Kind.Float, float[].class); - addArraycopySnippetMethod(Kind.Double, double[].class); - addArraycopySnippetMethod(Kind.Object, Object[].class); - genericArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class); - } catch (SecurityException | NoSuchMethodException e) { - throw new GraalInternalError(e); - } - } - - public static Method getSnippetForKind(Kind kind) { - return arraycopyMethods.get(kind); - } - - private static final Kind VECTOR_KIND = Kind.Long; - private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); - - public static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter("baseKind") Kind baseKind) { - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - int header = arrayBaseOffset(baseKind); - int elementSize = arrayIndexScale(baseKind); - long byteLength = (long) length * elementSize; - long nonVectorBytes = byteLength % VECTOR_SIZE; - long srcOffset = (long) srcPos * elementSize; - long destOffset = (long) destPos * elementSize; - if (src == dest && srcPos < destPos) { // bad aliased case - probability(NOT_FREQUENT_PROBABILITY); - for (long i = byteLength - elementSize; i >= byteLength - nonVectorBytes; i -= elementSize) { - UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); - } - long vectorLength = byteLength - nonVectorBytes; - for (long i = vectorLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < nonVectorBytes; i += elementSize) { - UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); - } - for (long i = nonVectorBytes; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } - } - - public static void checkNonNull(Object obj) { - if (obj == null) { - probability(DEOPT_PATH_PROBABILITY); - checkNPECounter.inc(); - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - } - - public static int checkArrayType(Word hub) { - int layoutHelper = readLayoutHelper(hub); - if (layoutHelper >= 0) { - probability(DEOPT_PATH_PROBABILITY); - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - return layoutHelper; - } - - public static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) { - if (srcPos < 0) { - probability(DEOPT_PATH_PROBABILITY); - checkAIOOBECounter.inc(); - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - if (destPos < 0) { - probability(DEOPT_PATH_PROBABILITY); - checkAIOOBECounter.inc(); - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - if (length < 0) { - probability(DEOPT_PATH_PROBABILITY); - checkAIOOBECounter.inc(); - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - if (srcPos + length > ArrayLengthNode.arrayLength(src)) { - probability(DEOPT_PATH_PROBABILITY); - checkAIOOBECounter.inc(); - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - if (destPos + length > ArrayLengthNode.arrayLength(dest)) { - probability(DEOPT_PATH_PROBABILITY); - checkAIOOBECounter.inc(); - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - checkSuccessCounter.inc(); - } - - @Snippet - public static void arraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { - byteCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); - } - - @Snippet - public static void arraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { - booleanCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); - } - - @Snippet - public static void arraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { - charCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Char); - } - - @Snippet - public static void arraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { - shortCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Short); - } - - @Snippet - public static void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { - intCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Int); - } - - @Snippet - public static void arraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { - floatCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Float); - } - - @Snippet - public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { - longCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - Kind baseKind = Kind.Long; - int header = arrayBaseOffset(baseKind); - long byteLength = (long) length * arrayIndexScale(baseKind); - long srcOffset = (long) srcPos * arrayIndexScale(baseKind); - long destOffset = (long) destPos * arrayIndexScale(baseKind); - if (src == dest && srcPos < destPos) { // bad aliased case - for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } - } - - @Snippet - public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { - doubleCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - Kind baseKind = Kind.Double; - int header = arrayBaseOffset(baseKind); - long byteLength = (long) length * arrayIndexScale(baseKind); - long srcOffset = (long) srcPos * arrayIndexScale(baseKind); - long destOffset = (long) destPos * arrayIndexScale(baseKind); - if (src == dest && srcPos < destPos) { // bad aliased case - for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } - } - - // Does NOT perform store checks - @Snippet - public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { - objectCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - final int scale = arrayIndexScale(Kind.Object); - int header = arrayBaseOffset(Kind.Object); - if (src == dest && srcPos < destPos) { // bad aliased case - long start = (long) (length - 1) * scale; - for (long i = start; i >= 0; i -= scale) { - Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); - DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); - } - } else { - long end = (long) length * scale; - for (long i = 0; i < end; i += scale) { - Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); - DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); - } - } - if (length > 0) { - int cardShift = cardTableShift(); - long cardStart = cardTableStart(); - long dstAddr = GetObjectAddressNode.get(dest); - long start = (dstAddr + header + (long) destPos * scale) >>> cardShift; - long end = (dstAddr + header + ((long) destPos + length - 1) * scale) >>> cardShift; - long count = end - start + 1; - while (count-- > 0) { - DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean); - } - } - } - - @Snippet - public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { - - // loading the hubs also checks for nullness - Word srcHub = loadHub(src); - Word destHub = loadHub(dest); - - int layoutHelper = checkArrayType(srcHub); - if (srcHub.equal(destHub) && src != dest) { - probability(FAST_PATH_PROBABILITY); - - checkLimits(src, srcPos, dest, destPos, length); - - arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); - } else { - genericObjectCallCounter.inc(); - System.arraycopy(src, srcPos, dest, destPos, length); - } - } - - public static void arraycopyInnerloop(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { - int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); - int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); - - Word memory = (Word) Word.fromObject(src); - - Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize); - Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize); - Word destStart = destOffset; - long sizeInBytes = ((long) length) << log2ElementSize; - Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); - - int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE); - Word destNonVectorEnd = destStart.add(nonVectorBytes); - - while (destOffset.belowThan(destNonVectorEnd)) { - destOffset.writeByte(0, srcOffset.readByte(0, UNKNOWN_LOCATION), ANY_LOCATION); - destOffset = destOffset.add(1); - srcOffset = srcOffset.add(1); - } - while (destOffset.belowThan(destEnd)) { - destOffset.writeWord(0, srcOffset.readWord(0, UNKNOWN_LOCATION), ANY_LOCATION); - destOffset = destOffset.add(wordSize()); - srcOffset = srcOffset.add(wordSize()); - } - - if ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) != 0) { - genericPrimitiveCallCounter.inc(); - - } else { - probability(LIKELY_PROBABILITY); - genericObjectExactCallCounter.inc(); - - if (length > 0) { - int cardShift = cardTableShift(); - long cardStart = cardTableStart(); - Word destCardOffset = destStart.unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); - Word destCardEnd = destEnd.subtract(1).unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); - while (destCardOffset.belowOrEqual(destCardEnd)) { - DirectStoreNode.store(destCardOffset.rawValue(), false, Kind.Boolean); - destCardOffset = destCardOffset.add(1); - } - } - } - } - - private static final SnippetCounter.Group checkCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("System.arraycopy checkInputs") : null; - private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess"); - private static final SnippetCounter checkNPECounter = new SnippetCounter(checkCounters, "checkNPE", "checkNPE"); - private static final SnippetCounter checkAIOOBECounter = new SnippetCounter(checkCounters, "checkAIOOBE", "checkAIOOBE"); - - private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("System.arraycopy") : null; - private static final SnippetCounter byteCounter = new SnippetCounter(counters, "byte[]", "arraycopy for byte[] arrays"); - private static final SnippetCounter charCounter = new SnippetCounter(counters, "char[]", "arraycopy for char[] arrays"); - private static final SnippetCounter shortCounter = new SnippetCounter(counters, "short[]", "arraycopy for short[] arrays"); - private static final SnippetCounter intCounter = new SnippetCounter(counters, "int[]", "arraycopy for int[] arrays"); - private static final SnippetCounter booleanCounter = new SnippetCounter(counters, "boolean[]", "arraycopy for boolean[] arrays"); - private static final SnippetCounter longCounter = new SnippetCounter(counters, "long[]", "arraycopy for long[] arrays"); - private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays"); - private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays"); - private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays"); - private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays"); - private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays"); - private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method"); - -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.api.code.DeoptimizationAction.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.hotspot.snippets.TypeCheckSnippetUtils.*; -import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; -import static com.oracle.graal.snippets.SnippetTemplate.*; -import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.Snippet.Varargs; -import com.oracle.graal.snippets.Snippet.VarargsParameter; -import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; -import com.oracle.graal.snippets.SnippetTemplate.Arguments; -import com.oracle.graal.snippets.SnippetTemplate.Key; -import com.oracle.graal.snippets.nodes.*; -import com.oracle.graal.word.*; - -/** - * Snippets used for implementing the type test of a checkcast instruction. - * - * The type tests implemented are described in the paper <a - * href="http://dl.acm.org/citation.cfm?id=583821"> Fast subtype checking in the HotSpot JVM</a> by - * Cliff Click and John Rose. - */ -public class CheckCastSnippets implements SnippetsInterface { - - @NodeIntrinsic(BreakpointNode.class) - static native void bkpt(Object object, Word hub, Word objectHub); - - // @formatter:off - - /** - * Type test used when the type being tested against is a final type. - */ - @Snippet - public static Object checkcastExact( - @Parameter("object") Object object, - @Parameter("exactHub") Word exactHub, - @ConstantParameter("checkNull") boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); - isNull.inc(); - } else { - Word objectHub = loadHub(object); - if (objectHub.notEqual(exactHub)) { - probability(DEOPT_PATH_PROBABILITY); - exactMiss.inc(); - //bkpt(object, exactHub, objectHub); - DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); - } - exactHit.inc(); - } - return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); - } - - /** - * Type test used when the type being tested against is a restricted primary type. - * - * This test ignores use of hints altogether as the display-based type check only - * involves one extra load where the second load should hit the same cache line as the - * first. - */ - @Snippet - public static Object checkcastPrimary( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @ConstantParameter("checkNull") boolean checkNull, - @ConstantParameter("superCheckOffset") int superCheckOffset) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); - isNull.inc(); - } else { - Word objectHub = loadHub(object); - if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { - probability(DEOPT_PATH_PROBABILITY); - displayMiss.inc(); - DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); - } - displayHit.inc(); - } - return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); - } - - /** - * Type test used when the type being tested against is a restricted secondary type. - */ - @Snippet - public static Object checkcastSecondary( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @VarargsParameter("hints") Word[] hints, - @ConstantParameter("checkNull") boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); - isNull.inc(); - } else { - Word objectHub = loadHub(object); - // if we get an exact match: succeed immediately - ExplodeLoopNode.explodeLoop(); - for (int i = 0; i < hints.length; i++) { - Word hintHub = hints[i]; - if (hintHub.equal(objectHub)) { - hintsHit.inc(); - return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); - } - } - if (!checkSecondarySubType(hub, objectHub)) { - DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); - } - } - return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); - } - - /** - * Type test used when the type being tested against is not known at compile time (e.g. the type test - * in an object array store check). - */ - @Snippet - public static Object checkcastDynamic( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @ConstantParameter("checkNull") boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); - isNull.inc(); - } else { - Word objectHub = loadHub(object); - if (!checkUnknownSubType(hub, objectHub)) { - DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); - } - } - return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic()); - } - - // @formatter:on - - public static class Templates extends AbstractTemplates<CheckCastSnippets> { - - private final ResolvedJavaMethod exact; - private final ResolvedJavaMethod primary; - private final ResolvedJavaMethod secondary; - private final ResolvedJavaMethod dynamic; - - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, CheckCastSnippets.class); - exact = snippet("checkcastExact", Object.class, Word.class, boolean.class); - primary = snippet("checkcastPrimary", Word.class, Object.class, boolean.class, int.class); - secondary = snippet("checkcastSecondary", Word.class, Object.class, Word[].class, boolean.class); - dynamic = snippet("checkcastDynamic", Word.class, Object.class, boolean.class); - } - - /** - * Lowers a checkcast node. - */ - public void lower(CheckCastNode checkcast, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) checkcast.graph(); - ValueNode object = checkcast.object(); - final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) checkcast.type(); - TypeCheckHints hintInfo = new TypeCheckHints(checkcast.type(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); - ValueNode hub = ConstantNode.forConstant(type.klass(), runtime, checkcast.graph()); - boolean checkNull = !object.stamp().nonNull(); - Arguments arguments; - Key key; - - assert type != null; - if (hintInfo.exact) { - ConstantNode[] hints = createHints(hintInfo, runtime, graph); - assert hints.length == 1; - key = new Key(exact).add("checkNull", checkNull); - arguments = arguments("object", object).add("exactHub", hints[0]); - } else if (type.isPrimaryType()) { - key = new Key(primary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); - arguments = arguments("hub", hub).add("object", object); - } else { - ConstantNode[] hints = createHints(hintInfo, runtime, graph); - key = new Key(secondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); - arguments = arguments("hub", hub).add("object", object).add("hints", hints); - } - - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, arguments); - template.instantiate(runtime, checkcast, DEFAULT_REPLACER, arguments); - } - - /** - * Lowers a dynamic checkcast node. - */ - public void lower(CheckCastDynamicNode checkcast) { - StructuredGraph graph = (StructuredGraph) checkcast.graph(); - ValueNode hub = checkcast.type(); - ValueNode object = checkcast.object(); - boolean checkNull = !object.stamp().nonNull(); - - Key key = new Key(dynamic).add("checkNull", checkNull); - Arguments arguments = arguments("hub", hub).add("object", object); - - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering dynamic checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, arguments); - template.instantiate(runtime, checkcast, DEFAULT_REPLACER, arguments); - } - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.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", optional = true) -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), UNKNOWN_LOCATION); - if (getAESCryptClass().isInstance(embeddedCipher)) { - crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); - } else { - encrypt(rcvr, in, inOffset, inLength, out, outOffset); - } - } - - private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { - Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), UNKNOWN_LOCATION).add(arrayBaseOffset(Kind.Byte)); - Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), UNKNOWN_LOCATION).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); - if (encrypt) { - EncryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength); - } else { - DecryptAESCryptStubCall.call(inAddr, outAddr, kAddr, rAddr, inLength); - } - - } - - @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), UNKNOWN_LOCATION); - if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { - crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); - } else { - decrypt(rcvr, in, inOffset, inLength, out, outOffset); - } - } - - abstract static class AESCryptStubCall 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; - - private final Descriptor descriptor; - - public AESCryptStubCall(ValueNode in, ValueNode out, ValueNode key, ValueNode r, ValueNode inLength, Descriptor descriptor) { - super(StampFactory.forVoid()); - this.in = in; - this.out = out; - this.key = key; - this.r = r; - this.inLength = inLength; - this.descriptor = descriptor; - } - - @Override - public void generate(LIRGenerator gen) { - RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); - gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength)); - } - } - - public static class EncryptAESCryptStubCall extends AESCryptStubCall { - - 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(in, out, key, r, inLength, ENCRYPT); - } - - @NodeIntrinsic - public static native void call(Word in, Word out, Word key, Word r, int inLength); - } - - public static class DecryptAESCryptStubCall extends AESCryptStubCall { - - 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(in, out, key, r, inLength, DECRYPT); - } - - @NodeIntrinsic - public static native void call(Word in, Word out, Word key, Word r, int inLength); - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; - -import java.lang.reflect.*; - -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; -import com.oracle.graal.word.*; - -/** - * Substitutions for {@link java.lang.Class} methods. - */ -@ClassSubstitution(java.lang.Class.class) -public class ClassSubstitutions { - - @MethodSubstitution(isStatic = false) - public static int getModifiers(final Class<?> thisObj) { - Word klass = loadWordFromObject(thisObj, klassOffset()); - if (klass.equal(0)) { - // Class for primitive type - return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; - } else { - return klass.readInt(klassModifierFlagsOffset(), FINAL_LOCATION); - } - } - - @MethodSubstitution(isStatic = false) - public static boolean isInterface(final Class<?> thisObj) { - Word klass = loadWordFromObject(thisObj, klassOffset()); - if (klass.equal(0)) { - return false; - } else { - int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION); - return (accessFlags & Modifier.INTERFACE) != 0; - } - } - - @MethodSubstitution(isStatic = false) - public static boolean isArray(final Class<?> thisObj) { - Word klass = loadWordFromObject(thisObj, klassOffset()); - if (klass.equal(0)) { - return false; - } else { - return (readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0; - } - } - - @MethodSubstitution(isStatic = false) - public static boolean isPrimitive(final Class<?> thisObj) { - Word klass = loadWordFromObject(thisObj, klassOffset()); - return klass.equal(0); - } - - @MethodSubstitution(isStatic = false) - public static Class<?> getSuperclass(final Class<?> thisObj) { - Word klass = loadWordFromObject(thisObj, klassOffset()); - if (klass.notEqual(0)) { - int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION); - if ((accessFlags & Modifier.INTERFACE) == 0) { - if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) { - return Object.class; - } else { - Word superKlass = klass.readWord(klassSuperKlassOffset(), FINAL_LOCATION); - if (superKlass.equal(0)) { - return null; - } else { - return unsafeCast(superKlass.readObject(classMirrorOffset(), FINAL_LOCATION), Class.class, true, true); - } - } - } - } - return null; - } - - @MethodSubstitution(isStatic = false) - public static Class<?> getComponentType(final Class<?> thisObj) { - Word klass = loadWordFromObject(thisObj, klassOffset()); - if (klass.notEqual(0)) { - if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) { - return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset(), FINAL_LOCATION), Class.class, true, true); - } - } - return null; - } - - @MethodSubstitution(isStatic = false) - public static boolean isInstance(final Class<?> thisObj, Object obj) { - return !isPrimitive(thisObj) && ConditionalNode.materializeIsInstance(thisObj, obj); - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,550 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.snippets.Snippet.Fold; -import com.oracle.graal.snippets.nodes.*; -import com.oracle.graal.word.*; - -//JaCoCo Exclude - -/** - * A collection of methods used in HotSpot snippets and substitutions. - */ -public class HotSpotSnippetUtils { - - public static final Object ANY_LOCATION = LocationNode.ANY_LOCATION; - public static final Object UNKNOWN_LOCATION = LocationNode.UNKNOWN_LOCATION; - public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION; - - public static HotSpotVMConfig config() { - return HotSpotGraalRuntime.getInstance().getConfig(); - } - - @Fold - public static boolean verifyOops() { - return config().verifyOops; - } - - public static final Object TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop"); - - @Fold - public static int threadTlabTopOffset() { - return config().threadTlabTopOffset; - } - - public static final Object TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd"); - - @Fold - private static int threadTlabEndOffset() { - return config().threadTlabEndOffset; - } - - public static final Object TLAB_START_LOCATION = LocationNode.createLocation("TlabStart"); - - @Fold - private static int threadTlabStartOffset() { - return config().threadTlabStartOffset; - } - - public static Word readTlabTop(Word thread) { - return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION); - } - - public static Word readTlabEnd(Word thread) { - return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION); - } - - public static Word readTlabStart(Word thread) { - return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION); - } - - public static void writeTlabTop(Word thread, Word top) { - thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION); - } - - public static void initializeTlab(Word thread, Word start, Word end) { - thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION); - thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION); - thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION); - } - - @Fold - public static int threadObjectOffset() { - return config().threadObjectOffset; - } - - @Fold - public static int osThreadOffset() { - return config().osThreadOffset; - } - - @Fold - public static int osThreadInterruptedOffset() { - return config().osThreadInterruptedOffset; - } - - @Fold - public static Kind wordKind() { - return HotSpotGraalRuntime.getInstance().getTarget().wordKind; - } - - @Fold - public static Register threadRegister() { - return HotSpotGraalRuntime.getInstance().getRuntime().threadRegister(); - } - - @Fold - public static Register stackPointerRegister() { - return HotSpotGraalRuntime.getInstance().getRuntime().stackPointerRegister(); - } - - @Fold - public static int wordSize() { - return HotSpotGraalRuntime.getInstance().getTarget().wordSize; - } - - @Fold - public static int pageSize() { - return Unsafe.getUnsafe().pageSize(); - } - - public static final Object PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord"); - - @Fold - public static int prototypeMarkWordOffset() { - return config().prototypeMarkWordOffset; - } - - @Fold - public static long arrayPrototypeMarkWord() { - return config().arrayPrototypeMarkWord; - } - - @Fold - public static int klassAccessFlagsOffset() { - return config().klassAccessFlagsOffset; - } - - @Fold - private static int klassLayoutHelperOffset() { - return config().klassLayoutHelperOffset; - } - - public static int readLayoutHelper(Word hub) { - return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION); - } - - @Fold - public static int arrayKlassLayoutHelperIdentifier() { - return config().arrayKlassLayoutHelperIdentifier; - } - - @Fold - public static int arrayKlassComponentMirrorOffset() { - return config().arrayKlassComponentMirrorOffset; - } - - @Fold - public static int klassSuperKlassOffset() { - return config().klassSuperKlassOffset; - } - - public static final Object MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord"); - - @Fold - public static int markOffset() { - return config().markOffset; - } - - public static final Object HUB_LOCATION = LocationNode.createLocation("Hub"); - - @Fold - private static int hubOffset() { - return config().hubOffset; - } - - public static void initializeObjectHeader(Word memory, Word markWord, Word hub) { - memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION); - memory.writeWord(hubOffset(), hub, HUB_LOCATION); - } - - @Fold - public static int unlockedMask() { - return config().unlockedMask; - } - - /** - * Mask for a biasable, locked or unlocked mark word. - * - * <pre> - * +----------------------------------+-+-+ - * | 1|1|1| - * +----------------------------------+-+-+ - * </pre> - * - */ - @Fold - public static int biasedLockMaskInPlace() { - return config().biasedLockMaskInPlace; - } - - @Fold - public static int epochMaskInPlace() { - return config().epochMaskInPlace; - } - - /** - * Pattern for a biasable, unlocked mark word. - * - * <pre> - * +----------------------------------+-+-+ - * | 1|0|1| - * +----------------------------------+-+-+ - * </pre> - * - */ - @Fold - public static int biasedLockPattern() { - return config().biasedLockPattern; - } - - @Fold - public static int ageMaskInPlace() { - return config().ageMaskInPlace; - } - - @Fold - public static int metaspaceArrayLengthOffset() { - return config().metaspaceArrayLengthOffset; - } - - @Fold - public static int metaspaceArrayBaseOffset() { - return config().metaspaceArrayBaseOffset; - } - - @Fold - public static int arrayLengthOffset() { - return config().arrayLengthOffset; - } - - @Fold - public static int arrayBaseOffset(Kind elementKind) { - return HotSpotRuntime.getArrayBaseOffset(elementKind); - } - - @Fold - public static int arrayIndexScale(Kind elementKind) { - return HotSpotRuntime.getArrayIndexScale(elementKind); - } - - @Fold - public static int cardTableShift() { - return config().cardtableShift; - } - - @Fold - public static long cardTableStart() { - return config().cardtableStartAddress; - } - - @Fold - public static int superCheckOffsetOffset() { - return config().superCheckOffsetOffset; - } - - public static final Object SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache"); - - @Fold - public static int secondarySuperCacheOffset() { - return config().secondarySuperCacheOffset; - } - - public static final Object SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers"); - - @Fold - public static int secondarySupersOffset() { - return config().secondarySupersOffset; - } - - public static final Object DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord"); - - @Fold - public static int lockDisplacedMarkOffset() { - return config().basicLockDisplacedHeaderOffset; - } - - @Fold - public static boolean useBiasedLocking() { - return config().useBiasedLocking; - } - - @Fold - static int uninitializedIdentityHashCodeValue() { - return config().uninitializedIdentityHashCodeValue; - } - - @Fold - static int identityHashCodeShift() { - return config().identityHashCodeShift; - } - - /** - * Loads the hub from a object, null checking it first. - */ - public static Word loadHub(Object object) { - return loadHubIntrinsic(object, wordKind()); - } - - public static Object verifyOop(Object object) { - if (verifyOops()) { - VerifyOopStubCall.call(object); - } - return object; - } - - /** - * Gets the value of the stack pointer register as a Word. - */ - public static Word stackPointer() { - return HotSpotSnippetUtils.registerAsWord(stackPointerRegister(), true, false); - } - - /** - * Gets the value of the thread register as a Word. - */ - public static Word thread() { - return HotSpotSnippetUtils.registerAsWord(threadRegister(), true, false); - } - - public static Word loadWordFromObject(Object object, int offset) { - return loadWordFromObjectIntrinsic(object, 0, offset, wordKind()); - } - - @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true) - public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming); - - @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) - private static native Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); - - @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true) - static native Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word); - - @Fold - public static int log2WordSize() { - return CodeUtil.log2(wordSize()); - } - - public static final Object CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState"); - - @Fold - public static int klassStateOffset() { - return config().klassStateOffset; - } - - @Fold - public static int klassStateFullyInitialized() { - return config().klassStateFullyInitialized; - } - - @Fold - public static int klassModifierFlagsOffset() { - return config().klassModifierFlagsOffset; - } - - @Fold - public static int klassOffset() { - return config().klassOffset; - } - - @Fold - public static int classMirrorOffset() { - return config().classMirrorOffset; - } - - @Fold - public static int klassInstanceSizeOffset() { - return config().klassInstanceSizeOffset; - } - - public static final Object HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop"); - - @Fold - public static long heapTopAddress() { - return config().heapTopAddress; - } - - public static final Object HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd"); - - @Fold - public static long heapEndAddress() { - return config().heapEndAddress; - } - - @Fold - public static long tlabIntArrayMarkWord() { - return config().tlabIntArrayMarkWord; - } - - @Fold - public static boolean inlineContiguousAllocationSupported() { - return config().inlineContiguousAllocationSupported; - } - - @Fold - public static int tlabAlignmentReserveInHeapWords() { - return config().tlabAlignmentReserve; - } - - public static final Object TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize"); - - @Fold - public static int threadTlabSizeOffset() { - return config().threadTlabSizeOffset; - } - - public static final Object TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes"); - - @Fold - public static int threadAllocatedBytesOffset() { - return config().threadAllocatedBytesOffset; - } - - public static final Object TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit"); - - @Fold - public static int tlabRefillWasteLimitOffset() { - return config().tlabRefillWasteLimitOffset; - } - - public static final Object TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills"); - - @Fold - public static int tlabNumberOfRefillsOffset() { - return config().tlabNumberOfRefillsOffset; - } - - public static final Object TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste"); - - @Fold - public static int tlabFastRefillWasteOffset() { - return config().tlabFastRefillWasteOffset; - } - - public static final Object TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations"); - - @Fold - public static int tlabSlowAllocationsOffset() { - return config().tlabSlowAllocationsOffset; - } - - @Fold - public static int tlabRefillWasteIncrement() { - return config().tlabRefillWasteIncrement; - } - - @Fold - public static boolean tlabStats() { - return config().tlabStats; - } - - @Fold - public static int layoutHelperOffset() { - return config().layoutHelperOffset; - } - - @Fold - public static int layoutHelperHeaderSizeShift() { - return config().layoutHelperHeaderSizeShift; - } - - @Fold - public static int layoutHelperHeaderSizeMask() { - return config().layoutHelperHeaderSizeMask; - } - - @Fold - public static int layoutHelperLog2ElementSizeShift() { - return config().layoutHelperLog2ElementSizeShift; - } - - @Fold - public static int layoutHelperLog2ElementSizeMask() { - return config().layoutHelperLog2ElementSizeMask; - } - - @Fold - public static int layoutHelperElementTypeShift() { - return config().layoutHelperElementTypeShift; - } - - @Fold - public static int layoutHelperElementTypeMask() { - return config().layoutHelperElementTypeMask; - } - - @Fold - public static int layoutHelperElementTypePrimitiveInPlace() { - return config().layoutHelperElementTypePrimitiveInPlace; - } - - static { - assert arrayIndexScale(Kind.Byte) == 1; - assert arrayIndexScale(Kind.Boolean) == 1; - assert arrayIndexScale(Kind.Char) == 2; - assert arrayIndexScale(Kind.Short) == 2; - assert arrayIndexScale(Kind.Int) == 4; - assert arrayIndexScale(Kind.Long) == 8; - assert arrayIndexScale(Kind.Float) == 4; - assert arrayIndexScale(Kind.Double) == 8; - } - - static int computeHashCode(Object x) { - Word mark = loadWordFromObject(x, markOffset()); - - // this code is independent from biased locking (although it does not look that way) - final Word biasedLock = mark.and(biasedLockMaskInPlace()); - if (biasedLock.equal(Word.unsigned(unlockedMask()))) { - probability(FAST_PATH_PROBABILITY); - int hash = (int) mark.unsignedShiftRight(identityHashCodeShift()).rawValue(); - if (hash != uninitializedIdentityHashCodeValue()) { - probability(FAST_PATH_PROBABILITY); - return hash; - } - } - - return IdentityHashCodeStubCall.call(x); - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.hotspot.snippets.TypeCheckSnippetUtils.*; -import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.Snippet.Varargs; -import com.oracle.graal.snippets.Snippet.VarargsParameter; -import com.oracle.graal.snippets.SnippetTemplate.Arguments; -import com.oracle.graal.snippets.SnippetTemplate.Key; -import com.oracle.graal.snippets.nodes.*; -import com.oracle.graal.word.*; - -/** - * Snippets used for implementing the type test of an instanceof instruction. Since instanceof is a - * floating node, it is lowered separately for each of its usages. - * - * The type tests implemented are described in the paper <a - * href="http://dl.acm.org/citation.cfm?id=583821"> Fast subtype checking in the HotSpot JVM</a> by - * Cliff Click and John Rose. - */ -public class InstanceOfSnippets implements SnippetsInterface { - - // @formatter:off - - /** - * A test against a final type. - */ - @Snippet - public static Object instanceofExact( - @Parameter("object") Object object, - @Parameter("exactHub") Word exactHub, - @Parameter("trueValue") Object trueValue, - @Parameter("falseValue") Object falseValue, - @ConstantParameter("checkNull") boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); - isNull.inc(); - return falseValue; - } - Word objectHub = loadHub(object); - if (objectHub.notEqual(exactHub)) { - probability(LIKELY_PROBABILITY); - exactMiss.inc(); - return falseValue; - } - exactHit.inc(); - return trueValue; - } - - /** - * A test against a primary type. - */ - @Snippet - public static Object instanceofPrimary( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @Parameter("trueValue") Object trueValue, - @Parameter("falseValue") Object falseValue, - @ConstantParameter("checkNull") boolean checkNull, - @ConstantParameter("superCheckOffset") int superCheckOffset) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); - isNull.inc(); - return falseValue; - } - Word objectHub = loadHub(object); - if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { - probability(NOT_LIKELY_PROBABILITY); - displayMiss.inc(); - return falseValue; - } - displayHit.inc(); - return trueValue; - } - - /** - * A test against a restricted secondary type type. - */ - @Snippet - public static Object instanceofSecondary( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @Parameter("trueValue") Object trueValue, - @Parameter("falseValue") Object falseValue, - @VarargsParameter("hints") Word[] hints, - @ConstantParameter("checkNull") boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); - isNull.inc(); - return falseValue; - } - Word objectHub = loadHub(object); - // if we get an exact match: succeed immediately - ExplodeLoopNode.explodeLoop(); - for (int i = 0; i < hints.length; i++) { - Word hintHub = hints[i]; - if (hintHub.equal(objectHub)) { - probability(NOT_FREQUENT_PROBABILITY); - hintsHit.inc(); - return trueValue; - } - } - if (!checkSecondarySubType(hub, objectHub)) { - return falseValue; - } - return trueValue; - } - - /** - * Type test used when the type being tested against is not known at compile time. - */ - @Snippet - public static Object instanceofDynamic( - @Parameter("mirror") Class mirror, - @Parameter("object") Object object, - @Parameter("trueValue") Object trueValue, - @Parameter("falseValue") Object falseValue, - @ConstantParameter("checkNull") boolean checkNull) { - if (checkNull && object == null) { - probability(NOT_FREQUENT_PROBABILITY); - isNull.inc(); - return falseValue; - } - - Word hub = loadWordFromObject(mirror, klassOffset()); - Word objectHub = loadHub(object); - if (!checkUnknownSubType(hub, objectHub)) { - return falseValue; - } - return trueValue; - } - - // @formatter:on - - public static class Templates extends InstanceOfSnippetsTemplates<InstanceOfSnippets> { - - private final ResolvedJavaMethod instanceofExact; - private final ResolvedJavaMethod instanceofPrimary; - private final ResolvedJavaMethod instanceofSecondary; - private final ResolvedJavaMethod instanceofDynamic; - - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, InstanceOfSnippets.class); - instanceofExact = snippet("instanceofExact", Object.class, Word.class, Object.class, Object.class, boolean.class); - instanceofPrimary = snippet("instanceofPrimary", Word.class, Object.class, Object.class, Object.class, boolean.class, int.class); - instanceofSecondary = snippet("instanceofSecondary", Word.class, Object.class, Object.class, Object.class, Word[].class, boolean.class); - instanceofDynamic = snippet("instanceofDynamic", Class.class, Object.class, Object.class, Object.class, boolean.class); - } - - @Override - protected KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) { - if (replacer.instanceOf instanceof InstanceOfNode) { - InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf; - ValueNode trueValue = replacer.trueValue; - ValueNode falseValue = replacer.falseValue; - ValueNode object = instanceOf.object(); - TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints); - final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type(); - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph()); - boolean checkNull = !object.stamp().nonNull(); - Arguments arguments; - Key key; - if (hintInfo.exact) { - ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); - assert hints.length == 1; - key = new Key(instanceofExact).add("checkNull", checkNull); - arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue); - } else if (type.isPrimaryType()) { - key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); - arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); - } else { - ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); - key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); - arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue); - } - return new KeyAndArguments(key, arguments); - } else { - assert replacer.instanceOf instanceof InstanceOfDynamicNode; - InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf; - ValueNode trueValue = replacer.trueValue; - ValueNode falseValue = replacer.falseValue; - ValueNode object = instanceOf.object(); - ValueNode mirror = instanceOf.mirror(); - boolean checkNull = !object.stamp().nonNull(); - Key key = new Key(instanceofDynamic).add("checkNull", checkNull); - Arguments arguments = arguments("mirror", mirror).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); - return new KeyAndArguments(key, arguments); - } - } - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,548 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.hotspot.nodes.BeginLockScopeNode.*; -import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; -import static com.oracle.graal.hotspot.nodes.EndLockScopeNode.*; -import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.snippets.SnippetTemplate.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; -import com.oracle.graal.snippets.SnippetTemplate.Arguments; -import com.oracle.graal.snippets.SnippetTemplate.Key; -import com.oracle.graal.word.*; - -/** - * Snippets used for implementing the monitorenter and monitorexit instructions. - * - * The locking algorithm used is described in the paper <a - * href="http://dl.acm.org/citation.cfm?id=1167515.1167496"> Eliminating synchronization-related - * atomic operations with biased locking and bulk rebiasing</a> by Kenneth Russell and David - * Detlefs. - */ -public class MonitorSnippets implements SnippetsInterface { - - /** - * Monitor operations on objects whose type contains this substring will be traced. - */ - private static final String TRACE_TYPE_FILTER = System.getProperty("graal.monitors.trace.typeFilter"); - - /** - * Monitor operations in methods whose fully qualified name contains this substring will be - * traced. - */ - private static final String TRACE_METHOD_FILTER = System.getProperty("graal.monitors.trace.methodFilter"); - - public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced"); - - @Snippet - public static void monitorenter(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("trace") boolean trace) { - verifyOop(object); - - if (checkNull && object == null) { - DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); - } - - // Load the mark word - this includes a null-check on object - final Word mark = loadWordFromObject(object, markOffset()); - - final Word lock = beginLockScope(false); - - trace(trace, " object: 0x%016lx\n", Word.fromObject(object)); - trace(trace, " lock: 0x%016lx\n", lock); - trace(trace, " mark: 0x%016lx\n", mark); - - incCounter(); - - if (useBiasedLocking()) { - // See whether the lock is currently biased toward our thread and - // whether the epoch is still valid. - // Note that the runtime guarantees sufficient alignment of JavaThread - // pointers to allow age to be placed into low bits. - final Word biasableLockBits = mark.and(biasedLockMaskInPlace()); - - // First check to see whether biasing is enabled for this object - if (biasableLockBits.notEqual(Word.unsigned(biasedLockPattern()))) { - // Biasing not enabled -> fall through to lightweight locking - } else { - probability(FREQUENT_PROBABILITY); - // The bias pattern is present in the object's mark word. Need to check - // whether the bias owner and the epoch are both still current. - Word hub = loadHub(object); - final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - final Word thread = thread(); - final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace()); - trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord); - trace(trace, " thread: 0x%016lx\n", thread); - trace(trace, " tmp: 0x%016lx\n", tmp); - if (tmp.equal(0)) { - // Object is already biased to current thread -> done - probability(FREQUENT_PROBABILITY); - traceObject(trace, "+lock{bias:existing}", object); - return; - } - - // At this point we know that the mark word has the bias pattern and - // that we are not the bias owner in the current epoch. We need to - // figure out more details about the state of the mark word in order to - // know what operations can be legally performed on the object's - // mark word. - - // If the low three bits in the xor result aren't clear, that means - // the prototype header is no longer biasable and we have to revoke - // the bias on this object. - if (tmp.and(biasedLockMaskInPlace()).equal(0)) { - probability(FREQUENT_PROBABILITY); - // Biasing is still enabled for object's type. See whether the - // epoch of the current bias is still valid, meaning that the epoch - // bits of the mark word are equal to the epoch bits of the - // prototype mark word. (Note that the prototype mark word's epoch bits - // only change at a safepoint.) If not, attempt to rebias the object - // toward the current thread. Note that we must be absolutely sure - // that the current epoch is invalid in order to do this because - // otherwise the manipulations it performs on the mark word are - // illegal. - if (tmp.and(epochMaskInPlace()).equal(0)) { - probability(FREQUENT_PROBABILITY); - // The epoch of the current bias is still valid but we know nothing - // about the owner; it might be set or it might be clear. Try to - // acquire the bias of the object using an atomic operation. If this - // fails we will go in to the runtime to revoke the object's bias. - // Note that we first construct the presumed unbiased header so we - // don't accidentally blow away another thread's valid bias. - Word unbiasedMark = mark.and(biasedLockMaskInPlace() | ageMaskInPlace() | epochMaskInPlace()); - Word biasedMark = unbiasedMark.or(thread); - trace(trace, " unbiasedMark: 0x%016lx\n", unbiasedMark); - trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark)) { - // Object is now biased to current thread -> done - traceObject(trace, "+lock{bias:acquired}", object); - return; - } - // If the biasing toward our thread failed, this means that another thread - // owns the bias and we need to revoke that bias. The revocation will occur - // in the interpreter runtime. - probability(DEOPT_PATH_PROBABILITY); - traceObject(trace, "+lock{stub:revoke}", object); - MonitorEnterStubCall.call(object, lock); - return; - } else { - // At this point we know the epoch has expired, meaning that the - // current bias owner, if any, is actually invalid. Under these - // circumstances _only_, are we allowed to use the current mark word - // value as the comparison value when doing the CAS to acquire the - // bias in the current epoch. In other words, we allow transfer of - // the bias from one thread to another directly in this situation. - Word biasedMark = prototypeMarkWord.or(thread); - trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark)) { - // Object is now biased to current thread -> done - traceObject(trace, "+lock{bias:transfer}", object); - return; - } - // If the biasing toward our thread failed, then another thread - // succeeded in biasing it toward itself and we need to revoke that - // bias. The revocation will occur in the runtime in the slow case. - probability(DEOPT_PATH_PROBABILITY); - traceObject(trace, "+lock{stub:epoch-expired}", object); - MonitorEnterStubCall.call(object, lock); - return; - } - } else { - // The prototype mark word doesn't have the bias bit set any - // more, indicating that objects of this data type are not supposed - // to be biased any more. We are going to try to reset the mark of - // this object to the prototype value and fall through to the - // CAS-based locking scheme. Note that if our CAS fails, it means - // that another thread raced us for the privilege of revoking the - // bias of this particular object, so it's okay to continue in the - // normal locking code. - Word result = compareAndSwap(object, markOffset(), mark, prototypeMarkWord, MARK_WORD_LOCATION); - - // Fall through to the normal CAS-based lock, because no matter what - // the result of the above CAS, some thread must have succeeded in - // removing the bias bit from the object's header. - - if (ENABLE_BREAKPOINT) { - bkpt(object, mark, tmp, result); - } - } - } - } - - // Create the unlocked mark word pattern - Word unlockedMark = mark.or(unlockedMask()); - trace(trace, " unlockedMark: 0x%016lx\n", unlockedMark); - - // Copy this unlocked mark word into the lock slot on the stack - lock.writeWord(lockDisplacedMarkOffset(), unlockedMark, DISPLACED_MARK_WORD_LOCATION); - - // Test if the object's mark word is unlocked, and if so, store the - // (address of) the lock slot into the object's mark word. - Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock, MARK_WORD_LOCATION); - if (currentMark.notEqual(unlockedMark)) { - trace(trace, " currentMark: 0x%016lx\n", currentMark); - // The mark word in the object header was not the same. - // Either the object is locked by another thread or is already locked - // by the current thread. The latter is true if the mark word - // is a stack pointer into the current thread's stack, i.e.: - // - // 1) (currentMark & aligned_mask) == 0 - // 2) rsp <= currentMark - // 3) currentMark <= rsp + page_size - // - // These 3 tests can be done by evaluating the following expression: - // - // (currentMark - rsp) & (aligned_mask - page_size) - // - // assuming both the stack pointer and page_size have their least - // significant 2 bits cleared and page_size is a power of 2 - final Word alignedMask = Word.unsigned(wordSize() - 1); - final Word stackPointer = stackPointer(); - if (currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0)) { - // Most likely not a recursive lock, go into a slow runtime call - probability(DEOPT_PATH_PROBABILITY); - traceObject(trace, "+lock{stub:failed-cas}", object); - MonitorEnterStubCall.call(object, lock); - return; - } else { - // Recursively locked => write 0 to the lock slot - lock.writeWord(lockDisplacedMarkOffset(), Word.zero(), DISPLACED_MARK_WORD_LOCATION); - traceObject(trace, "+lock{recursive}", object); - } - } else { - traceObject(trace, "+lock{cas}", object); - } - } - - @Snippet - public static void monitorenterEliminated() { - incCounter(); - beginLockScope(true); - } - - /** - * Calls straight out to the monitorenter stub. - */ - @Snippet - public static void monitorenterStub(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("trace") boolean trace) { - verifyOop(object); - incCounter(); - if (checkNull && object == null) { - DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); - } - // BeginLockScope nodes do not read from object so a use of object - // cannot float about the null check above - final Word lock = beginLockScope(false); - traceObject(trace, "+lock{stub}", object); - MonitorEnterStubCall.call(object, lock); - } - - @Snippet - public static void monitorexit(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) { - trace(trace, " object: 0x%016lx\n", Word.fromObject(object)); - if (useBiasedLocking()) { - // Check for biased locking unlock case, which is a no-op - // Note: we do not have to check the thread ID for two reasons. - // First, the interpreter checks for IllegalMonitorStateException at - // a higher level. Second, if the bias was revoked while we held the - // lock, the object could not be rebiased toward another thread, so - // the bias bit would be clear. - final Word mark = loadWordFromObject(object, markOffset()); - trace(trace, " mark: 0x%016lx\n", mark); - if (mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern()))) { - probability(FREQUENT_PROBABILITY); - endLockScope(); - decCounter(); - traceObject(trace, "-lock{bias}", object); - return; - } - } - - final Word lock = CurrentLockNode.currentLock(); - - // Load displaced mark - final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION); - trace(trace, " displacedMark: 0x%016lx\n", displacedMark); - - if (displacedMark.equal(0)) { - // Recursive locking => done - traceObject(trace, "-lock{recursive}", object); - } else { - verifyOop(object); - // Test if object's mark word is pointing to the displaced mark word, and if so, restore - // the displaced mark in the object - if the object's mark word is not pointing to - // the displaced mark word, do unlocking via runtime call. - if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock)) { - // The object's mark word was not pointing to the displaced header, - // we do unlocking via runtime call. - probability(DEOPT_PATH_PROBABILITY); - traceObject(trace, "-lock{stub}", object); - MonitorExitStubCall.call(object); - } else { - traceObject(trace, "-lock{cas}", object); - } - } - endLockScope(); - decCounter(); - } - - /** - * Calls straight out to the monitorexit stub. - */ - @Snippet - public static void monitorexitStub(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) { - verifyOop(object); - traceObject(trace, "-lock{stub}", object); - MonitorExitStubCall.call(object); - endLockScope(); - decCounter(); - } - - @Snippet - public static void monitorexitEliminated() { - endLockScope(); - decCounter(); - } - - private static void traceObject(boolean enabled, String action, Object object) { - if (enabled) { - Log.print(action); - Log.print(' '); - Log.printlnObject(object); - } - } - - private static void trace(boolean enabled, String format, WordBase value) { - if (enabled) { - Log.printf(format, value.rawValue()); - } - } - - /** - * Leaving the breakpoint code in to provide an example of how to use the {@link BreakpointNode} - * intrinsic. - */ - private static final boolean ENABLE_BREAKPOINT = false; - - private static final Object MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter"); - - @NodeIntrinsic(BreakpointNode.class) - static native void bkpt(Object object, Word mark, Word tmp, Word value); - - private static void incCounter() { - if (CHECK_BALANCED_MONITORS) { - final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); - counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION); - } - } - - private static void decCounter() { - if (CHECK_BALANCED_MONITORS) { - final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); - counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION); - } - } - - @Snippet - private static void initCounter() { - final Word counter = MonitorCounterNode.counter(); - counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION); - } - - @Snippet - private static void checkCounter(String errMsg) { - final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); - if (count != 0) { - vmError(errMsg, count); - } - } - - public static class Templates extends AbstractTemplates<MonitorSnippets> { - - private final ResolvedJavaMethod monitorenter; - private final ResolvedJavaMethod monitorexit; - private final ResolvedJavaMethod monitorenterStub; - private final ResolvedJavaMethod monitorexitStub; - private final ResolvedJavaMethod monitorenterEliminated; - private final ResolvedJavaMethod monitorexitEliminated; - private final ResolvedJavaMethod initCounter; - private final ResolvedJavaMethod checkCounter; - private final boolean useFastLocking; - - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target, boolean useFastLocking) { - super(runtime, assumptions, target, MonitorSnippets.class); - monitorenter = snippet("monitorenter", Object.class, boolean.class, boolean.class); - monitorexit = snippet("monitorexit", Object.class, boolean.class); - monitorenterStub = snippet("monitorenterStub", Object.class, boolean.class, boolean.class); - monitorexitStub = snippet("monitorexitStub", Object.class, boolean.class); - monitorenterEliminated = snippet("monitorenterEliminated"); - monitorexitEliminated = snippet("monitorexitEliminated"); - initCounter = snippet("initCounter"); - checkCounter = snippet("checkCounter", String.class); - this.useFastLocking = useFastLocking; - } - - public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) monitorenterNode.graph(); - - checkBalancedMonitors(graph); - - FrameState stateAfter = monitorenterNode.stateAfter(); - boolean eliminated = monitorenterNode.eliminated(); - ResolvedJavaMethod method = eliminated ? monitorenterEliminated : useFastLocking ? monitorenter : monitorenterStub; - boolean checkNull = !monitorenterNode.object().stamp().nonNull(); - Key key = new Key(method); - if (method != monitorenterEliminated) { - key.add("checkNull", checkNull); - } - if (!eliminated) { - key.add("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); - } - - Arguments arguments = new Arguments(); - if (!eliminated) { - arguments.add("object", monitorenterNode.object()); - } - SnippetTemplate template = cache.get(key, assumptions); - Map<Node, Node> nodes = template.instantiate(runtime, monitorenterNode, DEFAULT_REPLACER, arguments); - for (Node n : nodes.values()) { - if (n instanceof BeginLockScopeNode) { - BeginLockScopeNode begin = (BeginLockScopeNode) n; - begin.setStateAfter(stateAfter); - } - } - } - - public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) monitorexitNode.graph(); - FrameState stateAfter = monitorexitNode.stateAfter(); - boolean eliminated = monitorexitNode.eliminated(); - ResolvedJavaMethod method = eliminated ? monitorexitEliminated : useFastLocking ? monitorexit : monitorexitStub; - Key key = new Key(method); - if (!eliminated) { - key.add("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); - } - Arguments arguments = new Arguments(); - if (!eliminated) { - arguments.add("object", monitorexitNode.object()); - } - SnippetTemplate template = cache.get(key, assumptions); - Map<Node, Node> nodes = template.instantiate(runtime, monitorexitNode, DEFAULT_REPLACER, arguments); - for (Node n : nodes.values()) { - if (n instanceof EndLockScopeNode) { - EndLockScopeNode end = (EndLockScopeNode) n; - end.setStateAfter(stateAfter); - } - } - } - - static boolean isTracingEnabledForType(ValueNode object) { - ResolvedJavaType type = object.objectStamp().type(); - if (TRACE_TYPE_FILTER == null) { - return false; - } else { - if (TRACE_TYPE_FILTER.length() == 0) { - return true; - } - if (type == null) { - return false; - } - return (type.getName().contains(TRACE_TYPE_FILTER)); - } - } - - static boolean isTracingEnabledForMethod(ResolvedJavaMethod method) { - if (TRACE_METHOD_FILTER == null) { - return false; - } else { - if (TRACE_METHOD_FILTER.length() == 0) { - return true; - } - if (method == null) { - return false; - } - return (MetaUtil.format("%H.%n", method).contains(TRACE_METHOD_FILTER)); - } - } - - /** - * If balanced monitor checking is enabled then nodes are inserted at the start and all - * return points of the graph to initialize and check the monitor counter respectively. - */ - private void checkBalancedMonitors(StructuredGraph graph) { - if (CHECK_BALANCED_MONITORS) { - NodeIterable<MonitorCounterNode> nodes = graph.getNodes().filter(MonitorCounterNode.class); - if (nodes.isEmpty()) { - // Only insert the nodes if this is the first monitorenter being lowered. - JavaType returnType = initCounter.getSignature().getReturnType(initCounter.getDeclaringClass()); - MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, initCounter, new ValueNode[0], returnType)); - InvokeNode invoke = graph.add(new InvokeNode(callTarget, 0)); - invoke.setStateAfter(graph.start().stateAfter()); - graph.addAfterFixed(graph.start(), invoke); - StructuredGraph inlineeGraph = (StructuredGraph) initCounter.getCompilerStorage().get(Graph.class); - InliningUtil.inline(invoke, inlineeGraph, false); - - List<ReturnNode> rets = graph.getNodes().filter(ReturnNode.class).snapshot(); - for (ReturnNode ret : rets) { - returnType = checkCounter.getSignature().getReturnType(checkCounter.getDeclaringClass()); - Object msg = ((HotSpotRuntime) runtime).registerGCRoot("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d"); - ConstantNode errMsg = ConstantNode.forObject(msg, runtime, graph); - callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter, new ValueNode[]{errMsg}, returnType)); - invoke = graph.add(new InvokeNode(callTarget, 0)); - List<ValueNode> stack = Collections.emptyList(); - FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false); - invoke.setStateAfter(graph.add(stateAfter)); - graph.addBeforeFixed(ret, invoke); - inlineeGraph = (StructuredGraph) checkCounter.getCompilerStorage().get(Graph.class); - InliningUtil.inline(invoke, inlineeGraph, false); - } - } - } - } - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,391 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.api.code.UnsignedMath.*; -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*; -import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; -import static com.oracle.graal.snippets.Snippet.Varargs.*; -import static com.oracle.graal.snippets.SnippetTemplate.*; -import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; -import static com.oracle.graal.snippets.nodes.ExplodeLoopNode.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.Snippet.VarargsParameter; -import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; -import com.oracle.graal.snippets.SnippetTemplate.Arguments; -import com.oracle.graal.snippets.SnippetTemplate.Key; -import com.oracle.graal.snippets.nodes.*; -import com.oracle.graal.word.*; - -/** - * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY. - */ -public class NewObjectSnippets implements SnippetsInterface { - - // @formatter:off - - @Snippet - public static Word allocate(@Parameter("size") int size) { - Word thread = thread(); - Word top = readTlabTop(thread); - Word end = readTlabEnd(thread); - Word newTop = top.add(size); - // this check might lead to problems if the TLAB is within 16GB of the address space end (checked in c++ code) - if (newTop.belowOrEqual(end)) { - probability(FAST_PATH_PROBABILITY); - writeTlabTop(thread, newTop); - return top; - } - return Word.zero(); - } - - @Snippet - public static Object initializeObject( - @Parameter("memory") Word memory, - @Parameter("hub") Word hub, - @Parameter("prototypeMarkWord") Word prototypeMarkWord, - @ConstantParameter("size") int size, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("locked") boolean locked) { - - Object result; - if (memory.equal(0)) { - new_stub.inc(); - result = NewInstanceStubCall.call(hub); - } else { - probability(FAST_PATH_PROBABILITY); - if (locked) { - formatObject(hub, size, memory, thread().or(biasedLockPattern()), fillContents); - } else { - formatObject(hub, size, memory, prototypeMarkWord, fillContents); - } - result = memory.toObject(); - } - return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic()); - } - - @Snippet - public static Object initializeArray( - @Parameter("memory") Word memory, - @Parameter("hub") Word hub, - @Parameter("length") int length, - @Parameter("allocationSize") int allocationSize, - @Parameter("prototypeMarkWord") Word prototypeMarkWord, - @ConstantParameter("headerSize") int headerSize, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("locked") boolean locked) { - if (locked) { - return initializeArray(memory, hub, length, allocationSize, thread().or(biasedLockPattern()), headerSize, fillContents); - } else { - return initializeArray(memory, hub, length, allocationSize, prototypeMarkWord, headerSize, fillContents); - } - } - - private static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, int headerSize, boolean fillContents) { - Object result; - if (memory.equal(0)) { - newarray_stub.inc(); - result = NewArrayStubCall.call(hub, length); - } else { - probability(FAST_PATH_PROBABILITY); - newarray_loopInit.inc(); - formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents); - result = memory.toObject(); - } - return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); - } - - /** - * Maximum array length for which fast path allocation is used. - */ - public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; - - @Snippet - public static Object allocateArrayAndInitialize( - @Parameter("length") int length, - @ConstantParameter("alignment") int alignment, - @ConstantParameter("headerSize") int headerSize, - @ConstantParameter("log2ElementSize") int log2ElementSize, - @ConstantParameter("type") ResolvedJavaType type) { - if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { - probability(DEOPT_PATH_PROBABILITY); - // This handles both negative array sizes and very large array sizes - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); - Word memory = TLABAllocateNode.allocateVariableSize(allocationSize); - return InitializeArrayNode.initialize(memory, length, allocationSize, type, true, false); - } - - /** - * Computes the size of the memory chunk allocated for an array. This size accounts for the array - * header size, boy size and any padding after the last element to satisfy object alignment requirements. - * - * @param length the number of elements in the array - * @param alignment the object alignment requirement - * @param headerSize the size of the array header - * @param log2ElementSize log2 of the size of an element in the array - */ - public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) { - int size = (length << log2ElementSize) + headerSize + (alignment - 1); - int mask = ~(alignment - 1); - return size & mask; - } - - /** - * Calls the runtime stub for implementing MULTIANEWARRAY. - */ - @Snippet - public static Object newmultiarray( - @Parameter("hub") Word hub, - @ConstantParameter("rank") int rank, - @VarargsParameter("dimensions") int[] dimensions) { - Word dims = DimensionsNode.allocaDimsArray(rank); - ExplodeLoopNode.explodeLoop(); - for (int i = 0; i < rank; i++) { - dims.writeInt(i * 4, dimensions[i], ANY_LOCATION); - } - return NewMultiArrayStubCall.call(hub, rank, dims); - } - - /** - * Maximum size of an object whose body is initialized by a sequence of - * zero-stores to its fields. Larger objects have their bodies initialized - * in a loop. - */ - private static final int MAX_UNROLLED_OBJECT_ZEROING_SIZE = 10 * wordSize(); - - /** - * Formats some allocated memory with an object header zeroes out the rest. - */ - private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) { - Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord; - initializeObjectHeader(memory, prototypeMarkWord, hub); - if (fillContents) { - if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { - new_seqInit.inc(); - explodeLoop(); - for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { - memory.writeWord(offset, Word.zero(), ANY_LOCATION); - } - } else { - new_loopInit.inc(); - for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { - memory.writeWord(offset, Word.zero(), ANY_LOCATION); - } - } - } - } - - /** - * Formats some allocated memory with an object header zeroes out the rest. - */ - public static void formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { - memory.writeInt(arrayLengthOffset(), length, ANY_LOCATION); - // store hub last as the concurrent garbage collectors assume length is valid if hub field is not null - initializeObjectHeader(memory, prototypeMarkWord, hub); - if (fillContents) { - for (int offset = headerSize; offset < allocationSize; offset += wordSize()) { - memory.writeWord(offset, Word.zero(), ANY_LOCATION); - } - } - } - - // @formatter:on - - public static class Templates extends AbstractTemplates<NewObjectSnippets> { - - private final ResolvedJavaMethod allocate; - private final ResolvedJavaMethod initializeObject; - private final ResolvedJavaMethod initializeArray; - private final ResolvedJavaMethod allocateArrayAndInitialize; - private final ResolvedJavaMethod newmultiarray; - private final TargetDescription target; - private final boolean useTLAB; - - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target, boolean useTLAB) { - super(runtime, assumptions, target, NewObjectSnippets.class); - this.target = target; - this.useTLAB = useTLAB; - allocate = snippet("allocate", int.class); - initializeObject = snippet("initializeObject", Word.class, Word.class, Word.class, int.class, boolean.class, boolean.class); - initializeArray = snippet("initializeArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); - allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class); - newmultiarray = snippet("newmultiarray", Word.class, int.class, int[].class); - } - - /** - * Lowers a {@link NewInstanceNode}. - */ - @SuppressWarnings("unused") - public void lower(NewInstanceNode newInstanceNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newInstanceNode.graph(); - HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass(); - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - int size = instanceSize(type); - - ValueNode memory; - if (!useTLAB) { - memory = ConstantNode.defaultForKind(target.wordKind, graph); - } else { - ConstantNode sizeNode = ConstantNode.forInt(size, graph); - TLABAllocateNode tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); - graph.addBeforeFixed(newInstanceNode, tlabAllocateNode); - memory = tlabAllocateNode; - } - InitializeObjectNode initializeNode = graph.add(new InitializeObjectNode(memory, type, newInstanceNode.fillContents(), newInstanceNode.locked())); - graph.replaceFixedWithFixed(newInstanceNode, initializeNode); - } - - /** - * Lowers a {@link NewArrayNode}. - */ - @SuppressWarnings("unused") - public void lower(NewArrayNode newArrayNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newArrayNode.graph(); - ValueNode lengthNode = newArrayNode.length(); - TLABAllocateNode tlabAllocateNode; - ResolvedJavaType elementType = newArrayNode.elementType(); - ResolvedJavaType arrayType = elementType.getArrayClass(); - Kind elementKind = elementType.getKind(); - final int alignment = target.wordSize; - final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind); - final Integer length = lengthNode.isConstant() ? Integer.valueOf(lengthNode.asConstant().asInt()) : null; - int log2ElementSize = CodeUtil.log2(target.sizeInBytes(elementKind)); - if (!useTLAB) { - ConstantNode zero = ConstantNode.defaultForKind(target.wordKind, graph); - // value for 'size' doesn't matter as it isn't used since a stub call will be made - // anyway - // for both allocation and initialization - it just needs to be non-null - ConstantNode size = ConstantNode.forInt(-1, graph); - InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); - graph.replaceFixedWithFixed(newArrayNode, initializeNode); - } else if (length != null && belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { - // Calculate aligned size - int size = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); - ConstantNode sizeNode = ConstantNode.forInt(size, graph); - tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); - graph.addBeforeFixed(newArrayNode, tlabAllocateNode); - InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); - graph.replaceFixedWithFixed(newArrayNode, initializeNode); - } else { - Key key = new Key(allocateArrayAndInitialize).add("alignment", alignment).add("headerSize", headerSize).add("log2ElementSize", log2ElementSize).add("type", arrayType); - Arguments arguments = new Arguments().add("length", lengthNode); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, arguments); - template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, arguments); - } - } - - @SuppressWarnings("unused") - public void lower(TLABAllocateNode tlabAllocateNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) tlabAllocateNode.graph(); - ValueNode size = tlabAllocateNode.size(); - Key key = new Key(allocate); - Arguments arguments = arguments("size", size); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering fastAllocate in %s: node=%s, template=%s, arguments=%s", graph, tlabAllocateNode, template, arguments); - template.instantiate(runtime, tlabAllocateNode, DEFAULT_REPLACER, arguments); - } - - @SuppressWarnings("unused") - public void lower(InitializeObjectNode initializeNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) initializeNode.graph(); - HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type(); - assert !type.isArray(); - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - int size = instanceSize(type); - Key key = new Key(initializeObject).add("size", size).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); - ValueNode memory = initializeNode.memory(); - Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); - template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); - } - - @SuppressWarnings("unused") - public void lower(InitializeArrayNode initializeNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) initializeNode.graph(); - HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) initializeNode.type(); - ResolvedJavaType elementType = type.getComponentType(); - assert elementType != null; - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - Kind elementKind = elementType.getKind(); - final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind); - Key key = new Key(initializeArray).add("headerSize", headerSize).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); - ValueNode memory = initializeNode.memory(); - Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()).add("allocationSize", initializeNode.allocationSize()).add("length", - initializeNode.length()); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); - template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); - } - - @SuppressWarnings("unused") - public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) newmultiarrayNode.graph(); - int rank = newmultiarrayNode.dimensionCount(); - ValueNode[] dims = new ValueNode[rank]; - for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) { - dims[i] = newmultiarrayNode.dimension(i); - } - HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type(); - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - Key key = new Key(newmultiarray).add("dimensions", vargargs(new int[rank], StampFactory.forKind(Kind.Int))).add("rank", rank); - Arguments arguments = arguments("dimensions", dims).add("hub", hub); - SnippetTemplate template = cache.get(key, assumptions); - template.instantiate(runtime, newmultiarrayNode, DEFAULT_REPLACER, arguments); - } - - private static int instanceSize(HotSpotResolvedObjectType type) { - int size = type.instanceSize(); - assert (size % wordSize()) == 0; - assert size >= 0; - return size; - } - } - - private static final SnippetCounter.Group countersNew = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewInstance") : null; - private static final SnippetCounter new_seqInit = new SnippetCounter(countersNew, "tlabSeqInit", "TLAB alloc with unrolled zeroing"); - private static final SnippetCounter new_loopInit = new SnippetCounter(countersNew, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); - private static final SnippetCounter new_stub = new SnippetCounter(countersNew, "stub", "alloc and zeroing via stub"); - - private static final SnippetCounter.Group countersNewArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewArray") : null; - private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); - private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewArray, "stub", "alloc and zeroing via stub"); -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +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.snippets; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.nodes.*; - -public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider { - - public ObjectCloneNode(Invoke invoke) { - super(invoke); - } - - @Override - public boolean inferStamp() { - return updateStamp(getObject().stamp()); - } - - private ValueNode getObject() { - return arguments.get(0); - } - - @Override - protected StructuredGraph getSnippetGraph(LoweringTool tool) { - if (!GraalOptions.IntrinsifyObjectClone) { - return null; - } - - ResolvedJavaType type = getObject().objectStamp().type(); - Method method; - /* - * The first condition tests if the parameter is an array, the second condition tests if the - * parameter can be an array. Otherwise, the parameter is known to be a non-array object. - */ - if (type.isArray()) { - method = ObjectCloneSnippets.arrayCloneMethod; - } else if (type == null || type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) { - method = ObjectCloneSnippets.genericCloneMethod; - } else { - method = ObjectCloneSnippets.instanceCloneMethod; - } - ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method); - StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); - - assert snippetGraph != null : "ObjectCloneSnippets should be installed"; - return snippetGraph; - } - - private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) { - return metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type); - } - - private static ResolvedJavaType getConcreteType(ObjectStamp stamp, Assumptions assumptions) { - if (stamp.isExactType() || stamp.type() == null) { - return stamp.type(); - } else { - ResolvedJavaType type = stamp.type().findUniqueConcreteSubtype(); - if (type != null) { - assumptions.recordConcreteSubtype(stamp.type(), type); - } - return type; - } - } - - @Override - public void virtualize(VirtualizerTool tool) { - State originalState = tool.getObjectState(getObject()); - if (originalState != null && originalState.getState() == EscapeState.Virtual) { - VirtualObjectNode originalVirtual = originalState.getVirtualObject(); - if (isCloneableType(originalVirtual.type(), tool.getMetaAccessProvider())) { - ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()]; - for (int i = 0; i < newEntryState.length; i++) { - newEntryState[i] = originalState.getEntry(i); - } - VirtualObjectNode newVirtual = originalVirtual.duplicate(); - tool.createVirtualObject(newVirtual, newEntryState, 0); - tool.replaceWithVirtual(newVirtual); - } - } else { - ValueNode obj; - if (originalState != null) { - obj = originalState.getMaterializedValue(); - } else { - obj = tool.getReplacedValue(getObject()); - } - ResolvedJavaType type = getConcreteType(obj.objectStamp(), tool.getAssumptions()); - if (isCloneableType(type, tool.getMetaAccessProvider())) { - if (!type.isArray()) { - VirtualInstanceNode newVirtual = new VirtualInstanceNode(type); - ResolvedJavaField[] fields = newVirtual.getFields(); - - ValueNode[] state = new ValueNode[fields.length]; - final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; - for (int i = 0; i < fields.length; i++) { - state[i] = loads[i] = graph().add(new LoadFieldNode(obj, fields[i])); - } - - final StructuredGraph structuredGraph = (StructuredGraph) graph(); - tool.customAction(new Runnable() { - - public void run() { - for (LoadFieldNode load : loads) { - structuredGraph.addBeforeFixed(ObjectCloneNode.this, load); - } - } - }); - tool.createVirtualObject(newVirtual, state, 0); - tool.replaceWithVirtual(newVirtual); - } - } - } - } - - @Override - public ValueNode length() { - if (getObject() instanceof ArrayLengthProvider) { - return ((ArrayLengthProvider) getObject()).length(); - } else { - return null; - } - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.word.*; - -public class ObjectCloneSnippets implements SnippetsInterface { - - public static final Method instanceCloneMethod = getCloneMethod("instanceClone"); - public static final Method arrayCloneMethod = getCloneMethod("arrayClone"); - public static final Method genericCloneMethod = getCloneMethod("genericClone"); - - private static Method getCloneMethod(String name) { - try { - return ObjectCloneSnippets.class.getDeclaredMethod(name, Object.class); - } catch (SecurityException | NoSuchMethodException e) { - throw new GraalInternalError(e); - } - } - - private static Object instanceClone(Object src, Word hub, int layoutHelper) { - int instanceSize = layoutHelper; - Pointer memory = NewObjectSnippets.allocate(instanceSize); - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false); - - memory = Word.fromObject(result); - for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { - memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); - } - - return result; - } - - private static Object arrayClone(Object src, Word hub, int layoutHelper) { - int arrayLength = ArrayLengthNode.arrayLength(src); - int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); - int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); - int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); - - Pointer memory = NewObjectSnippets.allocate(sizeInBytes); - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false); - - memory = Word.fromObject(result); - for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { - memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); - } - return result; - } - - private static Word getAndCheckHub(Object src) { - Word hub = loadHub(src); - if (!(src instanceof Cloneable)) { - probability(DEOPT_PATH_PROBABILITY); - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); - } - return hub; - } - - @Snippet - public static Object instanceClone(Object src) { - instanceCloneCounter.inc(); - Word hub = getAndCheckHub(src); - return instanceClone(src, hub, hub.readInt(layoutHelperOffset(), FINAL_LOCATION)); - } - - @Snippet - public static Object arrayClone(Object src) { - arrayCloneCounter.inc(); - Word hub = getAndCheckHub(src); - int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); - return arrayClone(src, hub, layoutHelper); - } - - @Snippet - public static Object genericClone(Object src) { - genericCloneCounter.inc(); - Word hub = getAndCheckHub(src); - int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); - if (layoutHelper < 0) { - probability(LIKELY_PROBABILITY); - genericArrayCloneCounter.inc(); - return arrayClone(src, hub, layoutHelper); - } else { - genericInstanceCloneCounter.inc(); - return instanceClone(src, hub, layoutHelper); - } - } - - private static final SnippetCounter.Group cloneCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Object.clone") : null; - private static final SnippetCounter instanceCloneCounter = new SnippetCounter(cloneCounters, "instanceClone", "clone snippet for instances"); - private static final SnippetCounter arrayCloneCounter = new SnippetCounter(cloneCounters, "arrayClone", "clone snippet for arrays"); - private static final SnippetCounter genericCloneCounter = new SnippetCounter(cloneCounters, "genericClone", "clone snippet for arrays and instances"); - - private static final SnippetCounter.Group genericCloneCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Object.clone generic snippet") : null; - private static final SnippetCounter genericInstanceCloneCounter = new SnippetCounter(genericCloneCounters, "genericInstanceClone", "generic clone implementation took instance path"); - private static final SnippetCounter genericArrayCloneCounter = new SnippetCounter(genericCloneCounters, "genericArrayClone", "generic clone implementation took array path"); - -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; - -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.ClassSubstitution.MacroSubstitution; -import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; -import com.oracle.graal.word.*; - -/** - * Substitutions for {@link java.lang.Object} methods. - */ -@ClassSubstitution(java.lang.Object.class) -public class ObjectSubstitutions { - - @MethodSubstitution(isStatic = false) - public static Class<?> getClass(final Object thisObj) { - Word hub = loadHub(thisObj); - return unsafeCast(hub.readObject(Word.signed(classMirrorOffset()), LocationNode.FINAL_LOCATION), Class.class, true, true); - } - - @MethodSubstitution(isStatic = false) - public static int hashCode(final Object thisObj) { - return computeHashCode(thisObj); - } - - @MacroSubstitution(macro = ObjectCloneNode.class, isStatic = false) - public static native Object clone(Object obj); -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.ClassSubstitution.MacroSubstitution; -import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; - -/** - * Substitutions for {@link java.lang.System} methods. - */ -@ClassSubstitution(java.lang.System.class) -public class SystemSubstitutions { - - public static final Descriptor JAVA_TIME_MILLIS = new Descriptor("javaTimeMillis", false, long.class); - public static final Descriptor JAVA_TIME_NANOS = new Descriptor("javaTimeNanos", false, long.class); - - @MacroSubstitution(macro = ArrayCopyNode.class) - public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); - - @MethodSubstitution - public static long currentTimeMillis() { - return callLong(JAVA_TIME_MILLIS); - } - - @MethodSubstitution - public static long nanoTime() { - return callLong(JAVA_TIME_NANOS); - } - - @MethodSubstitution - public static int identityHashCode(Object x) { - if (x == null) { - probability(NOT_FREQUENT_PROBABILITY); - return 0; - } - - return computeHashCode(x); - } - - @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true) - public static native long callLong(@ConstantNodeParameter Descriptor descriptor); -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; - -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; -import com.oracle.graal.word.*; - -/** - * Substitutions for {@link java.lang.Thread} methods. - */ -@ClassSubstitution(java.lang.Thread.class) -public class ThreadSubstitutions { - - @MethodSubstitution - public static Thread currentThread() { - return CurrentThread.get(); - } - - @MethodSubstitution(isStatic = false) - private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) { - Word rawThread = HotSpotCurrentRawThreadNode.get(); - Thread thread = (Thread) rawThread.readObject(threadObjectOffset(), FINAL_LOCATION); - if (thisObject == thread) { - Word osThread = rawThread.readWord(osThreadOffset(), FINAL_LOCATION); - boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), UNKNOWN_LOCATION) != 0; - if (!interrupted || !clearInterrupted) { - return interrupted; - } - } - - return ThreadIsInterruptedStubCall.call(thisObject, clearInterrupted) != 0; - } -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +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.snippets; - -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.word.*; - -/** - * Utilities and common code paths used by the type check snippets. - */ -public class TypeCheckSnippetUtils { - - public static final Object TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay"); - - static boolean checkSecondarySubType(Word t, Word s) { - // if (S.cache == T) return true - if (s.readWord(secondarySuperCacheOffset(), SECONDARY_SUPER_CACHE_LOCATION).equal(t)) { - cacheHit.inc(); - return true; - } - - return checkSelfAndSupers(t, s); - } - - static boolean checkUnknownSubType(Word t, Word s) { - // int off = T.offset - int superCheckOffset = t.readInt(superCheckOffsetOffset(), FINAL_LOCATION); - boolean primary = superCheckOffset != secondarySuperCacheOffset(); - - // if (T = S[off]) return true - if (s.readWord(superCheckOffset, TYPE_DISPLAY_LOCATION).equal(t)) { - if (primary) { - cacheHit.inc(); - } else { - displayHit.inc(); - } - return true; - } - - // if (off != &cache) return false - if (primary) { - displayMiss.inc(); - return false; - } - - return checkSelfAndSupers(t, s); - } - - private static boolean checkSelfAndSupers(Word t, Word s) { - // if (T == S) return true - if (s.equal(t)) { - T_equals_S.inc(); - return true; - } - - // if (S.scan_s_s_array(T)) { S.cache = T; return true; } - Word secondarySupers = s.readWord(secondarySupersOffset(), SECONDARY_SUPERS_LOCATION); - int length = secondarySupers.readInt(metaspaceArrayLengthOffset(), FINAL_LOCATION); - for (int i = 0; i < length; i++) { - if (t.equal(loadSecondarySupersElement(secondarySupers, i))) { - probability(NOT_LIKELY_PROBABILITY); - s.writeWord(secondarySuperCacheOffset(), t, SECONDARY_SUPER_CACHE_LOCATION); - secondariesHit.inc(); - return true; - } - } - secondariesMiss.inc(); - return false; - } - - static ConstantNode[] createHints(TypeCheckHints hints, MetaAccessProvider runtime, Graph graph) { - ConstantNode[] hintHubs = new ConstantNode[hints.types.length]; - for (int i = 0; i < hintHubs.length; i++) { - hintHubs[i] = ConstantNode.forConstant(((HotSpotResolvedObjectType) hints.types[i]).klass(), runtime, graph); - } - return hintHubs; - } - - static Word loadSecondarySupersElement(Word metaspaceArray, int index) { - return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize(), FINAL_LOCATION); - } - - private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("TypeCheck") : null; - static final SnippetCounter hintsHit = new SnippetCounter(counters, "hintsHit", "hit a hint type"); - static final SnippetCounter exactHit = new SnippetCounter(counters, "exactHit", "exact type test succeeded"); - static final SnippetCounter exactMiss = new SnippetCounter(counters, "exactMiss", "exact type test failed"); - static final SnippetCounter isNull = new SnippetCounter(counters, "isNull", "object tested was null"); - static final SnippetCounter cacheHit = new SnippetCounter(counters, "cacheHit", "secondary type cache hit"); - static final SnippetCounter secondariesHit = new SnippetCounter(counters, "secondariesHit", "secondaries scan succeeded"); - static final SnippetCounter secondariesMiss = new SnippetCounter(counters, "secondariesMiss", "secondaries scan failed"); - static final SnippetCounter displayHit = new SnippetCounter(counters, "displayHit", "primary type test succeeded"); - static final SnippetCounter displayMiss = new SnippetCounter(counters, "displayMiss", "primary type test failed"); - static final SnippetCounter T_equals_S = new SnippetCounter(counters, "T_equals_S", "object type was equal to secondary type"); - -}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Thu Mar 21 11:09:19 2013 +0100 @@ -22,19 +22,18 @@ */ package com.oracle.graal.hotspot.stubs; -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.hotspot.snippets.NewObjectSnippets.*; +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.snippets.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.SnippetTemplate.Key; +import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.SnippetTemplate.*; import com.oracle.graal.word.*; /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Thu Mar 21 11:09:19 2013 +0100 @@ -24,19 +24,17 @@ import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; -import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import static com.oracle.graal.hotspot.snippets.NewObjectSnippets.*; +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.snippets.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Fold; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.SnippetTemplate.Key; +import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.SnippetTemplate.*; import com.oracle.graal.word.*; /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Thu Mar 21 11:09:19 2013 +0100 @@ -40,19 +40,18 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; -import com.oracle.graal.snippets.SnippetTemplate.Key; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.SnippetTemplate.*; /** * Base class for implementing some low level code providing the out-of-line slow path for a * snippet. A concrete stub is defined a subclass of this class. * <p> * Implementation detail: The stub classes re-use some of the functionality for {@link Snippet}s - * purely for convenience (e.g., can re-use the {@link SnippetInstaller}). + * purely for convenience (e.g., can re-use the {@link ReplacementsInstaller}). */ -public abstract class Stub extends AbstractTemplates implements SnippetsInterface { +public abstract class Stub extends AbstractTemplates implements Snippets { /** * The method implementing the stub.
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/System_identityHashCode01.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/System_identityHashCode01.java Thu Mar 21 11:09:19 2013 +0100 @@ -22,8 +22,9 @@ */ package com.oracle.graal.jtt.lang; +import org.junit.*; + import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -47,6 +48,9 @@ if (i == 2) { return hash2 == System.identityHashCode(object2); } + if (i == 3) { + return 0 == System.identityHashCode(null); + } return false; } @@ -70,4 +74,8 @@ runTest("test", 3); } + @Test + public void run4() throws Throwable { + runTest("test", 4); + } }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon Mar 18 19:18:42 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Thu Mar 21 11:09:19 2013 +0100 @@ -113,7 +113,7 @@ // Debug settings: public static boolean Debug = true; - public static boolean DebugSnippets = false; + public static boolean DebugReplacements = false; public static boolean PerThreadDebugValues = ____; public static boolean SummarizeDebugValues = ____; public static boolean SummarizePerPhase = ____;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,193 @@ +/* + * 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.amd64; + +import static com.oracle.graal.replacements.SnippetTemplate.*; +import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.calc.ConvertNode.Op; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match + * the semantics of the JVM specification. + */ +public class AMD64ConvertSnippets implements Snippets { + + /** + * Converts a float to an int. + * <p> + * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the + * conversion. If the float value is a NaN, infinity or if the result of the conversion is + * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and + * extra tests are required on the float value to return the correct int value. + * + * @param input the float being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static int f2i(@Parameter("input") float input, @Parameter("result") int result) { + if (result == Integer.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Float.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0f) { + // input is > 0 -> return max int + return Integer.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a float to a long. + * <p> + * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the + * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns + * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct + * long value. + * + * @param input the float being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static long f2l(@Parameter("input") float input, @Parameter("result") long result) { + if (result == Long.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Float.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0f) { + // input is > 0 -> return max int + return Long.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a double to an int. + * <p> + * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the + * conversion. If the double value is a NaN, infinity or if the result of the conversion is + * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and + * extra tests are required on the double value to return the correct int value. + * + * @param input the double being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static int d2i(@Parameter("input") double input, @Parameter("result") int result) { + if (result == Integer.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Double.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0d) { + // input is positive -> return maxInt + return Integer.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a double to a long. + * <p> + * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the + * conversion. If the double value is a NaN, infinity or if the result of the conversion is + * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra + * tests are required on the double value to return the correct long value. + * + * @param input the double being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static long d2l(@Parameter("input") double input, @Parameter("result") long result) { + if (result == Long.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Double.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0d) { + // input is positive -> return maxInt + return Long.MAX_VALUE; + } + } + return result; + } + + public static class Templates extends AbstractTemplates<AMD64ConvertSnippets> { + + private final ResolvedJavaMethod f2i; + private final ResolvedJavaMethod f2l; + private final ResolvedJavaMethod d2i; + private final ResolvedJavaMethod d2l; + + public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { + super(runtime, assumptions, target, AMD64ConvertSnippets.class); + f2i = snippet("f2i", float.class, int.class); + f2l = snippet("f2l", float.class, long.class); + d2i = snippet("d2i", double.class, int.class); + d2l = snippet("d2l", double.class, long.class); + } + + public void lower(ConvertNode convert, LoweringTool tool) { + if (convert.opcode == Op.F2I) { + lower0(convert, tool, f2i); + } else if (convert.opcode == Op.F2L) { + lower0(convert, tool, f2l); + } else if (convert.opcode == Op.D2I) { + lower0(convert, tool, d2i); + } else if (convert.opcode == Op.D2L) { + lower0(convert, tool, d2l); + } + } + + private void lower0(ConvertNode convert, LoweringTool tool, ResolvedJavaMethod snippet) { + StructuredGraph graph = (StructuredGraph) convert.graph(); + + // Insert a unique placeholder node in place of the Convert node so that the + // Convert node can be used as an input to the snippet. All usage of the + // Convert node are replaced by the placeholder which in turn is replaced by the + // snippet. + + LocalNode replacee = graph.add(new LocalNode(Integer.MAX_VALUE, convert.stamp())); + convert.replaceAtUsages(replacee); + Key key = new Key(snippet); + Arguments arguments = arguments("input", convert.value()).add("result", convert); + SnippetTemplate template = cache.get(key, assumptions); + Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, arguments); + template.instantiate(runtime, replacee, DEFAULT_REPLACER, tool, arguments); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/overview.html Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,36 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> +<head> +<!-- + +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. Oracle designates this +particular file as subject to the "Classpath" exception as provided +by Oracle in the LICENSE file that accompanied this code. + +This code is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +version 2 for more details (a copy is included in the LICENSE file that +accompanied this code). + +You should have received a copy of the GNU General Public License version +2 along with this work; if not, write to the Free Software Foundation, +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. +--> + +</head> +<body> + +Documentation for the <code>com.oracle.graal.snippets.test</code> project. + +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/CheckCastTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests the implementation of checkcast, allowing profiling information to be manually specified. + */ +public class CheckCastTest extends TypeCheckTest { + + @Override + protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { + CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); + if (ccn != null) { + CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile)); + graph.replaceFixedWithFixed(ccn, ccnNew); + } + } + + @LongTest + public void test1() { + test("asNumber", profile(), 111); + test("asNumber", profile(Integer.class), 111); + test("asNumber", profile(Long.class, Short.class), 111); + test("asNumberExt", profile(), 111); + test("asNumberExt", profile(Integer.class), 111); + test("asNumberExt", profile(Long.class, Short.class), 111); + } + + @LongTest + public void test2() { + test("asString", profile(), "111"); + test("asString", profile(String.class), "111"); + test("asString", profile(String.class), "111"); + + final String nullString = null; + test("asString", profile(), nullString); + test("asString", profile(String.class), nullString); + test("asString", profile(String.class), nullString); + + test("asStringExt", profile(), "111"); + test("asStringExt", profile(String.class), "111"); + test("asStringExt", profile(String.class), "111"); + } + + @LongTest + public void test3() { + test("asNumber", profile(), "111"); + } + + @LongTest + public void test4() { + test("asString", profile(String.class), 111); + } + + @LongTest + public void test5() { + test("asNumberExt", profile(), "111"); + } + + @LongTest + public void test6() { + test("asStringExt", profile(String.class), 111); + } + + @LongTest + public void test7() { + Throwable throwable = new Exception(); + test("asThrowable", profile(), throwable); + test("asThrowable", profile(Throwable.class), throwable); + test("asThrowable", profile(Exception.class, Error.class), throwable); + } + + @LongTest + public void test8() { + test("arrayStore", new Object[100], "111"); + } + + @LongTest + public void test8_1() { + test("arrayFill", new Object[100], "111"); + } + + public static Number asNumber(Object o) { + return (Number) o; + } + + public static String asString(Object o) { + return (String) o; + } + + public static Throwable asThrowable(Object o) { + return (Throwable) o; + } + + public static ValueNode asValueNode(Object o) { + return (ValueNode) o; + } + + public static Number asNumberExt(Object o) { + Number n = (Number) o; + return n.intValue() + 10; + } + + public static String asStringExt(Object o) { + String s = (String) o; + return "#" + s; + } + + public static Object[] arrayStore(Object[] arr, Object value) { + arr[15] = value; + return arr; + } + + public static Object[] arrayFill(Object[] arr, Object value) { + for (int i = 0; i < arr.length; i++) { + arr[i] = value; + } + return arr; + } + + static class Depth1 implements Cloneable { + } + + static class Depth2 extends Depth1 { + } + + static class Depth3 extends Depth2 { + } + + static class Depth4 extends Depth3 { + } + + static class Depth5 extends Depth4 { + } + + static class Depth6 extends Depth5 { + } + + static class Depth7 extends Depth6 { + } + + static class Depth8 extends Depth7 { + } + + static class Depth9 extends Depth8 { + } + + static class Depth10 extends Depth9 { + } + + static class Depth11 extends Depth10 { + } + + static class Depth12 extends Depth11 { + } + + static class Depth13 extends Depth12 { + } + + static class Depth14 extends Depth12 { + } + + public static Depth12 asDepth12(Object o) { + return (Depth12) o; + } + + public static Depth12[][] asDepth12Arr(Object o) { + return (Depth12[][]) o; + } + + public static Cloneable asCloneable(Object o) { + return (Cloneable) o; + } + + @LongTest + public void test9() { + Object o = new Depth13(); + test("asDepth12", profile(), o); + test("asDepth12", profile(Depth13.class), o); + test("asDepth12", profile(Depth13.class, Depth14.class), o); + } + + @LongTest + public void test10() { + Object o = new Depth13[3][]; + test("asDepth12Arr", o); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfDynamicTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.test.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests for {@link InstanceOfDynamicNode}. + */ +public class InstanceOfDynamicTest extends GraalCompilerTest { + + public static int id(int value) { + return value; + } + + @LongTest + public void test100() { + final Object nul = null; + test("isStringDynamic", nul); + test("isStringDynamic", "object"); + test("isStringDynamic", Object.class); + } + + @LongTest + public void test101() { + final Object nul = null; + test("isStringIntDynamic", nul); + test("isStringIntDynamic", "object"); + test("isStringIntDynamic", Object.class); + } + + @LongTest + public void test103() { + test("isInstanceDynamic", String.class, null); + test("isInstanceDynamic", String.class, "object"); + test("isInstanceDynamic", String.class, Object.class); + test("isInstanceDynamic", int.class, null); + test("isInstanceDynamic", int.class, "Object"); + test("isInstanceDynamic", int.class, Object.class); + } + + @LongTest + public void test104() { + test("isInstanceIntDynamic", String.class, null); + test("isInstanceIntDynamic", String.class, "object"); + test("isInstanceIntDynamic", String.class, Object.class); + test("isInstanceIntDynamic", int.class, null); + test("isInstanceIntDynamic", int.class, "Object"); + test("isInstanceIntDynamic", int.class, Object.class); + } + + public static boolean isStringDynamic(Object o) { + return String.class.isInstance(o); + } + + public static int isStringIntDynamic(Object o) { + if (String.class.isInstance(o)) { + return o.toString().length(); + } + return o.getClass().getName().length(); + } + + public static boolean isInstanceDynamic(Class c, Object o) { + return c.isInstance(o); + } + + public static int isInstanceIntDynamic(Class c, Object o) { + if (c.isInstance(o)) { + return o.toString().length(); + } + return o.getClass().getName().length(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import java.util.*; + + +import com.oracle.graal.api.code.CompilationResult.Call; +import com.oracle.graal.api.code.CompilationResult.Mark; +import com.oracle.graal.api.code.CompilationResult.Site; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.CheckCastTest.*; + +/** + * Tests the implementation of instanceof, allowing profiling information to be manually specified. + */ +public class InstanceOfTest extends TypeCheckTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + @Override + protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { + InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); + if (ion != null) { + InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.type(), ion.object(), profile)); + graph.replaceFloating(ion, ionNew); + } + } + + @LongTest + public void test1() { + test("isString", profile(), "object"); + test("isString", profile(String.class), "object"); + + test("isString", profile(), Object.class); + test("isString", profile(String.class), Object.class); + } + + @LongTest + public void test2() { + test("isStringInt", profile(), "object"); + test("isStringInt", profile(String.class), "object"); + + test("isStringInt", profile(), Object.class); + test("isStringInt", profile(String.class), Object.class); + } + + @LongTest + public void test2_1() { + test("isStringIntComplex", profile(), "object"); + test("isStringIntComplex", profile(String.class), "object"); + + test("isStringIntComplex", profile(), Object.class); + test("isStringIntComplex", profile(String.class), Object.class); + } + + @LongTest + public void test3() { + Throwable throwable = new Exception(); + test("isThrowable", profile(), throwable); + test("isThrowable", profile(Throwable.class), throwable); + test("isThrowable", profile(Exception.class, Error.class), throwable); + + test("isThrowable", profile(), Object.class); + test("isThrowable", profile(Throwable.class), Object.class); + test("isThrowable", profile(Exception.class, Error.class), Object.class); + } + + @LongTest + public void test3_1() { + onlyFirstIsException(new Exception(), new Error()); + test("onlyFirstIsException", profile(), new Exception(), new Error()); + test("onlyFirstIsException", profile(), new Error(), new Exception()); + test("onlyFirstIsException", profile(), new Exception(), new Exception()); + test("onlyFirstIsException", profile(), new Error(), new Error()); + } + + @LongTest + public void test4() { + Throwable throwable = new Exception(); + test("isThrowableInt", profile(), throwable); + test("isThrowableInt", profile(Throwable.class), throwable); + test("isThrowableInt", profile(Exception.class, Error.class), throwable); + + test("isThrowableInt", profile(), Object.class); + test("isThrowableInt", profile(Throwable.class), Object.class); + test("isThrowableInt", profile(Exception.class, Error.class), Object.class); + } + + @LongTest + public void test5() { + Map map = new HashMap<>(); + test("isMap", profile(), map); + test("isMap", profile(HashMap.class), map); + test("isMap", profile(TreeMap.class, HashMap.class), map); + + test("isMap", profile(), Object.class); + test("isMap", profile(HashMap.class), Object.class); + test("isMap", profile(TreeMap.class, HashMap.class), Object.class); + } + + @LongTest + public void test6() { + Map map = new HashMap<>(); + test("isMapInt", profile(), map); + test("isMapInt", profile(HashMap.class), map); + test("isMapInt", profile(TreeMap.class, HashMap.class), map); + + test("isMapInt", profile(), Object.class); + test("isMapInt", profile(HashMap.class), Object.class); + test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); + } + + @LongTest + public void test7() { + Object o = new Depth13(); + test("isDepth12", profile(), o); + test("isDepth12", profile(Depth13.class), o); + test("isDepth12", profile(Depth13.class, Depth14.class), o); + + o = "not a depth"; + test("isDepth12", profile(), o); + test("isDepth12", profile(Depth13.class), o); + test("isDepth12", profile(Depth13.class, Depth14.class), o); + } + + @LongTest + public void test8() { + Object o = new Depth13(); + test("isDepth12Int", profile(), o); + test("isDepth12Int", profile(Depth13.class), o); + test("isDepth12Int", profile(Depth13.class, Depth14.class), o); + + o = "not a depth"; + test("isDepth12Int", profile(), o); + test("isDepth12Int", profile(Depth13.class), o); + test("isDepth12Int", profile(Depth13.class, Depth14.class), o); + } + + public static boolean isString(Object o) { + return o instanceof String; + } + + public static int isStringInt(Object o) { + if (o instanceof String) { + return id(1); + } + return id(0); + } + + public static int isStringIntComplex(Object o) { + if (o instanceof String || o instanceof Integer) { + return id(o instanceof String ? 1 : 0); + } + return id(0); + } + + public static int id(int value) { + return value; + } + + public static boolean isThrowable(Object o) { + return ((Throwable) o) instanceof Exception; + } + + public static int onlyFirstIsException(Throwable t1, Throwable t2) { + if (t1 instanceof Exception ^ t2 instanceof Exception) { + return t1 instanceof Exception ? 1 : -1; + } + return -1; + } + + public static int isThrowableInt(Object o) { + int result = o instanceof Throwable ? 4 : 5; + if (o instanceof Throwable) { + return id(4); + } + return result; + } + + public static boolean isMap(Object o) { + return o instanceof Map; + } + + public static int isMapInt(Object o) { + if (o instanceof Map) { + return id(1); + } + return id(0); + } + + public static boolean isDepth12(Object o) { + return o instanceof Depth12; + } + + public static int isDepth12Int(Object o) { + if (o instanceof Depth12) { + return id(0); + } + return id(0); + } + + abstract static class MySite { + + final int offset; + + MySite(int offset) { + this.offset = offset; + } + } + + static class MyMark extends MySite { + + MyMark(int offset) { + super(offset); + } + } + + abstract static class MySafepoint extends MySite { + + MySafepoint(int offset) { + super(offset); + } + } + + static class MyCall extends MySafepoint { + + MyCall(int offset) { + super(offset); + } + } + + @LongTest + public void test9() { + MyCall callAt63 = new MyCall(63); + MyMark markAt63 = new MyMark(63); + test("compareMySites", callAt63, callAt63); + test("compareMySites", callAt63, markAt63); + test("compareMySites", markAt63, callAt63); + test("compareMySites", markAt63, markAt63); + } + + public static int compareMySites(MySite s1, MySite s2) { + if (s1.offset == s2.offset && (s1 instanceof MyMark ^ s2 instanceof MyMark)) { + return s1 instanceof MyMark ? -1 : 1; + } + return s1.offset - s2.offset; + } + + @LongTest + public void test10() { + Mark[] noMarks = {}; + Call callAt63 = new Call(null, 63, 5, true, null); + Mark markAt63 = new Mark(63, "1", noMarks); + test("compareSites", callAt63, callAt63); + test("compareSites", callAt63, markAt63); + test("compareSites", markAt63, callAt63); + test("compareSites", markAt63, markAt63); + } + + public static int compareSites(Site s1, Site s2) { + if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { + return s1 instanceof Mark ? -1 : 1; + } + return s1.pcOffset - s2.pcOffset; + } + + /** + * This test exists to show the kind of pattern that is be optimizable by + * {@code removeIntermediateMaterialization()} in {@link IfNode}. + * <p> + * The test exists in this source file as the transformation was originally motivated by the + * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}. + */ + @LongTest + public void test_removeIntermediateMaterialization() { + List<String> list = Arrays.asList("1", "2", "3", "4"); + test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); + test("removeIntermediateMaterialization", profile(), list, null, "yes", "no"); + test("removeIntermediateMaterialization", profile(), null, "2", "yes", "no"); + } + + public static String removeIntermediateMaterialization(List<Object> list, Object e, String a, String b) { + boolean test; + if (list == null || e == null) { + test = false; + } else { + test = false; + for (Object i : list) { + if (i.equals(e)) { + test = true; + break; + } + } + } + if (test) { + return a; + } + return b; + } + + abstract static class A { + } + + static class B extends A { + } + + static class C extends B { + } + + abstract static class D extends C { + } + + public static boolean isArrayOfA(Object o) { + return o instanceof A[]; + } + + public static boolean isArrayOfB(Object o) { + return o instanceof B[]; + } + + public static boolean isArrayOfC(Object o) { + return o instanceof C[]; + } + + public static boolean isArrayOfD(Object o) { + return o instanceof D[]; + } + + @LongTest + public void testArray() { + Object aArray = new A[10]; + test("isArrayOfA", aArray); + + Object bArray = new B[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + + Object cArray = new C[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfA", cArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + test("isArrayOfB", cArray); + test("isArrayOfC", aArray); + test("isArrayOfC", bArray); + test("isArrayOfC", cArray); + + Object dArray = new D[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfA", cArray); + test("isArrayOfA", dArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + test("isArrayOfB", cArray); + test("isArrayOfB", dArray); + test("isArrayOfC", aArray); + test("isArrayOfC", bArray); + test("isArrayOfC", cArray); + test("isArrayOfC", dArray); + test("isArrayOfD", aArray); + test("isArrayOfD", bArray); + test("isArrayOfD", cArray); + test("isArrayOfD", dArray); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InvokeTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; + +/** + * Tests the implementation of the snippets for lowering the INVOKE* instructions. + */ +public class InvokeTest extends GraalCompilerTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + public interface I { + + String virtualMethod(String s); + } + + public static class A implements I { + + final String name = "A"; + + public String virtualMethod(String s) { + return name + s; + } + } + + @SuppressWarnings("static-method") + private String privateMethod(String s) { + return s; + } + + @Test + public void test1() { + test("invokestatic", "a string"); + test("invokespecialConstructor", "a string"); + test("invokespecial", this, "a string"); + test("invokevirtual", new A(), "a string"); + test("invokevirtual2", new A(), "a string"); + test("invokeinterface", new A(), "a string"); + Object[] args = {null}; + test("invokestatic", args); + test("invokespecialConstructor", args); + test("invokespecial", null, null); + test("invokevirtual", null, null); + test("invokevirtual2", null, null); + test("invokeinterface", null, null); + } + + public static String invokestatic(String s) { + return staticMethod(s); + } + + public static String staticMethod(String s) { + return s; + } + + public static String invokespecialConstructor(String s) { + return new A().virtualMethod(s); + } + + public static String invokespecial(InvokeTest a, String s) { + return a.privateMethod(s); + } + + public static String invokevirtual(A a, String s) { + return a.virtualMethod(s); + } + + public static String invokevirtual2(A a, String s) { + a.virtualMethod(s); + return a.virtualMethod(s); + } + + public static String invokeinterface(I i, String s) { + return i.virtualMethod(s); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MethodSubstitutionTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,462 @@ +/* + * 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.replacements; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.*; + +import sun.misc.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Tests if {@link MethodSubstitution}s are inlined correctly. Most test cases only assert that + * there are no remaining invocations in the graph. This is sufficient if the method that is being + * substituted is a native method. For Java methods, additional checks are necessary. + */ +public class MethodSubstitutionTest extends GraalCompilerTest { + + @Test + public void testObjectSubstitutions() { + test("getClass_"); + test("objectHashCode"); + } + + @SuppressWarnings("all") + public static boolean getClass_(Object obj, Class<?> clazz) { + return obj.getClass() == clazz; + } + + @SuppressWarnings("all") + public static int objectHashCode(TestClassA obj) { + return obj.hashCode(); + } + + @Test + public void testClassSubstitutions() { + test("getModifiers"); + test("isInstance"); + test("isInterface"); + test("isArray"); + test("isPrimitive"); + test("getSuperClass"); + test("getComponentType"); + } + + @SuppressWarnings("all") + public static int getModifiers(Class<?> clazz) { + return clazz.getModifiers(); + } + + @SuppressWarnings("all") + public static boolean isInstance(Class<?> clazz) { + return clazz.isInstance(Number.class); + } + + @SuppressWarnings("all") + public static boolean isInterface(Class<?> clazz) { + return clazz.isInterface(); + } + + @SuppressWarnings("all") + public static boolean isArray(Class<?> clazz) { + return clazz.isArray(); + } + + @SuppressWarnings("all") + public static boolean isPrimitive(Class<?> clazz) { + return clazz.isPrimitive(); + } + + @SuppressWarnings("all") + public static Class<?> getSuperClass(Class<?> clazz) { + return clazz.getSuperclass(); + } + + @SuppressWarnings("all") + public static Class<?> getComponentType(Class<?> clazz) { + return clazz.getComponentType(); + } + + @Test + public void testThreadSubstitutions() { + test("currentThread"); + test("threadIsInterrupted"); + test("threadInterrupted"); + } + + @SuppressWarnings("all") + public static Thread currentThread() { + return Thread.currentThread(); + } + + @SuppressWarnings("all") + public static boolean threadIsInterrupted(Thread thread) { + return thread.isInterrupted(); + } + + @SuppressWarnings("all") + public static boolean threadInterrupted() { + return Thread.interrupted(); + } + + @Test + public void testSystemSubstitutions() { + test("systemTime"); + test("systemIdentityHashCode"); + } + + @SuppressWarnings("all") + public static long systemTime() { + return System.currentTimeMillis() + System.nanoTime(); + } + + @SuppressWarnings("all") + public static int systemIdentityHashCode(Object obj) { + return System.identityHashCode(obj); + } + + @Test + public void testUnsafeSubstitutions() { + test("unsafeCompareAndSwapInt"); + test("unsafeCompareAndSwapLong"); + test("unsafeCompareAndSwapObject"); + + test("unsafeGetBoolean"); + test("unsafeGetByte"); + test("unsafeGetShort"); + test("unsafeGetChar"); + test("unsafeGetInt"); + test("unsafeGetFloat"); + test("unsafeGetDouble"); + test("unsafeGetObject"); + + test("unsafePutBoolean"); + test("unsafePutByte"); + test("unsafePutShort"); + test("unsafePutChar"); + test("unsafePutInt"); + test("unsafePutFloat"); + test("unsafePutDouble"); + test("unsafePutObject"); + + test("unsafeDirectMemoryRead"); + test("unsafeDirectMemoryWrite"); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapInt(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapInt(obj, offset, 0, 1); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapLong(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapLong(obj, offset, 0, 1); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapObject(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapObject(obj, offset, null, new Object()); + } + + @SuppressWarnings("all") + public static boolean unsafeGetBoolean(Unsafe unsafe, Object obj, long offset) { + return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetByte(Unsafe unsafe, Object obj, long offset) { + return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetShort(Unsafe unsafe, Object obj, long offset) { + return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetChar(Unsafe unsafe, Object obj, long offset) { + return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetInt(Unsafe unsafe, Object obj, long offset) { + return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static long unsafeGetLong(Unsafe unsafe, Object obj, long offset) { + return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static float unsafeGetFloat(Unsafe unsafe, Object obj, long offset) { + return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static double unsafeGetDouble(Unsafe unsafe, Object obj, long offset) { + return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static boolean unsafeGetObject(Unsafe unsafe, Object obj, long offset) { + return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static void unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) { + unsafe.putBoolean(obj, offset, value); + unsafe.putBooleanVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) { + unsafe.putByte(obj, offset, value); + unsafe.putByteVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) { + unsafe.putShort(obj, offset, value); + unsafe.putShortVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) { + unsafe.putChar(obj, offset, value); + unsafe.putCharVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) { + unsafe.putInt(obj, offset, value); + unsafe.putIntVolatile(obj, offset, value); + unsafe.putOrderedInt(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) { + unsafe.putLong(obj, offset, value); + unsafe.putLongVolatile(obj, offset, value); + unsafe.putOrderedLong(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) { + unsafe.putFloat(obj, offset, value); + unsafe.putFloatVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) { + unsafe.putDouble(obj, offset, value); + unsafe.putDoubleVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value) { + unsafe.putObject(obj, offset, value); + unsafe.putObjectVolatile(obj, offset, value); + unsafe.putOrderedObject(obj, offset, value); + } + + @SuppressWarnings("all") + public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) { + // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist + return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address); + } + + @SuppressWarnings("all") + public static void unsafeDirectMemoryWrite(Unsafe unsafe, long address, byte value) { + // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist + unsafe.putByte(address, value); + unsafe.putShort(address, value); + unsafe.putChar(address, (char) value); + unsafe.putInt(address, value); + unsafe.putLong(address, value); + unsafe.putFloat(address, value); + unsafe.putDouble(address, value); + } + + @Test + public void testMathSubstitutions() { + assertInGraph(assertNotInGraph(test("mathAbs"), IfNode.class), MathIntrinsicNode.class); // Java + test("math"); + } + + @SuppressWarnings("all") + public static double mathAbs(double value) { + return Math.abs(value); + } + + @SuppressWarnings("all") + public static double math(double value) { + return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); + // Math.exp(value) + + // Math.pow(value, 13); + } + + @Test + public void testIntegerSubstitutions() { + assertInGraph(test("integerReverseBytes"), ReverseBytesNode.class); // Java + assertInGraph(test("integerNumberOfLeadingZeros"), BitScanReverseNode.class); // Java + assertInGraph(test("integerNumberOfTrailingZeros"), BitScanForwardNode.class); // Java + assertInGraph(test("integerBitCount"), BitCountNode.class); // Java + } + + @SuppressWarnings("all") + public static int integerReverseBytes(int value) { + return Integer.reverseBytes(value); + } + + @SuppressWarnings("all") + public static int integerNumberOfLeadingZeros(int value) { + return Integer.numberOfLeadingZeros(value); + } + + @SuppressWarnings("all") + public static int integerNumberOfTrailingZeros(int value) { + return Integer.numberOfTrailingZeros(value); + } + + @SuppressWarnings("all") + public static int integerBitCount(int value) { + return Integer.bitCount(value); + } + + @Test + public void testLongSubstitutions() { + assertInGraph(test("longReverseBytes"), ReverseBytesNode.class); // Java + assertInGraph(test("longNumberOfLeadingZeros"), BitScanReverseNode.class); // Java + assertInGraph(test("longNumberOfTrailingZeros"), BitScanForwardNode.class); // Java + assertInGraph(test("longBitCount"), BitCountNode.class); // Java + } + + @SuppressWarnings("all") + public static long longReverseBytes(long value) { + return Long.reverseBytes(value); + } + + @SuppressWarnings("all") + public static long longNumberOfLeadingZeros(long value) { + return Long.numberOfLeadingZeros(value); + } + + @SuppressWarnings("all") + public static long longNumberOfTrailingZeros(long value) { + return Long.numberOfTrailingZeros(value); + } + + @SuppressWarnings("all") + public static int longBitCount(long value) { + return Long.bitCount(value); + } + + @Test + public void testFloatSubstitutions() { + assertInGraph(test("floatToIntBits"), ConvertNode.class); // Java + test("intBitsToFloat"); + } + + @SuppressWarnings("all") + public static int floatToIntBits(float value) { + return Float.floatToIntBits(value); + } + + @SuppressWarnings("all") + public static float intBitsToFloat(int value) { + return Float.intBitsToFloat(value); + } + + @Test + public void testDoubleSubstitutions() { + assertInGraph(test("doubleToLongBits"), ConvertNode.class); // Java + test("longBitsToDouble"); + } + + @SuppressWarnings("all") + public static long doubleToLongBits(double value) { + return Double.doubleToLongBits(value); + } + + @SuppressWarnings("all") + public static double longBitsToDouble(long value) { + return Double.longBitsToDouble(value); + } + + private StructuredGraph test(final String snippet) { + return Debug.scope("MethodSubstitutionTest", runtime.lookupJavaMethod(getMethod(snippet)), new Callable<StructuredGraph>() { + + @Override + public StructuredGraph call() { + StructuredGraph graph = parse(snippet); + PhasePlan phasePlan = getDefaultPhasePlan(); + Assumptions assumptions = new Assumptions(true); + new ComputeProbabilityPhase().apply(graph); + Debug.dump(graph, "Graph"); + new InliningPhase(runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); + Debug.dump(graph, "Graph"); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + + assertNotInGraph(graph, Invoke.class); + return graph; + } + }); + } + + private static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + fail(node.toString()); + } + } + return graph; + } + + private static StructuredGraph assertInGraph(StructuredGraph graph, Class<?> clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + return graph; + } + } + fail("Graph does not contain a node of class " + clazz.getName()); + return graph; + } + + private static class TestClassA { + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MonitorTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,217 @@ +/* + * 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.replacements; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.virtual.phases.ea.*; + +public class MonitorTest extends GraalCompilerTest { + + @Test + public void test0() { + test("lockObjectSimple", new Object(), new Object()); + test("lockObjectSimple", new Object(), null); + } + + @Test + public void test0_1() { + test("lockThisSimple", "test1", new Object()); + test("lockThisSimple", "test1", null); + } + + @Test + public void test0_2() { + test("lockObjectSimple", null, "test1"); + } + + @Test + public void test1_1() { + test("lockObject", new Object(), "test1", new String[1]); + } + + @Test + public void test1_2() { + test("lockObject", null, "test1_1", new String[1]); + } + + @Test + public void test2() { + test("lockThis", "test2", new String[1]); + } + + /** + * Tests monitor operations on {@link PartialEscapeAnalysisPhase virtual objects}. + */ + @Test + public void test3() { + test("lockLocalObject", "test3", new String[1]); + } + + /** + * Tests recursive locking of objects which should be biasable. + */ + @Test + public void test4() { + Chars src = new Chars("1234567890".toCharArray()); + Chars dst = new Chars(src.data.length); + test("copyObj", src, dst, 100); + } + + /** + * Tests recursive locking of objects which do not appear to be biasable. + */ + @Test + public void test5() { + char[] src = "1234567890".toCharArray(); + char[] dst = new char[src.length]; + test("copyArr", src, dst, 100); + } + + /** + * Extends {@link #test4()} with contention. + */ + @Test + public void test6() { + Chars src = new Chars("1234567890".toCharArray()); + Chars dst = new Chars(src.data.length); + int n = Runtime.getRuntime().availableProcessors(); + testN(n, "copyObj", src, dst, 100); + } + + /** + * Extends {@link #test5()} with contention. + */ + @Test + public void test7() { + char[] src = "1234567890".toCharArray(); + char[] dst = new char[src.length]; + int n = Runtime.getRuntime().availableProcessors(); + testN(n, "copyArr", src, dst, 100); + } + + private static String setAndGet(String[] box, String value) { + synchronized (box) { + box[0] = null; + } + + // Do a GC while a object is locked (by the caller) + System.gc(); + + synchronized (box) { + box[0] = value; + } + return box[0]; + } + + public static Object lockObjectSimple(Object o, Object value) { + synchronized (o) { + value.hashCode(); + return value; + } + } + + public String lockThisSimple(String value, Object o) { + synchronized (this) { + synchronized (value) { + o.hashCode(); + return value; + } + } + } + + public static String lockObject(Object o, String value, String[] box) { + synchronized (o) { + return setAndGet(box, value); + } + } + + public String lockThis(String value, String[] box) { + synchronized (this) { + return setAndGet(box, value); + } + } + + public static String lockLocalObject(String value, String[] box) { + Object o = new Object(); + synchronized (o) { + return setAndGet(box, value); + } + } + + static class Chars { + + final char[] data; + + public Chars(int size) { + this.data = new char[size]; + } + + public Chars(char[] data) { + this.data = data; + } + } + + public static String copyObj(Chars src, Chars dst, int n) { + System.out.println(Thread.currentThread().getName() + " reps=" + n + ", src.length=" + src.data.length); + int total = 0; + for (int j = 0; j < n; j++) { + for (int i = 0; i < src.data.length; i++) { + synchronized (src) { + synchronized (dst) { + synchronized (src) { + synchronized (dst) { + dst.data[i] = src.data[i]; + total++; + } + } + } + } + } + } + System.out.println(Thread.currentThread().getName() + " total " + total); + return new String(dst.data); + } + + public static String copyArr(char[] src, char[] dst, int n) { + System.out.println(Thread.currentThread().getName() + " reps=" + n + ", src.length=" + src.length); + int total = 0; + for (int j = 0; j < n; j++) { + for (int i = 0; i < src.length; i++) { + synchronized (src) { + synchronized (dst) { + synchronized (src) { + synchronized (dst) { + dst[i] = src[i]; + total++; + } + } + } + } + } + } + System.out.println(Thread.currentThread().getName() + " total " + total); + return new String(dst); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewArrayTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; + +/** + * Tests the implementation of {@code [A]NEWARRAY}. + */ +public class NewArrayTest extends GraalCompilerTest { + + @Override + protected void assertEquals(Object expected, Object actual) { + Assert.assertTrue(expected != null); + Assert.assertTrue(actual != null); + super.assertEquals(expected.getClass(), actual.getClass()); + if (expected instanceof int[]) { + Assert.assertArrayEquals((int[]) expected, (int[]) actual); + } else if (expected instanceof byte[]) { + Assert.assertArrayEquals((byte[]) expected, (byte[]) actual); + } else if (expected instanceof char[]) { + Assert.assertArrayEquals((char[]) expected, (char[]) actual); + } else if (expected instanceof short[]) { + Assert.assertArrayEquals((short[]) expected, (short[]) actual); + } else if (expected instanceof float[]) { + Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f); + } else if (expected instanceof long[]) { + Assert.assertArrayEquals((long[]) expected, (long[]) actual); + } else if (expected instanceof double[]) { + Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d); + } else if (expected instanceof Object[]) { + Assert.assertArrayEquals((Object[]) expected, (Object[]) actual); + } else { + Assert.fail("non-array value encountered: " + expected); + } + } + + @LongTest + public void test1() { + for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) { + test("new" + type + "Array7"); + test("new" + type + "ArrayMinus7"); + test("new" + type + "Array", 7); + test("new" + type + "Array", -7); + test("new" + type + "Array", Integer.MAX_VALUE); + test("new" + type + "Array", Integer.MIN_VALUE); + } + } + + public static Object newCharArray7() { + return new char[7]; + } + + public static Object newCharArrayMinus7() { + return new char[-7]; + } + + public static Object newCharArray(int length) { + return new char[length]; + } + + public static Object newShortArray7() { + return new short[7]; + } + + public static Object newShortArrayMinus7() { + return new short[-7]; + } + + public static Object newShortArray(int length) { + return new short[length]; + } + + public static Object newFloatArray7() { + return new float[7]; + } + + public static Object newFloatArrayMinus7() { + return new float[-7]; + } + + public static Object newFloatArray(int length) { + return new float[length]; + } + + public static Object newLongArray7() { + return new long[7]; + } + + public static Object newLongArrayMinus7() { + return new long[-7]; + } + + public static Object newLongArray(int length) { + return new long[length]; + } + + public static Object newDoubleArray7() { + return new double[7]; + } + + public static Object newDoubleArrayMinus7() { + return new double[-7]; + } + + public static Object newDoubleArray(int length) { + return new double[length]; + } + + public static Object newIntArray7() { + return new int[7]; + } + + public static Object newIntArrayMinus7() { + return new int[-7]; + } + + public static Object newIntArray(int length) { + return new int[length]; + } + + public static Object newByteArray7() { + return new byte[7]; + } + + public static Object newByteArrayMinus7() { + return new byte[-7]; + } + + public static Object newByteArray(int length) { + return new byte[length]; + } + + public static Object newStringArray7() { + return new String[7]; + } + + public static Object newStringArrayMinus7() { + return new String[-7]; + } + + public static Object newStringArray(int length) { + return new String[length]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewInstanceTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; + +/** + * Tests the implementation of {@code NEW}. + */ +public class NewInstanceTest extends GraalCompilerTest { + + @Override + protected void assertEquals(Object expected, Object actual) { + Assert.assertTrue(expected != null); + Assert.assertTrue(actual != null); + super.assertEquals(expected.getClass(), actual.getClass()); + + if (expected instanceof Object[]) { + Assert.assertTrue(actual instanceof Object[]); + Object[] eArr = (Object[]) expected; + Object[] aArr = (Object[]) actual; + Assert.assertTrue(eArr.length == aArr.length); + for (int i = 0; i < eArr.length; i++) { + assertEquals(eArr[i], aArr[i]); + } + } else if (expected.getClass() != Object.class) { + try { + expected.getClass().getDeclaredMethod("equals", Object.class); + super.assertEquals(expected, actual); + } catch (Exception e) { + } + } + } + + @LongTest + public void test1() { + test("newObject"); + } + + @LongTest + public void test2() { + test("newObjectTwice"); + } + + public static Object newObject() { + return new Object(); + } + + @LongTest + public void test3() { + test("newObjectLoop", 100); + } + + @LongTest + public void test4() { + test("newBigObject"); + } + + @LongTest + public void test5() { + test("newSomeObject"); + } + + @LongTest + public void test6() { + test("newEmptyString"); + } + + @LongTest + public void test7() { + test("newString", "value"); + } + + @LongTest + public void test8() { + test("newHashMap", 31); + } + + @LongTest + public void test9() { + test("newRegression", true); + } + + public static Object[] newObjectTwice() { + Object[] res = {new Object(), new Object()}; + return res; + } + + public static Object[] newObjectLoop(int n) { + Object[] res = new Object[n]; + for (int i = 0; i < n; i++) { + res[i] = new Object(); + } + return res; + } + + public static BigObject newBigObject() { + return new BigObject(); + } + + public static SomeObject newSomeObject() { + return new SomeObject(); + } + + public static String newEmptyString() { + return new String(); + } + + public static String newString(String value) { + return new String(value); + } + + public static HashMap newHashMap(int initialCapacity) { + return new HashMap(initialCapacity); + } + + static class SomeObject { + + String name = "o1"; + HashMap<String, Object> map = new HashMap<>(); + + public SomeObject() { + map.put(name, this.getClass()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SomeObject) { + SomeObject so = (SomeObject) obj; + return so.name.equals(name) && so.map.equals(map); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + } + + static class BigObject { + + Object f01; + Object f02; + Object f03; + Object f04; + Object f05; + Object f06; + Object f07; + Object f08; + Object f09; + Object f10; + Object f12; + Object f13; + Object f14; + Object f15; + Object f16; + Object f17; + Object f18; + Object f19; + Object f20; + Object f21; + Object f22; + Object f23; + Object f24; + Object f25; + Object f26; + Object f27; + Object f28; + Object f29; + Object f30; + Object f31; + Object f32; + Object f33; + Object f34; + Object f35; + Object f36; + Object f37; + Object f38; + Object f39; + Object f40; + Object f41; + Object f42; + Object f43; + Object f44; + Object f45; + } + + /** + * Tests that an earlier bug does not occur. The issue was that the loading of the TLAB 'top' + * and 'end' values was being GVN'ed from each branch of the 'if' statement. This meant that the + * allocated B object in the true branch overwrote the allocated array. The cause is that + * RegisterNode was a floating node and the reads from it were UnsafeLoads which are also + * floating. The fix was to make RegisterNode a fixed node (which it should have been in the + * first place). + */ + public static Object newRegression(boolean condition) { + Object result; + if (condition) { + Object[] arr = {0, 1, 2, 3, 4, 5}; + result = new B(); + for (int i = 0; i < arr.length; ++i) { + // If the bug exists, the values of arr will now be deadbeef values + // and the virtual dispatch will cause a segfault. This can result in + // either a VM crash or a spurious NullPointerException. + if (arr[i].equals(Integer.valueOf(i))) { + return false; + } + } + } else { + result = new B(); + } + return result; + } + + static class B { + + long f1 = 0xdeadbeefdeadbe01L; + long f2 = 0xdeadbeefdeadbe02L; + long f3 = 0xdeadbeefdeadbe03L; + long f4 = 0xdeadbeefdeadbe04L; + long f5 = 0xdeadbeefdeadbe05L; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewMultiArrayTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,128 @@ +/* + * 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.replacements; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests the lowering of the MULTIANEWARRAY instruction. + */ +public class NewMultiArrayTest extends GraalCompilerTest { + + private static int rank(ResolvedJavaType type) { + String name = type.getName(); + int dims = 0; + while (dims < name.length() && name.charAt(dims) == '[') { + dims++; + } + return dims; + } + + @Override + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { + boolean forceCompile = false; + if (bottomType != null) { + List<NewMultiArrayNode> snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot(); + assert snapshot != null; + assert snapshot.size() == 1; + + NewMultiArrayNode node = snapshot.get(0); + assert rank(arrayType) == dimensions.length; + int rank = dimensions.length; + ValueNode[] dimensionNodes = new ValueNode[rank]; + for (int i = 0; i < rank; i++) { + dimensionNodes[i] = graph.unique(ConstantNode.forInt(dimensions[i], graph)); + } + + NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes)); + graph.replaceFixedWithFixed(node, repl); + forceCompile = true; + } + return super.getCode(method, graph, forceCompile); + } + + @Override + protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + if (bottomType != null) { + try { + return Array.newInstance(bottomClass, dimensions); + } catch (Exception e) { + throw new InvocationTargetException(e); + } + } + return super.referenceInvoke(method, receiver, args); + } + + ResolvedJavaType arrayType; + ResolvedJavaType bottomType; + Class bottomClass; + int[] dimensions; + + @LongTest + public void test1() { + for (Class clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) { + bottomClass = clazz; + bottomType = runtime.lookupJavaType(clazz); + arrayType = bottomType; + for (int rank : new int[]{1, 2, 10, 50, 100, 200, 254, 255}) { + while (rank(arrayType) != rank) { + arrayType = arrayType.getArrayClass(); + } + + dimensions = new int[rank]; + for (int i = 0; i < rank; i++) { + dimensions[i] = 1; + } + + test("newMultiArray"); + } + } + bottomType = null; + arrayType = null; + } + + public static Object newMultiArray() { + // This is merely a template - the NewMultiArrayNode is replaced in getCode() above. + // This also means we need a separate test for correct handling of negative dimensions + // as deoptimization won't do what we want for a graph modified to be different from the + // source bytecode. + return new Object[10][9][8]; + } + + @LongTest + public void test2() { + test("newMultiArrayException"); + } + + public static Object newMultiArrayException() { + return new Object[10][9][-8]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/PointerTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,399 @@ +/* + * 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 java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Tests for the {@link Pointer} read and write operations. + */ +public class PointerTest extends GraalCompilerTest implements Snippets { + + private static final Object ID = new Object(); + private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}; + private final TargetDescription target; + private final ReplacementsInstaller installer; + + public PointerTest() { + target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); + installer = new ReplacementsInstaller(runtime, new Assumptions(false), target); + } + + private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>(); + + @Override + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); + return installer.makeGraph(resolvedMethod, inliningPolicy.get()); + } + + @Test + public void test_read1() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "1"), kind, false, ID); + } + } + + @Test + public void test_read2() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "2"), kind, true, ID); + } + } + + @Test + public void test_read3() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "3"), kind, false, LocationNode.UNKNOWN_LOCATION); + } + } + + @Test + public void test_write1() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "1"), kind, false, ID); + } + } + + @Test + public void test_write2() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "2"), kind, true, ID); + } + } + + @Test + public void test_write3() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION); + } + } + + private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + ReadNode read = (ReadNode) graph.start().next(); + Assert.assertEquals(kind.getStackKind(), read.kind()); + + UnsafeCastNode cast = (UnsafeCastNode) read.object(); + Assert.assertEquals(graph.getLocal(0), cast.object()); + Assert.assertEquals(target.wordKind, cast.kind()); + + IndexedLocationNode location = (IndexedLocationNode) read.location(); + Assert.assertEquals(kind, location.getValueKind()); + Assert.assertEquals(locationIdentity, location.locationIdentity()); + Assert.assertEquals(1, location.indexScaling()); + + if (indexConvert) { + ConvertNode convert = (ConvertNode) location.index(); + Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); + Assert.assertEquals(graph.getLocal(1), convert.value()); + } else { + Assert.assertEquals(graph.getLocal(1), location.index()); + } + + ReturnNode ret = (ReturnNode) read.next(); + Assert.assertEquals(read, ret.result()); + } + + private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + WriteNode write = (WriteNode) graph.start().next(); + Assert.assertEquals(graph.getLocal(2), write.value()); + Assert.assertEquals(Kind.Void, write.kind()); + Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci); + + UnsafeCastNode cast = (UnsafeCastNode) write.object(); + Assert.assertEquals(graph.getLocal(0), cast.object()); + Assert.assertEquals(target.wordKind, cast.kind()); + + IndexedLocationNode location = (IndexedLocationNode) write.location(); + Assert.assertEquals(kind, location.getValueKind()); + Assert.assertEquals(locationIdentity, location.locationIdentity()); + Assert.assertEquals(1, location.indexScaling()); + + if (indexConvert) { + ConvertNode convert = (ConvertNode) location.index(); + Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); + Assert.assertEquals(graph.getLocal(1), convert.value()); + } else { + Assert.assertEquals(graph.getLocal(1), location.index()); + } + + AbstractStateSplit stateSplit = (AbstractStateSplit) write.next(); + Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci); + + ReturnNode ret = (ReturnNode) stateSplit.next(); + Assert.assertEquals(null, ret.result()); + } + + @Snippet + public static byte readByte1(Object o, int offset) { + return Word.fromObject(o).readByte(offset, ID); + } + + @Snippet + public static byte readByte2(Object o, int offset) { + return Word.fromObject(o).readByte(Word.signed(offset), ID); + } + + @Snippet + public static byte readByte3(Object o, int offset) { + return Word.fromObject(o).readByte(offset); + } + + @Snippet + public static void writeByte1(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(offset, value, ID); + } + + @Snippet + public static void writeByte2(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeByte3(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(offset, value); + } + + @Snippet + public static char readChar1(Object o, int offset) { + return Word.fromObject(o).readChar(offset, ID); + } + + @Snippet + public static char readChar2(Object o, int offset) { + return Word.fromObject(o).readChar(Word.signed(offset), ID); + } + + @Snippet + public static char readChar3(Object o, int offset) { + return Word.fromObject(o).readChar(offset); + } + + @Snippet + public static void writeChar1(Object o, int offset, char value) { + Word.fromObject(o).writeChar(offset, value, ID); + } + + @Snippet + public static void writeChar2(Object o, int offset, char value) { + Word.fromObject(o).writeChar(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeChar3(Object o, int offset, char value) { + Word.fromObject(o).writeChar(offset, value); + } + + @Snippet + public static short readShort1(Object o, int offset) { + return Word.fromObject(o).readShort(offset, ID); + } + + @Snippet + public static short readShort2(Object o, int offset) { + return Word.fromObject(o).readShort(Word.signed(offset), ID); + } + + @Snippet + public static short readShort3(Object o, int offset) { + return Word.fromObject(o).readShort(offset); + } + + @Snippet + public static void writeShort1(Object o, int offset, short value) { + Word.fromObject(o).writeShort(offset, value, ID); + } + + @Snippet + public static void writeShort2(Object o, int offset, short value) { + Word.fromObject(o).writeShort(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeShort3(Object o, int offset, short value) { + Word.fromObject(o).writeShort(offset, value); + } + + @Snippet + public static int readInt1(Object o, int offset) { + return Word.fromObject(o).readInt(offset, ID); + } + + @Snippet + public static int readInt2(Object o, int offset) { + return Word.fromObject(o).readInt(Word.signed(offset), ID); + } + + @Snippet + public static int readInt3(Object o, int offset) { + return Word.fromObject(o).readInt(offset); + } + + @Snippet + public static void writeInt1(Object o, int offset, int value) { + Word.fromObject(o).writeInt(offset, value, ID); + } + + @Snippet + public static void writeInt2(Object o, int offset, int value) { + Word.fromObject(o).writeInt(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeInt3(Object o, int offset, int value) { + Word.fromObject(o).writeInt(offset, value); + } + + @Snippet + public static long readLong1(Object o, int offset) { + return Word.fromObject(o).readLong(offset, ID); + } + + @Snippet + public static long readLong2(Object o, int offset) { + return Word.fromObject(o).readLong(Word.signed(offset), ID); + } + + @Snippet + public static long readLong3(Object o, int offset) { + return Word.fromObject(o).readLong(offset); + } + + @Snippet + public static void writeLong1(Object o, int offset, long value) { + Word.fromObject(o).writeLong(offset, value, ID); + } + + @Snippet + public static void writeLong2(Object o, int offset, long value) { + Word.fromObject(o).writeLong(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeLong3(Object o, int offset, long value) { + Word.fromObject(o).writeLong(offset, value); + } + + @Snippet + public static float readFloat1(Object o, int offset) { + return Word.fromObject(o).readFloat(offset, ID); + } + + @Snippet + public static float readFloat2(Object o, int offset) { + return Word.fromObject(o).readFloat(Word.signed(offset), ID); + } + + @Snippet + public static float readFloat3(Object o, int offset) { + return Word.fromObject(o).readFloat(offset); + } + + @Snippet + public static void writeFloat1(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(offset, value, ID); + } + + @Snippet + public static void writeFloat2(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeFloat3(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(offset, value); + } + + @Snippet + public static double readDouble1(Object o, int offset) { + return Word.fromObject(o).readDouble(offset, ID); + } + + @Snippet + public static double readDouble2(Object o, int offset) { + return Word.fromObject(o).readDouble(Word.signed(offset), ID); + } + + @Snippet + public static double readDouble3(Object o, int offset) { + return Word.fromObject(o).readDouble(offset); + } + + @Snippet + public static void writeDouble1(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(offset, value, ID); + } + + @Snippet + public static void writeDouble2(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeDouble3(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(offset, value); + } + + @Snippet + public static Object readObject1(Object o, int offset) { + return Word.fromObject(o).readObject(offset, ID); + } + + @Snippet + public static Object readObject2(Object o, int offset) { + return Word.fromObject(o).readObject(Word.signed(offset), ID); + } + + @Snippet + public static Object readObject3(Object o, int offset) { + return Word.fromObject(o).readObject(offset); + } + + @Snippet + public static void writeObject1(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(offset, value, ID); + } + + @Snippet + public static void writeObject2(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeObject3(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(offset, value); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/TypeCheckTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; + +/** + * Base class for checkcast and instanceof test classes. + */ +public abstract class TypeCheckTest extends GraalCompilerTest { + + protected abstract void replaceProfile(StructuredGraph graph, JavaTypeProfile profile); + + protected JavaTypeProfile currentProfile; + + @Override + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { + boolean forceCompile = false; + if (currentProfile != null) { + replaceProfile(graph, currentProfile); + forceCompile = true; + } + return super.getCode(method, graph, forceCompile); + } + + protected JavaTypeProfile profile(Class... types) { + if (types.length == 0) { + return null; + } + ProfiledType[] ptypes = new ProfiledType[types.length]; + for (int i = 0; i < types.length; i++) { + ptypes[i] = new ProfiledType(runtime.lookupJavaType(types[i]), 1.0D / types.length); + } + return new JavaTypeProfile(0.0D, ptypes); + } + + protected void test(String name, JavaTypeProfile profile, Object... args) { + assert currentProfile == null; + currentProfile = profile; + try { + super.test(name, args); + } finally { + currentProfile = null; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/WordTest.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Tests for the {@link Word} type. + */ +public class WordTest extends GraalCompilerTest implements Snippets { + + private final ReplacementsInstaller installer; + + public WordTest() { + TargetDescription target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); + installer = new ReplacementsInstaller(runtime, new Assumptions(false), target); + } + + private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>(); + + @Override + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); + return installer.makeGraph(resolvedMethod, inliningPolicy.get()); + } + + @LongTest + public void construction() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, + Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; + for (long word : words) { + test("unsigned_long", word); + test("unsigned_int", (int) word); + test("signed_long", word); + test("signed_int", (int) word); + } + } + + @LongTest + public void test_arithmetic() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, + Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; + for (long word : words) { + test("unsigned_not", word); + test("signed_not", word); + for (long addend : words) { + test("unsigned_plus_int", word, (int) addend); + test("unsigned_minus_int", word, (int) addend); + test("unsigned_plus_int", word, -((int) addend)); + test("unsigned_minus_int", word, -((int) addend)); + test("unsigned_plus_long", word, addend); + test("unsigned_minus_long", word, addend); + test("unsigned_plus_long", word, -addend); + test("unsigned_minus_long", word, -addend); + test("signed_plus_int", word, (int) addend); + test("signed_minus_int", word, (int) addend); + test("signed_plus_int", word, -((int) addend)); + test("signed_minus_int", word, -((int) addend)); + test("signed_plus_long", word, addend); + test("signed_minus_long", word, addend); + test("signed_plus_long", word, -addend); + test("signed_minus_long", word, -addend); + + test("and_int", word, (int) addend); + test("or_int", word, (int) addend); + test("and_int", word, -((int) addend)); + test("or_int", word, -((int) addend)); + test("and_long", word, addend); + test("or_long", word, addend); + test("and_long", word, -addend); + test("or_long", word, -addend); + } + } + } + + @LongTest + public void test_compare() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; + for (long word1 : words) { + for (long word2 : words) { + for (String method : new String[]{"aboveOrEqual", "above", "belowOrEqual", "below"}) { + test(method, word1, word2); + test(method, word2, word1); + } + } + } + } + + @Snippet + public static long unsigned_long(long word) { + return Word.unsigned(word).rawValue(); + } + + @Snippet + public static long unsigned_int(int word) { + return Word.unsigned(word).rawValue(); + } + + @Snippet + public static long signed_long(long word) { + return Word.signed(word).rawValue(); + } + + @Snippet + public static long signed_int(int word) { + return Word.signed(word).rawValue(); + } + + @Snippet + public static long unsigned_plus_int(long word, int addend) { + return Word.unsigned(word).add(addend).rawValue(); + } + + @Snippet + public static long unsigned_minus_int(long word, int addend) { + return Word.unsigned(word).subtract(addend).rawValue(); + } + + @Snippet + public static long unsigned_plus_long(long word, long addend) { + return Word.unsigned(word).add(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long unsigned_minus_long(long word, long addend) { + return Word.unsigned(word).subtract(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long signed_plus_int(long word, int addend) { + return Word.signed(word).add(addend).rawValue(); + } + + @Snippet + public static long signed_minus_int(long word, int addend) { + return Word.signed(word).subtract(addend).rawValue(); + } + + @Snippet + public static long signed_plus_long(long word, long addend) { + return Word.signed(word).add(Word.signed(addend)).rawValue(); + } + + @Snippet + public static long signed_minus_long(long word, long addend) { + return Word.signed(word).subtract(Word.signed(addend)).rawValue(); + } + + @Snippet + public static long signed_not(long word) { + return Word.signed(word).not().rawValue(); + } + + @Snippet + public static long unsigned_not(long word) { + return Word.unsigned(word).not().rawValue(); + } + + @Snippet + public static boolean aboveOrEqual(long word1, long word2) { + return Word.unsigned(word1).aboveOrEqual(Word.unsigned(word2)); + } + + @Snippet + public static boolean above(long word1, long word2) { + return Word.unsigned(word1).aboveThan(Word.unsigned(word2)); + } + + @Snippet + public static boolean belowOrEqual(long word1, long word2) { + return Word.unsigned(word1).belowOrEqual(Word.unsigned(word2)); + } + + @Snippet + public static boolean below(long word1, long word2) { + return Word.unsigned(word1).belowThan(Word.unsigned(word2)); + } + + @Snippet + public static long and_int(long word, int addend) { + return Word.unsigned(word).and(addend).rawValue(); + } + + @Snippet + public static long or_int(long word, int addend) { + return Word.unsigned(word).or(addend).rawValue(); + } + + @Snippet + public static long and_long(long word, long addend) { + return Word.unsigned(word).and(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long or_long(long word, long addend) { + return Word.unsigned(word).or(Word.unsigned(addend)).rawValue(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/overview.html Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,36 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> +<head> +<!-- + +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. Oracle designates this +particular file as subject to the "Classpath" exception as provided +by Oracle in the LICENSE file that accompanied this code. + +This code is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +version 2 for more details (a copy is included in the LICENSE file that +accompanied this code). + +You should have received a copy of the GNU General Public License version +2 along with this work; if not, write to the Free Software Foundation, +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +or visit www.oracle.com if you need additional information or have any +questions. +--> + +</head> +<body> + +Documentation for the <code>com.oracle.graal.snippets</code> project. + +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ClassSubstitution.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import java.lang.annotation.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Denotes a class that substitutes methods of another specified class. The substitute methods are + * exactly those annotated by {@link MethodSubstitution}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ClassSubstitution { + + /** + * Specifies the original class. + * <p> + * If the default value is specified for this element, then a non-default value must be given + * for the {@link #className()} element. + */ + Class<?> value() default ClassSubstitution.class; + + /** + * Specifies the original class. + * <p> + * This method is provided for cases where the original class is not accessible (according to + * Java language access control rules). + * <p> + * If the default value is specified for this element, then a non-default value must be given + * for the {@link #value()} element. + */ + String className() default ""; + + /** + * Determines if the substitutions are for classes that may not be part of the runtime. + * Substitutions for such classes are omitted if the original classes cannot be found. + */ + boolean optional() default false; + + /** + * 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 original method. + * <p> + * If the default value is specified for this element, then the name of the original method + * is same as the substitute method. + */ + String value() default ""; + + /** + * Determines if the original method is static. + */ + boolean isStatic() default true; + + /** + * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the original + * method. + * <p> + * If the default value is specified for this element, then the signature of the original + * method is the same as the substitute method. + */ + String signature() default ""; + } + + /** + * Denotes a macro substitute method. This replaces a method invocation with an instance of the + * specified node class. + * + * A macro substitution can be combined with a normal substitution, so that the macro node can + * be replaced with the actual substitution code during lowering. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface MacroSubstitution { + + /** + * Gets the name of the substituted method. + * <p> + * If the default value is specified for this element, then the name of the substituted + * method is same as the substitute method. + */ + String value() default ""; + + /** + * Determines if the substituted method is static. + */ + boolean isStatic() default true; + + /** + * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the substituted + * method. + * <p> + * If the default value is specified for this element, then the signature of the substituted + * method is the same as the substitute method. + */ + String signature() default ""; + + /** + * The node class with which the method invocation should be replaced. It needs to be a + * subclass of {@link FixedWithNextNode}, and it is expected to provide a public constructor + * that takes an InvokeNode as a parameter. For most cases this class should subclass + * {@link MacroNode} and use its constructor. + */ + Class<? extends FixedWithNextNode> macro(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DoubleSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for {@link java.lang.Double} methods. + */ +@ClassSubstitution(java.lang.Double.class) +public class DoubleSubstitutions { + + private static final long NAN_RAW_LONG_BITS = Double.doubleToRawLongBits(Double.NaN); + + @MethodSubstitution + public static long doubleToRawLongBits(double value) { + @JavacBug(id = 6995200) + Long result = ConvertNode.convert(ConvertNode.Op.MOV_D2L, value); + return result; + } + + // TODO This method is not necessary, since the JDK method does exactly this + @MethodSubstitution + public static long doubleToLongBits(double value) { + if (value != value) { + return NAN_RAW_LONG_BITS; + } else { + return doubleToRawLongBits(value); + } + } + + @MethodSubstitution + public static double longBitsToDouble(long bits) { + @JavacBug(id = 6995200) + Double result = ConvertNode.convert(ConvertNode.Op.MOV_L2D, bits); + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/FloatSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for {@link java.lang.Float} methods. + */ +@ClassSubstitution(java.lang.Float.class) +public class FloatSubstitutions { + + private static final int NAN_RAW_INT_BITS = Float.floatToRawIntBits(Float.NaN); + + @MethodSubstitution + public static int floatToRawIntBits(float value) { + @JavacBug(id = 6995200) + Integer result = ConvertNode.convert(ConvertNode.Op.MOV_F2I, value); + return result; + } + + // TODO This method is not necessary, since the JDK method does exactly this + @MethodSubstitution + public static int floatToIntBits(float value) { + if (value != value) { + return NAN_RAW_INT_BITS; + } else { + return floatToRawIntBits(value); + } + } + + @MethodSubstitution + public static float intBitsToFloat(int bits) { + @JavacBug(id = 6995200) + Float result = ConvertNode.convert(ConvertNode.Op.MOV_I2F, bits); + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalIntrinsics.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.phases.*; + +/** + * Definition of the snippets that are VM-independent and can be intrinsified by Graal in any VM. + */ +public class GraalIntrinsics { + + public static void installIntrinsics(ReplacementsInstaller installer) { + if (GraalOptions.Intrinsify) { + installer.installSubstitutions(MathSubstitutionsX86.class); + installer.installSubstitutions(DoubleSubstitutions.class); + installer.installSubstitutions(FloatSubstitutions.class); + installer.installSubstitutions(NodeClassSubstitutions.class); + installer.installSubstitutions(LongSubstitutions.class); + installer.installSubstitutions(IntegerSubstitutions.class); + installer.installSubstitutions(UnsignedMathSubstitutions.class); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,338 @@ +/* + * 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.replacements; + +import static com.oracle.graal.nodes.calc.CompareNode.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.replacements.SnippetTemplate.*; + +/** + * Helper class for lowering {@link InstanceOfNode}s with snippets. The majority of the complexity + * in such a lowering derives from the fact that {@link InstanceOfNode} is a floating node. A + * snippet used to lower an {@link InstanceOfNode} will almost always incorporate control flow and + * replacing a floating node with control flow is not trivial. + * <p> + * The mechanism implemented in this class ensures that the graph for an instanceof snippet is + * instantiated once per {@link InstanceOfNode} being lowered. The result produced is then re-used + * by all usages of the node. Additionally, if there is a single usage that is an {@link IfNode}, + * the control flow in the snippet is connected directly to the true and false successors of the + * {@link IfNode}. This avoids materializing the instanceof test as a boolean which is then retested + * by the {@link IfNode}. + */ +public abstract class InstanceOfSnippetsTemplates<T extends Snippets> extends AbstractTemplates<T> { + + public InstanceOfSnippetsTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class<T> snippetsClass) { + super(runtime, assumptions, target, snippetsClass); + } + + /** + * The key and arguments used to retrieve and instantiate an instanceof snippet template. + */ + public static class KeyAndArguments { + + public final Key key; + public final Arguments arguments; + + public KeyAndArguments(Key key, Arguments arguments) { + this.key = key; + this.arguments = arguments; + } + + } + + /** + * Gets the key and arguments used to retrieve and instantiate an instanceof snippet template. + */ + protected abstract KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool); + + public void lower(FloatingNode instanceOf, LoweringTool tool) { + assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; + List<Node> usages = instanceOf.usages().snapshot(); + int nUsages = usages.size(); + + Instantiation instantiation = new Instantiation(); + for (Node usage : usages) { + final StructuredGraph graph = (StructuredGraph) usage.graph(); + + InstanceOfUsageReplacer replacer = createReplacer(instanceOf, tool, nUsages, instantiation, usage, graph); + + if (instantiation.isInitialized()) { + // No need to re-instantiate the snippet - just re-use its result + replacer.replaceUsingInstantiation(); + } else { + KeyAndArguments keyAndArguments = getKeyAndArguments(replacer, tool); + SnippetTemplate template = cache.get(keyAndArguments.key, assumptions); + template.instantiate(runtime, instanceOf, replacer, tool, keyAndArguments.arguments); + } + } + + assert instanceOf.usages().isEmpty(); + if (!instanceOf.isDeleted()) { + GraphUtil.killWithUnusedFloatingInputs(instanceOf); + } + } + + /** + * Gets the specific replacer object used to replace the usage of an instanceof node with the + * result of an instantiated instanceof snippet. + */ + protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) { + InstanceOfUsageReplacer replacer; + if (usage instanceof IfNode) { + replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage, nUsages == 1, tool); + } else { + assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage; + ConditionalNode c = (ConditionalNode) usage; + replacer = new ConditionalUsageReplacer(instantiation, c.trueValue(), c.falseValue(), instanceOf, c); + } + return replacer; + } + + /** + * The result of an instantiating an instanceof snippet. This enables a snippet instantiation to + * be re-used which reduces compile time and produces better code. + */ + public static final class Instantiation { + + private PhiNode result; + private CompareNode condition; + private ValueNode trueValue; + private ValueNode falseValue; + + /** + * Determines if the instantiation has occurred. + */ + boolean isInitialized() { + return result != null; + } + + void initialize(PhiNode phi, ValueNode t, ValueNode f) { + assert !isInitialized(); + this.result = phi; + this.trueValue = t; + this.falseValue = f; + } + + /** + * Gets the result of this instantiation as a condition. + * + * @param testValue the returned condition is true if the result is equal to this value + */ + CompareNode asCondition(ValueNode testValue) { + assert isInitialized(); + if (condition == null || condition.y() != testValue) { + // Re-use previously generated condition if the trueValue for the test is the same + condition = createCompareNode(Condition.EQ, result, testValue); + } + return condition; + } + + /** + * Gets the result of the instantiation as a materialized value. + * + * @param t the true value for the materialization + * @param f the false value for the materialization + */ + ValueNode asMaterialization(ValueNode t, ValueNode f) { + assert isInitialized(); + if (t == this.trueValue && f == this.falseValue) { + // Can simply use the phi result if the same materialized values are expected. + return result; + } else { + return t.graph().unique(new ConditionalNode(asCondition(trueValue), t, f)); + } + } + } + + /** + * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}. + */ + public abstract static class InstanceOfUsageReplacer implements UsageReplacer { + + public final Instantiation instantiation; + public final FloatingNode instanceOf; + public final ValueNode trueValue; + public final ValueNode falseValue; + + public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) { + assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; + this.instantiation = instantiation; + this.instanceOf = instanceOf; + this.trueValue = trueValue; + this.falseValue = falseValue; + } + + /** + * Does the replacement based on a previously snippet instantiation. + */ + public abstract void replaceUsingInstantiation(); + } + + /** + * Replaces an {@link IfNode} usage of an {@link InstanceOfNode} or + * {@link InstanceOfDynamicNode}. + */ + public static class IfUsageReplacer extends InstanceOfUsageReplacer { + + private final boolean solitaryUsage; + private final IfNode usage; + private final boolean sameBlock; + + public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) { + super(instantiation, instanceOf, trueValue, falseValue); + this.sameBlock = tool.getBlockFor(usage) == tool.getBlockFor(instanceOf); + this.solitaryUsage = solitaryUsage; + this.usage = usage; + } + + @Override + public void replaceUsingInstantiation() { + usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue)); + } + + private boolean usageFollowsInstantiation() { + return instantiation.result != null && instantiation.result.merge().next() == usage; + } + + @Override + public void replace(ValueNode oldNode, ValueNode newNode) { + assert newNode instanceof PhiNode; + assert oldNode == instanceOf; + if (sameBlock && solitaryUsage && usageFollowsInstantiation()) { + removeIntermediateMaterialization(newNode); + } else { + newNode.inferStamp(); + instantiation.initialize((PhiNode) newNode, trueValue, falseValue); + usage.replaceFirstInput(oldNode, instantiation.asCondition(trueValue)); + } + } + + /** + * Directly wires the incoming edges of the merge at the end of the snippet to the outgoing + * edges of the IfNode that uses the materialized result. + */ + private void removeIntermediateMaterialization(ValueNode newNode) { + IfNode ifNode = usage; + PhiNode phi = (PhiNode) newNode; + MergeNode merge = phi.merge(); + assert merge.stateAfter() == null; + + List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot(); + assert phi.valueCount() == mergePredecessors.size(); + + List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size()); + List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size()); + + int endIndex = 0; + for (EndNode end : mergePredecessors) { + ValueNode endValue = phi.valueAt(endIndex++); + if (endValue == trueValue) { + trueEnds.add(end); + } else { + assert endValue == falseValue; + falseEnds.add(end); + } + } + + BeginNode trueSuccessor = ifNode.trueSuccessor(); + BeginNode falseSuccessor = ifNode.falseSuccessor(); + ifNode.setTrueSuccessor(null); + ifNode.setFalseSuccessor(null); + + connectEnds(merge, trueEnds, trueSuccessor); + connectEnds(merge, falseEnds, falseSuccessor); + + GraphUtil.killCFG(merge); + GraphUtil.killCFG(ifNode); + + assert !merge.isAlive() : merge; + assert !phi.isAlive() : phi; + } + + private static void connectEnds(MergeNode merge, List<EndNode> ends, BeginNode successor) { + if (ends.size() == 0) { + // InstanceOf has been lowered to always true or always false - this successor is + // therefore unreachable. + GraphUtil.killCFG(successor); + } else if (ends.size() == 1) { + EndNode end = ends.get(0); + ((FixedWithNextNode) end.predecessor()).setNext(successor); + merge.removeEnd(end); + GraphUtil.killCFG(end); + } else { + assert ends.size() > 1; + MergeNode newMerge = merge.graph().add(new MergeNode()); + + for (EndNode end : ends) { + newMerge.addForwardEnd(end); + } + newMerge.setNext(successor); + } + } + } + + /** + * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode} or + * {@link InstanceOfDynamicNode}. + */ + public static class ConditionalUsageReplacer extends InstanceOfUsageReplacer { + + public final ConditionalNode usage; + + public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) { + super(instantiation, instanceOf, trueValue, falseValue); + this.usage = usage; + } + + @Override + public void replaceUsingInstantiation() { + ValueNode newValue = instantiation.asMaterialization(trueValue, falseValue); + usage.replaceAtUsages(newValue); + usage.clearInputs(); + assert usage.usages().isEmpty(); + GraphUtil.killWithUnusedFloatingInputs(usage); + } + + @Override + public void replace(ValueNode oldNode, ValueNode newNode) { + assert newNode instanceof PhiNode; + assert oldNode == instanceOf; + newNode.inferStamp(); + instantiation.initialize((PhiNode) newNode, trueValue, falseValue); + usage.replaceAtUsages(newNode); + usage.clearInputs(); + assert usage.usages().isEmpty(); + GraphUtil.killWithUnusedFloatingInputs(usage); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntegerSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; + +@ClassSubstitution(Integer.class) +public class IntegerSubstitutions { + + @MethodSubstitution + public static int reverseBytes(int i) { + return ReverseBytesNode.reverse(i); + } + + @MethodSubstitution + public static int numberOfLeadingZeros(int i) { + if (i == 0) { + return 32; + } + return 31 - BitScanReverseNode.scan(i); + } + + @MethodSubstitution + public static int numberOfTrailingZeros(int i) { + if (i == 0) { + return 32; + } + return BitScanForwardNode.scan(i); + } + + @MethodSubstitution + public static int bitCount(int i) { + return BitCountNode.bitCount(i); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/JavacBug.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +/** + * Used to indicate that an otherwise strange looking code pattern is required to work around a bug + * in javac. + */ +public @interface JavacBug { + + /** + * A description of the bug. Only really useful if there is no existing entry for the bug in the + * <a href="http://bugs.sun.com/bugdatabase/">Bug Database</a>. + */ + String value() default ""; + + /** + * An identifier in the <a href="http://bugs.sun.com/bugdatabase/">Bug Database</a>. + */ + int id() default 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,201 @@ +/* + * 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.replacements; + +import java.io.*; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; + +//JaCoCo Exclude + +/** + * Provides {@link PrintStream}-like logging facility. This should only be used in + * {@linkplain Snippet snippets}. + */ +public final class Log { + + public static final Descriptor LOG_PRIMITIVE = new Descriptor("logPrimitive", false, void.class, int.class, long.class, boolean.class); + public static final Descriptor LOG_OBJECT = new Descriptor("logObject", false, void.class, Object.class, int.class); + public static final Descriptor LOG_PRINTF = new Descriptor("logPrintf", false, void.class, Object.class, long.class, long.class, long.class); + + // Note: Must be kept in sync with constants in c1_Runtime1.hpp + private static final int LOG_OBJECT_NEWLINE = 0x01; + private static final int LOG_OBJECT_STRING = 0x02; + private static final int LOG_OBJECT_ADDRESS = 0x04; + + @NodeIntrinsic(RuntimeCallNode.class) + private static native void log(@ConstantNodeParameter Descriptor logObject, Object object, int flags); + + @NodeIntrinsic(RuntimeCallNode.class) + private static native void log(@ConstantNodeParameter Descriptor logPrimitive, int typeChar, long value, boolean newline); + + @NodeIntrinsic(RuntimeCallNode.class) + private static native void printf(@ConstantNodeParameter Descriptor logPrintf, String format, long v1, long v2, long v3); + + public static void print(boolean value) { + log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, false); + } + + public static void print(byte value) { + log(LOG_PRIMITIVE, Kind.Byte.getTypeChar(), value, false); + } + + public static void print(char value) { + log(LOG_PRIMITIVE, Kind.Char.getTypeChar(), value, false); + } + + public static void print(short value) { + log(LOG_PRIMITIVE, Kind.Short.getTypeChar(), value, false); + } + + public static void print(int value) { + log(LOG_PRIMITIVE, Kind.Int.getTypeChar(), value, false); + } + + public static void print(long value) { + log(LOG_PRIMITIVE, Kind.Long.getTypeChar(), value, false); + } + + /** + * Prints a formatted string to the log stream. + * + * @param format a C style printf format value that can contain at most one conversion specifier + * (i.e., a sequence of characters starting with '%'). + * @param value the value associated with the conversion specifier + */ + public static void printf(String format, long value) { + printf(LOG_PRINTF, format, value, 0L, 0L); + } + + public static void printf(String format, long v1, long v2) { + printf(LOG_PRINTF, format, v1, v2, 0L); + } + + public static void printf(String format, long v1, long v2, long v3) { + printf(LOG_PRINTF, format, v1, v2, v3); + } + + public static void print(float value) { + if (Float.isNaN(value)) { + print("NaN"); + } else if (value == Float.POSITIVE_INFINITY) { + print("Infinity"); + } else if (value == Float.NEGATIVE_INFINITY) { + print("-Infinity"); + } else { + log(LOG_PRIMITIVE, Kind.Float.getTypeChar(), Float.floatToRawIntBits(value), false); + } + } + + public static void print(double value) { + if (Double.isNaN(value)) { + print("NaN"); + } else if (value == Double.POSITIVE_INFINITY) { + print("Infinity"); + } else if (value == Double.NEGATIVE_INFINITY) { + print("-Infinity"); + } else { + log(LOG_PRIMITIVE, Kind.Double.getTypeChar(), Double.doubleToRawLongBits(value), false); + } + } + + public static void print(String value) { + log(LOG_OBJECT, value, LOG_OBJECT_STRING); + } + + public static void printAddress(Object o) { + log(LOG_OBJECT, o, LOG_OBJECT_ADDRESS); + } + + public static void printObject(Object o) { + log(LOG_OBJECT, o, 0); + } + + public static void println(boolean value) { + log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, true); + } + + public static void println(byte value) { + log(LOG_PRIMITIVE, Kind.Byte.getTypeChar(), value, true); + } + + public static void println(char value) { + log(LOG_PRIMITIVE, Kind.Char.getTypeChar(), value, true); + } + + public static void println(short value) { + log(LOG_PRIMITIVE, Kind.Short.getTypeChar(), value, true); + } + + public static void println(int value) { + log(LOG_PRIMITIVE, Kind.Int.getTypeChar(), value, true); + } + + public static void println(long value) { + log(LOG_PRIMITIVE, Kind.Long.getTypeChar(), value, true); + } + + public static void println(float value) { + if (Float.isNaN(value)) { + println("NaN"); + } else if (value == Float.POSITIVE_INFINITY) { + println("Infinity"); + } else if (value == Float.NEGATIVE_INFINITY) { + println("-Infinity"); + } else { + log(LOG_PRIMITIVE, Kind.Float.getTypeChar(), Float.floatToRawIntBits(value), true); + } + } + + public static void println(double value) { + if (Double.isNaN(value)) { + println("NaN"); + } else if (value == Double.POSITIVE_INFINITY) { + println("Infinity"); + } else if (value == Double.NEGATIVE_INFINITY) { + println("-Infinity"); + } else { + log(LOG_PRIMITIVE, Kind.Double.getTypeChar(), Double.doubleToRawLongBits(value), true); + } + } + + public static void println(String value) { + log(LOG_OBJECT, value, LOG_OBJECT_NEWLINE | LOG_OBJECT_STRING); + } + + public static void printlnAddress(Object o) { + log(LOG_OBJECT, o, LOG_OBJECT_NEWLINE | LOG_OBJECT_ADDRESS); + } + + public static void printlnObject(Object o) { + log(LOG_OBJECT, o, LOG_OBJECT_NEWLINE); + } + + public static void println() { + println(""); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/LongSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; + +@ClassSubstitution(Long.class) +public class LongSubstitutions { + + @MethodSubstitution + public static long reverseBytes(long i) { + return ReverseBytesNode.reverse(i); + } + + @MethodSubstitution + public static int numberOfLeadingZeros(long i) { + if (i == 0) { + return 64; + } + return 63 - BitScanReverseNode.scan(i); + } + + @MethodSubstitution + public static int numberOfTrailingZeros(long i) { + if (i == 0) { + return 64; + } + return BitScanForwardNode.scan(i); + } + + @MethodSubstitution + public static int bitCount(long i) { + return BitCountNode.bitCount(i); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.replacements.nodes.MathIntrinsicNode.*; + +/** + * Substitutions for {@link java.lang.Math} methods. + */ +@ClassSubstitution(java.lang.Math.class) +public class MathSubstitutionsX86 { + + private static final double PI_4 = 0.7853981633974483; + + @MethodSubstitution + public static double abs(double x) { + return MathIntrinsicNode.compute(x, Operation.ABS); + } + + @MethodSubstitution + public static double sqrt(double x) { + return MathIntrinsicNode.compute(x, Operation.SQRT); + } + + @MethodSubstitution + public static double log(double x) { + return MathIntrinsicNode.compute(x, Operation.LOG); + } + + @MethodSubstitution + public static double log10(double x) { + return MathIntrinsicNode.compute(x, Operation.LOG10); + } + + // NOTE on snippets below: + // Math.sin(), .cos() and .tan() guarantee a value within 1 ULP of the + // exact result, but x87 trigonometric FPU instructions are only that + // accurate within [-pi/4, pi/4]. Examine the passed value and provide + // a slow path for inputs outside of that interval. + + @MethodSubstitution + public static double sin(double x) { + if (abs(x) < PI_4) { + return MathIntrinsicNode.compute(x, Operation.SIN); + } else { + return callDouble(ARITHMETIC_SIN, x); + } + } + + @MethodSubstitution + public static double cos(double x) { + if (abs(x) < PI_4) { + return MathIntrinsicNode.compute(x, Operation.COS); + } else { + return callDouble(ARITHMETIC_COS, x); + } + } + + @MethodSubstitution + public static double tan(double x) { + if (abs(x) < PI_4) { + return MathIntrinsicNode.compute(x, Operation.TAN); + } else { + return callDouble(ARITHMETIC_TAN, x); + } + } + + public static final Descriptor ARITHMETIC_SIN = new Descriptor("arithmeticSin", false, double.class, double.class); + public static final Descriptor ARITHMETIC_COS = new Descriptor("arithmeticCos", false, double.class, double.class); + public static final Descriptor ARITHMETIC_TAN = new Descriptor("arithmeticTan", false, double.class, double.class); + + @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true) + public static native double callDouble(@ConstantNodeParameter Descriptor descriptor, double value); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for improving the performance of some critical methods in {@link NodeClass} + * methods. These substitutions improve the performance by forcing the relevant methods to be + * inlined (intrinsification being a special form of inlining) and removing a checked cast. The + * latter cannot be done directly in Java code as {@link UnsafeCastNode} is not available to the + * project containing {@link NodeClass}. + */ +@ClassSubstitution(NodeClass.class) +public class NodeClassSubstitutions { + + @MethodSubstitution + private static Node getNode(Node node, long offset) { + return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false); + } + + @MethodSubstitution + private static NodeList getNodeList(Node node, long offset) { + return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false); + } + + @MethodSubstitution + private static void putNode(Node node, long offset, Node value) { + UnsafeStoreNode.store(node, 0, offset, value, Kind.Object); + } + + @MethodSubstitution + private static void putNodeList(Node node, long offset, NodeList value) { + UnsafeStoreNode.store(node, 0, offset, value, Kind.Object); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import static com.oracle.graal.api.meta.MetaUtil.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with + * {@link Fold} with the result of invoking the annotated method via reflection. + */ +public class NodeIntrinsificationPhase extends Phase { + + private final MetaAccessProvider runtime; + private final BoxingMethodPool pool; + + public NodeIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) { + this.runtime = runtime; + this.pool = pool; + } + + @Override + protected void run(StructuredGraph graph) { + for (Invoke i : graph.getInvokes()) { + if (i.callTarget() instanceof MethodCallTargetNode) { + tryIntrinsify(i); + } + } + } + + public static Class<?>[] signatureToTypes(Signature signature, ResolvedJavaType accessingClass) { + int count = signature.getParameterCount(false); + Class<?>[] result = new Class<?>[count]; + for (int i = 0; i < result.length; ++i) { + result[i] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader()); + } + return result; + } + + private boolean tryIntrinsify(Invoke invoke) { + ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); + NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); + ResolvedJavaType declaringClass = target.getDeclaringClass(); + if (intrinsic != null) { + assert target.getAnnotation(Fold.class) == null; + + Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); + ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass); + + // Prepare the arguments for the reflective constructor call on the node class. + Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); + if (nodeConstructorArguments == null) { + return false; + } + + // Create the new node instance. + Class<?> c = getNodeClass(target, intrinsic); + Node newInstance = createNodeInstance(c, parameterTypes, returnType, intrinsic.setStampFromReturnType(), nodeConstructorArguments); + + // Replace the invoke with the new node. + invoke.node().graph().add(newInstance); + invoke.intrinsify(newInstance); + + // Clean up checkcast instructions inserted by javac if the return type is generic. + cleanUpReturnCheckCast(newInstance); + } else if (target.getAnnotation(Fold.class) != null) { + Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); + + // Prepare the arguments for the reflective method call + Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); + if (arguments == null) { + return false; + } + Object receiver = null; + if (!invoke.methodCallTarget().isStatic()) { + receiver = arguments[0]; + arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray(); + } + + // Call the method + Constant constant = callMethod(target.getSignature().getReturnKind(), getMirrorOrFail(declaringClass, Thread.currentThread().getContextClassLoader()), target.getName(), parameterTypes, + receiver, arguments); + + if (constant != null) { + // Replace the invoke with the result of the call + ConstantNode node = ConstantNode.forConstant(constant, runtime, invoke.node().graph()); + invoke.intrinsify(node); + + // Clean up checkcast instructions inserted by javac if the return type is generic. + cleanUpReturnCheckCast(node); + } else { + // Remove the invoke + invoke.intrinsify(null); + } + } + return true; + } + + /** + * Converts the arguments of an invoke node to object values suitable for use as the arguments + * to a reflective invocation of a Java constructor or method. + * + * @param folding specifies if the invocation is for handling a {@link Fold} annotation + * @return the arguments for the reflective invocation or null if an argument of {@code invoke} + * that is expected to be constant isn't + */ + private Object[] prepareArguments(Invoke invoke, Class<?>[] parameterTypes, ResolvedJavaMethod target, boolean folding) { + NodeInputList<ValueNode> arguments = invoke.callTarget().arguments(); + Object[] reflectionCallArguments = new Object[arguments.size()]; + for (int i = 0; i < reflectionCallArguments.length; ++i) { + int parameterIndex = i; + if (!invoke.methodCallTarget().isStatic()) { + parameterIndex--; + } + ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); + if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { + if (!(argument instanceof ConstantNode)) { + return null; + } + ConstantNode constantNode = (ConstantNode) argument; + Constant constant = constantNode.asConstant(); + Object o = constant.asBoxedValue(); + if (o instanceof Class<?>) { + reflectionCallArguments[i] = runtime.lookupJavaType((Class<?>) o); + parameterTypes[i] = ResolvedJavaType.class; + } else { + if (parameterTypes[i] == boolean.class) { + reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0); + } else if (parameterTypes[i] == byte.class) { + reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt()); + } else if (parameterTypes[i] == short.class) { + reflectionCallArguments[i] = Short.valueOf((short) constant.asInt()); + } else if (parameterTypes[i] == char.class) { + reflectionCallArguments[i] = Character.valueOf((char) constant.asInt()); + } else { + reflectionCallArguments[i] = o; + } + } + } else { + reflectionCallArguments[i] = argument; + parameterTypes[i] = ValueNode.class; + } + } + return reflectionCallArguments; + } + + private static Class<?> getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { + Class<?> result = intrinsic.value(); + if (result == NodeIntrinsic.class) { + return getMirrorOrFail(target.getDeclaringClass(), Thread.currentThread().getContextClassLoader()); + } + assert Node.class.isAssignableFrom(result); + return result; + } + + private ValueNode tryBoxingElimination(int parameterIndex, ResolvedJavaMethod target, ValueNode node) { + if (parameterIndex >= 0) { + Type type = target.getGenericParameterTypes()[parameterIndex]; + if (type instanceof TypeVariable) { + TypeVariable typeVariable = (TypeVariable) type; + if (typeVariable.getBounds().length == 1) { + Type boundType = typeVariable.getBounds()[0]; + if (boundType instanceof Class && ((Class) boundType).getSuperclass() == null) { + // Unbound generic => try boxing elimination + if (node.usages().count() == 2) { + if (node instanceof Invoke) { + Invoke invokeNode = (Invoke) node; + MethodCallTargetNode callTarget = invokeNode.methodCallTarget(); + if (pool.isBoxingMethod(callTarget.targetMethod())) { + FrameState stateAfter = invokeNode.stateAfter(); + assert stateAfter.usages().count() == 1; + invokeNode.node().replaceAtUsages(null); + ValueNode result = callTarget.arguments().get(0); + StructuredGraph graph = (StructuredGraph) node.graph(); + if (invokeNode instanceof InvokeWithExceptionNode) { + // Destroy exception edge & clear stateAfter. + InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; + + invokeWithExceptionNode.killExceptionEdge(); + graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); + } else { + graph.removeFixed((InvokeNode) invokeNode); + } + stateAfter.safeDelete(); + GraphUtil.propagateKill(callTarget); + return result; + } + } + } + } + } + } + } + return node; + } + + private static Class asBoxedType(Class type) { + if (!type.isPrimitive()) { + return type; + } + + if (Boolean.TYPE == type) { + return Boolean.class; + } + if (Character.TYPE == type) { + return Character.class; + } + if (Byte.TYPE == type) { + return Byte.class; + } + if (Short.TYPE == type) { + return Short.class; + } + if (Integer.TYPE == type) { + return Integer.class; + } + if (Long.TYPE == type) { + return Long.class; + } + if (Float.TYPE == type) { + return Float.class; + } + assert Double.TYPE == type; + return Double.class; + } + + static final int VARARGS = 0x00000080; + + private static Node createNodeInstance(Class<?> nodeClass, Class<?>[] parameterTypes, ResolvedJavaType returnType, boolean setStampFromReturnType, Object[] nodeConstructorArguments) { + Object[] arguments = null; + Constructor<?> constructor = null; + nextConstructor: for (Constructor c : nodeClass.getDeclaredConstructors()) { + Class[] signature = c.getParameterTypes(); + if ((c.getModifiers() & VARARGS) != 0) { + int fixedArgs = signature.length - 1; + if (parameterTypes.length < fixedArgs) { + continue nextConstructor; + } + + for (int i = 0; i < fixedArgs; i++) { + if (!parameterTypes[i].equals(signature[i])) { + continue nextConstructor; + } + } + + Class componentType = signature[fixedArgs].getComponentType(); + assert componentType != null : "expected last parameter of varargs constructor " + c + " to be an array type"; + Class boxedType = asBoxedType(componentType); + for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { + if (!boxedType.isInstance(nodeConstructorArguments[i])) { + continue nextConstructor; + } + } + + arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1); + int varargsLength = nodeConstructorArguments.length - fixedArgs; + Object varargs = Array.newInstance(componentType, varargsLength); + for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { + Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i]); + } + arguments[fixedArgs] = varargs; + constructor = c; + break; + } else if (Arrays.equals(parameterTypes, signature)) { + arguments = nodeConstructorArguments; + constructor = c; + break; + } + } + if (constructor == null) { + throw new GraalInternalError("Could not find constructor in " + nodeClass + " compatible with signature " + Arrays.toString(parameterTypes)); + } + constructor.setAccessible(true); + try { + ValueNode intrinsicNode = (ValueNode) constructor.newInstance(arguments); + if (setStampFromReturnType) { + if (returnType.getKind() == Kind.Object) { + intrinsicNode.setStamp(StampFactory.declared(returnType)); + } else { + intrinsicNode.setStamp(StampFactory.forKind(returnType.getKind())); + } + } + return intrinsicNode; + } catch (Exception e) { + throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e); + } + } + + /** + * Calls a Java method via reflection. + */ + private static Constant callMethod(Kind returnKind, Class<?> holder, String name, Class<?>[] parameterTypes, Object receiver, Object[] arguments) { + Method method; + try { + method = holder.getDeclaredMethod(name, parameterTypes); + method.setAccessible(true); + } catch (Exception e) { + throw new RuntimeException(e); + } + try { + Object result = method.invoke(receiver, arguments); + if (result == null) { + return null; + } + return Constant.forBoxed(returnKind, result); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String sourceLocation(Node n) { + String loc = GraphUtil.approxSourceLocation(n); + return loc == null ? "<unknown>" : loc; + } + + public void cleanUpReturnCheckCast(Node newInstance) { + if (newInstance instanceof ValueNode && (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { + StructuredGraph graph = (StructuredGraph) newInstance.graph(); + for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { + for (ProxyNode vpn : checkCastNode.usages().filter(ProxyNode.class).snapshot()) { + graph.replaceFloating(vpn, checkCastNode); + } + for (Node checkCastUsage : checkCastNode.usages().snapshot()) { + if (checkCastUsage instanceof ValueAnchorNode) { + ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; + graph.removeFixed(valueAnchorNode); + } else if (checkCastUsage instanceof MethodCallTargetNode) { + MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; + if (pool.isUnboxingMethod(checkCastCallTarget.targetMethod())) { + Invoke invokeNode = checkCastCallTarget.invoke(); + invokeNode.node().replaceAtUsages(newInstance); + if (invokeNode instanceof InvokeWithExceptionNode) { + // Destroy exception edge & clear stateAfter. + InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; + + invokeWithExceptionNode.killExceptionEdge(); + graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); + } else { + graph.removeFixed((InvokeNode) invokeNode); + } + checkCastCallTarget.safeDelete(); + } else { + assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) + + " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + + checkCastCallTarget.targetMethod(); + checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); + } + } else if (checkCastUsage instanceof FrameState) { + checkCastUsage.replaceFirstInput(checkCastNode, null); + } else if (checkCastUsage instanceof ReturnNode && checkCastNode.object().stamp() == StampFactory.forNodeIntrinsic()) { + checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); + } else { + assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode); + } + } + FixedNode next = checkCastNode.next(); + checkCastNode.setNext(null); + checkCastNode.replaceAtPredecessor(next); + GraphUtil.killCFG(checkCastNode); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Checks that a graph contains no calls to {@link NodeIntrinsic} or {@link Fold} methods. + */ +public class NodeIntrinsificationVerificationPhase extends Phase { + + public static boolean verify(StructuredGraph graph) { + new NodeIntrinsificationVerificationPhase().apply(graph); + return true; + } + + @Override + protected void run(StructuredGraph graph) { + for (Invoke i : graph.getInvokes()) { + if (i.callTarget() instanceof MethodCallTargetNode) { + checkInvoke(i); + } + } + } + + private static void checkInvoke(Invoke invoke) { + ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); + NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); + if (intrinsic != null) { + throw new GraalInternalError("Illegal call to node intrinsic in " + invoke.graph() + ": " + invoke); + } else if (target.getAnnotation(Fold.class) != null) { + throw new GraalInternalError("Illegal call to foldable method in " + invoke.graph() + ": " + invoke); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsInstaller.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import static com.oracle.graal.api.meta.MetaUtil.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import sun.misc.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.phases.*; + +/** + * Utility for managing the pre-processing and installation of replacements. Replacements are either + * {@linkplain Snippets snippets}, {@linkplain MethodSubstitution method substitutions} or + * {@link MacroSubstitution macro substitutions}. + */ +public class ReplacementsInstaller { + + protected final MetaAccessProvider runtime; + protected final TargetDescription target; + protected final Assumptions assumptions; + protected final BoxingMethodPool pool; + private final Thread owner; + + /** + * A graph cache used by this installer to avoid using the compiler storage for each method + * processed during snippet installation. Without this, all processed methods are to be + * determined as {@linkplain InliningUtil#canIntrinsify intrinsifiable}. + */ + private final Map<ResolvedJavaMethod, StructuredGraph> graphCache; + + public ReplacementsInstaller(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target) { + this.runtime = runtime; + this.target = target; + this.assumptions = assumptions; + this.pool = new BoxingMethodPool(runtime); + this.graphCache = new HashMap<>(); + this.owner = Thread.currentThread(); + } + + /** + * Finds all the snippet methods in a given class, builds a graph for them and installs the + * graph with the key value of {@code Graph.class} in the + * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each method. + */ + public void installSnippets(Class<? extends Snippets> snippets) { + for (Method method : snippets.getDeclaredMethods()) { + if (method.getAnnotation(Snippet.class) != null) { + int modifiers = method.getModifiers(); + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Snippet must not be abstract or native"); + } + ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); + assert snippet.getCompilerStorage().get(Graph.class) == null : method; + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + // System.out.println("snippet: " + graph); + snippet.getCompilerStorage().put(Graph.class, graph); + } + } + } + + /** + * Finds all the methods in a given class annotated with {@link MethodSubstitution} or + * {@link MacroSubstitution}. It builds graphs for the former and installs them in the + * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of the original (i.e., + * substituted) method with a key of {@code Graph.class}. For the latter, the denoted + * {@linkplain MacroSubstitution#macro() macro} node type is install in the compiler storage + * with a key of {@code Node.class}. + */ + public void installSubstitutions(Class<?> substitutions) { + assert owner == Thread.currentThread() : "substitution installation must be single threaded"; + ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class); + assert classSubstitution != null; + assert !Snippets.class.isAssignableFrom(substitutions); + for (Method substituteMethod : substitutions.getDeclaredMethods()) { + MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); + MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class); + if (methodSubstitution == null && macroSubstitution == null) { + continue; + } + + int modifiers = substituteMethod.getModifiers(); + if (!Modifier.isStatic(modifiers)) { + throw new RuntimeException("Substitution methods must be static: " + substituteMethod); + } + + if (methodSubstitution != null) { + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Substitution method must not be abstract or native: " + substituteMethod); + } + String originalName = originalName(substituteMethod, methodSubstitution.value()); + Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); + Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); + if (originalMethod != null) { + installMethodSubstitution(originalMethod, substituteMethod); + } + } + if (macroSubstitution != null) { + String originalName = originalName(substituteMethod, macroSubstitution.value()); + Class[] originalParameters = originalParameters(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); + Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); + if (originalMethod != null) { + installMacroSubstitution(originalMethod, macroSubstitution.macro()); + } + } + } + } + + // 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. + * + * @param originalMethod a method or constructor being substituted + * @param substituteMethod the substitute method + */ + protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { + substitute = runtime.lookupJavaMethod(substituteMethod); + if (originalMethod instanceof Method) { + original = runtime.lookupJavaMethod((Method) originalMethod); + } else { + original = runtime.lookupJavaConstructor((Constructor) originalMethod); + } + try { + Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); + StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute)); + Object oldValue = original.getCompilerStorage().put(Graph.class, graph); + assert oldValue == null; + } finally { + substitute = null; + original = null; + substituteCallsOriginal = false; + } + } + + /** + * Installs a macro substitution. + * + * @param originalMethod a method or constructor being substituted + * @param macro the substitute macro node class + */ + protected void installMacroSubstitution(Member originalMethod, Class<? extends FixedWithNextNode> macro) { + ResolvedJavaMethod originalJavaMethod; + if (originalMethod instanceof Method) { + originalJavaMethod = runtime.lookupJavaMethod((Method) originalMethod); + } else { + originalJavaMethod = runtime.lookupJavaConstructor((Constructor) originalMethod); + } + Object oldValue = originalJavaMethod.getCompilerStorage().put(Node.class, macro); + assert oldValue == null; + } + + private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { + Class<? extends SnippetInliningPolicy> policyClass = SnippetInliningPolicy.class; + Snippet snippet = method.getAnnotation(Snippet.class); + if (snippet != null) { + policyClass = snippet.inlining(); + } + if (policyClass == SnippetInliningPolicy.class) { + return new DefaultSnippetInliningPolicy(runtime, pool); + } + try { + return policyClass.getConstructor().newInstance(); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } + + /** + * Does final processing of a snippet graph. + */ + protected void finalizeGraph(ResolvedJavaMethod method, StructuredGraph graph) { + new NodeIntrinsificationPhase(runtime, pool).apply(graph); + assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph); + + new SnippetFrameStateCleanupPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); + + new InsertStateAfterPlaceholderPhase().apply(graph); + } + + public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable<StructuredGraph>() { + + @Override + public StructuredGraph call() throws Exception { + StructuredGraph graph = parseGraph(method, policy); + + finalizeGraph(method, graph); + + Debug.dump(graph, "%s: Final", method.getName()); + + return graph; + } + }); + } + + private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + StructuredGraph graph = graphCache.get(method); + if (graph == null) { + graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); + graphCache.put(method, graph); + } + return graph; + } + + /** + * Builds the initial graph for a snippet. + */ + protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod method) { + final StructuredGraph graph = new StructuredGraph(method); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); + GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); + graphBuilder.apply(graph); + + Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); + + new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); + new NodeIntrinsificationPhase(runtime, pool).apply(graph); + + return graph; + } + + /** + * Called after a graph is inlined. + * + * @param caller the graph into which {@code callee} was inlined + * @param callee the graph that was inlined into {@code caller} + */ + protected void afterInline(StructuredGraph caller, StructuredGraph callee) { + if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(runtime, target.wordKind).apply(caller); + new CanonicalizerPhase(runtime, assumptions).apply(caller); + } + } + + /** + * Called after all inlining for a given graph is complete. + */ + protected void afterInlining(StructuredGraph graph) { + new NodeIntrinsificationPhase(runtime, pool).apply(graph); + + new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); + + new DeadCodeEliminationPhase().apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(runtime, assumptions).apply(graph); + } + } + + private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { + assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : method; + final StructuredGraph graph = buildInitialGraph(method); + + for (Invoke invoke : graph.getInvokes()) { + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + ResolvedJavaMethod callee = callTarget.targetMethod(); + if (callee == substitute) { + final StructuredGraph originalGraph = new StructuredGraph(original); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); + InliningUtil.inline(invoke, originalGraph, true); + + Debug.dump(graph, "after inlining %s", callee); + afterInline(graph, originalGraph); + 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); + afterInline(graph, targetGraph); + } + } + } + + afterInlining(graph); + + for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { + end.disableSafepoint(); + } + + if (GraalOptions.ProbabilityAnalysis) { + new DeadCodeEliminationPhase().apply(graph); + new ComputeProbabilityPhase().apply(graph); + } + return graph; + } + + private static String originalName(Method substituteMethod, String methodSubstitution) { + if (methodSubstitution.isEmpty()) { + return substituteMethod.getName(); + } else { + return methodSubstitution; + } + } + + /** + * Resolves a name to a class. + * + * @param className the name of the class to resolve + * @param optional if true, resolution failure returns null + * @return the resolved class or null if resolution fails and {@code optional} is true + */ + private static Class resolveType(String className, boolean optional) { + try { + // Need to use launcher class path to handle classes + // that are not on the boot class path + ClassLoader cl = Launcher.getLauncher().getClassLoader(); + return Class.forName(className, false, cl); + } catch (ClassNotFoundException e) { + if (optional) { + return null; + } + throw new GraalInternalError("Could not resolve type " + className); + } + } + + private static Class resolveType(JavaType type) { + JavaType base = type; + int dimensions = 0; + while (base.getComponentType() != null) { + base = base.getComponentType(); + dimensions++; + } + + Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false); + return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass(); + } + + private Class[] originalParameters(Method substituteMethod, String methodSubstitution, boolean isStatic) { + Class[] parameters; + if (methodSubstitution.isEmpty()) { + parameters = substituteMethod.getParameterTypes(); + if (!isStatic) { + assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter"; + parameters = Arrays.copyOfRange(parameters, 1, parameters.length); + } + } else { + Signature signature = runtime.parseMethodDescriptor(methodSubstitution); + parameters = new Class[signature.getParameterCount(false)]; + for (int i = 0; i < parameters.length; i++) { + parameters[i] = resolveType(signature.getParameterType(i, null)); + } + } + return parameters; + } + + private static Member originalMethod(ClassSubstitution classSubstitution, String name, Class[] parameters) { + Class<?> originalClass = classSubstitution.value(); + if (originalClass == ClassSubstitution.class) { + originalClass = resolveType(classSubstitution.className(), classSubstitution.optional()); + if (originalClass == null) { + // optional class was not found + return null; + } + } + try { + if (name.equals("<init>")) { + return originalClass.getDeclaredConstructor(parameters); + } else { + return originalClass.getDeclaredMethod(name, parameters); + } + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalInternalError(e); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import java.lang.annotation.*; +import java.lang.reflect.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.type.*; +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 + * nodes that have runtime dependent semantics (e.g. the {@code CHECKCAST} bytecode). + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +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<? extends SnippetInliningPolicy> inlining() default SnippetInliningPolicy.class; + + /** + * 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); + } + + /** + * The default inlining policy which inlines everything except for methods in any of the + * following categories. + * <ul> + * <li>{@linkplain Fold foldable} methods</li> + * <li>{@linkplain NodeIntrinsic node intrinsics}</li> + * <li>native methods</li> + * <li>constructors of {@link Throwable} classes</li> + * </ul> + */ + public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { + + private final MetaAccessProvider metaAccess; + private final BoxingMethodPool pool; + + public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess, BoxingMethodPool pool) { + this.metaAccess = metaAccess; + this.pool = pool; + } + + @Override + public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { + if (Modifier.isNative(method.getModifiers())) { + 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.getName().equals("<init>")) { + return false; + } + } + if (method.getAnnotation(Word.Operation.class) != null) { + return false; + } + if (pool.isSpecialMethod(method)) { + return false; + } + return true; + } + } + + /** + * Annotates a method replaced by a compile-time constant. A (resolved) call to the annotated + * method is replaced with a constant obtained by calling the annotated method via reflection. + * + * All arguments to such a method (including the receiver if applicable) must be compile-time + * constants. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public static @interface Fold { + } + + /** + * Denotes a snippet parameter that will be bound during snippet template + * {@linkplain SnippetTemplate#instantiate instantiation}. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface Parameter { + + /** + * The name of this parameter. + */ + String value(); + } + + /** + * 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 + * (the contents of the array are ignored) bound to the parameter during + * {@linkplain SnippetTemplate#instantiate instantiation}. + * + * Such a parameter must be used in a counted loop in the snippet preceded by a call to + * {@link ExplodeLoopNode#explodeLoop()}. The counted looped must be a standard iteration over + * all the loop's elements (i.e. {@code for (T e : arr) ... }). + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface VarargsParameter { + + /** + * The name of this parameter. + */ + String value(); + } + + /** + * Denotes a snippet parameter that will bound to a constant value during snippet template + * {@linkplain SnippetTemplate#instantiate instantiation}. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + public @interface ConstantParameter { + + /** + * The name of this constant. + */ + String value(); + } + + /** + * Wrapper for the prototype value of a {@linkplain VarargsParameter varargs} parameter. + */ + public static class Varargs { + + private final Object args; + private final Class argType; + private final int length; + private final Stamp argStamp; + + public static Varargs vargargs(Object array, Stamp argStamp) { + return new Varargs(array, argStamp); + } + + public Varargs(Object array, Stamp argStamp) { + assert array != null; + this.argType = array.getClass().getComponentType(); + this.argStamp = argStamp; + assert this.argType != null; + this.length = java.lang.reflect.Array.getLength(array); + this.args = array; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Varargs) { + Varargs other = (Varargs) obj; + return other.argType == argType && other.length == length; + } + return false; + } + + public Object getArray() { + return args; + } + + public Stamp getArgStamp() { + return argStamp; + } + + @Override + public int hashCode() { + return argType.hashCode() ^ length; + } + + @Override + public String toString() { + return argType.getName() + "[" + length + "]"; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,155 @@ +/* + * 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.replacements; + +//JaCoCo Exclude + +import static com.oracle.graal.graph.FieldIntrospection.*; + +import java.io.*; +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering + * snippet specific metrics. + */ +public class SnippetCounter implements Comparable<SnippetCounter> { + + /** + * A group of related counters. + */ + public static class Group { + + final String name; + final List<SnippetCounter> counters; + + public Group(String name) { + this.name = name; + this.counters = new ArrayList<>(); + } + + @Override + public synchronized String toString() { + Collections.sort(counters); + + long total = 0; + int maxNameLen = 0; + for (SnippetCounter c : counters) { + total += c.value; + maxNameLen = Math.max(c.name.length(), maxNameLen); + } + + StringBuilder buf = new StringBuilder(String.format("Counters: %s%n", name)); + + for (SnippetCounter c : counters) { + double percent = total == 0D ? 0D : ((double) (c.value * 100)) / total; + buf.append(String.format(" %" + maxNameLen + "s: %5.2f%%%10d // %s%n", c.name, percent, c.value, c.description)); + } + return buf.toString(); + } + } + + /** + * Sorts counters in descending order of their {@linkplain #value() values}. + */ + @Override + public int compareTo(SnippetCounter o) { + if (value > o.value) { + return -1; + } else if (o.value < value) { + return 1; + } + return 0; + } + + private static final List<Group> groups = new ArrayList<>(); + + private final Group group; + private final int index; + private final String name; + private final String description; + private long value; + + @Fold + private static int countOffset() { + try { + return (int) unsafe.objectFieldOffset(SnippetCounter.class.getDeclaredField("value")); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } + + /** + * Creates a counter. + * + * @param group the group to which the counter belongs. If this is null, the newly created + * counter is disabled and {@linkplain #inc() incrementing} is a no-op. + * @param name the name of the counter + * @param description a brief comment describing the metric represented by the counter + */ + public SnippetCounter(Group group, String name, String description) { + this.group = group; + this.name = name; + this.description = description; + if (group != null) { + List<SnippetCounter> counters = group.counters; + this.index = counters.size(); + counters.add(this); + if (index == 0) { + groups.add(group); + } + } else { + this.index = -1; + } + } + + /** + * Increments the value of this counter. This method can be safely used in a snippet if it is + * invoked on a compile-time constant {@link SnippetCounter} object. + */ + public void inc() { + if (group != null) { + DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1); + } + } + + /** + * Gets the value of this counter. + */ + public long value() { + return value; + } + + /** + * Prints all the counter groups to a given stream. + */ + public static void printGroups(PrintStream out) { + for (Group group : groups) { + out.println(group); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import java.util.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; + +/** + * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a + * snippet. + * + * The frame states of side-effecting nodes are replaced with + * {@linkplain FrameState#INVALID_FRAMESTATE_BCI invalid} frame states. Loops that contain invalid + * frame states are also assigned an invalid frame state. + * + * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. + */ +public class SnippetFrameStateCleanupPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null); + } + + private static class CleanupState { + + public boolean containsFrameState; + + public CleanupState(boolean containsFrameState) { + this.containsFrameState = containsFrameState; + } + } + + /** + * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid + * frame states, so that they can be marked with an invalid frame state. + */ + private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<CleanupState> { + + @Override + protected void processNode(FixedNode node, CleanupState currentState) { + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); + if (frameState != null) { + if (stateSplit.hasSideEffect()) { + currentState.containsFrameState = true; + stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + } else { + stateSplit.setStateAfter(null); + } + if (frameState.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(frameState); + } + } + } + } + + @Override + protected CleanupState merge(MergeNode merge, List<CleanupState> states) { + for (CleanupState state : states) { + if (state.containsFrameState) { + return new CleanupState(true); + } + } + return new CleanupState(false); + } + + @Override + protected CleanupState afterSplit(BeginNode node, CleanupState oldState) { + return new CleanupState(oldState.containsFrameState); + } + + @Override + protected Map<LoopExitNode, CleanupState> processLoop(LoopBeginNode loop, CleanupState initialState) { + LoopInfo<CleanupState> info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false)); + boolean containsFrameState = false; + for (CleanupState state : info.endStates.values()) { + containsFrameState |= state.containsFrameState; + } + if (containsFrameState) { + loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + } + if (containsFrameState || initialState.containsFrameState) { + for (CleanupState state : info.exitStates.values()) { + state.containsFrameState = true; + } + } + return info.exitStates; + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,752 @@ +/* + * 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.replacements; + +import java.lang.reflect.*; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.loop.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; +import com.oracle.graal.word.phases.*; + +/** + * A snippet template is a graph created by parsing a snippet method and then specialized by binding + * constants to the snippet's {@link ConstantParameter} parameters. + * + * Snippet templates can be managed in a {@link Cache}. + */ +public class SnippetTemplate { + + /** + * A snippet template key encapsulates the method from which a snippet was built and the + * arguments used to specialize the snippet. + * + * @see Cache + */ + public static class Key implements Iterable<Map.Entry<String, Object>> { + + public final ResolvedJavaMethod method; + private final HashMap<String, Object> map = new HashMap<>(); + private int hash; + + public Key(ResolvedJavaMethod method) { + this.method = method; + this.hash = method.hashCode(); + } + + public Key add(String name, Object value) { + assert !map.containsKey(name); + map.put(name, value); + hash = hash ^ name.hashCode(); + if (value != null) { + hash *= (value.hashCode() + 1); + } + return this; + } + + public int length() { + return map.size(); + } + + public Object get(String name) { + return map.get(name); + } + + @Override + public Iterator<Entry<String, Object>> iterator() { + return map.entrySet().iterator(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Key) { + Key other = (Key) obj; + return other.method == method && other.map.equals(map); + } + return false; + } + + @Override + public int hashCode() { + return hash; + } + + @Override + public String toString() { + return MetaUtil.format("%h.%n", method) + map.toString(); + } + + public Set<String> names() { + return map.keySet(); + } + } + + /** + * Arguments used to instantiate a template. + */ + public static class Arguments implements Iterable<Map.Entry<String, Object>> { + + private final HashMap<String, Object> map = new HashMap<>(); + + public static Arguments arguments(String name, Object value) { + return new Arguments().add(name, value); + } + + public Arguments add(String name, Object value) { + assert !map.containsKey(name); + map.put(name, value); + return this; + } + + public int length() { + return map.size(); + } + + @Override + public Iterator<Entry<String, Object>> iterator() { + return map.entrySet().iterator(); + } + + @Override + public String toString() { + return map.toString(); + } + } + + /** + * A collection of snippet templates accessed by a {@link Key} instance. + */ + public static class Cache { + + private final ConcurrentHashMap<SnippetTemplate.Key, SnippetTemplate> templates = new ConcurrentHashMap<>(); + private final MetaAccessProvider runtime; + private final TargetDescription target; + + public Cache(MetaAccessProvider runtime, TargetDescription target) { + this.runtime = runtime; + this.target = target; + } + + /** + * Gets a template for a given key, creating it first if necessary. + */ + public SnippetTemplate get(final SnippetTemplate.Key key, final Assumptions assumptions) { + SnippetTemplate template = templates.get(key); + if (template == null) { + template = Debug.scope("SnippetSpecialization", key.method, new Callable<SnippetTemplate>() { + + @Override + public SnippetTemplate call() throws Exception { + return new SnippetTemplate(runtime, assumptions, target, key); + } + }); + // System.out.println(key + " -> " + template); + templates.put(key, template); + } + return template; + } + } + + public abstract static class AbstractTemplates<T extends Snippets> { + + protected final Cache cache; + protected final MetaAccessProvider runtime; + protected final Assumptions assumptions; + protected Class<?> snippetsClass; + + public AbstractTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class<T> snippetsClass) { + this.runtime = runtime; + this.assumptions = assumptions; + if (snippetsClass == null) { + assert this instanceof Snippets; + this.snippetsClass = getClass(); + } else { + this.snippetsClass = snippetsClass; + } + this.cache = new Cache(runtime, target); + } + + protected ResolvedJavaMethod snippet(String name, Class<?>... parameterTypes) { + try { + ResolvedJavaMethod snippet = runtime.lookupJavaMethod(snippetsClass.getDeclaredMethod(name, parameterTypes)); + assert snippet.getAnnotation(Snippet.class) != null : "snippet is not annotated with @" + Snippet.class.getSimpleName(); + return snippet; + } catch (NoSuchMethodException e) { + throw new GraalInternalError(e); + } + } + } + + private static final Object UNUSED_PARAMETER = "DEAD PARAMETER"; + + /** + * Determines if any parameter of a given method is annotated with {@link ConstantParameter}. + */ + public static boolean hasConstantParameter(ResolvedJavaMethod method) { + for (ConstantParameter p : MetaUtil.getParameterAnnotations(ConstantParameter.class, method)) { + if (p != null) { + return true; + } + } + return false; + } + + /** + * Creates a snippet template. + */ + public SnippetTemplate(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, SnippetTemplate.Key key) { + ResolvedJavaMethod method = key.method; + assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + method; + Signature signature = method.getSignature(); + + // Copy snippet graph, replacing constant parameters with given arguments + StructuredGraph snippetGraph = (StructuredGraph) method.getCompilerStorage().get(Graph.class); + StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); + IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>(); + replacements.put(snippetGraph.start(), snippetCopy.start()); + + int parameterCount = signature.getParameterCount(false); + assert checkTemplate(runtime, key, parameterCount, method, signature); + + Parameter[] parameterAnnotations = new Parameter[parameterCount]; + VarargsParameter[] varargsParameterAnnotations = new VarargsParameter[parameterCount]; + ConstantNode[] placeholders = new ConstantNode[parameterCount]; + for (int i = 0; i < parameterCount; i++) { + ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); + if (c != null) { + String name = c.value(); + Object arg = key.get(name); + Kind kind = signature.getParameterKind(i); + Constant constantArg; + if (arg instanceof Constant) { + constantArg = (Constant) arg; + } else { + constantArg = Constant.forBoxed(kind, arg); + } + replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(constantArg, runtime, snippetCopy)); + } else { + VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); + if (vp != null) { + String name = vp.value(); + Varargs varargs = (Varargs) key.get(name); + Object array = varargs.getArray(); + ConstantNode placeholder = ConstantNode.forObject(array, runtime, snippetCopy); + replacements.put(snippetGraph.getLocal(i), placeholder); + placeholders[i] = placeholder; + varargsParameterAnnotations[i] = vp; + } else { + parameterAnnotations[i] = MetaUtil.getParameterAnnotation(Parameter.class, i, method); + } + } + } + snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); + + Debug.dump(snippetCopy, "Before specialization"); + if (!replacements.isEmpty()) { + // Do deferred intrinsification of node intrinsics + new NodeIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy); + new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy); + + new CanonicalizerPhase(runtime, assumptions, 0, null).apply(snippetCopy); + } + assert NodeIntrinsificationVerificationPhase.verify(snippetCopy); + + // Gather the template parameters + parameters = new HashMap<>(); + for (int i = 0; i < parameterCount; i++) { + VarargsParameter vp = varargsParameterAnnotations[i]; + if (vp != null) { + assert snippetCopy.getLocal(i) == null; + Varargs varargs = (Varargs) key.get(vp.value()); + Object array = varargs.getArray(); + int length = Array.getLength(array); + LocalNode[] locals = new LocalNode[length]; + Stamp stamp = varargs.getArgStamp(); + for (int j = 0; j < length; j++) { + assert (parameterCount & 0xFFFF) == parameterCount; + int idx = i << 16 | j; + LocalNode local = snippetCopy.unique(new LocalNode(idx, stamp)); + locals[j] = local; + } + parameters.put(vp.value(), locals); + + ConstantNode placeholder = placeholders[i]; + assert placeholder != null; + for (Node usage : placeholder.usages().snapshot()) { + if (usage instanceof LoadIndexedNode) { + LoadIndexedNode loadIndexed = (LoadIndexedNode) usage; + Debug.dump(snippetCopy, "Before replacing %s", loadIndexed); + LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(locals, loadIndexed.index(), loadIndexed.stamp())); + snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter); + Debug.dump(snippetCopy, "After replacing %s", loadIndexed); + } + } + } else { + Parameter p = parameterAnnotations[i]; + if (p != null) { + LocalNode local = snippetCopy.getLocal(i); + if (local == null) { + // Parameter value was eliminated + parameters.put(p.value(), UNUSED_PARAMETER); + } else { + parameters.put(p.value(), local); + } + } + } + } + + // Do any required loop explosion + boolean exploded = false; + do { + exploded = false; + ExplodeLoopNode explodeLoop = snippetCopy.getNodes().filter(ExplodeLoopNode.class).first(); + if (explodeLoop != null) { // Earlier canonicalization may have removed the loop + // altogether + LoopBeginNode loopBegin = explodeLoop.findLoopBegin(); + if (loopBegin != null) { + LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin); + int mark = snippetCopy.getMark(); + LoopTransformations.fullUnroll(loop, runtime, null); + new CanonicalizerPhase(runtime, assumptions, mark, null).apply(snippetCopy); + } + FixedNode explodeLoopNext = explodeLoop.next(); + explodeLoop.clearSuccessors(); + explodeLoop.replaceAtPredecessor(explodeLoopNext); + explodeLoop.replaceAtUsages(null); + GraphUtil.killCFG(explodeLoop); + exploded = true; + } + } while (exploded); + + // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free + // of side-effects that prevent deoptimizing to a point before the snippet). + ArrayList<StateSplit> curSideEffectNodes = new ArrayList<>(); + ArrayList<ValueNode> curStampNodes = new ArrayList<>(); + for (Node node : snippetCopy.getNodes()) { + if (node instanceof ValueNode && ((ValueNode) node).stamp() == StampFactory.forNodeIntrinsic()) { + curStampNodes.add((ValueNode) node); + } + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); + if (stateSplit.hasSideEffect()) { + curSideEffectNodes.add((StateSplit) node); + } + if (frameState != null) { + stateSplit.setStateAfter(null); + } + } + } + + new DeadCodeEliminationPhase().apply(snippetCopy); + + assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders); + + this.snippet = snippetCopy; + ReturnNode retNode = null; + StartNode entryPointNode = snippet.start(); + + new DeadCodeEliminationPhase().apply(snippetCopy); + + nodes = new ArrayList<>(snippet.getNodeCount()); + for (Node node : snippet.getNodes()) { + if (node == entryPointNode || node == entryPointNode.stateAfter()) { + // Do nothing. + } else { + nodes.add(node); + if (node instanceof ReturnNode) { + retNode = (ReturnNode) node; + } + } + } + + this.sideEffectNodes = curSideEffectNodes; + this.stampNodes = curStampNodes; + this.returnNode = retNode; + } + + private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, ConstantNode[] placeholders) { + for (int i = 0; i < parameterCount; i++) { + if (placeholders[i] != null) { + assert placeholders[i].isDeleted() : placeholders[i]; + } + } + return true; + } + + private static boolean checkConstantArgument(MetaAccessProvider runtime, final ResolvedJavaMethod method, Signature signature, int i, String name, Object arg, Kind kind) { + ResolvedJavaType type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass()); + if (runtime.lookupJavaType(WordBase.class).isAssignableFrom(type)) { + assert arg instanceof Constant : method + ": word constant parameters must be passed boxed in a Constant value: " + arg; + return true; + } + if (kind == Kind.Object) { + assert arg == null || type.isInstance(Constant.forObject(arg)) : method + ": wrong value type for " + name + ": expected " + type.getName() + ", got " + arg.getClass().getName(); + } else { + assert arg != null && kind.toBoxedJavaClass() == arg.getClass() : method + ": wrong value kind for " + name + ": expected " + kind + ", got " + + (arg == null ? "null" : arg.getClass().getSimpleName()); + } + return true; + } + + private static boolean checkVarargs(final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) { + Object arg = varargs.getArray(); + ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass()); + assert type.isArray() : "varargs parameter must be an array type"; + assert type.isInstance(Constant.forObject(arg)) : "value for " + name + " is not a " + MetaUtil.toJavaName(type) + " instance: " + arg; + return true; + } + + /** + * The graph built from the snippet method. + */ + private final StructuredGraph snippet; + + /** + * The named parameters of this template that must be bound to values during instantiation. For + * a parameter that is still live after specialization, the value in this map is either a + * {@link LocalNode} instance or a {@link LocalNode} array. For an eliminated parameter, the + * value is identical to the key. + */ + private final Map<String, Object> parameters; + + /** + * The return node (if any) of the snippet. + */ + private final ReturnNode returnNode; + + /** + * Nodes that inherit the {@link StateSplit#stateAfter()} from the replacee during + * instantiation. + */ + private final ArrayList<StateSplit> sideEffectNodes; + + /** + * The nodes that inherit the {@link ValueNode#stamp()} from the replacee during instantiation. + */ + private final ArrayList<ValueNode> stampNodes; + + /** + * The nodes to be inlined when this specialization is instantiated. + */ + private final ArrayList<Node> nodes; + + /** + * Gets the instantiation-time bindings to this template's parameters. + * + * @return the map that will be used to bind arguments to parameters when inlining this template + */ + private IdentityHashMap<Node, Node> bind(StructuredGraph replaceeGraph, MetaAccessProvider runtime, SnippetTemplate.Arguments args) { + IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>(); + assert args.length() == parameters.size() : "number of args (" + args.length() + ") != number of parameters (" + parameters.size() + ")"; + for (Map.Entry<String, Object> e : args) { + String name = e.getKey(); + Object parameter = parameters.get(name); + assert parameter != null : this + " has no parameter named " + name; + Object argument = e.getValue(); + if (parameter instanceof LocalNode) { + if (argument instanceof ValueNode) { + replacements.put((LocalNode) parameter, (ValueNode) argument); + } else { + Kind kind = ((LocalNode) parameter).kind(); + assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + name; + Constant constant = Constant.forBoxed(kind, argument); + replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph)); + } + } else if (parameter instanceof LocalNode[]) { + LocalNode[] locals = (LocalNode[]) parameter; + int length = locals.length; + List list = null; + Object array = null; + if (argument instanceof List) { + list = (List) argument; + assert list.size() == length : length + " != " + list.size(); + } else { + array = argument; + assert array != null && array.getClass().isArray(); + assert Array.getLength(array) == length : length + " != " + Array.getLength(array); + } + + for (int j = 0; j < length; j++) { + LocalNode local = locals[j]; + assert local != null; + Object value = list != null ? list.get(j) : Array.get(array, j); + if (value instanceof ValueNode) { + replacements.put(local, (ValueNode) value); + } else { + Constant constant = Constant.forBoxed(local.kind(), value); + ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph); + replacements.put(local, element); + } + } + } else { + assert parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + name + " -> " + parameter; + } + } + return replacements; + } + + /** + * Logic for replacing a snippet-lowered node at its usages with the return value of the + * snippet. An alternative to the {@linkplain SnippetTemplate#DEFAULT_REPLACER default} + * replacement logic can be used to handle mismatches between the stamp of the node being + * lowered and the stamp of the snippet's return value. + */ + public interface UsageReplacer { + + /** + * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}. + */ + void replace(ValueNode oldNode, ValueNode newNode); + } + + /** + * Represents the default {@link UsageReplacer usage replacer} logic which simply delegates to + * {@link Node#replaceAtUsages(Node)}. + */ + public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() { + + @Override + public void replace(ValueNode oldNode, ValueNode newNode) { + oldNode.replaceAtUsages(newNode); + } + }; + + /** + * Replaces a given fixed node with this specialized snippet. + * + * @param runtime + * @param replacee the node that will be replaced + * @param replacer object that replaces the usages of {@code replacee} + * @param args the arguments to be bound to the flattened positional parameters of the snippet + * @return the map of duplicated nodes (original -> duplicate) + */ + public Map<Node, Node> instantiate(MetaAccessProvider runtime, FixedNode replacee, UsageReplacer replacer, SnippetTemplate.Arguments args) { + + // Inline the snippet nodes, replacing parameters with the given args in the process + String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; + StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); + StartNode entryPointNode = snippet.start(); + FixedNode firstCFGNode = entryPointNode.next(); + StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, runtime, args); + Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements); + Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); + + // Re-wire the control flow graph around the replacee + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + replacee.replaceAtPredecessor(firstCFGNodeDuplicate); + FixedNode next = null; + if (replacee instanceof FixedWithNextNode) { + FixedWithNextNode fwn = (FixedWithNextNode) replacee; + next = fwn.next(); + fwn.setNext(null); + } + + if (replacee instanceof StateSplit) { + for (StateSplit sideEffectNode : sideEffectNodes) { + assert ((StateSplit) replacee).hasSideEffect(); + Node sideEffectDup = duplicates.get(sideEffectNode); + ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); + } + } + for (ValueNode stampNode : stampNodes) { + Node stampDup = duplicates.get(stampNode); + ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); + } + + // Replace all usages of the replacee with the value returned by the snippet + ValueNode returnValue = null; + if (returnNode != null) { + if (returnNode.result() instanceof LocalNode) { + returnValue = (ValueNode) replacements.get(returnNode.result()); + } else { + returnValue = (ValueNode) duplicates.get(returnNode.result()); + } + assert returnValue != null || replacee.usages().isEmpty(); + replacer.replace(replacee, returnValue); + + Node returnDuplicate = duplicates.get(returnNode); + if (returnDuplicate.isAlive()) { + returnDuplicate.clearInputs(); + returnDuplicate.replaceAndDelete(next); + } + } + + // Remove the replacee from its graph + replacee.clearInputs(); + replacee.replaceAtUsages(null); + GraphUtil.killCFG(replacee); + + Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); + return duplicates; + } + + /** + * Gets a copy of the specialized graph. + */ + public StructuredGraph copySpecializedGraph() { + return snippet.copy(); + } + + /** + * Replaces a given floating node with this specialized snippet. + * + * @param runtime + * @param replacee the node that will be replaced + * @param replacer object that replaces the usages of {@code replacee} + * @param args the arguments to be bound to the flattened positional parameters of the snippet + */ + public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, SnippetTemplate.Arguments args) { + + // Inline the snippet nodes, replacing parameters with the given args in the process + String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; + StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); + StartNode entryPointNode = snippet.start(); + FixedNode firstCFGNode = entryPointNode.next(); + StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); + IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, runtime, args); + Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements); + Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); + + FixedWithNextNode lastFixedNode = tool.lastFixedNode(); + assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph; + FixedNode next = lastFixedNode.next(); + lastFixedNode.setNext(null); + FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); + replaceeGraph.addAfterFixed(lastFixedNode, firstCFGNodeDuplicate); + + if (replacee instanceof StateSplit) { + for (StateSplit sideEffectNode : sideEffectNodes) { + assert ((StateSplit) replacee).hasSideEffect(); + Node sideEffectDup = duplicates.get(sideEffectNode); + ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); + } + } + for (ValueNode stampNode : stampNodes) { + Node stampDup = duplicates.get(stampNode); + ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); + } + + // Replace all usages of the replacee with the value returned by the snippet + assert returnNode != null : replaceeGraph; + ValueNode returnValue = null; + if (returnNode.result() instanceof LocalNode) { + returnValue = (ValueNode) replacements.get(returnNode.result()); + } else { + returnValue = (ValueNode) duplicates.get(returnNode.result()); + } + assert returnValue != null || replacee.usages().isEmpty(); + replacer.replace(replacee, returnValue); + + tool.setLastFixedNode(null); + Node returnDuplicate = duplicates.get(returnNode); + if (returnDuplicate.isAlive()) { + returnDuplicate.clearInputs(); + returnDuplicate.replaceAndDelete(next); + if (next != null && next.predecessor() instanceof FixedWithNextNode) { + tool.setLastFixedNode((FixedWithNextNode) next.predecessor()); + } + } + + Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(snippet.toString()).append('('); + String sep = ""; + for (Map.Entry<String, Object> e : parameters.entrySet()) { + String name = e.getKey(); + Object value = e.getValue(); + buf.append(sep); + sep = ", "; + if (value == UNUSED_PARAMETER) { + buf.append("<unused> ").append(name); + } else if (value instanceof LocalNode) { + LocalNode local = (LocalNode) value; + buf.append(local.kind().getJavaName()).append(' ').append(name); + } else { + LocalNode[] locals = (LocalNode[]) value; + String kind = locals.length == 0 ? "?" : locals[0].kind().getJavaName(); + buf.append(kind).append('[').append(locals.length).append("] ").append(name); + } + } + return buf.append(')').toString(); + } + + private static boolean checkTemplate(MetaAccessProvider runtime, SnippetTemplate.Key key, int parameterCount, ResolvedJavaMethod method, Signature signature) { + Set<String> expected = new HashSet<>(); + for (int i = 0; i < parameterCount; i++) { + ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); + VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); + Parameter p = MetaUtil.getParameterAnnotation(Parameter.class, i, method); + if (c != null) { + assert vp == null && p == null; + String name = c.value(); + expected.add(name); + Kind kind = signature.getParameterKind(i); + assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; + assert checkConstantArgument(runtime, method, signature, i, c.value(), key.get(name), kind); + } else if (vp != null) { + assert p == null; + String name = vp.value(); + expected.add(name); + assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; + assert key.get(name) instanceof Varargs; + Varargs varargs = (Varargs) key.get(name); + assert checkVarargs(method, signature, i, name, varargs); + } else { + assert p != null : method + ": parameter " + i + " must be annotated with exactly one of " + "@" + ConstantParameter.class.getSimpleName() + " or " + "@" + + VarargsParameter.class.getSimpleName() + " or " + "@" + Parameter.class.getSimpleName(); + } + } + if (!key.names().containsAll(expected)) { + expected.removeAll(key.names()); + assert false : expected + " missing from key " + key; + } + if (!expected.containsAll(key.names())) { + Set<String> namesCopy = new HashSet<>(key.names()); + namesCopy.removeAll(expected); + assert false : "parameter(s) " + namesCopy + " should be annotated with @" + ConstantParameter.class.getSimpleName() + " or @" + VarargsParameter.class.getSimpleName() + " in " + + MetaUtil.format("%H.%n(%p)", method); + } + return true; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippets.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +/** + * Marker interface for a class that defines one or more {@link Snippet}s. + */ +public interface Snippets { +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.replacements.ClassSubstitution.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Substitutions for {@link sun.misc.Unsafe} methods. + */ +@ClassSubstitution(sun.misc.Unsafe.class) +public class UnsafeSubstitutions { + + @MethodSubstitution(isStatic = false) + public static boolean compareAndSwapObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object expected, Object x) { + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); + } + + @MethodSubstitution(isStatic = false) + public static boolean compareAndSwapInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int expected, int x) { + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); + } + + @MethodSubstitution(isStatic = false) + public static boolean compareAndSwapLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long expected, long x) { + return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); + } + + @MethodSubstitution(isStatic = false) + public static Object getObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + return UnsafeLoadNode.load(o, 0, offset, Kind.Object); + } + + @MethodSubstitution(isStatic = false) + public static Object getObjectVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + Object result = getObject(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Object); + } + + @MethodSubstitution(isStatic = false) + public static void putObjectVolatile(final Object thisObj, Object o, long offset, Object x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putObject(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static void putOrderedObject(final Object thisObj, Object o, long offset, Object x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putObject(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static int getInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + Integer value = UnsafeLoadNode.load(o, 0, offset, Kind.Int); + return value; + } + + @MethodSubstitution(isStatic = false) + public static int getIntVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + int result = getInt(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Int); + } + + @MethodSubstitution(isStatic = false) + public static void putIntVolatile(final Object thisObj, Object o, long offset, int x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putInt(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static void putOrderedInt(final Object thisObj, Object o, long offset, int x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putInt(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static boolean getBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Boolean result = UnsafeLoadNode.load(o, 0, offset, Kind.Boolean); + return result; + } + + @MethodSubstitution(isStatic = false) + public static boolean getBooleanVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + boolean result = getBoolean(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, boolean x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Boolean); + } + + @MethodSubstitution(isStatic = false) + public static void putBooleanVolatile(final Object thisObj, Object o, long offset, boolean x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putBoolean(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static byte getByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Byte result = UnsafeLoadNode.load(o, 0, offset, Kind.Byte); + return result; + } + + @MethodSubstitution(isStatic = false) + public static byte getByteVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + byte result = getByte(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, byte x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Byte); + } + + @MethodSubstitution(isStatic = false) + public static void putByteVolatile(final Object thisObj, Object o, long offset, byte x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putByte(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static short getShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Short result = UnsafeLoadNode.load(o, 0, offset, Kind.Short); + return result; + } + + @MethodSubstitution(isStatic = false) + public static short getShortVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + short result = getShort(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, short x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Short); + } + + @MethodSubstitution(isStatic = false) + public static void putShortVolatile(final Object thisObj, Object o, long offset, short x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putShort(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static char getChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Character result = UnsafeLoadNode.load(o, 0, offset, Kind.Char); + return result; + } + + @MethodSubstitution(isStatic = false) + public static char getCharVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + char result = getChar(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, char x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Char); + } + + @MethodSubstitution(isStatic = false) + public static void putCharVolatile(final Object thisObj, Object o, long offset, char x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putChar(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static long getLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Long result = UnsafeLoadNode.load(o, 0, offset, Kind.Long); + return result; + } + + @MethodSubstitution(isStatic = false) + public static long getLongVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + long result = getLong(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Long); + } + + @MethodSubstitution(isStatic = false) + public static void putLongVolatile(final Object thisObj, Object o, long offset, long x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putLong(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static void putOrderedLong(final Object thisObj, Object o, long offset, long x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putLong(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static float getFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Float result = UnsafeLoadNode.load(o, 0, offset, Kind.Float); + return result; + } + + @MethodSubstitution(isStatic = false) + public static float getFloatVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + float result = getFloat(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, float x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Float); + } + + @MethodSubstitution(isStatic = false) + public static void putFloatVolatile(final Object thisObj, Object o, long offset, float x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putFloat(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static double getDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { + @JavacBug(id = 6995200) + Double result = UnsafeLoadNode.load(o, 0, offset, Kind.Double); + return result; + } + + @MethodSubstitution(isStatic = false) + public static double getDoubleVolatile(final Object thisObj, Object o, long offset) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); + double result = getDouble(thisObj, o, offset); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); + return result; + } + + @MethodSubstitution(isStatic = false) + public static void putDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, double x) { + UnsafeStoreNode.store(o, 0, offset, x, Kind.Double); + } + + @MethodSubstitution(isStatic = false) + public static void putDoubleVolatile(final Object thisObj, Object o, long offset, double x) { + MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); + putDouble(thisObj, o, offset, x); + MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); + } + + @MethodSubstitution(isStatic = false) + public static void putByte(@SuppressWarnings("unused") final Object thisObj, long address, byte value) { + DirectStoreNode.store(address, value, Kind.Byte); + } + + @MethodSubstitution(isStatic = false) + public static void putShort(@SuppressWarnings("unused") final Object thisObj, long address, short value) { + DirectStoreNode.store(address, value, Kind.Short); + } + + @MethodSubstitution(isStatic = false) + public static void putChar(@SuppressWarnings("unused") final Object thisObj, long address, char value) { + DirectStoreNode.store(address, value, Kind.Char); + } + + @MethodSubstitution(isStatic = false) + public static void putInt(@SuppressWarnings("unused") final Object thisObj, long address, int value) { + DirectStoreNode.store(address, value, Kind.Int); + } + + @MethodSubstitution(isStatic = false) + public static void putLong(@SuppressWarnings("unused") final Object thisObj, long address, long value) { + DirectStoreNode.store(address, value, Kind.Long); + } + + @MethodSubstitution(isStatic = false) + public static void putFloat(@SuppressWarnings("unused") final Object thisObj, long address, float value) { + DirectStoreNode.store(address, value, Kind.Float); + } + + @MethodSubstitution(isStatic = false) + public static void putDouble(@SuppressWarnings("unused") final Object thisObj, long address, double value) { + DirectStoreNode.store(address, value, Kind.Double); + } + + @MethodSubstitution(isStatic = false) + public static byte getByte(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Byte); + } + + @MethodSubstitution(isStatic = false) + public static short getShort(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Short); + } + + @MethodSubstitution(isStatic = false) + public static char getChar(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Char); + } + + @MethodSubstitution(isStatic = false) + public static int getInt(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Int); + } + + @MethodSubstitution(isStatic = false) + public static long getLong(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Long); + } + + @MethodSubstitution(isStatic = false) + public static float getFloat(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Float); + } + + @MethodSubstitution(isStatic = false) + public static double getDouble(@SuppressWarnings("unused") final Object thisObj, long address) { + return DirectReadNode.read(address, Kind.Double); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsignedMathSubstitutions.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements; + +import static com.oracle.graal.nodes.calc.ConditionalNode.*; +import static com.oracle.graal.nodes.calc.Condition.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.replacements.ClassSubstitution.*; + +/** + * Substitutions for {@link UnsignedMath}. + */ +@ClassSubstitution(UnsignedMath.class) +public class UnsignedMathSubstitutions { + + @MethodSubstitution + public static boolean aboveThan(int a, int b) { + return materializeCondition(BT, b, a); + } + + @MethodSubstitution + public static boolean aboveOrEqual(int a, int b) { + return !materializeCondition(BT, a, b); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + @MethodSubstitution + public static boolean belowThan(int a, int b) { + return materializeCondition(BT, a, b); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + @MethodSubstitution + public static boolean belowOrEqual(int a, int b) { + return !materializeCondition(BT, b, a); + } + + /** + * Unsigned comparison aboveThan for two numbers. + */ + @MethodSubstitution + public static boolean aboveThan(long a, long b) { + return materializeCondition(BT, b, a); + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + @MethodSubstitution + public static boolean aboveOrEqual(long a, long b) { + return !materializeCondition(BT, a, b); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + @MethodSubstitution + public static boolean belowThan(long a, long b) { + return materializeCondition(BT, a, b); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + @MethodSubstitution + public static boolean belowOrEqual(long a, long b) { + return !materializeCondition(BT, b, a); + } + + /** + * Unsigned division for two numbers. + */ + @MethodSubstitution + public static int divide(int a, int b) { + return unsignedDivide(Kind.Int, a, b); + } + + /** + * Unsigned remainder for two numbers. + */ + @MethodSubstitution + public static int remainder(int a, int b) { + return unsignedRemainder(Kind.Int, a, b); + } + + /** + * Unsigned division for two numbers. + */ + @MethodSubstitution + public static long divide(long a, long b) { + return unsignedDivide(Kind.Long, a, b); + } + + /** + * Unsigned remainder for two numbers. + */ + @MethodSubstitution + public static long remainder(long a, long b) { + return unsignedRemainder(Kind.Long, a, b); + } + + @NodeIntrinsic(UnsignedDivNode.class) + private static native int unsignedDivide(@ConstantNodeParameter Kind kind, int a, int b); + + @NodeIntrinsic(UnsignedDivNode.class) + private static native long unsignedDivide(@ConstantNodeParameter Kind kind, long a, long b); + + @NodeIntrinsic(UnsignedRemNode.class) + private static native int unsignedRemainder(@ConstantNodeParameter Kind kind, int a, int b); + + @NodeIntrinsic(UnsignedRemNode.class) + private static native long unsignedRemainder(@ConstantNodeParameter Kind kind, long a, long b); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + @Input private ValueNode value; + + public BitCountNode(ValueNode value) { + super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + this.value = value; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (value.isConstant()) { + long v = value.asConstant().asLong(); + if (value.kind().getStackKind() == Kind.Int) { + return ConstantNode.forInt(Integer.bitCount((int) v), graph()); + } else if (value.kind() == Kind.Long) { + return ConstantNode.forInt(Long.bitCount(v), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native int bitCount(int v); + + @NodeIntrinsic + public static native int bitCount(long v); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(Kind.Int); + gen.emitBitCount(result, gen.operand(value)); + gen.setResult(this, result); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + @Input private ValueNode value; + + public BitScanForwardNode(ValueNode value) { + super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + this.value = value; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (value.isConstant()) { + long v = value.asConstant().asLong(); + if (value.kind().getStackKind() == Kind.Int) { + return ConstantNode.forInt(Integer.numberOfTrailingZeros((int) v), graph()); + } else if (value.kind() == Kind.Long) { + return ConstantNode.forInt(Long.numberOfTrailingZeros(v), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native int scan(long v); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(Kind.Int); + gen.emitBitScanForward(result, gen.operand(value)); + gen.setResult(this, result); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + @Input private ValueNode value; + + public BitScanReverseNode(ValueNode value) { + super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); + this.value = value; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (value.isConstant()) { + long v = value.asConstant().asLong(); + if (value.kind().getStackKind() == Kind.Int) { + return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros((int) v), graph()); + } else if (value.kind() == Kind.Long) { + return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(v), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native int scan(int v); + + @NodeIntrinsic + public static native int scan(long v); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(Kind.Int); + gen.emitBitScanReverse(result, gen.operand(value)); + gen.setResult(this, result); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BranchProbabilityNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 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.nodes; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +/** + * Instances of this node class will look for a preceding if node and put the given probability into + * the if node's taken probability. Then the branch probability node will be removed. This node is + * intended primarily for snippets, so that they can define their fast and slow paths. + */ +public class BranchProbabilityNode extends FixedWithNextNode implements Simplifiable { + + public static final double LIKELY_PROBABILITY = 0.6; + public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY; + + public static final double FREQUENT_PROBABILITY = 0.9; + public static final double NOT_FREQUENT_PROBABILITY = 1 - FREQUENT_PROBABILITY; + + public static final double FAST_PATH_PROBABILITY = 0.99; + public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY; + + public static final double NOT_DEOPT_PATH_PROBABILITY = 0.999; + public static final double DEOPT_PATH_PROBABILITY = 1 - NOT_DEOPT_PATH_PROBABILITY; + + private final double probability; + + public BranchProbabilityNode(double probability) { + super(StampFactory.forVoid()); + assert probability >= 0 && probability <= 1; + this.probability = probability; + } + + @Override + public void simplify(SimplifierTool tool) { + FixedNode current = this; + while (!(current instanceof BeginNode)) { + current = (FixedNode) current.predecessor(); + } + BeginNode begin = (BeginNode) current; + assert begin.predecessor() instanceof IfNode : "explicit branch probability cannot follow a merge, only if nodes"; + IfNode ifNode = (IfNode) begin.predecessor(); + if (ifNode.trueSuccessor() == begin) { + ifNode.setTrueSuccessorProbability(probability); + } else { + ifNode.setTrueSuccessorProbability(1 - probability); + } + + FixedNode next = next(); + setNext(null); + ((FixedWithNextNode) predecessor()).setNext(next); + GraphUtil.killCFG(this); + } + + @NodeIntrinsic + public static native void probability(@ConstantNodeParameter double probability); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,69 @@ +/* + * 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.replacements.nodes; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.word.*; + +/** + * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a + * {@link StateSplit} and does not include a write barrier. + */ +public class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode object; + @Input private ValueNode value; + @Input private ValueNode offset; + private final int displacement; + + public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value) { + super(StampFactory.forVoid()); + this.object = object; + this.value = value; + this.offset = offset; + this.displacement = displacement; + } + + @NodeIntrinsic + public static native void storeObject(Object obj, @ConstantNodeParameter int displacement, long offset, Object value); + + @NodeIntrinsic + public static native void storeLong(Object obj, @ConstantNodeParameter int displacement, long offset, long value); + + @NodeIntrinsic + public static native void storeWord(Object obj, @ConstantNodeParameter int displacement, long offset, Word value); + + @NodeIntrinsic + public static native void storeInt(Object obj, @ConstantNodeParameter int displacement, long offset, int value); + + @Override + public void lower(LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) this.graph(); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1); + WriteNode write = graph.add(new WriteNode(object, value, location)); + graph.replaceFixedWithFixed(this, write); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,53 @@ +/* + * 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.replacements.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a + * {@link StateSplit} and takes a computed address instead of an object. + */ +public class DirectReadNode extends FixedWithNextNode implements LIRLowerable { + + @Input private ValueNode address; + private final Kind readKind; + + public DirectReadNode(ValueNode address, Kind readKind) { + super(StampFactory.forKind(readKind)); + this.address = address; + this.readKind = readKind; + } + + @Override + public void generate(LIRGeneratorTool gen) { + gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, false)); + } + + @NodeIntrinsic + public static native <T> T read(long address, @ConstantNodeParameter Kind kind); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,83 @@ +/* + * 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.replacements.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a + * {@link StateSplit} and takes a computed address instead of an object. + */ +public class DirectStoreNode extends FixedWithNextNode implements LIRLowerable { + + @Input private ValueNode address; + @Input private ValueNode value; + private final Kind kind; + + public DirectStoreNode(ValueNode address, ValueNode value, Kind kind) { + super(StampFactory.forVoid()); + this.address = address; + this.value = value; + this.kind = kind; + } + + @Override + public void generate(LIRGeneratorTool gen) { + Value v = gen.operand(value); + gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, false); + } + + /* + * The kind of the store is provided explicitly in these intrinsics because it is not always + * possible to determine the kind from the given value during compilation (because stack kinds + * are used). + */ + + @NodeIntrinsic + public static native void store(long address, boolean value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, byte value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, short value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, char value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, int value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, long value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, float value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native void store(long address, double value, @ConstantNodeParameter Kind kind); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,66 @@ +/* + * 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.replacements.nodes; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Placeholder node to denote to snippet preparation that the following loop must be completely + * unrolled. + * + * @see VarargsParameter + */ +public final class ExplodeLoopNode extends FixedWithNextNode { + + public ExplodeLoopNode() { + super(StampFactory.forVoid()); + } + + public LoopBeginNode findLoopBegin() { + Node next = next(); + ArrayList<Node> succs = new ArrayList<>(); + while (!(next instanceof LoopBeginNode)) { + assert next != null : "cannot find loop after " + this; + for (Node n : next.cfgSuccessors()) { + succs.add(n); + } + if (succs.size() == 1) { + next = succs.get(0); + } else { + return null; + } + } + return (LoopBeginNode) next; + } + + /** + * A call to this method must be placed immediately prior to the loop that is to be exploded. + */ + @NodeIntrinsic + public static native void explodeLoop(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.nodes; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.Snippet.*; + +/** + * Implements the semantics of {@link VarargsParameter}. + */ +public final class LoadSnippetVarargParameterNode extends FixedWithNextNode implements Canonicalizable { + + @Input private ValueNode index; + + private final LocalNode[] locals; + + public LoadSnippetVarargParameterNode(LocalNode[] locals, ValueNode index, Stamp stamp) { + super(stamp); + this.index = index; + this.locals = locals; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (index.isConstant()) { + return locals[index.asConstant().asInt()]; + } + return this; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,88 @@ +/* + * 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.nodes; + +import java.lang.reflect.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.common.*; + +public class MacroNode extends AbstractStateSplit implements Lowerable { + + @Input protected final NodeInputList<ValueNode> arguments; + + private final int bci; + private final ResolvedJavaMethod targetMethod; + private final JavaType returnType; + + protected MacroNode(Invoke invoke) { + super(invoke.node().stamp(), invoke.stateAfter()); + this.arguments = new NodeInputList<>(this, invoke.methodCallTarget().arguments()); + this.bci = invoke.bci(); + this.targetMethod = invoke.methodCallTarget().targetMethod(); + this.returnType = invoke.methodCallTarget().returnType(); + } + + public int getBci() { + return bci; + } + + public ResolvedJavaMethod getTargetMethod() { + return targetMethod; + } + + @SuppressWarnings("unused") + protected StructuredGraph getSnippetGraph(LoweringTool tool) { + return null; + } + + @Override + public void lower(LoweringTool tool) { + StructuredGraph snippetGraph = getSnippetGraph(tool); + + InvokeNode invoke = replaceWithInvoke(); + + if (snippetGraph != null) { + InliningUtil.inline(invoke, snippetGraph, false); + } + } + + private InvokeNode replaceWithInvoke() { + InvokeNode invoke = createInvoke(); + ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); + return invoke; + } + + protected InvokeNode createInvoke() { + InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special; + MethodCallTargetNode callTarget = graph().add(new MethodCallTargetNode(invokeKind, targetMethod, arguments.toArray(new ValueNode[arguments.size()]), returnType)); + InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci)); + invoke.setStateAfter(stateAfter()); + return invoke; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,117 @@ +/* + * 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.replacements.nodes; + +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.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class MathIntrinsicNode extends FloatingNode implements Canonicalizable, LIRGenLowerable { + + @Input private ValueNode x; + private final Operation operation; + + public enum Operation { + ABS, SQRT, LOG, LOG10, SIN, COS, TAN + } + + public ValueNode x() { + return x; + } + + public Operation operation() { + return operation; + } + + public MathIntrinsicNode(ValueNode x, Operation op) { + super(StampFactory.forKind(x.kind())); + assert x.kind() == Kind.Double; + this.x = x; + this.operation = op; + } + + @Override + public void generate(LIRGenerator gen) { + Variable input = gen.load(gen.operand(x())); + Variable result = gen.newVariable(kind()); + switch (operation()) { + case ABS: + gen.emitMathAbs(result, input); + break; + case SQRT: + gen.emitMathSqrt(result, input); + break; + case LOG: + gen.emitMathLog(result, input, false); + break; + case LOG10: + gen.emitMathLog(result, input, true); + break; + case SIN: + gen.emitMathSin(result, input); + break; + case COS: + gen.emitMathCos(result, input); + break; + case TAN: + gen.emitMathTan(result, input); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + gen.setResult(this, result); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (x().isConstant()) { + double value = x().asConstant().asDouble(); + switch (operation()) { + case ABS: + return ConstantNode.forDouble(Math.abs(value), graph()); + case SQRT: + return ConstantNode.forDouble(Math.sqrt(value), graph()); + case LOG: + return ConstantNode.forDouble(Math.log(value), graph()); + case LOG10: + return ConstantNode.forDouble(Math.log10(value), graph()); + case SIN: + return ConstantNode.forDouble(Math.sin(value), graph()); + case COS: + return ConstantNode.forDouble(Math.cos(value), graph()); + case TAN: + return ConstantNode.forDouble(Math.tan(value), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native double compute(double x, @ConstantNodeParameter Operation op); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, 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.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * Access the value of a specific register. + */ +@NodeInfo(nameTemplate = "ReadRegister %{p#register}") +public final class ReadRegisterNode extends FixedWithNextNode implements LIRGenLowerable { + + /** + * The fixed register to access. + */ + private final Register register; + + /** + * When true, subsequent uses of this node use the fixed register; when false, the value is + * moved into a new virtual register so that the fixed register is not seen by uses. + */ + private final boolean directUse; + + /** + * When true, this node is also an implicit definition of the value for the register allocator, + * i.e., the register is an implicit incoming value; when false, the register must be defined in + * the same method or must be an register excluded from register allocation. + */ + private final boolean incoming; + + public ReadRegisterNode(Register register, Kind kind, boolean directUse, boolean incoming) { + super(StampFactory.forKind(kind)); + this.register = register; + this.directUse = directUse; + this.incoming = incoming; + } + + /** + * Constructor to be used by node intrinsics where the stamp is inferred from the intrinsic + * definition. + */ + public ReadRegisterNode(Register register, boolean directUse, boolean incoming) { + super(StampFactory.forNodeIntrinsic()); + this.register = register; + this.directUse = directUse; + this.incoming = incoming; + } + + @Override + public void generate(LIRGenerator generator) { + Value result = register.asValue(kind()); + if (incoming) { + generator.emitIncomingValues(new Value[]{result}); + } + if (!directUse) { + result = generator.emitMove(result); + } + generator.setResult(this, result); + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(Verbosity.Name) + "%" + register; + } else { + return super.toString(verbosity); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.replacements.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { + + @Input private ValueNode value; + + public ReverseBytesNode(ValueNode value) { + super(StampFactory.forKind(value.kind())); + assert kind().getStackKind() == Kind.Int || kind() == Kind.Long; + this.value = value; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (value.isConstant()) { + long v = value.asConstant().asLong(); + if (kind().getStackKind() == Kind.Int) { + return ConstantNode.forInt(Integer.reverseBytes((int) v), graph()); + } else if (kind() == Kind.Long) { + return ConstantNode.forLong(Long.reverseBytes(v), graph()); + } + } + return this; + } + + @NodeIntrinsic + public static native int reverse(int v); + + @NodeIntrinsic + public static native long reverse(long v); + + @Override + public void generate(LIRGenerator gen) { + Variable result = gen.newVariable(value.kind()); + gen.emitByteSwap(result, gen.operand(value)); + gen.setResult(this, result); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java Thu Mar 21 11:09:19 2013 +0100 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, 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.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Changes the value of a specific register. + */ +@NodeInfo(nameTemplate = "WriteRegister %{p#register}") +public final class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable { + + /** + * The fixed register to access. + */ + private final Register register; + + /** + * The new value assigned to the register. + */ + @Input private ValueNode value; + + public WriteRegisterNode(Register register, ValueNode value) { + super(StampFactory.forVoid()); + this.register = register; + this.value = value; + } + + @Override + public void generate(LIRGeneratorTool generator) { + Value val = generator.operand(value); + generator.emitMove(val, register.asValue(val.getKind())); + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(Verbosity.Name) + "%" + register; + } else { + return super.toString(verbosity); + } + } +}
--- a/graal/com.oracle.graal.snippets.amd64/src/com/oracle/graal/snippets/amd64/AMD64ConvertSnippets.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +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.snippets.amd64; - -import static com.oracle.graal.snippets.SnippetTemplate.*; -import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; -import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.calc.ConvertNode.Op; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; -import com.oracle.graal.snippets.SnippetTemplate.Arguments; -import com.oracle.graal.snippets.SnippetTemplate.Key; - -/** - * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match - * the semantics of the JVM specification. - */ -public class AMD64ConvertSnippets implements SnippetsInterface { - - /** - * Converts a float to an int. - * <p> - * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the - * conversion. If the float value is a NaN, infinity or if the result of the conversion is - * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and - * extra tests are required on the float value to return the correct int value. - * - * @param input the float being converted - * @param result the result produced by the CVTTSS2SI instruction - */ - @Snippet - public static int f2i(@Parameter("input") float input, @Parameter("result") int result) { - if (result == Integer.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); - if (Float.isNaN(input)) { - // input is NaN -> return 0 - return 0; - } else if (input > 0.0f) { - // input is > 0 -> return max int - return Integer.MAX_VALUE; - } - } - return result; - } - - /** - * Converts a float to a long. - * <p> - * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the - * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns - * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct - * long value. - * - * @param input the float being converted - * @param result the result produced by the CVTTSS2SI instruction - */ - @Snippet - public static long f2l(@Parameter("input") float input, @Parameter("result") long result) { - if (result == Long.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); - if (Float.isNaN(input)) { - // input is NaN -> return 0 - return 0; - } else if (input > 0.0f) { - // input is > 0 -> return max int - return Long.MAX_VALUE; - } - } - return result; - } - - /** - * Converts a double to an int. - * <p> - * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the - * conversion. If the double value is a NaN, infinity or if the result of the conversion is - * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and - * extra tests are required on the double value to return the correct int value. - * - * @param input the double being converted - * @param result the result produced by the CVTTSS2SI instruction - */ - @Snippet - public static int d2i(@Parameter("input") double input, @Parameter("result") int result) { - if (result == Integer.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); - if (Double.isNaN(input)) { - // input is NaN -> return 0 - return 0; - } else if (input > 0.0d) { - // input is positive -> return maxInt - return Integer.MAX_VALUE; - } - } - return result; - } - - /** - * Converts a double to a long. - * <p> - * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the - * conversion. If the double value is a NaN, infinity or if the result of the conversion is - * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra - * tests are required on the double value to return the correct long value. - * - * @param input the double being converted - * @param result the result produced by the CVTTSS2SI instruction - */ - @Snippet - public static long d2l(@Parameter("input") double input, @Parameter("result") long result) { - if (result == Long.MIN_VALUE) { - probability(NOT_FREQUENT_PROBABILITY); - if (Double.isNaN(input)) { - // input is NaN -> return 0 - return 0; - } else if (input > 0.0d) { - // input is positive -> return maxInt - return Long.MAX_VALUE; - } - } - return result; - } - - public static class Templates extends AbstractTemplates<AMD64ConvertSnippets> { - - private final ResolvedJavaMethod f2i; - private final ResolvedJavaMethod f2l; - private final ResolvedJavaMethod d2i; - private final ResolvedJavaMethod d2l; - - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, AMD64ConvertSnippets.class); - f2i = snippet("f2i", float.class, int.class); - f2l = snippet("f2l", float.class, long.class); - d2i = snippet("d2i", double.class, int.class); - d2l = snippet("d2l", double.class, long.class); - } - - public void lower(ConvertNode convert, LoweringTool tool) { - if (convert.opcode == Op.F2I) { - lower0(convert, tool, f2i); - } else if (convert.opcode == Op.F2L) { - lower0(convert, tool, f2l); - } else if (convert.opcode == Op.D2I) { - lower0(convert, tool, d2i); - } else if (convert.opcode == Op.D2L) { - lower0(convert, tool, d2l); - } - } - - private void lower0(ConvertNode convert, LoweringTool tool, ResolvedJavaMethod snippet) { - StructuredGraph graph = (StructuredGraph) convert.graph(); - - // Insert a unique placeholder node in place of the Convert node so that the - // Convert node can be used as an input to the snippet. All usage of the - // Convert node are replaced by the placeholder which in turn is replaced by the - // snippet. - - LocalNode replacee = graph.add(new LocalNode(Integer.MAX_VALUE, convert.stamp())); - convert.replaceAtUsages(replacee); - Key key = new Key(snippet); - Arguments arguments = arguments("input", convert.value()).add("result", convert); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, arguments); - template.instantiate(runtime, replacee, DEFAULT_REPLACER, tool, arguments); - } - } -}
--- a/graal/com.oracle.graal.snippets.test/overview.html Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -<!-- - -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. Oracle designates this -particular file as subject to the "Classpath" exception as provided -by Oracle in the LICENSE file that accompanied this code. - -This code is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -version 2 for more details (a copy is included in the LICENSE file that -accompanied this code). - -You should have received a copy of the GNU General Public License version -2 along with this work; if not, write to the Free Software Foundation, -Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - -Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -or visit www.oracle.com if you need additional information or have any -questions. ---> - -</head> -<body> - -Documentation for the <code>com.oracle.graal.snippets.test</code> project. - -</body> -</html>
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/CheckCastTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests the implementation of checkcast, allowing profiling information to be manually specified. - */ -public class CheckCastTest extends TypeCheckTest { - - @Override - protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { - CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); - if (ccn != null) { - CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile)); - graph.replaceFixedWithFixed(ccn, ccnNew); - } - } - - @LongTest - public void test1() { - test("asNumber", profile(), 111); - test("asNumber", profile(Integer.class), 111); - test("asNumber", profile(Long.class, Short.class), 111); - test("asNumberExt", profile(), 111); - test("asNumberExt", profile(Integer.class), 111); - test("asNumberExt", profile(Long.class, Short.class), 111); - } - - @LongTest - public void test2() { - test("asString", profile(), "111"); - test("asString", profile(String.class), "111"); - test("asString", profile(String.class), "111"); - - final String nullString = null; - test("asString", profile(), nullString); - test("asString", profile(String.class), nullString); - test("asString", profile(String.class), nullString); - - test("asStringExt", profile(), "111"); - test("asStringExt", profile(String.class), "111"); - test("asStringExt", profile(String.class), "111"); - } - - @LongTest - public void test3() { - test("asNumber", profile(), "111"); - } - - @LongTest - public void test4() { - test("asString", profile(String.class), 111); - } - - @LongTest - public void test5() { - test("asNumberExt", profile(), "111"); - } - - @LongTest - public void test6() { - test("asStringExt", profile(String.class), 111); - } - - @LongTest - public void test7() { - Throwable throwable = new Exception(); - test("asThrowable", profile(), throwable); - test("asThrowable", profile(Throwable.class), throwable); - test("asThrowable", profile(Exception.class, Error.class), throwable); - } - - @LongTest - public void test8() { - test("arrayStore", new Object[100], "111"); - } - - @LongTest - public void test8_1() { - test("arrayFill", new Object[100], "111"); - } - - public static Number asNumber(Object o) { - return (Number) o; - } - - public static String asString(Object o) { - return (String) o; - } - - public static Throwable asThrowable(Object o) { - return (Throwable) o; - } - - public static ValueNode asValueNode(Object o) { - return (ValueNode) o; - } - - public static Number asNumberExt(Object o) { - Number n = (Number) o; - return n.intValue() + 10; - } - - public static String asStringExt(Object o) { - String s = (String) o; - return "#" + s; - } - - public static Object[] arrayStore(Object[] arr, Object value) { - arr[15] = value; - return arr; - } - - public static Object[] arrayFill(Object[] arr, Object value) { - for (int i = 0; i < arr.length; i++) { - arr[i] = value; - } - return arr; - } - - static class Depth1 implements Cloneable { - } - - static class Depth2 extends Depth1 { - } - - static class Depth3 extends Depth2 { - } - - static class Depth4 extends Depth3 { - } - - static class Depth5 extends Depth4 { - } - - static class Depth6 extends Depth5 { - } - - static class Depth7 extends Depth6 { - } - - static class Depth8 extends Depth7 { - } - - static class Depth9 extends Depth8 { - } - - static class Depth10 extends Depth9 { - } - - static class Depth11 extends Depth10 { - } - - static class Depth12 extends Depth11 { - } - - static class Depth13 extends Depth12 { - } - - static class Depth14 extends Depth12 { - } - - public static Depth12 asDepth12(Object o) { - return (Depth12) o; - } - - public static Depth12[][] asDepth12Arr(Object o) { - return (Depth12[][]) o; - } - - public static Cloneable asCloneable(Object o) { - return (Cloneable) o; - } - - @LongTest - public void test9() { - Object o = new Depth13(); - test("asDepth12", profile(), o); - test("asDepth12", profile(Depth13.class), o); - test("asDepth12", profile(Depth13.class, Depth14.class), o); - } - - @LongTest - public void test10() { - Object o = new Depth13[3][]; - test("asDepth12Arr", o); - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.test.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests for {@link InstanceOfDynamicNode}. - */ -public class InstanceOfDynamicTest extends GraalCompilerTest { - - public static int id(int value) { - return value; - } - - @LongTest - public void test100() { - final Object nul = null; - test("isStringDynamic", nul); - test("isStringDynamic", "object"); - test("isStringDynamic", Object.class); - } - - @LongTest - public void test101() { - final Object nul = null; - test("isStringIntDynamic", nul); - test("isStringIntDynamic", "object"); - test("isStringIntDynamic", Object.class); - } - - @LongTest - public void test103() { - test("isInstanceDynamic", String.class, null); - test("isInstanceDynamic", String.class, "object"); - test("isInstanceDynamic", String.class, Object.class); - test("isInstanceDynamic", int.class, null); - test("isInstanceDynamic", int.class, "Object"); - test("isInstanceDynamic", int.class, Object.class); - } - - @LongTest - public void test104() { - test("isInstanceIntDynamic", String.class, null); - test("isInstanceIntDynamic", String.class, "object"); - test("isInstanceIntDynamic", String.class, Object.class); - test("isInstanceIntDynamic", int.class, null); - test("isInstanceIntDynamic", int.class, "Object"); - test("isInstanceIntDynamic", int.class, Object.class); - } - - public static boolean isStringDynamic(Object o) { - return String.class.isInstance(o); - } - - public static int isStringIntDynamic(Object o) { - if (String.class.isInstance(o)) { - return o.toString().length(); - } - return o.getClass().getName().length(); - } - - public static boolean isInstanceDynamic(Class c, Object o) { - return c.isInstance(o); - } - - public static int isInstanceIntDynamic(Class c, Object o) { - if (c.isInstance(o)) { - return o.toString().length(); - } - return o.getClass().getName().length(); - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,400 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.util.*; - - -import com.oracle.graal.api.code.CompilationResult.Call; -import com.oracle.graal.api.code.CompilationResult.Mark; -import com.oracle.graal.api.code.CompilationResult.Site; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.snippets.CheckCastTest.Depth12; -import com.oracle.graal.snippets.CheckCastTest.Depth13; -import com.oracle.graal.snippets.CheckCastTest.Depth14; - -/** - * Tests the implementation of instanceof, allowing profiling information to be manually specified. - */ -public class InstanceOfTest extends TypeCheckTest { - - @Override - protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { - phasePlan.disablePhase(InliningPhase.class); - } - - @Override - protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { - InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); - if (ion != null) { - InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.type(), ion.object(), profile)); - graph.replaceFloating(ion, ionNew); - } - } - - @LongTest - public void test1() { - test("isString", profile(), "object"); - test("isString", profile(String.class), "object"); - - test("isString", profile(), Object.class); - test("isString", profile(String.class), Object.class); - } - - @LongTest - public void test2() { - test("isStringInt", profile(), "object"); - test("isStringInt", profile(String.class), "object"); - - test("isStringInt", profile(), Object.class); - test("isStringInt", profile(String.class), Object.class); - } - - @LongTest - public void test2_1() { - test("isStringIntComplex", profile(), "object"); - test("isStringIntComplex", profile(String.class), "object"); - - test("isStringIntComplex", profile(), Object.class); - test("isStringIntComplex", profile(String.class), Object.class); - } - - @LongTest - public void test3() { - Throwable throwable = new Exception(); - test("isThrowable", profile(), throwable); - test("isThrowable", profile(Throwable.class), throwable); - test("isThrowable", profile(Exception.class, Error.class), throwable); - - test("isThrowable", profile(), Object.class); - test("isThrowable", profile(Throwable.class), Object.class); - test("isThrowable", profile(Exception.class, Error.class), Object.class); - } - - @LongTest - public void test3_1() { - onlyFirstIsException(new Exception(), new Error()); - test("onlyFirstIsException", profile(), new Exception(), new Error()); - test("onlyFirstIsException", profile(), new Error(), new Exception()); - test("onlyFirstIsException", profile(), new Exception(), new Exception()); - test("onlyFirstIsException", profile(), new Error(), new Error()); - } - - @LongTest - public void test4() { - Throwable throwable = new Exception(); - test("isThrowableInt", profile(), throwable); - test("isThrowableInt", profile(Throwable.class), throwable); - test("isThrowableInt", profile(Exception.class, Error.class), throwable); - - test("isThrowableInt", profile(), Object.class); - test("isThrowableInt", profile(Throwable.class), Object.class); - test("isThrowableInt", profile(Exception.class, Error.class), Object.class); - } - - @LongTest - public void test5() { - Map map = new HashMap<>(); - test("isMap", profile(), map); - test("isMap", profile(HashMap.class), map); - test("isMap", profile(TreeMap.class, HashMap.class), map); - - test("isMap", profile(), Object.class); - test("isMap", profile(HashMap.class), Object.class); - test("isMap", profile(TreeMap.class, HashMap.class), Object.class); - } - - @LongTest - public void test6() { - Map map = new HashMap<>(); - test("isMapInt", profile(), map); - test("isMapInt", profile(HashMap.class), map); - test("isMapInt", profile(TreeMap.class, HashMap.class), map); - - test("isMapInt", profile(), Object.class); - test("isMapInt", profile(HashMap.class), Object.class); - test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); - } - - @LongTest - public void test7() { - Object o = new Depth13(); - test("isDepth12", profile(), o); - test("isDepth12", profile(Depth13.class), o); - test("isDepth12", profile(Depth13.class, Depth14.class), o); - - o = "not a depth"; - test("isDepth12", profile(), o); - test("isDepth12", profile(Depth13.class), o); - test("isDepth12", profile(Depth13.class, Depth14.class), o); - } - - @LongTest - public void test8() { - Object o = new Depth13(); - test("isDepth12Int", profile(), o); - test("isDepth12Int", profile(Depth13.class), o); - test("isDepth12Int", profile(Depth13.class, Depth14.class), o); - - o = "not a depth"; - test("isDepth12Int", profile(), o); - test("isDepth12Int", profile(Depth13.class), o); - test("isDepth12Int", profile(Depth13.class, Depth14.class), o); - } - - public static boolean isString(Object o) { - return o instanceof String; - } - - public static int isStringInt(Object o) { - if (o instanceof String) { - return id(1); - } - return id(0); - } - - public static int isStringIntComplex(Object o) { - if (o instanceof String || o instanceof Integer) { - return id(o instanceof String ? 1 : 0); - } - return id(0); - } - - public static int id(int value) { - return value; - } - - public static boolean isThrowable(Object o) { - return ((Throwable) o) instanceof Exception; - } - - public static int onlyFirstIsException(Throwable t1, Throwable t2) { - if (t1 instanceof Exception ^ t2 instanceof Exception) { - return t1 instanceof Exception ? 1 : -1; - } - return -1; - } - - public static int isThrowableInt(Object o) { - int result = o instanceof Throwable ? 4 : 5; - if (o instanceof Throwable) { - return id(4); - } - return result; - } - - public static boolean isMap(Object o) { - return o instanceof Map; - } - - public static int isMapInt(Object o) { - if (o instanceof Map) { - return id(1); - } - return id(0); - } - - public static boolean isDepth12(Object o) { - return o instanceof Depth12; - } - - public static int isDepth12Int(Object o) { - if (o instanceof Depth12) { - return id(0); - } - return id(0); - } - - abstract static class MySite { - - final int offset; - - MySite(int offset) { - this.offset = offset; - } - } - - static class MyMark extends MySite { - - MyMark(int offset) { - super(offset); - } - } - - abstract static class MySafepoint extends MySite { - - MySafepoint(int offset) { - super(offset); - } - } - - static class MyCall extends MySafepoint { - - MyCall(int offset) { - super(offset); - } - } - - @LongTest - public void test9() { - MyCall callAt63 = new MyCall(63); - MyMark markAt63 = new MyMark(63); - test("compareMySites", callAt63, callAt63); - test("compareMySites", callAt63, markAt63); - test("compareMySites", markAt63, callAt63); - test("compareMySites", markAt63, markAt63); - } - - public static int compareMySites(MySite s1, MySite s2) { - if (s1.offset == s2.offset && (s1 instanceof MyMark ^ s2 instanceof MyMark)) { - return s1 instanceof MyMark ? -1 : 1; - } - return s1.offset - s2.offset; - } - - @LongTest - public void test10() { - Mark[] noMarks = {}; - Call callAt63 = new Call(null, 63, 5, true, null); - Mark markAt63 = new Mark(63, "1", noMarks); - test("compareSites", callAt63, callAt63); - test("compareSites", callAt63, markAt63); - test("compareSites", markAt63, callAt63); - test("compareSites", markAt63, markAt63); - } - - public static int compareSites(Site s1, Site s2) { - if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { - return s1 instanceof Mark ? -1 : 1; - } - return s1.pcOffset - s2.pcOffset; - } - - /** - * This test exists to show the kind of pattern that is be optimizable by - * {@code removeIntermediateMaterialization()} in {@link IfNode}. - * <p> - * The test exists in this source file as the transformation was originally motivated by the - * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}. - */ - @LongTest - public void test_removeIntermediateMaterialization() { - List<String> list = Arrays.asList("1", "2", "3", "4"); - test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); - test("removeIntermediateMaterialization", profile(), list, null, "yes", "no"); - test("removeIntermediateMaterialization", profile(), null, "2", "yes", "no"); - } - - public static String removeIntermediateMaterialization(List<Object> list, Object e, String a, String b) { - boolean test; - if (list == null || e == null) { - test = false; - } else { - test = false; - for (Object i : list) { - if (i.equals(e)) { - test = true; - break; - } - } - } - if (test) { - return a; - } - return b; - } - - abstract static class A { - } - - static class B extends A { - } - - static class C extends B { - } - - abstract static class D extends C { - } - - public static boolean isArrayOfA(Object o) { - return o instanceof A[]; - } - - public static boolean isArrayOfB(Object o) { - return o instanceof B[]; - } - - public static boolean isArrayOfC(Object o) { - return o instanceof C[]; - } - - public static boolean isArrayOfD(Object o) { - return o instanceof D[]; - } - - @LongTest - public void testArray() { - Object aArray = new A[10]; - test("isArrayOfA", aArray); - - Object bArray = new B[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - - Object cArray = new C[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfA", cArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - test("isArrayOfB", cArray); - test("isArrayOfC", aArray); - test("isArrayOfC", bArray); - test("isArrayOfC", cArray); - - Object dArray = new D[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfA", cArray); - test("isArrayOfA", dArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - test("isArrayOfB", cArray); - test("isArrayOfB", dArray); - test("isArrayOfC", aArray); - test("isArrayOfC", bArray); - test("isArrayOfC", cArray); - test("isArrayOfC", dArray); - test("isArrayOfD", aArray); - test("isArrayOfD", bArray); - test("isArrayOfD", cArray); - test("isArrayOfD", dArray); - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,461 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import static org.junit.Assert.*; - -import java.util.concurrent.*; - -import org.junit.*; - -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.snippets.nodes.*; - -/** - * Tests if compiler intrinsics are inlined correctly. Most test cases only assert that there are no - * remaining invocations in the graph. This is sufficient if the method that is being intrinsified - * is a native method. For Java methods, additional checks are necessary. - */ -public class IntrinsificationTest extends GraalCompilerTest { - - @Test - public void testObjectIntrinsics() { - test("getClassSnippet"); - test("objectHashCodeSnippet"); - } - - @SuppressWarnings("all") - public static boolean getClassSnippet(Object obj, Class<?> clazz) { - return obj.getClass() == clazz; - } - - @SuppressWarnings("all") - public static int objectHashCodeSnippet(TestClassA obj) { - return obj.hashCode(); - } - - @Test - public void testClassIntrinsics() { - test("getModifiersSnippet"); - test("isInstanceSnippet"); - test("isInterfaceSnippet"); - test("isArraySnippet"); - test("isPrimitiveSnippet"); - test("getSuperClassSnippet"); - test("getComponentTypeSnippet"); - } - - @SuppressWarnings("all") - public static int getModifiersSnippet(Class<?> clazz) { - return clazz.getModifiers(); - } - - @SuppressWarnings("all") - public static boolean isInstanceSnippet(Class<?> clazz) { - return clazz.isInstance(Number.class); - } - - @SuppressWarnings("all") - public static boolean isInterfaceSnippet(Class<?> clazz) { - return clazz.isInterface(); - } - - @SuppressWarnings("all") - public static boolean isArraySnippet(Class<?> clazz) { - return clazz.isArray(); - } - - @SuppressWarnings("all") - public static boolean isPrimitiveSnippet(Class<?> clazz) { - return clazz.isPrimitive(); - } - - @SuppressWarnings("all") - public static Class<?> getSuperClassSnippet(Class<?> clazz) { - return clazz.getSuperclass(); - } - - @SuppressWarnings("all") - public static Class<?> getComponentTypeSnippet(Class<?> clazz) { - return clazz.getComponentType(); - } - - @Test - public void testThreadIntrinsics() { - test("currentThreadSnippet"); - test("threadIsInterruptedSnippet"); - test("threadInterruptedSnippet"); - } - - @SuppressWarnings("all") - public static Thread currentThreadSnippet() { - return Thread.currentThread(); - } - - @SuppressWarnings("all") - public static boolean threadIsInterruptedSnippet(Thread thread) { - return thread.isInterrupted(); - } - - @SuppressWarnings("all") - public static boolean threadInterruptedSnippet() { - return Thread.interrupted(); - } - - @Test - public void testSystemIntrinsics() { - test("systemTimeSnippet"); - test("systemIdentityHashCode"); - } - - @SuppressWarnings("all") - public static long systemTimeSnippet() { - return System.currentTimeMillis() + System.nanoTime(); - } - - @SuppressWarnings("all") - public static int systemIdentityHashCode(Object obj) { - return System.identityHashCode(obj); - } - - @Test - public void testUnsafeIntrinsics() { - test("unsafeCompareAndSwapIntSnippet"); - test("unsafeCompareAndSwapLongSnippet"); - test("unsafeCompareAndSwapObjectSnippet"); - - test("unsafeGetBooleanSnippet"); - test("unsafeGetByteSnippet"); - test("unsafeGetShortSnippet"); - test("unsafeGetCharSnippet"); - test("unsafeGetIntSnippet"); - test("unsafeGetFloatSnippet"); - test("unsafeGetDoubleSnippet"); - test("unsafeGetObjectSnippet"); - - test("unsafePutBooleanSnippet"); - test("unsafePutByteSnippet"); - test("unsafePutShortSnippet"); - test("unsafePutCharSnippet"); - test("unsafePutIntSnippet"); - test("unsafePutFloatSnippet"); - test("unsafePutDoubleSnippet"); - test("unsafePutObjectSnippet"); - - test("unsafeDirectMemoryReadSnippet"); - test("unsafeDirectMemoryWriteSnippet"); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapIntSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapInt(obj, offset, 0, 1); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapLongSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapLong(obj, offset, 0, 1); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapObjectSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapObject(obj, offset, null, new Object()); - } - - @SuppressWarnings("all") - public static boolean unsafeGetBooleanSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetByteSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetShortSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetCharSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetIntSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static long unsafeGetLongSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static float unsafeGetFloatSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static double unsafeGetDoubleSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static boolean unsafeGetObjectSnippet(Unsafe unsafe, Object obj, long offset) { - return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static void unsafePutBooleanSnippet(Unsafe unsafe, Object obj, long offset, boolean value) { - unsafe.putBoolean(obj, offset, value); - unsafe.putBooleanVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutByteSnippet(Unsafe unsafe, Object obj, long offset, byte value) { - unsafe.putByte(obj, offset, value); - unsafe.putByteVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutShortSnippet(Unsafe unsafe, Object obj, long offset, short value) { - unsafe.putShort(obj, offset, value); - unsafe.putShortVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutCharSnippet(Unsafe unsafe, Object obj, long offset, char value) { - unsafe.putChar(obj, offset, value); - unsafe.putCharVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutIntSnippet(Unsafe unsafe, Object obj, long offset, int value) { - unsafe.putInt(obj, offset, value); - unsafe.putIntVolatile(obj, offset, value); - unsafe.putOrderedInt(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutLongSnippet(Unsafe unsafe, Object obj, long offset, long value) { - unsafe.putLong(obj, offset, value); - unsafe.putLongVolatile(obj, offset, value); - unsafe.putOrderedLong(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutFloatSnippet(Unsafe unsafe, Object obj, long offset, float value) { - unsafe.putFloat(obj, offset, value); - unsafe.putFloatVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutDoubleSnippet(Unsafe unsafe, Object obj, long offset, double value) { - unsafe.putDouble(obj, offset, value); - unsafe.putDoubleVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutObjectSnippet(Unsafe unsafe, Object obj, long offset, Object value) { - unsafe.putObject(obj, offset, value); - unsafe.putObjectVolatile(obj, offset, value); - unsafe.putOrderedObject(obj, offset, value); - } - - @SuppressWarnings("all") - public static double unsafeDirectMemoryReadSnippet(Unsafe unsafe, long address) { - // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist - return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address); - } - - @SuppressWarnings("all") - public static void unsafeDirectMemoryWriteSnippet(Unsafe unsafe, long address, byte value) { - // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist - unsafe.putByte(address, value); - unsafe.putShort(address, value); - unsafe.putChar(address, (char) value); - unsafe.putInt(address, value); - unsafe.putLong(address, value); - unsafe.putFloat(address, value); - unsafe.putDouble(address, value); - } - - @Test - public void testMathIntrinsics() { - assertInGraph(assertNotInGraph(test("mathAbsSnippet"), IfNode.class), MathIntrinsicNode.class); // Java - test("mathSnippet"); - } - - @SuppressWarnings("all") - public static double mathAbsSnippet(double value) { - return Math.abs(value); - } - - @SuppressWarnings("all") - public static double mathSnippet(double value) { - return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); - // Math.exp(value) + - // Math.pow(value, 13); - } - - @Test - public void testIntegerIntrinsics() { - assertInGraph(test("integerReverseBytesSnippet"), ReverseBytesNode.class); // Java - assertInGraph(test("integerNumberOfLeadingZerosSnippet"), BitScanReverseNode.class); // Java - assertInGraph(test("integerNumberOfTrailingZerosSnippet"), BitScanForwardNode.class); // Java - assertInGraph(test("integerBitCountSnippet"), BitCountNode.class); // Java - } - - @SuppressWarnings("all") - public static int integerReverseBytesSnippet(int value) { - return Integer.reverseBytes(value); - } - - @SuppressWarnings("all") - public static int integerNumberOfLeadingZerosSnippet(int value) { - return Integer.numberOfLeadingZeros(value); - } - - @SuppressWarnings("all") - public static int integerNumberOfTrailingZerosSnippet(int value) { - return Integer.numberOfTrailingZeros(value); - } - - @SuppressWarnings("all") - public static int integerBitCountSnippet(int value) { - return Integer.bitCount(value); - } - - @Test - public void testLongIntrinsics() { - assertInGraph(test("longReverseBytesSnippet"), ReverseBytesNode.class); // Java - assertInGraph(test("longNumberOfLeadingZerosSnippet"), BitScanReverseNode.class); // Java - assertInGraph(test("longNumberOfTrailingZerosSnippet"), BitScanForwardNode.class); // Java - assertInGraph(test("longBitCountSnippet"), BitCountNode.class); // Java - } - - @SuppressWarnings("all") - public static long longReverseBytesSnippet(long value) { - return Long.reverseBytes(value); - } - - @SuppressWarnings("all") - public static long longNumberOfLeadingZerosSnippet(long value) { - return Long.numberOfLeadingZeros(value); - } - - @SuppressWarnings("all") - public static long longNumberOfTrailingZerosSnippet(long value) { - return Long.numberOfTrailingZeros(value); - } - - @SuppressWarnings("all") - public static int longBitCountSnippet(long value) { - return Long.bitCount(value); - } - - @Test - public void testFloatIntrinsics() { - assertInGraph(test("floatToIntBitsSnippet"), ConvertNode.class); // Java - test("intBitsToFloatSnippet"); - } - - @SuppressWarnings("all") - public static int floatToIntBitsSnippet(float value) { - return Float.floatToIntBits(value); - } - - @SuppressWarnings("all") - public static float intBitsToFloatSnippet(int value) { - return Float.intBitsToFloat(value); - } - - @Test - public void testDoubleIntrinsics() { - assertInGraph(test("doubleToLongBitsSnippet"), ConvertNode.class); // Java - test("longBitsToDoubleSnippet"); - } - - @SuppressWarnings("all") - public static long doubleToLongBitsSnippet(double value) { - return Double.doubleToLongBits(value); - } - - @SuppressWarnings("all") - public static double longBitsToDoubleSnippet(long value) { - return Double.longBitsToDouble(value); - } - - private StructuredGraph test(final String snippet) { - return Debug.scope("IntrinsificationTest", runtime.lookupJavaMethod(getMethod(snippet)), new Callable<StructuredGraph>() { - - @Override - public StructuredGraph call() { - StructuredGraph graph = parse(snippet); - PhasePlan phasePlan = getDefaultPhasePlan(); - Assumptions assumptions = new Assumptions(true); - new ComputeProbabilityPhase().apply(graph); - Debug.dump(graph, "Graph"); - new InliningPhase(runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); - Debug.dump(graph, "Graph"); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - - assertNotInGraph(graph, Invoke.class); - return graph; - } - }); - } - - private static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) { - for (Node node : graph.getNodes()) { - if (clazz.isInstance(node)) { - fail(node.toString()); - } - } - return graph; - } - - private static StructuredGraph assertInGraph(StructuredGraph graph, Class<?> clazz) { - for (Node node : graph.getNodes()) { - if (clazz.isInstance(node)) { - return graph; - } - } - fail("Graph does not contain a node of class " + clazz.getName()); - return graph; - } - - private static class TestClassA { - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InvokeTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import org.junit.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; - -/** - * Tests the implementation of the snippets for lowering the INVOKE* instructions. - */ -public class InvokeTest extends GraalCompilerTest { - - @Override - protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { - phasePlan.disablePhase(InliningPhase.class); - } - - public interface I { - - String virtualMethod(String s); - } - - public static class A implements I { - - final String name = "A"; - - public String virtualMethod(String s) { - return name + s; - } - } - - @SuppressWarnings("static-method") - private String privateMethod(String s) { - return s; - } - - @Test - public void test1() { - test("invokestatic", "a string"); - test("invokespecialConstructor", "a string"); - test("invokespecial", this, "a string"); - test("invokevirtual", new A(), "a string"); - test("invokevirtual2", new A(), "a string"); - test("invokeinterface", new A(), "a string"); - Object[] args = {null}; - test("invokestatic", args); - test("invokespecialConstructor", args); - test("invokespecial", null, null); - test("invokevirtual", null, null); - test("invokevirtual2", null, null); - test("invokeinterface", null, null); - } - - public static String invokestatic(String s) { - return staticMethod(s); - } - - public static String staticMethod(String s) { - return s; - } - - public static String invokespecialConstructor(String s) { - return new A().virtualMethod(s); - } - - public static String invokespecial(InvokeTest a, String s) { - return a.privateMethod(s); - } - - public static String invokevirtual(A a, String s) { - return a.virtualMethod(s); - } - - public static String invokevirtual2(A a, String s) { - a.virtualMethod(s); - return a.virtualMethod(s); - } - - public static String invokeinterface(I i, String s) { - return i.virtualMethod(s); - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/MonitorTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.virtual.phases.ea.*; - -public class MonitorTest extends GraalCompilerTest { - - @Test - public void test0() { - test("lockObjectSimple", new Object(), new Object()); - test("lockObjectSimple", new Object(), null); - } - - @Test - public void test0_1() { - test("lockThisSimple", "test1", new Object()); - test("lockThisSimple", "test1", null); - } - - @Test - public void test0_2() { - test("lockObjectSimple", null, "test1"); - } - - @Test - public void test1_1() { - test("lockObject", new Object(), "test1", new String[1]); - } - - @Test - public void test1_2() { - test("lockObject", null, "test1_1", new String[1]); - } - - @Test - public void test2() { - test("lockThis", "test2", new String[1]); - } - - /** - * Tests monitor operations on {@link PartialEscapeAnalysisPhase virtual objects}. - */ - @Test - public void test3() { - test("lockLocalObject", "test3", new String[1]); - } - - /** - * Tests recursive locking of objects which should be biasable. - */ - @Test - public void test4() { - Chars src = new Chars("1234567890".toCharArray()); - Chars dst = new Chars(src.data.length); - test("copyObj", src, dst, 100); - } - - /** - * Tests recursive locking of objects which do not appear to be biasable. - */ - @Test - public void test5() { - char[] src = "1234567890".toCharArray(); - char[] dst = new char[src.length]; - test("copyArr", src, dst, 100); - } - - /** - * Extends {@link #test4()} with contention. - */ - @Test - public void test6() { - Chars src = new Chars("1234567890".toCharArray()); - Chars dst = new Chars(src.data.length); - int n = Runtime.getRuntime().availableProcessors(); - testN(n, "copyObj", src, dst, 100); - } - - /** - * Extends {@link #test5()} with contention. - */ - @Test - public void test7() { - char[] src = "1234567890".toCharArray(); - char[] dst = new char[src.length]; - int n = Runtime.getRuntime().availableProcessors(); - testN(n, "copyArr", src, dst, 100); - } - - private static String setAndGet(String[] box, String value) { - synchronized (box) { - box[0] = null; - } - - // Do a GC while a object is locked (by the caller) - System.gc(); - - synchronized (box) { - box[0] = value; - } - return box[0]; - } - - public static Object lockObjectSimple(Object o, Object value) { - synchronized (o) { - value.hashCode(); - return value; - } - } - - public String lockThisSimple(String value, Object o) { - synchronized (this) { - synchronized (value) { - o.hashCode(); - return value; - } - } - } - - public static String lockObject(Object o, String value, String[] box) { - synchronized (o) { - return setAndGet(box, value); - } - } - - public String lockThis(String value, String[] box) { - synchronized (this) { - return setAndGet(box, value); - } - } - - public static String lockLocalObject(String value, String[] box) { - Object o = new Object(); - synchronized (o) { - return setAndGet(box, value); - } - } - - static class Chars { - - final char[] data; - - public Chars(int size) { - this.data = new char[size]; - } - - public Chars(char[] data) { - this.data = data; - } - } - - public static String copyObj(Chars src, Chars dst, int n) { - System.out.println(Thread.currentThread().getName() + " reps=" + n + ", src.length=" + src.data.length); - int total = 0; - for (int j = 0; j < n; j++) { - for (int i = 0; i < src.data.length; i++) { - synchronized (src) { - synchronized (dst) { - synchronized (src) { - synchronized (dst) { - dst.data[i] = src.data[i]; - total++; - } - } - } - } - } - } - System.out.println(Thread.currentThread().getName() + " total " + total); - return new String(dst.data); - } - - public static String copyArr(char[] src, char[] dst, int n) { - System.out.println(Thread.currentThread().getName() + " reps=" + n + ", src.length=" + src.length); - int total = 0; - for (int j = 0; j < n; j++) { - for (int i = 0; i < src.length; i++) { - synchronized (src) { - synchronized (dst) { - synchronized (src) { - synchronized (dst) { - dst[i] = src[i]; - total++; - } - } - } - } - } - } - System.out.println(Thread.currentThread().getName() + " total " + total); - return new String(dst); - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewArrayTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; - -/** - * Tests the implementation of {@code [A]NEWARRAY}. - */ -public class NewArrayTest extends GraalCompilerTest { - - @Override - protected void assertEquals(Object expected, Object actual) { - Assert.assertTrue(expected != null); - Assert.assertTrue(actual != null); - super.assertEquals(expected.getClass(), actual.getClass()); - if (expected instanceof int[]) { - Assert.assertArrayEquals((int[]) expected, (int[]) actual); - } else if (expected instanceof byte[]) { - Assert.assertArrayEquals((byte[]) expected, (byte[]) actual); - } else if (expected instanceof char[]) { - Assert.assertArrayEquals((char[]) expected, (char[]) actual); - } else if (expected instanceof short[]) { - Assert.assertArrayEquals((short[]) expected, (short[]) actual); - } else if (expected instanceof float[]) { - Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f); - } else if (expected instanceof long[]) { - Assert.assertArrayEquals((long[]) expected, (long[]) actual); - } else if (expected instanceof double[]) { - Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d); - } else if (expected instanceof Object[]) { - Assert.assertArrayEquals((Object[]) expected, (Object[]) actual); - } else { - Assert.fail("non-array value encountered: " + expected); - } - } - - @LongTest - public void test1() { - for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) { - test("new" + type + "Array7"); - test("new" + type + "ArrayMinus7"); - test("new" + type + "Array", 7); - test("new" + type + "Array", -7); - test("new" + type + "Array", Integer.MAX_VALUE); - test("new" + type + "Array", Integer.MIN_VALUE); - } - } - - public static Object newCharArray7() { - return new char[7]; - } - - public static Object newCharArrayMinus7() { - return new char[-7]; - } - - public static Object newCharArray(int length) { - return new char[length]; - } - - public static Object newShortArray7() { - return new short[7]; - } - - public static Object newShortArrayMinus7() { - return new short[-7]; - } - - public static Object newShortArray(int length) { - return new short[length]; - } - - public static Object newFloatArray7() { - return new float[7]; - } - - public static Object newFloatArrayMinus7() { - return new float[-7]; - } - - public static Object newFloatArray(int length) { - return new float[length]; - } - - public static Object newLongArray7() { - return new long[7]; - } - - public static Object newLongArrayMinus7() { - return new long[-7]; - } - - public static Object newLongArray(int length) { - return new long[length]; - } - - public static Object newDoubleArray7() { - return new double[7]; - } - - public static Object newDoubleArrayMinus7() { - return new double[-7]; - } - - public static Object newDoubleArray(int length) { - return new double[length]; - } - - public static Object newIntArray7() { - return new int[7]; - } - - public static Object newIntArrayMinus7() { - return new int[-7]; - } - - public static Object newIntArray(int length) { - return new int[length]; - } - - public static Object newByteArray7() { - return new byte[7]; - } - - public static Object newByteArrayMinus7() { - return new byte[-7]; - } - - public static Object newByteArray(int length) { - return new byte[length]; - } - - public static Object newStringArray7() { - return new String[7]; - } - - public static Object newStringArrayMinus7() { - return new String[-7]; - } - - public static Object newStringArray(int length) { - return new String[length]; - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewInstanceTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.util.*; - -import org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; - -/** - * Tests the implementation of {@code NEW}. - */ -public class NewInstanceTest extends GraalCompilerTest { - - @Override - protected void assertEquals(Object expected, Object actual) { - Assert.assertTrue(expected != null); - Assert.assertTrue(actual != null); - super.assertEquals(expected.getClass(), actual.getClass()); - - if (expected instanceof Object[]) { - Assert.assertTrue(actual instanceof Object[]); - Object[] eArr = (Object[]) expected; - Object[] aArr = (Object[]) actual; - Assert.assertTrue(eArr.length == aArr.length); - for (int i = 0; i < eArr.length; i++) { - assertEquals(eArr[i], aArr[i]); - } - } else if (expected.getClass() != Object.class) { - try { - expected.getClass().getDeclaredMethod("equals", Object.class); - super.assertEquals(expected, actual); - } catch (Exception e) { - } - } - } - - @LongTest - public void test1() { - test("newObject"); - } - - @LongTest - public void test2() { - test("newObjectTwice"); - } - - public static Object newObject() { - return new Object(); - } - - @LongTest - public void test3() { - test("newObjectLoop", 100); - } - - @LongTest - public void test4() { - test("newBigObject"); - } - - @LongTest - public void test5() { - test("newSomeObject"); - } - - @LongTest - public void test6() { - test("newEmptyString"); - } - - @LongTest - public void test7() { - test("newString", "value"); - } - - @LongTest - public void test8() { - test("newHashMap", 31); - } - - @LongTest - public void test9() { - test("newRegression", true); - } - - public static Object[] newObjectTwice() { - Object[] res = {new Object(), new Object()}; - return res; - } - - public static Object[] newObjectLoop(int n) { - Object[] res = new Object[n]; - for (int i = 0; i < n; i++) { - res[i] = new Object(); - } - return res; - } - - public static BigObject newBigObject() { - return new BigObject(); - } - - public static SomeObject newSomeObject() { - return new SomeObject(); - } - - public static String newEmptyString() { - return new String(); - } - - public static String newString(String value) { - return new String(value); - } - - public static HashMap newHashMap(int initialCapacity) { - return new HashMap(initialCapacity); - } - - static class SomeObject { - - String name = "o1"; - HashMap<String, Object> map = new HashMap<>(); - - public SomeObject() { - map.put(name, this.getClass()); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof SomeObject) { - SomeObject so = (SomeObject) obj; - return so.name.equals(name) && so.map.equals(map); - } - return false; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - } - - static class BigObject { - - Object f01; - Object f02; - Object f03; - Object f04; - Object f05; - Object f06; - Object f07; - Object f08; - Object f09; - Object f10; - Object f12; - Object f13; - Object f14; - Object f15; - Object f16; - Object f17; - Object f18; - Object f19; - Object f20; - Object f21; - Object f22; - Object f23; - Object f24; - Object f25; - Object f26; - Object f27; - Object f28; - Object f29; - Object f30; - Object f31; - Object f32; - Object f33; - Object f34; - Object f35; - Object f36; - Object f37; - Object f38; - Object f39; - Object f40; - Object f41; - Object f42; - Object f43; - Object f44; - Object f45; - } - - /** - * Tests that an earlier bug does not occur. The issue was that the loading of the TLAB 'top' - * and 'end' values was being GVN'ed from each branch of the 'if' statement. This meant that the - * allocated B object in the true branch overwrote the allocated array. The cause is that - * RegisterNode was a floating node and the reads from it were UnsafeLoads which are also - * floating. The fix was to make RegisterNode a fixed node (which it should have been in the - * first place). - */ - public static Object newRegression(boolean condition) { - Object result; - if (condition) { - Object[] arr = {0, 1, 2, 3, 4, 5}; - result = new B(); - for (int i = 0; i < arr.length; ++i) { - // If the bug exists, the values of arr will now be deadbeef values - // and the virtual dispatch will cause a segfault. This can result in - // either a VM crash or a spurious NullPointerException. - if (arr[i].equals(Integer.valueOf(i))) { - return false; - } - } - } else { - result = new B(); - } - return result; - } - - static class B { - - long f1 = 0xdeadbeefdeadbe01L; - long f2 = 0xdeadbeefdeadbe02L; - long f3 = 0xdeadbeefdeadbe03L; - long f4 = 0xdeadbeefdeadbe04L; - long f5 = 0xdeadbeefdeadbe05L; - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests the lowering of the MULTIANEWARRAY instruction. - */ -public class NewMultiArrayTest extends GraalCompilerTest { - - private static int rank(ResolvedJavaType type) { - String name = type.getName(); - int dims = 0; - while (dims < name.length() && name.charAt(dims) == '[') { - dims++; - } - return dims; - } - - @Override - protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { - boolean forceCompile = false; - if (bottomType != null) { - List<NewMultiArrayNode> snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot(); - assert snapshot != null; - assert snapshot.size() == 1; - - NewMultiArrayNode node = snapshot.get(0); - assert rank(arrayType) == dimensions.length; - int rank = dimensions.length; - ValueNode[] dimensionNodes = new ValueNode[rank]; - for (int i = 0; i < rank; i++) { - dimensionNodes[i] = graph.unique(ConstantNode.forInt(dimensions[i], graph)); - } - - NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes)); - graph.replaceFixedWithFixed(node, repl); - forceCompile = true; - } - return super.getCode(method, graph, forceCompile); - } - - @Override - protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - if (bottomType != null) { - try { - return Array.newInstance(bottomClass, dimensions); - } catch (Exception e) { - throw new InvocationTargetException(e); - } - } - return super.referenceInvoke(method, receiver, args); - } - - ResolvedJavaType arrayType; - ResolvedJavaType bottomType; - Class bottomClass; - int[] dimensions; - - @LongTest - public void test1() { - for (Class clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) { - bottomClass = clazz; - bottomType = runtime.lookupJavaType(clazz); - arrayType = bottomType; - for (int rank : new int[]{1, 2, 10, 50, 100, 200, 254, 255}) { - while (rank(arrayType) != rank) { - arrayType = arrayType.getArrayClass(); - } - - dimensions = new int[rank]; - for (int i = 0; i < rank; i++) { - dimensions[i] = 1; - } - - test("newMultiArray"); - } - } - bottomType = null; - arrayType = null; - } - - public static Object newMultiArray() { - // This is merely a template - the NewMultiArrayNode is replaced in getCode() above. - // This also means we need a separate test for correct handling of negative dimensions - // as deoptimization won't do what we want for a graph modified to be different from the - // source bytecode. - return new Object[10][9][8]; - } - - @LongTest - public void test2() { - test("newMultiArrayException"); - } - - public static Object newMultiArrayException() { - return new Object[10][9][-8]; - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/PointerTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,399 +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.snippets; - -import java.lang.reflect.*; - -import org.junit.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.snippets.Snippet.SnippetInliningPolicy; -import com.oracle.graal.word.*; - -/** - * Tests for the {@link Pointer} read and write operations. - */ -public class PointerTest extends GraalCompilerTest implements SnippetsInterface { - - private static final Object ID = new Object(); - private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}; - private final TargetDescription target; - private final SnippetInstaller installer; - - public PointerTest() { - target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); - installer = new SnippetInstaller(runtime, new Assumptions(false), target); - } - - private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>(); - - @Override - protected StructuredGraph parse(Method m) { - ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get()); - } - - @Test - public void test_read1() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "1"), kind, false, ID); - } - } - - @Test - public void test_read2() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "2"), kind, true, ID); - } - } - - @Test - public void test_read3() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "3"), kind, false, LocationNode.UNKNOWN_LOCATION); - } - } - - @Test - public void test_write1() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "1"), kind, false, ID); - } - } - - @Test - public void test_write2() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "2"), kind, true, ID); - } - } - - @Test - public void test_write3() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION); - } - } - - private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { - ReadNode read = (ReadNode) graph.start().next(); - Assert.assertEquals(kind.getStackKind(), read.kind()); - - UnsafeCastNode cast = (UnsafeCastNode) read.object(); - Assert.assertEquals(graph.getLocal(0), cast.object()); - Assert.assertEquals(target.wordKind, cast.kind()); - - IndexedLocationNode location = (IndexedLocationNode) read.location(); - Assert.assertEquals(kind, location.getValueKind()); - Assert.assertEquals(locationIdentity, location.locationIdentity()); - Assert.assertEquals(1, location.indexScaling()); - - if (indexConvert) { - ConvertNode convert = (ConvertNode) location.index(); - Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); - Assert.assertEquals(graph.getLocal(1), convert.value()); - } else { - Assert.assertEquals(graph.getLocal(1), location.index()); - } - - ReturnNode ret = (ReturnNode) read.next(); - Assert.assertEquals(read, ret.result()); - } - - private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { - WriteNode write = (WriteNode) graph.start().next(); - Assert.assertEquals(graph.getLocal(2), write.value()); - Assert.assertEquals(Kind.Void, write.kind()); - Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci); - - UnsafeCastNode cast = (UnsafeCastNode) write.object(); - Assert.assertEquals(graph.getLocal(0), cast.object()); - Assert.assertEquals(target.wordKind, cast.kind()); - - IndexedLocationNode location = (IndexedLocationNode) write.location(); - Assert.assertEquals(kind, location.getValueKind()); - Assert.assertEquals(locationIdentity, location.locationIdentity()); - Assert.assertEquals(1, location.indexScaling()); - - if (indexConvert) { - ConvertNode convert = (ConvertNode) location.index(); - Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); - Assert.assertEquals(graph.getLocal(1), convert.value()); - } else { - Assert.assertEquals(graph.getLocal(1), location.index()); - } - - AbstractStateSplit stateSplit = (AbstractStateSplit) write.next(); - Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci); - - ReturnNode ret = (ReturnNode) stateSplit.next(); - Assert.assertEquals(null, ret.result()); - } - - @Snippet - public static byte readByte1(Object o, int offset) { - return Word.fromObject(o).readByte(offset, ID); - } - - @Snippet - public static byte readByte2(Object o, int offset) { - return Word.fromObject(o).readByte(Word.signed(offset), ID); - } - - @Snippet - public static byte readByte3(Object o, int offset) { - return Word.fromObject(o).readByte(offset); - } - - @Snippet - public static void writeByte1(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(offset, value, ID); - } - - @Snippet - public static void writeByte2(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeByte3(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(offset, value); - } - - @Snippet - public static char readChar1(Object o, int offset) { - return Word.fromObject(o).readChar(offset, ID); - } - - @Snippet - public static char readChar2(Object o, int offset) { - return Word.fromObject(o).readChar(Word.signed(offset), ID); - } - - @Snippet - public static char readChar3(Object o, int offset) { - return Word.fromObject(o).readChar(offset); - } - - @Snippet - public static void writeChar1(Object o, int offset, char value) { - Word.fromObject(o).writeChar(offset, value, ID); - } - - @Snippet - public static void writeChar2(Object o, int offset, char value) { - Word.fromObject(o).writeChar(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeChar3(Object o, int offset, char value) { - Word.fromObject(o).writeChar(offset, value); - } - - @Snippet - public static short readShort1(Object o, int offset) { - return Word.fromObject(o).readShort(offset, ID); - } - - @Snippet - public static short readShort2(Object o, int offset) { - return Word.fromObject(o).readShort(Word.signed(offset), ID); - } - - @Snippet - public static short readShort3(Object o, int offset) { - return Word.fromObject(o).readShort(offset); - } - - @Snippet - public static void writeShort1(Object o, int offset, short value) { - Word.fromObject(o).writeShort(offset, value, ID); - } - - @Snippet - public static void writeShort2(Object o, int offset, short value) { - Word.fromObject(o).writeShort(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeShort3(Object o, int offset, short value) { - Word.fromObject(o).writeShort(offset, value); - } - - @Snippet - public static int readInt1(Object o, int offset) { - return Word.fromObject(o).readInt(offset, ID); - } - - @Snippet - public static int readInt2(Object o, int offset) { - return Word.fromObject(o).readInt(Word.signed(offset), ID); - } - - @Snippet - public static int readInt3(Object o, int offset) { - return Word.fromObject(o).readInt(offset); - } - - @Snippet - public static void writeInt1(Object o, int offset, int value) { - Word.fromObject(o).writeInt(offset, value, ID); - } - - @Snippet - public static void writeInt2(Object o, int offset, int value) { - Word.fromObject(o).writeInt(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeInt3(Object o, int offset, int value) { - Word.fromObject(o).writeInt(offset, value); - } - - @Snippet - public static long readLong1(Object o, int offset) { - return Word.fromObject(o).readLong(offset, ID); - } - - @Snippet - public static long readLong2(Object o, int offset) { - return Word.fromObject(o).readLong(Word.signed(offset), ID); - } - - @Snippet - public static long readLong3(Object o, int offset) { - return Word.fromObject(o).readLong(offset); - } - - @Snippet - public static void writeLong1(Object o, int offset, long value) { - Word.fromObject(o).writeLong(offset, value, ID); - } - - @Snippet - public static void writeLong2(Object o, int offset, long value) { - Word.fromObject(o).writeLong(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeLong3(Object o, int offset, long value) { - Word.fromObject(o).writeLong(offset, value); - } - - @Snippet - public static float readFloat1(Object o, int offset) { - return Word.fromObject(o).readFloat(offset, ID); - } - - @Snippet - public static float readFloat2(Object o, int offset) { - return Word.fromObject(o).readFloat(Word.signed(offset), ID); - } - - @Snippet - public static float readFloat3(Object o, int offset) { - return Word.fromObject(o).readFloat(offset); - } - - @Snippet - public static void writeFloat1(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(offset, value, ID); - } - - @Snippet - public static void writeFloat2(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeFloat3(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(offset, value); - } - - @Snippet - public static double readDouble1(Object o, int offset) { - return Word.fromObject(o).readDouble(offset, ID); - } - - @Snippet - public static double readDouble2(Object o, int offset) { - return Word.fromObject(o).readDouble(Word.signed(offset), ID); - } - - @Snippet - public static double readDouble3(Object o, int offset) { - return Word.fromObject(o).readDouble(offset); - } - - @Snippet - public static void writeDouble1(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(offset, value, ID); - } - - @Snippet - public static void writeDouble2(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeDouble3(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(offset, value); - } - - @Snippet - public static Object readObject1(Object o, int offset) { - return Word.fromObject(o).readObject(offset, ID); - } - - @Snippet - public static Object readObject2(Object o, int offset) { - return Word.fromObject(o).readObject(Word.signed(offset), ID); - } - - @Snippet - public static Object readObject3(Object o, int offset) { - return Word.fromObject(o).readObject(offset); - } - - @Snippet - public static void writeObject1(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(offset, value, ID); - } - - @Snippet - public static void writeObject2(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeObject3(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(offset, value); - } - -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/TypeCheckTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; - -/** - * Base class for checkcast and instanceof test classes. - */ -public abstract class TypeCheckTest extends GraalCompilerTest { - - protected abstract void replaceProfile(StructuredGraph graph, JavaTypeProfile profile); - - protected JavaTypeProfile currentProfile; - - @Override - protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { - boolean forceCompile = false; - if (currentProfile != null) { - replaceProfile(graph, currentProfile); - forceCompile = true; - } - return super.getCode(method, graph, forceCompile); - } - - protected JavaTypeProfile profile(Class... types) { - if (types.length == 0) { - return null; - } - ProfiledType[] ptypes = new ProfiledType[types.length]; - for (int i = 0; i < types.length; i++) { - ptypes[i] = new ProfiledType(runtime.lookupJavaType(types[i]), 1.0D / types.length); - } - return new JavaTypeProfile(0.0D, ptypes); - } - - protected void test(String name, JavaTypeProfile profile, Object... args) { - assert currentProfile == null; - currentProfile = profile; - try { - super.test(name, args); - } finally { - currentProfile = null; - } - } -}
--- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.snippets.Snippet.SnippetInliningPolicy; -import com.oracle.graal.word.*; - -/** - * Tests for the {@link Word} type. - */ -public class WordTest extends GraalCompilerTest implements SnippetsInterface { - - private final SnippetInstaller installer; - - public WordTest() { - TargetDescription target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); - installer = new SnippetInstaller(runtime, new Assumptions(false), target); - } - - private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>(); - - @Override - protected StructuredGraph parse(Method m) { - ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get()); - } - - @LongTest - public void construction() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, - Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; - for (long word : words) { - test("unsigned_long", word); - test("unsigned_int", (int) word); - test("signed_long", word); - test("signed_int", (int) word); - } - } - - @LongTest - public void test_arithmetic() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, - Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; - for (long word : words) { - test("unsigned_not", word); - test("signed_not", word); - for (long addend : words) { - test("unsigned_plus_int", word, (int) addend); - test("unsigned_minus_int", word, (int) addend); - test("unsigned_plus_int", word, -((int) addend)); - test("unsigned_minus_int", word, -((int) addend)); - test("unsigned_plus_long", word, addend); - test("unsigned_minus_long", word, addend); - test("unsigned_plus_long", word, -addend); - test("unsigned_minus_long", word, -addend); - test("signed_plus_int", word, (int) addend); - test("signed_minus_int", word, (int) addend); - test("signed_plus_int", word, -((int) addend)); - test("signed_minus_int", word, -((int) addend)); - test("signed_plus_long", word, addend); - test("signed_minus_long", word, addend); - test("signed_plus_long", word, -addend); - test("signed_minus_long", word, -addend); - - test("and_int", word, (int) addend); - test("or_int", word, (int) addend); - test("and_int", word, -((int) addend)); - test("or_int", word, -((int) addend)); - test("and_long", word, addend); - test("or_long", word, addend); - test("and_long", word, -addend); - test("or_long", word, -addend); - } - } - } - - @LongTest - public void test_compare() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; - for (long word1 : words) { - for (long word2 : words) { - for (String method : new String[]{"aboveOrEqual", "above", "belowOrEqual", "below"}) { - test(method, word1, word2); - test(method, word2, word1); - } - } - } - } - - @Snippet - public static long unsigned_long(long word) { - return Word.unsigned(word).rawValue(); - } - - @Snippet - public static long unsigned_int(int word) { - return Word.unsigned(word).rawValue(); - } - - @Snippet - public static long signed_long(long word) { - return Word.signed(word).rawValue(); - } - - @Snippet - public static long signed_int(int word) { - return Word.signed(word).rawValue(); - } - - @Snippet - public static long unsigned_plus_int(long word, int addend) { - return Word.unsigned(word).add(addend).rawValue(); - } - - @Snippet - public static long unsigned_minus_int(long word, int addend) { - return Word.unsigned(word).subtract(addend).rawValue(); - } - - @Snippet - public static long unsigned_plus_long(long word, long addend) { - return Word.unsigned(word).add(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long unsigned_minus_long(long word, long addend) { - return Word.unsigned(word).subtract(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long signed_plus_int(long word, int addend) { - return Word.signed(word).add(addend).rawValue(); - } - - @Snippet - public static long signed_minus_int(long word, int addend) { - return Word.signed(word).subtract(addend).rawValue(); - } - - @Snippet - public static long signed_plus_long(long word, long addend) { - return Word.signed(word).add(Word.signed(addend)).rawValue(); - } - - @Snippet - public static long signed_minus_long(long word, long addend) { - return Word.signed(word).subtract(Word.signed(addend)).rawValue(); - } - - @Snippet - public static long signed_not(long word) { - return Word.signed(word).not().rawValue(); - } - - @Snippet - public static long unsigned_not(long word) { - return Word.unsigned(word).not().rawValue(); - } - - @Snippet - public static boolean aboveOrEqual(long word1, long word2) { - return Word.unsigned(word1).aboveOrEqual(Word.unsigned(word2)); - } - - @Snippet - public static boolean above(long word1, long word2) { - return Word.unsigned(word1).aboveThan(Word.unsigned(word2)); - } - - @Snippet - public static boolean belowOrEqual(long word1, long word2) { - return Word.unsigned(word1).belowOrEqual(Word.unsigned(word2)); - } - - @Snippet - public static boolean below(long word1, long word2) { - return Word.unsigned(word1).belowThan(Word.unsigned(word2)); - } - - @Snippet - public static long and_int(long word, int addend) { - return Word.unsigned(word).and(addend).rawValue(); - } - - @Snippet - public static long or_int(long word, int addend) { - return Word.unsigned(word).or(addend).rawValue(); - } - - @Snippet - public static long and_long(long word, long addend) { - return Word.unsigned(word).and(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long or_long(long word, long addend) { - return Word.unsigned(word).or(Word.unsigned(addend)).rawValue(); - } -}
--- a/graal/com.oracle.graal.snippets/overview.html Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -<!-- - -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. Oracle designates this -particular file as subject to the "Classpath" exception as provided -by Oracle in the LICENSE file that accompanied this code. - -This code is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -version 2 for more details (a copy is included in the LICENSE file that -accompanied this code). - -You should have received a copy of the GNU General Public License version -2 along with this work; if not, write to the Free Software Foundation, -Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - -Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -or visit www.oracle.com if you need additional information or have any -questions. ---> - -</head> -<body> - -Documentation for the <code>com.oracle.graal.snippets</code> project. - -</body> -</html>
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.lang.annotation.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.snippets.nodes.*; - -/** - * Denotes a class that substitutes methods of another specified class. The substitute methods are - * exactly those annotated by {@link MethodSubstitution}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface ClassSubstitution { - - /** - * Specifies the original class. - * <p> - * If the default value is specified for this element, then a non-default value must be given - * for the {@link #className()} element. - */ - Class<?> value() default ClassSubstitution.class; - - /** - * Specifies the original class. - * <p> - * This method is provided for cases where the original class is not accessible (according to - * Java language access control rules). - * <p> - * If the default value is specified for this element, then a non-default value must be given - * for the {@link #value()} element. - */ - String className() default ""; - - /** - * Determines if the substitutions are for classes that may not be part of the runtime. - * Substitutions for such classes are omitted if the original classes cannot be found. - */ - boolean optional() default false; - - /** - * 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 original method. - * <p> - * If the default value is specified for this element, then the name of the original method - * is same as the substitute method. - */ - String value() default ""; - - /** - * Determines if the original method is static. - */ - boolean isStatic() default true; - - /** - * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the original - * method. - * <p> - * If the default value is specified for this element, then the signature of the original - * method is the same as the substitute method. - */ - String signature() default ""; - } - - /** - * Denotes a macro substitute method. This replaces a method invocation with an instance of the - * specified node class. - * - * A macro substitution can be combined with a normal substitution, so that the macro node can - * be replaced with the actual substitution code during lowering. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public @interface MacroSubstitution { - - /** - * Gets the name of the substituted method. - * <p> - * If the default value is specified for this element, then the name of the substituted - * method is same as the substitute method. - */ - String value() default ""; - - /** - * Determines if the substituted method is static. - */ - boolean isStatic() default true; - - /** - * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the substituted - * method. - * <p> - * If the default value is specified for this element, then the signature of the substituted - * method is the same as the substitute method. - */ - String signature() default ""; - - /** - * The node class with which the method invocation should be replaced. It needs to be a - * subclass of {@link FixedWithNextNode}, and it is expected to provide a public constructor - * that takes an InvokeNode as a parameter. For most cases this class should subclass - * {@link MacroNode} and use its constructor. - */ - Class<? extends FixedWithNextNode> macro(); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/DoubleSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.snippets.ClassSubstitution.*; - -/** - * Substitutions for {@link java.lang.Double} methods. - */ -@ClassSubstitution(java.lang.Double.class) -public class DoubleSubstitutions { - - private static final long NAN_RAW_LONG_BITS = Double.doubleToRawLongBits(Double.NaN); - - @MethodSubstitution - public static long doubleToRawLongBits(double value) { - @JavacBug(id = 6995200) - Long result = ConvertNode.convert(ConvertNode.Op.MOV_D2L, value); - return result; - } - - // TODO This method is not necessary, since the JDK method does exactly this - @MethodSubstitution - public static long doubleToLongBits(double value) { - if (value != value) { - return NAN_RAW_LONG_BITS; - } else { - return doubleToRawLongBits(value); - } - } - - @MethodSubstitution - public static double longBitsToDouble(long bits) { - @JavacBug(id = 6995200) - Double result = ConvertNode.convert(ConvertNode.Op.MOV_L2D, bits); - return result; - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/FloatSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.snippets.ClassSubstitution.*; - -/** - * Substitutions for {@link java.lang.Float} methods. - */ -@ClassSubstitution(java.lang.Float.class) -public class FloatSubstitutions { - - private static final int NAN_RAW_INT_BITS = Float.floatToRawIntBits(Float.NaN); - - @MethodSubstitution - public static int floatToRawIntBits(float value) { - @JavacBug(id = 6995200) - Integer result = ConvertNode.convert(ConvertNode.Op.MOV_F2I, value); - return result; - } - - // TODO This method is not necessary, since the JDK method does exactly this - @MethodSubstitution - public static int floatToIntBits(float value) { - if (value != value) { - return NAN_RAW_INT_BITS; - } else { - return floatToRawIntBits(value); - } - } - - @MethodSubstitution - public static float intBitsToFloat(int bits) { - @JavacBug(id = 6995200) - Float result = ConvertNode.convert(ConvertNode.Op.MOV_I2F, bits); - return result; - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/GraalIntrinsics.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.phases.*; - -/** - * Definition of the snippets that are VM-independent and can be intrinsified by Graal in any VM. - */ -public class GraalIntrinsics { - - public static void installIntrinsics(SnippetInstaller installer) { - if (GraalOptions.Intrinsify) { - installer.installSubstitutions(MathSubstitutionsX86.class); - installer.installSubstitutions(DoubleSubstitutions.class); - installer.installSubstitutions(FloatSubstitutions.class); - installer.installSubstitutions(NodeClassSubstitutions.class); - installer.installSubstitutions(LongSubstitutions.class); - installer.installSubstitutions(IntegerSubstitutions.class); - installer.installSubstitutions(UnsignedMathSubstitutions.class); - } - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import static com.oracle.graal.nodes.calc.CompareNode.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; -import com.oracle.graal.snippets.SnippetTemplate.Arguments; -import com.oracle.graal.snippets.SnippetTemplate.Key; -import com.oracle.graal.snippets.SnippetTemplate.UsageReplacer; - -/** - * Helper class for lowering {@link InstanceOfNode}s with snippets. The majority of the complexity - * in such a lowering derives from the fact that {@link InstanceOfNode} is a floating node. A - * snippet used to lower an {@link InstanceOfNode} will almost always incorporate control flow and - * replacing a floating node with control flow is not trivial. - * <p> - * The mechanism implemented in this class ensures that the graph for an instanceof snippet is - * instantiated once per {@link InstanceOfNode} being lowered. The result produced the graph is then - * re-used by all usages of the node. Additionally, if there is a single usage that is an - * {@link IfNode}, the control flow in the snippet is connected directly to the true and false - * successors of the {@link IfNode}. This avoids materializating the instanceof test as a boolean - * which is then retested by the {@link IfNode}. - */ -public abstract class InstanceOfSnippetsTemplates<T extends SnippetsInterface> extends AbstractTemplates<T> { - - public InstanceOfSnippetsTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class<T> snippetsClass) { - super(runtime, assumptions, target, snippetsClass); - } - - /** - * The key and arguments used to retrieve and instantiate an instanceof snippet template. - */ - public static class KeyAndArguments { - - public final Key key; - public final Arguments arguments; - - public KeyAndArguments(Key key, Arguments arguments) { - this.key = key; - this.arguments = arguments; - } - - } - - /** - * Gets the key and arguments used to retrieve and instantiate an instanceof snippet template. - */ - protected abstract KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool); - - public void lower(FloatingNode instanceOf, LoweringTool tool) { - assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; - List<Node> usages = instanceOf.usages().snapshot(); - int nUsages = usages.size(); - - Instantiation instantiation = new Instantiation(); - for (Node usage : usages) { - final StructuredGraph graph = (StructuredGraph) usage.graph(); - - InstanceOfUsageReplacer replacer = createReplacer(instanceOf, tool, nUsages, instantiation, usage, graph); - - if (instantiation.isInitialized()) { - // No need to re-instantiate the snippet - just re-use its result - replacer.replaceUsingInstantiation(); - } else { - KeyAndArguments keyAndArguments = getKeyAndArguments(replacer, tool); - SnippetTemplate template = cache.get(keyAndArguments.key, assumptions); - template.instantiate(runtime, instanceOf, replacer, tool, keyAndArguments.arguments); - } - } - - assert instanceOf.usages().isEmpty(); - if (!instanceOf.isDeleted()) { - GraphUtil.killWithUnusedFloatingInputs(instanceOf); - } - } - - /** - * Gets the specific replacer object used to replace the usage of an instanceof node with the - * result of an instantiated instanceof snippet. - */ - protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) { - InstanceOfUsageReplacer replacer; - if (usage instanceof IfNode) { - replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage, nUsages == 1, tool); - } else { - assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage; - ConditionalNode c = (ConditionalNode) usage; - replacer = new ConditionalUsageReplacer(instantiation, c.trueValue(), c.falseValue(), instanceOf, c); - } - return replacer; - } - - /** - * The result of an instantiating an instanceof snippet. This enables a snippet instantiation to - * be re-used which reduces compile time and produces better code. - */ - public static final class Instantiation { - - private PhiNode result; - private CompareNode condition; - private ValueNode trueValue; - private ValueNode falseValue; - - /** - * Determines if the instantiation has occurred. - */ - boolean isInitialized() { - return result != null; - } - - void initialize(PhiNode phi, ValueNode t, ValueNode f) { - assert !isInitialized(); - this.result = phi; - this.trueValue = t; - this.falseValue = f; - } - - /** - * Gets the result of this instantiation as a condition. - * - * @param testValue the returned condition is true if the result is equal to this value - */ - CompareNode asCondition(ValueNode testValue) { - assert isInitialized(); - if (condition == null || condition.y() != testValue) { - // Re-use previously generated condition if the trueValue for the test is the same - condition = createCompareNode(Condition.EQ, result, testValue); - } - return condition; - } - - /** - * Gets the result of the instantiation as a materialized value. - * - * @param t the true value for the materialization - * @param f the false value for the materialization - */ - ValueNode asMaterialization(ValueNode t, ValueNode f) { - assert isInitialized(); - if (t == this.trueValue && f == this.falseValue) { - // Can simply use the phi result if the same materialized values are expected. - return result; - } else { - return t.graph().unique(new ConditionalNode(asCondition(trueValue), t, f)); - } - } - } - - /** - * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}. - */ - public abstract static class InstanceOfUsageReplacer implements UsageReplacer { - - public final Instantiation instantiation; - public final FloatingNode instanceOf; - public final ValueNode trueValue; - public final ValueNode falseValue; - - public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) { - assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; - this.instantiation = instantiation; - this.instanceOf = instanceOf; - this.trueValue = trueValue; - this.falseValue = falseValue; - } - - /** - * Does the replacement based on a previously snippet instantiation. - */ - public abstract void replaceUsingInstantiation(); - } - - /** - * Replaces an {@link IfNode} usage of an {@link InstanceOfNode} or - * {@link InstanceOfDynamicNode}. - */ - public static class IfUsageReplacer extends InstanceOfUsageReplacer { - - private final boolean solitaryUsage; - private final IfNode usage; - private final boolean sameBlock; - - public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) { - super(instantiation, instanceOf, trueValue, falseValue); - this.sameBlock = tool.getBlockFor(usage) == tool.getBlockFor(instanceOf); - this.solitaryUsage = solitaryUsage; - this.usage = usage; - } - - @Override - public void replaceUsingInstantiation() { - usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue)); - } - - private boolean usageFollowsInstantiation() { - return instantiation.result != null && instantiation.result.merge().next() == usage; - } - - @Override - public void replace(ValueNode oldNode, ValueNode newNode) { - assert newNode instanceof PhiNode; - assert oldNode == instanceOf; - if (sameBlock && solitaryUsage && usageFollowsInstantiation()) { - removeIntermediateMaterialization(newNode); - } else { - newNode.inferStamp(); - instantiation.initialize((PhiNode) newNode, trueValue, falseValue); - usage.replaceFirstInput(oldNode, instantiation.asCondition(trueValue)); - } - } - - /** - * Directly wires the incoming edges of the merge at the end of the snippet to the outgoing - * edges of the IfNode that uses the materialized result. - */ - private void removeIntermediateMaterialization(ValueNode newNode) { - IfNode ifNode = usage; - PhiNode phi = (PhiNode) newNode; - MergeNode merge = phi.merge(); - assert merge.stateAfter() == null; - - List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot(); - assert phi.valueCount() == mergePredecessors.size(); - - List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size()); - List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size()); - - int endIndex = 0; - for (EndNode end : mergePredecessors) { - ValueNode endValue = phi.valueAt(endIndex++); - if (endValue == trueValue) { - trueEnds.add(end); - } else { - assert endValue == falseValue; - falseEnds.add(end); - } - } - - BeginNode trueSuccessor = ifNode.trueSuccessor(); - BeginNode falseSuccessor = ifNode.falseSuccessor(); - ifNode.setTrueSuccessor(null); - ifNode.setFalseSuccessor(null); - - connectEnds(merge, trueEnds, trueSuccessor); - connectEnds(merge, falseEnds, falseSuccessor); - - GraphUtil.killCFG(merge); - GraphUtil.killCFG(ifNode); - - assert !merge.isAlive() : merge; - assert !phi.isAlive() : phi; - } - - private static void connectEnds(MergeNode merge, List<EndNode> ends, BeginNode successor) { - if (ends.size() == 0) { - // InstanceOf has been lowered to always true or always false - this successor is - // therefore unreachable. - GraphUtil.killCFG(successor); - } else if (ends.size() == 1) { - EndNode end = ends.get(0); - ((FixedWithNextNode) end.predecessor()).setNext(successor); - merge.removeEnd(end); - GraphUtil.killCFG(end); - } else { - assert ends.size() > 1; - MergeNode newMerge = merge.graph().add(new MergeNode()); - - for (EndNode end : ends) { - newMerge.addForwardEnd(end); - } - newMerge.setNext(successor); - } - } - } - - /** - * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode} or - * {@link InstanceOfDynamicNode}. - */ - public static class ConditionalUsageReplacer extends InstanceOfUsageReplacer { - - public final ConditionalNode usage; - - public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) { - super(instantiation, instanceOf, trueValue, falseValue); - this.usage = usage; - } - - @Override - public void replaceUsingInstantiation() { - ValueNode newValue = instantiation.asMaterialization(trueValue, falseValue); - usage.replaceAtUsages(newValue); - usage.clearInputs(); - assert usage.usages().isEmpty(); - GraphUtil.killWithUnusedFloatingInputs(usage); - } - - @Override - public void replace(ValueNode oldNode, ValueNode newNode) { - assert newNode instanceof PhiNode; - assert oldNode == instanceOf; - newNode.inferStamp(); - instantiation.initialize((PhiNode) newNode, trueValue, falseValue); - usage.replaceAtUsages(newNode); - usage.clearInputs(); - assert usage.usages().isEmpty(); - GraphUtil.killWithUnusedFloatingInputs(usage); - } - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/IntegerSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.snippets.ClassSubstitution.*; -import com.oracle.graal.snippets.nodes.*; - -@ClassSubstitution(Integer.class) -public class IntegerSubstitutions { - - @MethodSubstitution - public static int reverseBytes(int i) { - return ReverseBytesNode.reverse(i); - } - - @MethodSubstitution - public static int numberOfLeadingZeros(int i) { - if (i == 0) { - return 32; - } - return 31 - BitScanReverseNode.scan(i); - } - - @MethodSubstitution - public static int numberOfTrailingZeros(int i) { - if (i == 0) { - return 32; - } - return BitScanForwardNode.scan(i); - } - - @MethodSubstitution - public static int bitCount(int i) { - return BitCountNode.bitCount(i); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/JavacBug.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -/** - * Used to indicate that an otherwise strange looking code pattern is required to work around a bug - * in javac. - */ -public @interface JavacBug { - - /** - * A description of the bug. Only really useful if there is no existing entry for the bug in the - * <a href="http://bugs.sun.com/bugdatabase/">Bug Database</a>. - */ - String value() default ""; - - /** - * An identifier in the <a href="http://bugs.sun.com/bugdatabase/">Bug Database</a>. - */ - int id() default 0; -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.io.*; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; - -//JaCoCo Exclude - -/** - * Provides {@link PrintStream}-like logging facility. This should only be used in - * {@linkplain Snippet snippets}. - */ -public final class Log { - - public static final Descriptor LOG_PRIMITIVE = new Descriptor("logPrimitive", false, void.class, int.class, long.class, boolean.class); - public static final Descriptor LOG_OBJECT = new Descriptor("logObject", false, void.class, Object.class, int.class); - public static final Descriptor LOG_PRINTF = new Descriptor("logPrintf", false, void.class, Object.class, long.class, long.class, long.class); - - // Note: Must be kept in sync with constants in c1_Runtime1.hpp - private static final int LOG_OBJECT_NEWLINE = 0x01; - private static final int LOG_OBJECT_STRING = 0x02; - private static final int LOG_OBJECT_ADDRESS = 0x04; - - @NodeIntrinsic(RuntimeCallNode.class) - private static native void log(@ConstantNodeParameter Descriptor logObject, Object object, int flags); - - @NodeIntrinsic(RuntimeCallNode.class) - private static native void log(@ConstantNodeParameter Descriptor logPrimitive, int typeChar, long value, boolean newline); - - @NodeIntrinsic(RuntimeCallNode.class) - private static native void printf(@ConstantNodeParameter Descriptor logPrintf, String format, long v1, long v2, long v3); - - public static void print(boolean value) { - log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, false); - } - - public static void print(byte value) { - log(LOG_PRIMITIVE, Kind.Byte.getTypeChar(), value, false); - } - - public static void print(char value) { - log(LOG_PRIMITIVE, Kind.Char.getTypeChar(), value, false); - } - - public static void print(short value) { - log(LOG_PRIMITIVE, Kind.Short.getTypeChar(), value, false); - } - - public static void print(int value) { - log(LOG_PRIMITIVE, Kind.Int.getTypeChar(), value, false); - } - - public static void print(long value) { - log(LOG_PRIMITIVE, Kind.Long.getTypeChar(), value, false); - } - - /** - * Prints a formatted string to the log stream. - * - * @param format a C style printf format value that can contain at most one conversion specifier - * (i.e., a sequence of characters starting with '%'). - * @param value the value associated with the conversion specifier - */ - public static void printf(String format, long value) { - printf(LOG_PRINTF, format, value, 0L, 0L); - } - - public static void printf(String format, long v1, long v2) { - printf(LOG_PRINTF, format, v1, v2, 0L); - } - - public static void printf(String format, long v1, long v2, long v3) { - printf(LOG_PRINTF, format, v1, v2, v3); - } - - public static void print(float value) { - if (Float.isNaN(value)) { - print("NaN"); - } else if (value == Float.POSITIVE_INFINITY) { - print("Infinity"); - } else if (value == Float.NEGATIVE_INFINITY) { - print("-Infinity"); - } else { - log(LOG_PRIMITIVE, Kind.Float.getTypeChar(), Float.floatToRawIntBits(value), false); - } - } - - public static void print(double value) { - if (Double.isNaN(value)) { - print("NaN"); - } else if (value == Double.POSITIVE_INFINITY) { - print("Infinity"); - } else if (value == Double.NEGATIVE_INFINITY) { - print("-Infinity"); - } else { - log(LOG_PRIMITIVE, Kind.Double.getTypeChar(), Double.doubleToRawLongBits(value), false); - } - } - - public static void print(String value) { - log(LOG_OBJECT, value, LOG_OBJECT_STRING); - } - - public static void printAddress(Object o) { - log(LOG_OBJECT, o, LOG_OBJECT_ADDRESS); - } - - public static void printObject(Object o) { - log(LOG_OBJECT, o, 0); - } - - public static void println(boolean value) { - log(LOG_PRIMITIVE, Kind.Boolean.getTypeChar(), value ? 1L : 0L, true); - } - - public static void println(byte value) { - log(LOG_PRIMITIVE, Kind.Byte.getTypeChar(), value, true); - } - - public static void println(char value) { - log(LOG_PRIMITIVE, Kind.Char.getTypeChar(), value, true); - } - - public static void println(short value) { - log(LOG_PRIMITIVE, Kind.Short.getTypeChar(), value, true); - } - - public static void println(int value) { - log(LOG_PRIMITIVE, Kind.Int.getTypeChar(), value, true); - } - - public static void println(long value) { - log(LOG_PRIMITIVE, Kind.Long.getTypeChar(), value, true); - } - - public static void println(float value) { - if (Float.isNaN(value)) { - println("NaN"); - } else if (value == Float.POSITIVE_INFINITY) { - println("Infinity"); - } else if (value == Float.NEGATIVE_INFINITY) { - println("-Infinity"); - } else { - log(LOG_PRIMITIVE, Kind.Float.getTypeChar(), Float.floatToRawIntBits(value), true); - } - } - - public static void println(double value) { - if (Double.isNaN(value)) { - println("NaN"); - } else if (value == Double.POSITIVE_INFINITY) { - println("Infinity"); - } else if (value == Double.NEGATIVE_INFINITY) { - println("-Infinity"); - } else { - log(LOG_PRIMITIVE, Kind.Double.getTypeChar(), Double.doubleToRawLongBits(value), true); - } - } - - public static void println(String value) { - log(LOG_OBJECT, value, LOG_OBJECT_NEWLINE | LOG_OBJECT_STRING); - } - - public static void printlnAddress(Object o) { - log(LOG_OBJECT, o, LOG_OBJECT_NEWLINE | LOG_OBJECT_ADDRESS); - } - - public static void printlnObject(Object o) { - log(LOG_OBJECT, o, LOG_OBJECT_NEWLINE); - } - - public static void println() { - println(""); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/LongSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.snippets.ClassSubstitution.*; -import com.oracle.graal.snippets.nodes.*; - -@ClassSubstitution(Long.class) -public class LongSubstitutions { - - @MethodSubstitution - public static long reverseBytes(long i) { - return ReverseBytesNode.reverse(i); - } - - @MethodSubstitution - public static int numberOfLeadingZeros(long i) { - if (i == 0) { - return 64; - } - return 63 - BitScanReverseNode.scan(i); - } - - @MethodSubstitution - public static int numberOfTrailingZeros(long i) { - if (i == 0) { - return 64; - } - return BitScanForwardNode.scan(i); - } - - @MethodSubstitution - public static int bitCount(long i) { - return BitCountNode.bitCount(i); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSubstitutionsX86.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; -import com.oracle.graal.snippets.nodes.*; -import com.oracle.graal.snippets.nodes.MathIntrinsicNode.Operation; - -/** - * Substitutions for {@link java.lang.Math} methods. - */ -@ClassSubstitution(java.lang.Math.class) -public class MathSubstitutionsX86 { - - private static final double PI_4 = 0.7853981633974483; - - @MethodSubstitution - public static double abs(double x) { - return MathIntrinsicNode.compute(x, Operation.ABS); - } - - @MethodSubstitution - public static double sqrt(double x) { - return MathIntrinsicNode.compute(x, Operation.SQRT); - } - - @MethodSubstitution - public static double log(double x) { - return MathIntrinsicNode.compute(x, Operation.LOG); - } - - @MethodSubstitution - public static double log10(double x) { - return MathIntrinsicNode.compute(x, Operation.LOG10); - } - - // NOTE on snippets below: - // Math.sin(), .cos() and .tan() guarantee a value within 1 ULP of the - // exact result, but x87 trigonometric FPU instructions are only that - // accurate within [-pi/4, pi/4]. Examine the passed value and provide - // a slow path for inputs outside of that interval. - - @MethodSubstitution - public static double sin(double x) { - if (abs(x) < PI_4) { - return MathIntrinsicNode.compute(x, Operation.SIN); - } else { - return callDouble(ARITHMETIC_SIN, x); - } - } - - @MethodSubstitution - public static double cos(double x) { - if (abs(x) < PI_4) { - return MathIntrinsicNode.compute(x, Operation.COS); - } else { - return callDouble(ARITHMETIC_COS, x); - } - } - - @MethodSubstitution - public static double tan(double x) { - if (abs(x) < PI_4) { - return MathIntrinsicNode.compute(x, Operation.TAN); - } else { - return callDouble(ARITHMETIC_TAN, x); - } - } - - public static final Descriptor ARITHMETIC_SIN = new Descriptor("arithmeticSin", false, double.class, double.class); - public static final Descriptor ARITHMETIC_COS = new Descriptor("arithmeticCos", false, double.class, double.class); - public static final Descriptor ARITHMETIC_TAN = new Descriptor("arithmeticTan", false, double.class, double.class); - - @NodeIntrinsic(value = RuntimeCallNode.class, setStampFromReturnType = true) - public static native double callDouble(@ConstantNodeParameter Descriptor descriptor, double value); -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.snippets.ClassSubstitution.*; - -/** - * Substitutions for improving the performance of some critical methods in {@link NodeClass} - * methods. These substitutions improve the performance by forcing the relevant methods to be - * inlined (intrinsification being a special form of inlining) and removing a checked cast. The - * latter cannot be done directly in Java code as {@link UnsafeCastNode} is not available to the - * project containing {@link NodeClass}. - */ -@ClassSubstitution(NodeClass.class) -public class NodeClassSubstitutions { - - @MethodSubstitution - private static Node getNode(Node node, long offset) { - return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false); - } - - @MethodSubstitution - private static NodeList getNodeList(Node node, long offset) { - return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false); - } - - @MethodSubstitution - private static void putNode(Node node, long offset, Node value) { - UnsafeStoreNode.store(node, 0, offset, value, Kind.Object); - } - - @MethodSubstitution - private static void putNodeList(Node node, long offset, NodeList value) { - UnsafeStoreNode.store(node, 0, offset, value, Kind.Object); - } - -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.lang.annotation.*; -import java.lang.reflect.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.snippets.nodes.*; -import com.oracle.graal.word.*; - -/** - * A snippet is a Graal graph expressed as a Java source method. Graal snippets can be used for: - * <ul> - * <li>intrinsifying native JDK methods (see {@link ClassSubstitution})</li> - * <li>lowering operations that have runtime dependent semantics (e.g. the {@code CHECKCAST} - * bytecode)</li> - * <li>replacing a method call with a single graph node (see {@link NodeIntrinsic})</li> - * </ul> - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -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<? extends SnippetInliningPolicy> inlining() default SnippetInliningPolicy.class; - - /** - * 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); - } - - /** - * The default inlining policy which inlines everything except for methods in any of the - * following categories. - * <ul> - * <li>{@linkplain Fold foldable} methods</li> - * <li>{@linkplain NodeIntrinsic node intrinsics}</li> - * <li>native methods</li> - * <li>constructors of {@link Throwable} classes</li> - * </ul> - */ - public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { - - private final MetaAccessProvider metaAccess; - private final BoxingMethodPool pool; - - public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess, BoxingMethodPool pool) { - this.metaAccess = metaAccess; - this.pool = pool; - } - - @Override - public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { - if (Modifier.isNative(method.getModifiers())) { - 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.getName().equals("<init>")) { - return false; - } - } - if (method.getAnnotation(Word.Operation.class) != null) { - return false; - } - if (pool.isSpecialMethod(method)) { - return false; - } - return true; - } - } - - /** - * Annotates a method replaced by a compile-time constant. A (resolved) call to the annotated - * method is replaced with a constant obtained by calling the annotated method via reflection. - * - * All arguments to such a method (including the receiver if applicable) must be compile-time - * constants. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - public static @interface Fold { - } - - /** - * Denotes a snippet parameter that will be bound during snippet template - * {@linkplain SnippetTemplate#instantiate instantiation}. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface Parameter { - - /** - * The name of this parameter. - */ - String value(); - } - - /** - * 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 - * (the contents of the array are ignored) bound to the parameter during - * {@linkplain SnippetTemplate#instantiate instantiation}. - * - * Such a parameter must be used in a counted loop in the snippet preceded by a call to - * {@link ExplodeLoopNode#explodeLoop()}. The counted looped must be a standard iteration over - * all the loop's elements (i.e. {@code for (T e : arr) ... }). - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface VarargsParameter { - - /** - * The name of this parameter. - */ - String value(); - } - - /** - * Denotes a snippet parameter that will bound to a constant value during snippet template - * {@linkplain SnippetTemplate#instantiate instantiation}. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface ConstantParameter { - - /** - * The name of this constant. - */ - String value(); - } - - /** - * Wrapper for the prototype value of a {@linkplain VarargsParameter varargs} parameter. - */ - public static class Varargs { - - private final Object args; - private final Class argType; - private final int length; - private final Stamp argStamp; - - public static Varargs vargargs(Object array, Stamp argStamp) { - return new Varargs(array, argStamp); - } - - public Varargs(Object array, Stamp argStamp) { - assert array != null; - this.argType = array.getClass().getComponentType(); - this.argStamp = argStamp; - assert this.argType != null; - this.length = java.lang.reflect.Array.getLength(array); - this.args = array; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Varargs) { - Varargs other = (Varargs) obj; - return other.argType == argType && other.length == length; - } - return false; - } - - public Object getArray() { - return args; - } - - public Stamp getArgStamp() { - return argStamp; - } - - @Override - public int hashCode() { - return argType.hashCode() ^ length; - } - - @Override - public String toString() { - return argType.getName() + "[" + length + "]"; - } - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetCounter.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -//JaCoCo Exclude - -import static com.oracle.graal.graph.FieldIntrospection.*; - -import java.io.*; -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.snippets.Snippet.Fold; -import com.oracle.graal.snippets.nodes.*; - -/** - * A counter that can be safely {@linkplain #inc() incremented} from within a snippet for gathering - * snippet specific metrics. - */ -public class SnippetCounter implements Comparable<SnippetCounter> { - - /** - * A group of related counters. - */ - public static class Group { - - final String name; - final List<SnippetCounter> counters; - - public Group(String name) { - this.name = name; - this.counters = new ArrayList<>(); - } - - @Override - public synchronized String toString() { - Collections.sort(counters); - - long total = 0; - int maxNameLen = 0; - for (SnippetCounter c : counters) { - total += c.value; - maxNameLen = Math.max(c.name.length(), maxNameLen); - } - - StringBuilder buf = new StringBuilder(String.format("Counters: %s%n", name)); - - for (SnippetCounter c : counters) { - double percent = total == 0D ? 0D : ((double) (c.value * 100)) / total; - buf.append(String.format(" %" + maxNameLen + "s: %5.2f%%%10d // %s%n", c.name, percent, c.value, c.description)); - } - return buf.toString(); - } - } - - /** - * Sorts counters in descending order of their {@linkplain #value() values}. - */ - @Override - public int compareTo(SnippetCounter o) { - if (value > o.value) { - return -1; - } else if (o.value < value) { - return 1; - } - return 0; - } - - private static final List<Group> groups = new ArrayList<>(); - - private final Group group; - private final int index; - private final String name; - private final String description; - private long value; - - @Fold - private static int countOffset() { - try { - return (int) unsafe.objectFieldOffset(SnippetCounter.class.getDeclaredField("value")); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - /** - * Creates a counter. - * - * @param group the group to which the counter belongs. If this is null, the newly created - * counter is disabled and {@linkplain #inc() incrementing} is a no-op. - * @param name the name of the counter - * @param description a brief comment describing the metric represented by the counter - */ - public SnippetCounter(Group group, String name, String description) { - this.group = group; - this.name = name; - this.description = description; - if (group != null) { - List<SnippetCounter> counters = group.counters; - this.index = counters.size(); - counters.add(this); - if (index == 0) { - groups.add(group); - } - } else { - this.index = -1; - } - } - - /** - * Increments the value of this counter. This method can be safely used in a snippet if it is - * invoked on a compile-time constant {@link SnippetCounter} object. - */ - public void inc() { - if (group != null) { - DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1); - } - } - - /** - * Gets the value of this counter. - */ - public long value() { - return value; - } - - /** - * Prints all the counter groups to a given stream. - */ - public static void printGroups(PrintStream out) { - for (Group group : groups) { - out.println(group); - } - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.util.*; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; - -/** - * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a - * snippet. - * - * The frame states of side-effecting nodes are replaced with - * {@linkplain FrameState#INVALID_FRAMESTATE_BCI invalid} frame states. Loops that contain invalid - * frame states are also assigned an invalid frame state. - * - * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. - */ -public class SnippetFrameStateCleanupPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null); - } - - private static class CleanupState { - - public boolean containsFrameState; - - public CleanupState(boolean containsFrameState) { - this.containsFrameState = containsFrameState; - } - } - - /** - * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid - * frame states, so that they can be marked with an invalid frame state. - */ - private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure<CleanupState> { - - @Override - protected void processNode(FixedNode node, CleanupState currentState) { - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - if (frameState != null) { - if (stateSplit.hasSideEffect()) { - currentState.containsFrameState = true; - stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); - } else { - stateSplit.setStateAfter(null); - } - if (frameState.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(frameState); - } - } - } - } - - @Override - protected CleanupState merge(MergeNode merge, List<CleanupState> states) { - for (CleanupState state : states) { - if (state.containsFrameState) { - return new CleanupState(true); - } - } - return new CleanupState(false); - } - - @Override - protected CleanupState afterSplit(BeginNode node, CleanupState oldState) { - return new CleanupState(oldState.containsFrameState); - } - - @Override - protected Map<LoopExitNode, CleanupState> processLoop(LoopBeginNode loop, CleanupState initialState) { - LoopInfo<CleanupState> info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false)); - boolean containsFrameState = false; - for (CleanupState state : info.endStates.values()) { - containsFrameState |= state.containsFrameState; - } - if (containsFrameState) { - loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); - } - if (containsFrameState || initialState.containsFrameState) { - for (CleanupState state : info.exitStates.values()) { - state.containsFrameState = true; - } - } - return info.exitStates; - } - - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,405 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import static com.oracle.graal.api.meta.MetaUtil.*; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.snippets.ClassSubstitution.MacroSubstitution; -import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; -import com.oracle.graal.snippets.Snippet.DefaultSnippetInliningPolicy; -import com.oracle.graal.snippets.Snippet.SnippetInliningPolicy; -import com.oracle.graal.word.phases.*; - -/** - * Utility for {@linkplain #installSnippets(Class) snippet} and - * {@linkplain #installSubstitutions(Class) substitution} installation. - */ -public class SnippetInstaller { - - protected final MetaAccessProvider runtime; - protected final TargetDescription target; - protected final Assumptions assumptions; - protected final BoxingMethodPool pool; - private final Thread owner; - - /** - * A graph cache used by this installer to avoid using the compiler storage for each method - * processed during snippet installation. Without this, all processed methods are to be - * determined as {@linkplain InliningUtil#canIntrinsify intrinsifiable}. - */ - private final Map<ResolvedJavaMethod, StructuredGraph> graphCache; - - public SnippetInstaller(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target) { - this.runtime = runtime; - this.target = target; - this.assumptions = assumptions; - this.pool = new BoxingMethodPool(runtime); - this.graphCache = new HashMap<>(); - this.owner = Thread.currentThread(); - } - - /** - * Finds all the snippet methods in a given class, builds a graph for them and installs the - * graph with the key value of {@code Graph.class} in the - * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each method. - */ - public void installSnippets(Class<? extends SnippetsInterface> clazz) { - for (Method method : clazz.getDeclaredMethods()) { - if (method.getAnnotation(Snippet.class) != null) { - int modifiers = method.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); - assert snippet.getCompilerStorage().get(Graph.class) == null : method; - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); - // System.out.println("snippet: " + graph); - snippet.getCompilerStorage().put(Graph.class, graph); - } - } - } - - /** - * Finds all the {@linkplain MethodSubstitution substitution} methods in a given class, builds a - * graph for them. If the original class is resolvable, then the graph is installed with the key - * value of {@code Graph.class} in the {@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); - assert classSubstitution != null; - assert !SnippetsInterface.class.isAssignableFrom(substitutions); - for (Method substituteMethod : substitutions.getDeclaredMethods()) { - MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); - MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class); - if (methodSubstitution == null && macroSubstitution == null) { - continue; - } - - int modifiers = substituteMethod.getModifiers(); - if (!Modifier.isStatic(modifiers)) { - throw new RuntimeException("Substitution methods must be static: " + substituteMethod); - } - - if (methodSubstitution != null) { - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Substitution method must not be abstract or native: " + substituteMethod); - } - String originalName = originalName(substituteMethod, methodSubstitution.value()); - Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); - Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); - if (originalMethod != null) { - installMethodSubstitution(originalMethod, substituteMethod); - } - } - if (macroSubstitution != null) { - String originalName = originalName(substituteMethod, macroSubstitution.value()); - Class[] originalParameters = originalParameters(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); - Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); - if (originalMethod != null) { - installMacroSubstitution(originalMethod, macroSubstitution.macro()); - } - } - } - } - - // 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. - * - * @param originalMethod a method or constructor being substituted - * @param substituteMethod the substitute method - */ - protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { - substitute = runtime.lookupJavaMethod(substituteMethod); - if (originalMethod instanceof Method) { - original = runtime.lookupJavaMethod((Method) originalMethod); - } else { - original = runtime.lookupJavaConstructor((Constructor) originalMethod); - } - try { - Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); - StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute)); - Object oldValue = original.getCompilerStorage().put(Graph.class, graph); - assert oldValue == null; - } finally { - substitute = null; - original = null; - substituteCallsOriginal = false; - } - } - - /** - * Installs a macro substitution. - * - * @param originalMethod a method or constructor being substituted - * @param macro the substitute macro node class - */ - protected void installMacroSubstitution(Member originalMethod, Class<? extends FixedWithNextNode> macro) { - ResolvedJavaMethod originalJavaMethod; - if (originalMethod instanceof Method) { - originalJavaMethod = runtime.lookupJavaMethod((Method) originalMethod); - } else { - originalJavaMethod = runtime.lookupJavaConstructor((Constructor) originalMethod); - } - Object oldValue = originalJavaMethod.getCompilerStorage().put(Node.class, macro); - assert oldValue == null; - } - - private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { - Class<? extends SnippetInliningPolicy> policyClass = SnippetInliningPolicy.class; - Snippet snippet = method.getAnnotation(Snippet.class); - if (snippet != null) { - policyClass = snippet.inlining(); - } - if (policyClass == SnippetInliningPolicy.class) { - return new DefaultSnippetInliningPolicy(runtime, pool); - } - try { - return policyClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - /** - * Does final processing of a snippet graph. - */ - protected void finalizeGraph(ResolvedJavaMethod method, StructuredGraph graph) { - new SnippetIntrinsificationPhase(runtime, pool).apply(graph); - assert SnippetTemplate.hasConstantParameter(method) || SnippetIntrinsificationVerificationPhase.verify(graph); - - new SnippetFrameStateCleanupPhase().apply(graph); - new DeadCodeEliminationPhase().apply(graph); - - new InsertStateAfterPlaceholderPhase().apply(graph); - } - - public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable<StructuredGraph>() { - - @Override - public StructuredGraph call() throws Exception { - StructuredGraph graph = parseGraph(method, policy); - - finalizeGraph(method, graph); - - Debug.dump(graph, "%s: Final", method.getName()); - - return graph; - } - }); - } - - private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - StructuredGraph graph = graphCache.get(method); - if (graph == null) { - graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); - graphCache.put(method, graph); - } - return graph; - } - - /** - * Builds the initial graph for a snippet. - */ - protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod method) { - final StructuredGraph graph = new StructuredGraph(method); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); - GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); - graphBuilder.apply(graph); - - Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); - - new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); - new SnippetIntrinsificationPhase(runtime, pool).apply(graph); - - return graph; - } - - /** - * Called after a graph is inlined. - * - * @param caller the graph into which {@code callee} was inlined - * @param callee the graph that was inlined into {@code caller} - */ - protected void afterInline(StructuredGraph caller, StructuredGraph callee) { - if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(runtime, target.wordKind).apply(caller); - new CanonicalizerPhase(runtime, assumptions).apply(caller); - } - } - - /** - * Called after all inlining for a given graph is complete. - */ - protected void afterInlining(StructuredGraph graph) { - new SnippetIntrinsificationPhase(runtime, pool).apply(graph); - - new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); - - new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); - } - } - - private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : method; - final StructuredGraph graph = buildInitialGraph(method); - - for (Invoke invoke : graph.getInvokes()) { - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod callee = callTarget.targetMethod(); - if (callee == substitute) { - final StructuredGraph originalGraph = new StructuredGraph(original); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); - InliningUtil.inline(invoke, originalGraph, true); - - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, originalGraph); - 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); - afterInline(graph, targetGraph); - } - } - } - - afterInlining(graph); - - for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { - end.disableSafepoint(); - } - - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(graph); - new ComputeProbabilityPhase().apply(graph); - } - return graph; - } - - private static String originalName(Method substituteMethod, String methodSubstitution) { - if (methodSubstitution.isEmpty()) { - return substituteMethod.getName(); - } else { - return methodSubstitution; - } - } - - /** - * Resolves a name to a class. - * - * @param className the name of the class to resolve - * @param optional if true, resolution failure returns null - * @return the resolved class or null if resolution fails and {@code optional} is true - */ - private static Class resolveType(String className, boolean optional) { - try { - // Need to use launcher class path to handle classes - // that are not on the boot class path - ClassLoader cl = Launcher.getLauncher().getClassLoader(); - return Class.forName(className, false, cl); - } catch (ClassNotFoundException e) { - if (optional) { - return null; - } - throw new GraalInternalError("Could not resolve type " + className); - } - } - - private static Class resolveType(JavaType type) { - JavaType base = type; - int dimensions = 0; - while (base.getComponentType() != null) { - base = base.getComponentType(); - dimensions++; - } - - Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false); - return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass(); - } - - private Class[] originalParameters(Method substituteMethod, String methodSubstitution, boolean isStatic) { - Class[] parameters; - if (methodSubstitution.isEmpty()) { - parameters = substituteMethod.getParameterTypes(); - if (!isStatic) { - assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter"; - parameters = Arrays.copyOfRange(parameters, 1, parameters.length); - } - } else { - Signature signature = runtime.parseMethodDescriptor(methodSubstitution); - parameters = new Class[signature.getParameterCount(false)]; - for (int i = 0; i < parameters.length; i++) { - parameters[i] = resolveType(signature.getParameterType(i, null)); - } - } - return parameters; - } - - private static Member originalMethod(ClassSubstitution classSubstitution, String name, Class[] parameters) { - Class<?> originalClass = classSubstitution.value(); - if (originalClass == ClassSubstitution.class) { - originalClass = resolveType(classSubstitution.className(), classSubstitution.optional()); - if (originalClass == null) { - // optional class was not found - return null; - } - } - try { - if (name.equals("<init>")) { - return originalClass.getDeclaredConstructor(parameters); - } else { - return originalClass.getDeclaredMethod(name, parameters); - } - } catch (NoSuchMethodException | SecurityException e) { - throw new GraalInternalError(e); - } - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import static com.oracle.graal.api.meta.MetaUtil.*; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.Snippet.Fold; - -public class SnippetIntrinsificationPhase extends Phase { - - private final MetaAccessProvider runtime; - private final BoxingMethodPool pool; - - public SnippetIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) { - this.runtime = runtime; - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke i : graph.getInvokes()) { - if (i.callTarget() instanceof MethodCallTargetNode) { - tryIntrinsify(i); - } - } - } - - public static Class<?>[] signatureToTypes(Signature signature, ResolvedJavaType accessingClass) { - int count = signature.getParameterCount(false); - Class<?>[] result = new Class<?>[count]; - for (int i = 0; i < result.length; ++i) { - result[i] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader()); - } - return result; - } - - private boolean tryIntrinsify(Invoke invoke) { - ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); - NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); - ResolvedJavaType declaringClass = target.getDeclaringClass(); - if (intrinsic != null) { - assert target.getAnnotation(Fold.class) == null; - assert Modifier.isNative(target.getModifiers()) : "node intrinsic " + target + " should be native"; - - Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); - ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass); - - // Prepare the arguments for the reflective constructor call on the node class. - Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); - if (nodeConstructorArguments == null) { - return false; - } - - // Create the new node instance. - Class<?> c = getNodeClass(target, intrinsic); - Node newInstance = createNodeInstance(c, parameterTypes, returnType, intrinsic.setStampFromReturnType(), nodeConstructorArguments); - - // Replace the invoke with the new node. - invoke.node().graph().add(newInstance); - invoke.intrinsify(newInstance); - - // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(newInstance); - } else if (target.getAnnotation(Fold.class) != null) { - Class<?>[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); - - // Prepare the arguments for the reflective method call - Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); - if (arguments == null) { - return false; - } - Object receiver = null; - if (!invoke.methodCallTarget().isStatic()) { - receiver = arguments[0]; - arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray(); - } - - // Call the method - Constant constant = callMethod(target.getSignature().getReturnKind(), getMirrorOrFail(declaringClass, Thread.currentThread().getContextClassLoader()), target.getName(), parameterTypes, - receiver, arguments); - - if (constant != null) { - // Replace the invoke with the result of the call - ConstantNode node = ConstantNode.forConstant(constant, runtime, invoke.node().graph()); - invoke.intrinsify(node); - - // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(node); - } else { - // Remove the invoke - invoke.intrinsify(null); - } - } - return true; - } - - /** - * Converts the arguments of an invoke node to object values suitable for use as the arguments - * to a reflective invocation of a Java constructor or method. - * - * @param folding specifies if the invocation is for handling a {@link Fold} annotation - * @return the arguments for the reflective invocation or null if an argument of {@code invoke} - * that is expected to be constant isn't - */ - private Object[] prepareArguments(Invoke invoke, Class<?>[] parameterTypes, ResolvedJavaMethod target, boolean folding) { - NodeInputList<ValueNode> arguments = invoke.callTarget().arguments(); - Object[] reflectionCallArguments = new Object[arguments.size()]; - for (int i = 0; i < reflectionCallArguments.length; ++i) { - int parameterIndex = i; - if (!invoke.methodCallTarget().isStatic()) { - parameterIndex--; - } - ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); - if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { - if (!(argument instanceof ConstantNode)) { - return null; - } - ConstantNode constantNode = (ConstantNode) argument; - Constant constant = constantNode.asConstant(); - Object o = constant.asBoxedValue(); - if (o instanceof Class<?>) { - reflectionCallArguments[i] = runtime.lookupJavaType((Class<?>) o); - parameterTypes[i] = ResolvedJavaType.class; - } else { - if (parameterTypes[i] == boolean.class) { - reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0); - } else if (parameterTypes[i] == byte.class) { - reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt()); - } else if (parameterTypes[i] == short.class) { - reflectionCallArguments[i] = Short.valueOf((short) constant.asInt()); - } else if (parameterTypes[i] == char.class) { - reflectionCallArguments[i] = Character.valueOf((char) constant.asInt()); - } else { - reflectionCallArguments[i] = o; - } - } - } else { - reflectionCallArguments[i] = argument; - parameterTypes[i] = ValueNode.class; - } - } - return reflectionCallArguments; - } - - private static Class<?> getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { - Class<?> result = intrinsic.value(); - if (result == NodeIntrinsic.class) { - return getMirrorOrFail(target.getDeclaringClass(), Thread.currentThread().getContextClassLoader()); - } - assert Node.class.isAssignableFrom(result); - return result; - } - - private ValueNode tryBoxingElimination(int parameterIndex, ResolvedJavaMethod target, ValueNode node) { - if (parameterIndex >= 0) { - Type type = target.getGenericParameterTypes()[parameterIndex]; - if (type instanceof TypeVariable) { - TypeVariable typeVariable = (TypeVariable) type; - if (typeVariable.getBounds().length == 1) { - Type boundType = typeVariable.getBounds()[0]; - if (boundType instanceof Class && ((Class) boundType).getSuperclass() == null) { - // Unbound generic => try boxing elimination - if (node.usages().count() == 2) { - if (node instanceof Invoke) { - Invoke invokeNode = (Invoke) node; - MethodCallTargetNode callTarget = invokeNode.methodCallTarget(); - if (pool.isBoxingMethod(callTarget.targetMethod())) { - FrameState stateAfter = invokeNode.stateAfter(); - assert stateAfter.usages().count() == 1; - invokeNode.node().replaceAtUsages(null); - ValueNode result = callTarget.arguments().get(0); - StructuredGraph graph = (StructuredGraph) node.graph(); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; - - invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - stateAfter.safeDelete(); - GraphUtil.propagateKill(callTarget); - return result; - } - } - } - } - } - } - } - return node; - } - - private static Class asBoxedType(Class type) { - if (!type.isPrimitive()) { - return type; - } - - if (Boolean.TYPE == type) { - return Boolean.class; - } - if (Character.TYPE == type) { - return Character.class; - } - if (Byte.TYPE == type) { - return Byte.class; - } - if (Short.TYPE == type) { - return Short.class; - } - if (Integer.TYPE == type) { - return Integer.class; - } - if (Long.TYPE == type) { - return Long.class; - } - if (Float.TYPE == type) { - return Float.class; - } - assert Double.TYPE == type; - return Double.class; - } - - static final int VARARGS = 0x00000080; - - private static Node createNodeInstance(Class<?> nodeClass, Class<?>[] parameterTypes, ResolvedJavaType returnType, boolean setStampFromReturnType, Object[] nodeConstructorArguments) { - Object[] arguments = null; - Constructor<?> constructor = null; - nextConstructor: for (Constructor c : nodeClass.getDeclaredConstructors()) { - Class[] signature = c.getParameterTypes(); - if ((c.getModifiers() & VARARGS) != 0) { - int fixedArgs = signature.length - 1; - if (parameterTypes.length < fixedArgs) { - continue nextConstructor; - } - - for (int i = 0; i < fixedArgs; i++) { - if (!parameterTypes[i].equals(signature[i])) { - continue nextConstructor; - } - } - - Class componentType = signature[fixedArgs].getComponentType(); - assert componentType != null : "expected last parameter of varargs constructor " + c + " to be an array type"; - Class boxedType = asBoxedType(componentType); - for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { - if (!boxedType.isInstance(nodeConstructorArguments[i])) { - continue nextConstructor; - } - } - - arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1); - int varargsLength = nodeConstructorArguments.length - fixedArgs; - Object varargs = Array.newInstance(componentType, varargsLength); - for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { - Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i]); - } - arguments[fixedArgs] = varargs; - constructor = c; - break; - } else if (Arrays.equals(parameterTypes, signature)) { - arguments = nodeConstructorArguments; - constructor = c; - break; - } - } - if (constructor == null) { - throw new GraalInternalError("Could not find constructor in " + nodeClass + " compatible with signature " + Arrays.toString(parameterTypes)); - } - constructor.setAccessible(true); - try { - ValueNode intrinsicNode = (ValueNode) constructor.newInstance(arguments); - if (setStampFromReturnType) { - if (returnType.getKind() == Kind.Object) { - intrinsicNode.setStamp(StampFactory.declared(returnType)); - } else { - intrinsicNode.setStamp(StampFactory.forKind(returnType.getKind())); - } - } - return intrinsicNode; - } catch (Exception e) { - throw new RuntimeException(constructor + Arrays.toString(nodeConstructorArguments), e); - } - } - - /** - * Calls a Java method via reflection. - */ - private static Constant callMethod(Kind returnKind, Class<?> holder, String name, Class<?>[] parameterTypes, Object receiver, Object[] arguments) { - Method method; - try { - method = holder.getDeclaredMethod(name, parameterTypes); - method.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - try { - Object result = method.invoke(receiver, arguments); - if (result == null) { - return null; - } - return Constant.forBoxed(returnKind, result); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private static String sourceLocation(Node n) { - String loc = GraphUtil.approxSourceLocation(n); - return loc == null ? "<unknown>" : loc; - } - - public void cleanUpReturnCheckCast(Node newInstance) { - if (newInstance instanceof ValueNode && (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { - StructuredGraph graph = (StructuredGraph) newInstance.graph(); - for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { - for (ProxyNode vpn : checkCastNode.usages().filter(ProxyNode.class).snapshot()) { - graph.replaceFloating(vpn, checkCastNode); - } - for (Node checkCastUsage : checkCastNode.usages().snapshot()) { - if (checkCastUsage instanceof ValueAnchorNode) { - ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; - graph.removeFixed(valueAnchorNode); - } else if (checkCastUsage instanceof MethodCallTargetNode) { - MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; - if (pool.isUnboxingMethod(checkCastCallTarget.targetMethod())) { - Invoke invokeNode = checkCastCallTarget.invoke(); - invokeNode.node().replaceAtUsages(newInstance); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; - - invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - checkCastCallTarget.safeDelete(); - } else { - assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) + - " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + - checkCastCallTarget.targetMethod(); - checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); - } - } else if (checkCastUsage instanceof FrameState) { - checkCastUsage.replaceFirstInput(checkCastNode, null); - } else if (checkCastUsage instanceof ReturnNode && checkCastNode.object().stamp() == StampFactory.forNodeIntrinsic()) { - checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); - } else { - assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode); - } - } - FixedNode next = checkCastNode.next(); - checkCastNode.setNext(null); - checkCastNode.replaceAtPredecessor(next); - GraphUtil.killCFG(checkCastNode); - } - } - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationVerificationPhase.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.snippets.Snippet.Fold; - -/** - * Checks that a graph contains no calls to {@link NodeIntrinsic} or {@link Fold} methods. - */ -public class SnippetIntrinsificationVerificationPhase extends Phase { - - public static boolean verify(StructuredGraph graph) { - new SnippetIntrinsificationVerificationPhase().apply(graph); - return true; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke i : graph.getInvokes()) { - if (i.callTarget() instanceof MethodCallTargetNode) { - checkInvoke(i); - } - } - } - - private static void checkInvoke(Invoke invoke) { - ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); - NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); - if (intrinsic != null) { - throw new GraalInternalError("Illegal call to node intrinsic in " + invoke.graph() + ": " + invoke); - } else if (target.getAnnotation(Fold.class) != null) { - throw new GraalInternalError("Illegal call to foldable method in " + invoke.graph() + ": " + invoke); - } - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetProvider.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.compiler.target.*; - -public interface SnippetProvider { - - void installSnippets(Backend backend, SnippetInstaller installer, Assumptions assumptions); -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,755 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import java.lang.reflect.*; -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.loop.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Parameter; -import com.oracle.graal.snippets.Snippet.Varargs; -import com.oracle.graal.snippets.Snippet.VarargsParameter; -import com.oracle.graal.snippets.nodes.*; -import com.oracle.graal.word.*; -import com.oracle.graal.word.phases.*; - -/** - * A snippet template is a graph created by parsing a snippet method and then specialized by binding - * constants to the snippet's {@link ConstantParameter} parameters. - * - * Snippet templates can be managed in a {@link Cache}. - */ -public class SnippetTemplate { - - /** - * A snippet template key encapsulates the method from which a snippet was built and the - * arguments used to specialize the snippet. - * - * @see Cache - */ - public static class Key implements Iterable<Map.Entry<String, Object>> { - - public final ResolvedJavaMethod method; - private final HashMap<String, Object> map = new HashMap<>(); - private int hash; - - public Key(ResolvedJavaMethod method) { - this.method = method; - this.hash = method.hashCode(); - } - - public Key add(String name, Object value) { - assert !map.containsKey(name); - map.put(name, value); - hash = hash ^ name.hashCode(); - if (value != null) { - hash *= (value.hashCode() + 1); - } - return this; - } - - public int length() { - return map.size(); - } - - public Object get(String name) { - return map.get(name); - } - - @Override - public Iterator<Entry<String, Object>> iterator() { - return map.entrySet().iterator(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Key) { - Key other = (Key) obj; - return other.method == method && other.map.equals(map); - } - return false; - } - - @Override - public int hashCode() { - return hash; - } - - @Override - public String toString() { - return MetaUtil.format("%h.%n", method) + map.toString(); - } - - public Set<String> names() { - return map.keySet(); - } - } - - /** - * Arguments used to instantiate a template. - */ - public static class Arguments implements Iterable<Map.Entry<String, Object>> { - - private final HashMap<String, Object> map = new HashMap<>(); - - public static Arguments arguments(String name, Object value) { - return new Arguments().add(name, value); - } - - public Arguments add(String name, Object value) { - assert !map.containsKey(name); - map.put(name, value); - return this; - } - - public int length() { - return map.size(); - } - - @Override - public Iterator<Entry<String, Object>> iterator() { - return map.entrySet().iterator(); - } - - @Override - public String toString() { - return map.toString(); - } - } - - /** - * A collection of snippet templates accessed by a {@link Key} instance. - */ - public static class Cache { - - private final ConcurrentHashMap<SnippetTemplate.Key, SnippetTemplate> templates = new ConcurrentHashMap<>(); - private final MetaAccessProvider runtime; - private final TargetDescription target; - - public Cache(MetaAccessProvider runtime, TargetDescription target) { - this.runtime = runtime; - this.target = target; - } - - /** - * Gets a template for a given key, creating it first if necessary. - */ - public SnippetTemplate get(final SnippetTemplate.Key key, final Assumptions assumptions) { - SnippetTemplate template = templates.get(key); - if (template == null) { - template = Debug.scope("SnippetSpecialization", key.method, new Callable<SnippetTemplate>() { - - @Override - public SnippetTemplate call() throws Exception { - return new SnippetTemplate(runtime, assumptions, target, key); - } - }); - // System.out.println(key + " -> " + template); - templates.put(key, template); - } - return template; - } - } - - public abstract static class AbstractTemplates<T extends SnippetsInterface> { - - protected final Cache cache; - protected final MetaAccessProvider runtime; - protected final Assumptions assumptions; - protected Class<?> snippetsClass; - - public AbstractTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class<T> snippetsClass) { - this.runtime = runtime; - this.assumptions = assumptions; - if (snippetsClass == null) { - assert this instanceof SnippetsInterface; - this.snippetsClass = getClass(); - } else { - this.snippetsClass = snippetsClass; - } - this.cache = new Cache(runtime, target); - } - - protected ResolvedJavaMethod snippet(String name, Class<?>... parameterTypes) { - try { - ResolvedJavaMethod snippet = runtime.lookupJavaMethod(snippetsClass.getDeclaredMethod(name, parameterTypes)); - assert snippet.getAnnotation(Snippet.class) != null : "snippet is not annotated with @" + Snippet.class.getSimpleName(); - return snippet; - } catch (NoSuchMethodException e) { - throw new GraalInternalError(e); - } - } - } - - private static final Object UNUSED_PARAMETER = "DEAD PARAMETER"; - - /** - * Determines if any parameter of a given method is annotated with {@link ConstantParameter}. - */ - public static boolean hasConstantParameter(ResolvedJavaMethod method) { - for (ConstantParameter p : MetaUtil.getParameterAnnotations(ConstantParameter.class, method)) { - if (p != null) { - return true; - } - } - return false; - } - - /** - * Creates a snippet template. - */ - public SnippetTemplate(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, SnippetTemplate.Key key) { - ResolvedJavaMethod method = key.method; - assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + method; - Signature signature = method.getSignature(); - - // Copy snippet graph, replacing constant parameters with given arguments - StructuredGraph snippetGraph = (StructuredGraph) method.getCompilerStorage().get(Graph.class); - StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); - IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>(); - replacements.put(snippetGraph.start(), snippetCopy.start()); - - int parameterCount = signature.getParameterCount(false); - assert checkTemplate(runtime, key, parameterCount, method, signature); - - Parameter[] parameterAnnotations = new Parameter[parameterCount]; - VarargsParameter[] varargsParameterAnnotations = new VarargsParameter[parameterCount]; - ConstantNode[] placeholders = new ConstantNode[parameterCount]; - for (int i = 0; i < parameterCount; i++) { - ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); - if (c != null) { - String name = c.value(); - Object arg = key.get(name); - Kind kind = signature.getParameterKind(i); - Constant constantArg; - if (arg instanceof Constant) { - constantArg = (Constant) arg; - } else { - constantArg = Constant.forBoxed(kind, arg); - } - replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(constantArg, runtime, snippetCopy)); - } else { - VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); - if (vp != null) { - String name = vp.value(); - Varargs varargs = (Varargs) key.get(name); - Object array = varargs.getArray(); - ConstantNode placeholder = ConstantNode.forObject(array, runtime, snippetCopy); - replacements.put(snippetGraph.getLocal(i), placeholder); - placeholders[i] = placeholder; - varargsParameterAnnotations[i] = vp; - } else { - parameterAnnotations[i] = MetaUtil.getParameterAnnotation(Parameter.class, i, method); - } - } - } - snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); - - Debug.dump(snippetCopy, "Before specialization"); - if (!replacements.isEmpty()) { - // Do deferred intrinsification of node intrinsics - new SnippetIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy); - new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy); - - new CanonicalizerPhase(runtime, assumptions, 0, null).apply(snippetCopy); - } - assert SnippetIntrinsificationVerificationPhase.verify(snippetCopy); - - // Gather the template parameters - parameters = new HashMap<>(); - for (int i = 0; i < parameterCount; i++) { - VarargsParameter vp = varargsParameterAnnotations[i]; - if (vp != null) { - assert snippetCopy.getLocal(i) == null; - Varargs varargs = (Varargs) key.get(vp.value()); - Object array = varargs.getArray(); - int length = Array.getLength(array); - LocalNode[] locals = new LocalNode[length]; - Stamp stamp = varargs.getArgStamp(); - for (int j = 0; j < length; j++) { - assert (parameterCount & 0xFFFF) == parameterCount; - int idx = i << 16 | j; - LocalNode local = snippetCopy.unique(new LocalNode(idx, stamp)); - locals[j] = local; - } - parameters.put(vp.value(), locals); - - ConstantNode placeholder = placeholders[i]; - assert placeholder != null; - for (Node usage : placeholder.usages().snapshot()) { - if (usage instanceof LoadIndexedNode) { - LoadIndexedNode loadIndexed = (LoadIndexedNode) usage; - Debug.dump(snippetCopy, "Before replacing %s", loadIndexed); - LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(locals, loadIndexed.index(), loadIndexed.stamp())); - snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter); - Debug.dump(snippetCopy, "After replacing %s", loadIndexed); - } - } - } else { - Parameter p = parameterAnnotations[i]; - if (p != null) { - LocalNode local = snippetCopy.getLocal(i); - if (local == null) { - // Parameter value was eliminated - parameters.put(p.value(), UNUSED_PARAMETER); - } else { - parameters.put(p.value(), local); - } - } - } - } - - // Do any required loop explosion - boolean exploded = false; - do { - exploded = false; - ExplodeLoopNode explodeLoop = snippetCopy.getNodes().filter(ExplodeLoopNode.class).first(); - if (explodeLoop != null) { // Earlier canonicalization may have removed the loop - // altogether - LoopBeginNode loopBegin = explodeLoop.findLoopBegin(); - if (loopBegin != null) { - LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin); - int mark = snippetCopy.getMark(); - LoopTransformations.fullUnroll(loop, runtime, null); - new CanonicalizerPhase(runtime, assumptions, mark, null).apply(snippetCopy); - } - FixedNode explodeLoopNext = explodeLoop.next(); - explodeLoop.clearSuccessors(); - explodeLoop.replaceAtPredecessor(explodeLoopNext); - explodeLoop.replaceAtUsages(null); - GraphUtil.killCFG(explodeLoop); - exploded = true; - } - } while (exploded); - - // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free - // of side-effects that prevent deoptimizing to a point before the snippet). - ArrayList<StateSplit> curSideEffectNodes = new ArrayList<>(); - ArrayList<ValueNode> curStampNodes = new ArrayList<>(); - for (Node node : snippetCopy.getNodes()) { - if (node instanceof ValueNode && ((ValueNode) node).stamp() == StampFactory.forNodeIntrinsic()) { - curStampNodes.add((ValueNode) node); - } - if (node instanceof StateSplit) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - if (stateSplit.hasSideEffect()) { - curSideEffectNodes.add((StateSplit) node); - } - if (frameState != null) { - stateSplit.setStateAfter(null); - } - } - } - - new DeadCodeEliminationPhase().apply(snippetCopy); - - assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders); - - this.snippet = snippetCopy; - ReturnNode retNode = null; - StartNode entryPointNode = snippet.start(); - - new DeadCodeEliminationPhase().apply(snippetCopy); - - nodes = new ArrayList<>(snippet.getNodeCount()); - for (Node node : snippet.getNodes()) { - if (node == entryPointNode || node == entryPointNode.stateAfter()) { - // Do nothing. - } else { - nodes.add(node); - if (node instanceof ReturnNode) { - retNode = (ReturnNode) node; - } - } - } - - this.sideEffectNodes = curSideEffectNodes; - this.stampNodes = curStampNodes; - this.returnNode = retNode; - } - - private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, ConstantNode[] placeholders) { - for (int i = 0; i < parameterCount; i++) { - if (placeholders[i] != null) { - assert placeholders[i].isDeleted() : placeholders[i]; - } - } - return true; - } - - private static boolean checkConstantArgument(MetaAccessProvider runtime, final ResolvedJavaMethod method, Signature signature, int i, String name, Object arg, Kind kind) { - ResolvedJavaType type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass()); - if (runtime.lookupJavaType(WordBase.class).isAssignableFrom(type)) { - assert arg instanceof Constant : method + ": word constant parameters must be passed boxed in a Constant value: " + arg; - return true; - } - if (kind == Kind.Object) { - assert arg == null || type.isInstance(Constant.forObject(arg)) : method + ": wrong value type for " + name + ": expected " + type.getName() + ", got " + arg.getClass().getName(); - } else { - assert arg != null && kind.toBoxedJavaClass() == arg.getClass() : method + ": wrong value kind for " + name + ": expected " + kind + ", got " + - (arg == null ? "null" : arg.getClass().getSimpleName()); - } - return true; - } - - private static boolean checkVarargs(final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) { - Object arg = varargs.getArray(); - ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass()); - assert type.isArray() : "varargs parameter must be an array type"; - assert type.isInstance(Constant.forObject(arg)) : "value for " + name + " is not a " + MetaUtil.toJavaName(type) + " instance: " + arg; - return true; - } - - /** - * The graph built from the snippet method. - */ - private final StructuredGraph snippet; - - /** - * The named parameters of this template that must be bound to values during instantiation. For - * a parameter that is still live after specialization, the value in this map is either a - * {@link LocalNode} instance or a {@link LocalNode} array. For an eliminated parameter, the - * value is identical to the key. - */ - private final Map<String, Object> parameters; - - /** - * The return node (if any) of the snippet. - */ - private final ReturnNode returnNode; - - /** - * Nodes that inherit the {@link StateSplit#stateAfter()} from the replacee during - * instantiation. - */ - private final ArrayList<StateSplit> sideEffectNodes; - - /** - * The nodes that inherit the {@link ValueNode#stamp()} from the replacee during instantiation. - */ - private final ArrayList<ValueNode> stampNodes; - - /** - * The nodes to be inlined when this specialization is instantiated. - */ - private final ArrayList<Node> nodes; - - /** - * Gets the instantiation-time bindings to this template's parameters. - * - * @return the map that will be used to bind arguments to parameters when inlining this template - */ - private IdentityHashMap<Node, Node> bind(StructuredGraph replaceeGraph, MetaAccessProvider runtime, SnippetTemplate.Arguments args) { - IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>(); - assert args.length() == parameters.size() : "number of args (" + args.length() + ") != number of parameters (" + parameters.size() + ")"; - for (Map.Entry<String, Object> e : args) { - String name = e.getKey(); - Object parameter = parameters.get(name); - assert parameter != null : this + " has no parameter named " + name; - Object argument = e.getValue(); - if (parameter instanceof LocalNode) { - if (argument instanceof ValueNode) { - replacements.put((LocalNode) parameter, (ValueNode) argument); - } else { - Kind kind = ((LocalNode) parameter).kind(); - assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + name; - Constant constant = Constant.forBoxed(kind, argument); - replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph)); - } - } else if (parameter instanceof LocalNode[]) { - LocalNode[] locals = (LocalNode[]) parameter; - int length = locals.length; - List list = null; - Object array = null; - if (argument instanceof List) { - list = (List) argument; - assert list.size() == length : length + " != " + list.size(); - } else { - array = argument; - assert array != null && array.getClass().isArray(); - assert Array.getLength(array) == length : length + " != " + Array.getLength(array); - } - - for (int j = 0; j < length; j++) { - LocalNode local = locals[j]; - assert local != null; - Object value = list != null ? list.get(j) : Array.get(array, j); - if (value instanceof ValueNode) { - replacements.put(local, (ValueNode) value); - } else { - Constant constant = Constant.forBoxed(local.kind(), value); - ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph); - replacements.put(local, element); - } - } - } else { - assert parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + name + " -> " + parameter; - } - } - return replacements; - } - - /** - * Logic for replacing a snippet-lowered node at its usages with the return value of the - * snippet. An alternative to the {@linkplain SnippetTemplate#DEFAULT_REPLACER default} - * replacement logic can be used to handle mismatches between the stamp of the node being - * lowered and the stamp of the snippet's return value. - */ - public interface UsageReplacer { - - /** - * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}. - */ - void replace(ValueNode oldNode, ValueNode newNode); - } - - /** - * Represents the default {@link UsageReplacer usage replacer} logic which simply delegates to - * {@link Node#replaceAtUsages(Node)}. - */ - public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() { - - @Override - public void replace(ValueNode oldNode, ValueNode newNode) { - oldNode.replaceAtUsages(newNode); - } - }; - - /** - * Replaces a given fixed node with this specialized snippet. - * - * @param runtime - * @param replacee the node that will be replaced - * @param replacer object that replaces the usages of {@code replacee} - * @param args the arguments to be bound to the flattened positional parameters of the snippet - * @return the map of duplicated nodes (original -> duplicate) - */ - public Map<Node, Node> instantiate(MetaAccessProvider runtime, FixedNode replacee, UsageReplacer replacer, SnippetTemplate.Arguments args) { - - // Inline the snippet nodes, replacing parameters with the given args in the process - String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; - StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); - StartNode entryPointNode = snippet.start(); - FixedNode firstCFGNode = entryPointNode.next(); - StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); - IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, runtime, args); - Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements); - Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); - - // Re-wire the control flow graph around the replacee - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - replacee.replaceAtPredecessor(firstCFGNodeDuplicate); - FixedNode next = null; - if (replacee instanceof FixedWithNextNode) { - FixedWithNextNode fwn = (FixedWithNextNode) replacee; - next = fwn.next(); - fwn.setNext(null); - } - - if (replacee instanceof StateSplit) { - for (StateSplit sideEffectNode : sideEffectNodes) { - assert ((StateSplit) replacee).hasSideEffect(); - Node sideEffectDup = duplicates.get(sideEffectNode); - ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); - } - } - for (ValueNode stampNode : stampNodes) { - Node stampDup = duplicates.get(stampNode); - ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); - } - - // Replace all usages of the replacee with the value returned by the snippet - ValueNode returnValue = null; - if (returnNode != null) { - if (returnNode.result() instanceof LocalNode) { - returnValue = (ValueNode) replacements.get(returnNode.result()); - } else { - returnValue = (ValueNode) duplicates.get(returnNode.result()); - } - assert returnValue != null || replacee.usages().isEmpty(); - replacer.replace(replacee, returnValue); - - Node returnDuplicate = duplicates.get(returnNode); - if (returnDuplicate.isAlive()) { - returnDuplicate.clearInputs(); - returnDuplicate.replaceAndDelete(next); - } - } - - // Remove the replacee from its graph - replacee.clearInputs(); - replacee.replaceAtUsages(null); - GraphUtil.killCFG(replacee); - - Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); - return duplicates; - } - - /** - * Gets a copy of the specialized graph. - */ - public StructuredGraph copySpecializedGraph() { - return snippet.copy(); - } - - /** - * Replaces a given floating node with this specialized snippet. - * - * @param runtime - * @param replacee the node that will be replaced - * @param replacer object that replaces the usages of {@code replacee} - * @param args the arguments to be bound to the flattened positional parameters of the snippet - */ - public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, SnippetTemplate.Arguments args) { - - // Inline the snippet nodes, replacing parameters with the given args in the process - String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; - StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method()); - StartNode entryPointNode = snippet.start(); - FixedNode firstCFGNode = entryPointNode.next(); - StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph(); - IdentityHashMap<Node, Node> replacements = bind(replaceeGraph, runtime, args); - Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements); - Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); - - FixedWithNextNode lastFixedNode = tool.lastFixedNode(); - assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph; - FixedNode next = lastFixedNode.next(); - lastFixedNode.setNext(null); - FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - replaceeGraph.addAfterFixed(lastFixedNode, firstCFGNodeDuplicate); - - if (replacee instanceof StateSplit) { - for (StateSplit sideEffectNode : sideEffectNodes) { - assert ((StateSplit) replacee).hasSideEffect(); - Node sideEffectDup = duplicates.get(sideEffectNode); - ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); - } - } - for (ValueNode stampNode : stampNodes) { - Node stampDup = duplicates.get(stampNode); - ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); - } - - // Replace all usages of the replacee with the value returned by the snippet - assert returnNode != null : replaceeGraph; - ValueNode returnValue = null; - if (returnNode.result() instanceof LocalNode) { - returnValue = (ValueNode) replacements.get(returnNode.result()); - } else { - returnValue = (ValueNode) duplicates.get(returnNode.result()); - } - assert returnValue != null || replacee.usages().isEmpty(); - replacer.replace(replacee, returnValue); - - tool.setLastFixedNode(null); - Node returnDuplicate = duplicates.get(returnNode); - if (returnDuplicate.isAlive()) { - returnDuplicate.clearInputs(); - returnDuplicate.replaceAndDelete(next); - if (next != null && next.predecessor() instanceof FixedWithNextNode) { - tool.setLastFixedNode((FixedWithNextNode) next.predecessor()); - } - } - - Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(snippet.toString()).append('('); - String sep = ""; - for (Map.Entry<String, Object> e : parameters.entrySet()) { - String name = e.getKey(); - Object value = e.getValue(); - buf.append(sep); - sep = ", "; - if (value == UNUSED_PARAMETER) { - buf.append("<unused> ").append(name); - } else if (value instanceof LocalNode) { - LocalNode local = (LocalNode) value; - buf.append(local.kind().getJavaName()).append(' ').append(name); - } else { - LocalNode[] locals = (LocalNode[]) value; - String kind = locals.length == 0 ? "?" : locals[0].kind().getJavaName(); - buf.append(kind).append('[').append(locals.length).append("] ").append(name); - } - } - return buf.append(')').toString(); - } - - private static boolean checkTemplate(MetaAccessProvider runtime, SnippetTemplate.Key key, int parameterCount, ResolvedJavaMethod method, Signature signature) { - Set<String> expected = new HashSet<>(); - for (int i = 0; i < parameterCount; i++) { - ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); - VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); - Parameter p = MetaUtil.getParameterAnnotation(Parameter.class, i, method); - if (c != null) { - assert vp == null && p == null; - String name = c.value(); - expected.add(name); - Kind kind = signature.getParameterKind(i); - assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; - assert checkConstantArgument(runtime, method, signature, i, c.value(), key.get(name), kind); - } else if (vp != null) { - assert p == null; - String name = vp.value(); - expected.add(name); - assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; - assert key.get(name) instanceof Varargs; - Varargs varargs = (Varargs) key.get(name); - assert checkVarargs(method, signature, i, name, varargs); - } else { - assert p != null : method + ": parameter " + i + " must be annotated with exactly one of " + "@" + ConstantParameter.class.getSimpleName() + " or " + "@" + - VarargsParameter.class.getSimpleName() + " or " + "@" + Parameter.class.getSimpleName(); - } - } - if (!key.names().containsAll(expected)) { - expected.removeAll(key.names()); - assert false : expected + " missing from key " + key; - } - if (!expected.containsAll(key.names())) { - Set<String> namesCopy = new HashSet<>(key.names()); - namesCopy.removeAll(expected); - assert false : "parameter(s) " + namesCopy + " should be annotated with @" + ConstantParameter.class.getSimpleName() + " or @" + VarargsParameter.class.getSimpleName() + " in " + - MetaUtil.format("%H.%n(%p)", method); - } - return true; - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetsInterface.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -/** - * Tagging interface for interfaces or classes providing snippets. - */ -public interface SnippetsInterface { - -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsafeSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,383 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; -import com.oracle.graal.snippets.nodes.*; - -/** - * Substitutions for {@link sun.misc.Unsafe} methods. - */ -@ClassSubstitution(sun.misc.Unsafe.class) -public class UnsafeSubstitutions { - - @MethodSubstitution(isStatic = false) - public static boolean compareAndSwapObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object expected, Object x) { - return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); - } - - @MethodSubstitution(isStatic = false) - public static boolean compareAndSwapInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int expected, int x) { - return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); - } - - @MethodSubstitution(isStatic = false) - public static boolean compareAndSwapLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long expected, long x) { - return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x); - } - - @MethodSubstitution(isStatic = false) - public static Object getObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - return UnsafeLoadNode.load(o, 0, offset, Kind.Object); - } - - @MethodSubstitution(isStatic = false) - public static Object getObjectVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - Object result = getObject(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putObject(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, Object x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Object); - } - - @MethodSubstitution(isStatic = false) - public static void putObjectVolatile(final Object thisObj, Object o, long offset, Object x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putObject(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static void putOrderedObject(final Object thisObj, Object o, long offset, Object x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putObject(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static int getInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - Integer value = UnsafeLoadNode.load(o, 0, offset, Kind.Int); - return value; - } - - @MethodSubstitution(isStatic = false) - public static int getIntVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - int result = getInt(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putInt(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, int x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Int); - } - - @MethodSubstitution(isStatic = false) - public static void putIntVolatile(final Object thisObj, Object o, long offset, int x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putInt(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static void putOrderedInt(final Object thisObj, Object o, long offset, int x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putInt(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static boolean getBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Boolean result = UnsafeLoadNode.load(o, 0, offset, Kind.Boolean); - return result; - } - - @MethodSubstitution(isStatic = false) - public static boolean getBooleanVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - boolean result = getBoolean(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putBoolean(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, boolean x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Boolean); - } - - @MethodSubstitution(isStatic = false) - public static void putBooleanVolatile(final Object thisObj, Object o, long offset, boolean x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putBoolean(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static byte getByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Byte result = UnsafeLoadNode.load(o, 0, offset, Kind.Byte); - return result; - } - - @MethodSubstitution(isStatic = false) - public static byte getByteVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - byte result = getByte(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putByte(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, byte x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Byte); - } - - @MethodSubstitution(isStatic = false) - public static void putByteVolatile(final Object thisObj, Object o, long offset, byte x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putByte(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static short getShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Short result = UnsafeLoadNode.load(o, 0, offset, Kind.Short); - return result; - } - - @MethodSubstitution(isStatic = false) - public static short getShortVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - short result = getShort(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putShort(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, short x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Short); - } - - @MethodSubstitution(isStatic = false) - public static void putShortVolatile(final Object thisObj, Object o, long offset, short x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putShort(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static char getChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Character result = UnsafeLoadNode.load(o, 0, offset, Kind.Char); - return result; - } - - @MethodSubstitution(isStatic = false) - public static char getCharVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - char result = getChar(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putChar(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, char x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Char); - } - - @MethodSubstitution(isStatic = false) - public static void putCharVolatile(final Object thisObj, Object o, long offset, char x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putChar(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static long getLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Long result = UnsafeLoadNode.load(o, 0, offset, Kind.Long); - return result; - } - - @MethodSubstitution(isStatic = false) - public static long getLongVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - long result = getLong(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putLong(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, long x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Long); - } - - @MethodSubstitution(isStatic = false) - public static void putLongVolatile(final Object thisObj, Object o, long offset, long x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putLong(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static void putOrderedLong(final Object thisObj, Object o, long offset, long x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putLong(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static float getFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Float result = UnsafeLoadNode.load(o, 0, offset, Kind.Float); - return result; - } - - @MethodSubstitution(isStatic = false) - public static float getFloatVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - float result = getFloat(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putFloat(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, float x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Float); - } - - @MethodSubstitution(isStatic = false) - public static void putFloatVolatile(final Object thisObj, Object o, long offset, float x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putFloat(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static double getDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset) { - @JavacBug(id = 6995200) - Double result = UnsafeLoadNode.load(o, 0, offset, Kind.Double); - return result; - } - - @MethodSubstitution(isStatic = false) - public static double getDoubleVolatile(final Object thisObj, Object o, long offset) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_READ); - double result = getDouble(thisObj, o, offset); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_READ); - return result; - } - - @MethodSubstitution(isStatic = false) - public static void putDouble(@SuppressWarnings("unused") final Object thisObj, Object o, long offset, double x) { - UnsafeStoreNode.store(o, 0, offset, x, Kind.Double); - } - - @MethodSubstitution(isStatic = false) - public static void putDoubleVolatile(final Object thisObj, Object o, long offset, double x) { - MembarNode.memoryBarrier(MemoryBarriers.JMM_PRE_VOLATILE_WRITE); - putDouble(thisObj, o, offset, x); - MembarNode.memoryBarrier(MemoryBarriers.JMM_POST_VOLATILE_WRITE); - } - - @MethodSubstitution(isStatic = false) - public static void putByte(@SuppressWarnings("unused") final Object thisObj, long address, byte value) { - DirectStoreNode.store(address, value, Kind.Byte); - } - - @MethodSubstitution(isStatic = false) - public static void putShort(@SuppressWarnings("unused") final Object thisObj, long address, short value) { - DirectStoreNode.store(address, value, Kind.Short); - } - - @MethodSubstitution(isStatic = false) - public static void putChar(@SuppressWarnings("unused") final Object thisObj, long address, char value) { - DirectStoreNode.store(address, value, Kind.Char); - } - - @MethodSubstitution(isStatic = false) - public static void putInt(@SuppressWarnings("unused") final Object thisObj, long address, int value) { - DirectStoreNode.store(address, value, Kind.Int); - } - - @MethodSubstitution(isStatic = false) - public static void putLong(@SuppressWarnings("unused") final Object thisObj, long address, long value) { - DirectStoreNode.store(address, value, Kind.Long); - } - - @MethodSubstitution(isStatic = false) - public static void putFloat(@SuppressWarnings("unused") final Object thisObj, long address, float value) { - DirectStoreNode.store(address, value, Kind.Float); - } - - @MethodSubstitution(isStatic = false) - public static void putDouble(@SuppressWarnings("unused") final Object thisObj, long address, double value) { - DirectStoreNode.store(address, value, Kind.Double); - } - - @MethodSubstitution(isStatic = false) - public static byte getByte(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Byte); - } - - @MethodSubstitution(isStatic = false) - public static short getShort(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Short); - } - - @MethodSubstitution(isStatic = false) - public static char getChar(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Char); - } - - @MethodSubstitution(isStatic = false) - public static int getInt(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Int); - } - - @MethodSubstitution(isStatic = false) - public static long getLong(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Long); - } - - @MethodSubstitution(isStatic = false) - public static float getFloat(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Float); - } - - @MethodSubstitution(isStatic = false) - public static double getDouble(@SuppressWarnings("unused") final Object thisObj, long address) { - return DirectReadNode.read(address, Kind.Double); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsignedMathSubstitutions.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets; - -import static com.oracle.graal.nodes.calc.ConditionalNode.*; -import static com.oracle.graal.nodes.calc.Condition.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.snippets.ClassSubstitution.*; - -/** - * Substitutions for {@link UnsignedMath}. - */ -@ClassSubstitution(UnsignedMath.class) -public class UnsignedMathSubstitutions { - - @MethodSubstitution - public static boolean aboveThan(int a, int b) { - return materializeCondition(BT, b, a); - } - - @MethodSubstitution - public static boolean aboveOrEqual(int a, int b) { - return !materializeCondition(BT, a, b); - } - - /** - * Unsigned comparison belowThan for two numbers. - */ - @MethodSubstitution - public static boolean belowThan(int a, int b) { - return materializeCondition(BT, a, b); - } - - /** - * Unsigned comparison belowOrEqual for two numbers. - */ - @MethodSubstitution - public static boolean belowOrEqual(int a, int b) { - return !materializeCondition(BT, b, a); - } - - /** - * Unsigned comparison aboveThan for two numbers. - */ - @MethodSubstitution - public static boolean aboveThan(long a, long b) { - return materializeCondition(BT, b, a); - } - - /** - * Unsigned comparison aboveOrEqual for two numbers. - */ - @MethodSubstitution - public static boolean aboveOrEqual(long a, long b) { - return !materializeCondition(BT, a, b); - } - - /** - * Unsigned comparison belowThan for two numbers. - */ - @MethodSubstitution - public static boolean belowThan(long a, long b) { - return materializeCondition(BT, a, b); - } - - /** - * Unsigned comparison belowOrEqual for two numbers. - */ - @MethodSubstitution - public static boolean belowOrEqual(long a, long b) { - return !materializeCondition(BT, b, a); - } - - /** - * Unsigned division for two numbers. - */ - @MethodSubstitution - public static int divide(int a, int b) { - return unsignedDivide(Kind.Int, a, b); - } - - /** - * Unsigned remainder for two numbers. - */ - @MethodSubstitution - public static int remainder(int a, int b) { - return unsignedRemainder(Kind.Int, a, b); - } - - /** - * Unsigned division for two numbers. - */ - @MethodSubstitution - public static long divide(long a, long b) { - return unsignedDivide(Kind.Long, a, b); - } - - /** - * Unsigned remainder for two numbers. - */ - @MethodSubstitution - public static long remainder(long a, long b) { - return unsignedRemainder(Kind.Long, a, b); - } - - @NodeIntrinsic(UnsignedDivNode.class) - private static native int unsignedDivide(@ConstantNodeParameter Kind kind, int a, int b); - - @NodeIntrinsic(UnsignedDivNode.class) - private static native long unsignedDivide(@ConstantNodeParameter Kind kind, long a, long b); - - @NodeIntrinsic(UnsignedRemNode.class) - private static native int unsignedRemainder(@ConstantNodeParameter Kind kind, int a, int b); - - @NodeIntrinsic(UnsignedRemNode.class) - private static native long unsignedRemainder(@ConstantNodeParameter Kind kind, long a, long b); -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/BitCountNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class BitCountNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode value; - - public BitCountNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); - this.value = value; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(Integer.bitCount((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(Long.bitCount(v), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native int bitCount(int v); - - @NodeIntrinsic - public static native int bitCount(long v); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(Kind.Int); - gen.emitBitCount(result, gen.operand(value)); - gen.setResult(this, result); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/BitScanForwardNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class BitScanForwardNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode value; - - public BitScanForwardNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); - this.value = value; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(Integer.numberOfTrailingZeros((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(Long.numberOfTrailingZeros(v), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native int scan(long v); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(Kind.Int); - gen.emitBitScanForward(result, gen.operand(value)); - gen.setResult(this, result); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/BitScanReverseNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class BitScanReverseNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode value; - - public BitScanReverseNode(ValueNode value) { - super(StampFactory.forInteger(Kind.Int, 0, value.kind().getBitCount())); - this.value = value; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (value.kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(31 - Integer.numberOfLeadingZeros((int) v), graph()); - } else if (value.kind() == Kind.Long) { - return ConstantNode.forInt(63 - Long.numberOfLeadingZeros(v), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native int scan(int v); - - @NodeIntrinsic - public static native int scan(long v); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(Kind.Int); - gen.emitBitScanReverse(result, gen.operand(value)); - gen.setResult(this, result); - } - -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/BranchProbabilityNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2012, 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.snippets.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; - -/** - * Instances of this node class will look for a preceding if node and put the given probability into - * the if node's taken probability. Then the branch probability node will be removed. This node is - * intended primarily for snippets, so that they can define their fast and slow paths. - */ -public class BranchProbabilityNode extends FixedWithNextNode implements Simplifiable { - - public static final double LIKELY_PROBABILITY = 0.6; - public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY; - - public static final double FREQUENT_PROBABILITY = 0.9; - public static final double NOT_FREQUENT_PROBABILITY = 1 - FREQUENT_PROBABILITY; - - public static final double FAST_PATH_PROBABILITY = 0.99; - public static final double SLOW_PATH_PROBABILITY = 1 - FAST_PATH_PROBABILITY; - - public static final double NOT_DEOPT_PATH_PROBABILITY = 0.999; - public static final double DEOPT_PATH_PROBABILITY = 1 - NOT_DEOPT_PATH_PROBABILITY; - - private final double probability; - - public BranchProbabilityNode(double probability) { - super(StampFactory.forVoid()); - assert probability >= 0 && probability <= 1; - this.probability = probability; - } - - @Override - public void simplify(SimplifierTool tool) { - FixedNode current = this; - while (!(current instanceof BeginNode)) { - current = (FixedNode) current.predecessor(); - } - BeginNode begin = (BeginNode) current; - assert begin.predecessor() instanceof IfNode : "explicit branch probability cannot follow a merge, only if nodes"; - IfNode ifNode = (IfNode) begin.predecessor(); - if (ifNode.trueSuccessor() == begin) { - ifNode.setTrueSuccessorProbability(probability); - } else { - ifNode.setTrueSuccessorProbability(1 - probability); - } - - FixedNode next = next(); - setNext(null); - ((FixedWithNextNode) predecessor()).setNext(next); - GraphUtil.killCFG(this); - } - - @NodeIntrinsic - public static native void probability(@ConstantNodeParameter double probability); - -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectObjectStoreNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; - -/** - * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a - * {@link StateSplit} and does not include a write barrier. - */ -public class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable { - - @Input private ValueNode object; - @Input private ValueNode value; - @Input private ValueNode offset; - private final int displacement; - - public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value) { - super(StampFactory.forVoid()); - this.object = object; - this.value = value; - this.offset = offset; - this.displacement = displacement; - } - - @NodeIntrinsic - public static native void storeObject(Object obj, @ConstantNodeParameter int displacement, long offset, Object value); - - @NodeIntrinsic - public static native void storeLong(Object obj, @ConstantNodeParameter int displacement, long offset, long value); - - @NodeIntrinsic - public static native void storeWord(Object obj, @ConstantNodeParameter int displacement, long offset, Word value); - - @NodeIntrinsic - public static native void storeInt(Object obj, @ConstantNodeParameter int displacement, long offset, int value); - - @Override - public void lower(LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) this.graph(); - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1); - WriteNode write = graph.add(new WriteNode(object, value, location)); - graph.replaceFixedWithFixed(this, write); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a - * {@link StateSplit} and takes a computed address instead of an object. - */ -public class DirectReadNode extends FixedWithNextNode implements LIRLowerable { - - @Input private ValueNode address; - private final Kind readKind; - - public DirectReadNode(ValueNode address, Kind readKind) { - super(StampFactory.forKind(readKind)); - this.address = address; - this.readKind = readKind; - } - - @Override - public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, false)); - } - - @NodeIntrinsic - public static native <T> T read(long address, @ConstantNodeParameter Kind kind); -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * A special purpose store node that differs from {@link UnsafeStoreNode} in that it is not a - * {@link StateSplit} and takes a computed address instead of an object. - */ -public class DirectStoreNode extends FixedWithNextNode implements LIRLowerable { - - @Input private ValueNode address; - @Input private ValueNode value; - private final Kind kind; - - public DirectStoreNode(ValueNode address, ValueNode value, Kind kind) { - super(StampFactory.forVoid()); - this.address = address; - this.value = value; - this.kind = kind; - } - - @Override - public void generate(LIRGeneratorTool gen) { - Value v = gen.operand(value); - gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, false); - } - - /* - * The kind of the store is provided explicitly in these intrinsics because it is not always - * possible to determine the kind from the given value during compilation (because stack kinds - * are used). - */ - - @NodeIntrinsic - public static native void store(long address, boolean value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, byte value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, short value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, char value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, int value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, long value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, float value, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native void store(long address, double value, @ConstantNodeParameter Kind kind); -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ExplodeLoopNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.snippets.Snippet.VarargsParameter; - -/** - * Placeholder node to denote to snippet preparation that the following loop must be completely - * unrolled. - * - * @see VarargsParameter - */ -public final class ExplodeLoopNode extends FixedWithNextNode { - - public ExplodeLoopNode() { - super(StampFactory.forVoid()); - } - - public LoopBeginNode findLoopBegin() { - Node next = next(); - ArrayList<Node> succs = new ArrayList<>(); - while (!(next instanceof LoopBeginNode)) { - assert next != null : "cannot find loop after " + this; - for (Node n : next.cfgSuccessors()) { - succs.add(n); - } - if (succs.size() == 1) { - next = succs.get(0); - } else { - return null; - } - } - return (LoopBeginNode) next; - } - - /** - * A call to this method must be placed immediately prior to the loop that is to be exploded. - */ - @NodeIntrinsic - public static native void explodeLoop(); -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadSnippetVarargParameterNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.snippets.Snippet.VarargsParameter; - -/** - * Implements the semantics of {@link VarargsParameter}. - */ -public final class LoadSnippetVarargParameterNode extends FixedWithNextNode implements Canonicalizable { - - @Input private ValueNode index; - - private final LocalNode[] locals; - - public LoadSnippetVarargParameterNode(LocalNode[] locals, ValueNode index, Stamp stamp) { - super(stamp); - this.index = index; - this.locals = locals; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (index.isConstant()) { - return locals[index.asConstant().asInt()]; - } - return this; - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +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.snippets.nodes; - -import java.lang.reflect.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.phases.common.*; - -public class MacroNode extends AbstractStateSplit implements Lowerable { - - @Input protected final NodeInputList<ValueNode> arguments; - - private final int bci; - private final ResolvedJavaMethod targetMethod; - private final JavaType returnType; - - protected MacroNode(Invoke invoke) { - super(invoke.node().stamp(), invoke.stateAfter()); - this.arguments = new NodeInputList<>(this, invoke.methodCallTarget().arguments()); - this.bci = invoke.bci(); - this.targetMethod = invoke.methodCallTarget().targetMethod(); - this.returnType = invoke.methodCallTarget().returnType(); - } - - public int getBci() { - return bci; - } - - public ResolvedJavaMethod getTargetMethod() { - return targetMethod; - } - - @SuppressWarnings("unused") - protected StructuredGraph getSnippetGraph(LoweringTool tool) { - return null; - } - - @Override - public void lower(LoweringTool tool) { - StructuredGraph snippetGraph = getSnippetGraph(tool); - - InvokeNode invoke = replaceWithInvoke(); - - if (snippetGraph != null) { - InliningUtil.inline(invoke, snippetGraph, false); - } - } - - private InvokeNode replaceWithInvoke() { - InvokeNode invoke = createInvoke(); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); - return invoke; - } - - protected InvokeNode createInvoke() { - InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special; - MethodCallTargetNode callTarget = graph().add(new MethodCallTargetNode(invokeKind, targetMethod, arguments.toArray(new ValueNode[arguments.size()]), returnType)); - InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci)); - invoke.setStateAfter(stateAfter()); - return invoke; - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MathIntrinsicNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -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.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class MathIntrinsicNode extends FloatingNode implements Canonicalizable, LIRGenLowerable { - - @Input private ValueNode x; - private final Operation operation; - - public enum Operation { - ABS, SQRT, LOG, LOG10, SIN, COS, TAN - } - - public ValueNode x() { - return x; - } - - public Operation operation() { - return operation; - } - - public MathIntrinsicNode(ValueNode x, Operation op) { - super(StampFactory.forKind(x.kind())); - assert x.kind() == Kind.Double; - this.x = x; - this.operation = op; - } - - @Override - public void generate(LIRGenerator gen) { - Variable input = gen.load(gen.operand(x())); - Variable result = gen.newVariable(kind()); - switch (operation()) { - case ABS: - gen.emitMathAbs(result, input); - break; - case SQRT: - gen.emitMathSqrt(result, input); - break; - case LOG: - gen.emitMathLog(result, input, false); - break; - case LOG10: - gen.emitMathLog(result, input, true); - break; - case SIN: - gen.emitMathSin(result, input); - break; - case COS: - gen.emitMathCos(result, input); - break; - case TAN: - gen.emitMathTan(result, input); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - gen.setResult(this, result); - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (x().isConstant()) { - double value = x().asConstant().asDouble(); - switch (operation()) { - case ABS: - return ConstantNode.forDouble(Math.abs(value), graph()); - case SQRT: - return ConstantNode.forDouble(Math.sqrt(value), graph()); - case LOG: - return ConstantNode.forDouble(Math.log(value), graph()); - case LOG10: - return ConstantNode.forDouble(Math.log10(value), graph()); - case SIN: - return ConstantNode.forDouble(Math.sin(value), graph()); - case COS: - return ConstantNode.forDouble(Math.cos(value), graph()); - case TAN: - return ConstantNode.forDouble(Math.tan(value), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native double compute(double x, @ConstantNodeParameter Operation op); -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ReadRegisterNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2012, 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.snippets.nodes; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * Access the value of a specific register. - */ -@NodeInfo(nameTemplate = "ReadRegister %{p#register}") -public final class ReadRegisterNode extends FixedWithNextNode implements LIRGenLowerable { - - /** - * The fixed register to access. - */ - private final Register register; - - /** - * When true, subsequent uses of this node use the fixed register; when false, the value is - * moved into a new virtual register so that the fixed register is not seen by uses. - */ - private final boolean directUse; - - /** - * When true, this node is also an implicit definition of the value for the register allocator, - * i.e., the register is an implicit incoming value; when false, the register must be defined in - * the same method or must be an register excluded from register allocation. - */ - private final boolean incoming; - - public ReadRegisterNode(Register register, Kind kind, boolean directUse, boolean incoming) { - super(StampFactory.forKind(kind)); - this.register = register; - this.directUse = directUse; - this.incoming = incoming; - } - - /** - * Constructor to be used by node intrinsics where the stamp is inferred from the intrinsic - * definition. - */ - public ReadRegisterNode(Register register, boolean directUse, boolean incoming) { - super(StampFactory.forNodeIntrinsic()); - this.register = register; - this.directUse = directUse; - this.incoming = incoming; - } - - @Override - public void generate(LIRGenerator generator) { - Value result = register.asValue(kind()); - if (incoming) { - generator.emitIncomingValues(new Value[]{result}); - } - if (!directUse) { - result = generator.emitMove(result); - } - generator.setResult(this, result); - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + "%" + register; - } else { - return super.toString(verbosity); - } - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ReverseBytesNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.snippets.nodes; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public class ReverseBytesNode extends FloatingNode implements LIRGenLowerable, Canonicalizable { - - @Input private ValueNode value; - - public ReverseBytesNode(ValueNode value) { - super(StampFactory.forKind(value.kind())); - assert kind().getStackKind() == Kind.Int || kind() == Kind.Long; - this.value = value; - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - long v = value.asConstant().asLong(); - if (kind().getStackKind() == Kind.Int) { - return ConstantNode.forInt(Integer.reverseBytes((int) v), graph()); - } else if (kind() == Kind.Long) { - return ConstantNode.forLong(Long.reverseBytes(v), graph()); - } - } - return this; - } - - @NodeIntrinsic - public static native int reverse(int v); - - @NodeIntrinsic - public static native long reverse(long v); - - @Override - public void generate(LIRGenerator gen) { - Variable result = gen.newVariable(value.kind()); - gen.emitByteSwap(result, gen.operand(value)); - gen.setResult(this, result); - } -}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/WriteRegisterNode.java Mon Mar 18 19:18:42 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2013, 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.snippets.nodes; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * Changes the value of a specific register. - */ -@NodeInfo(nameTemplate = "WriteRegister %{p#register}") -public final class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable { - - /** - * The fixed register to access. - */ - private final Register register; - - /** - * The new value assigned to the register. - */ - @Input private ValueNode value; - - public WriteRegisterNode(Register register, ValueNode value) { - super(StampFactory.forVoid()); - this.register = register; - this.value = value; - } - - @Override - public void generate(LIRGeneratorTool generator) { - Value val = generator.operand(value); - generator.emitMove(val, register.asValue(val.getKind())); - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + "%" + register; - } else { - return super.toString(verbosity); - } - } -}
--- a/make/build-graal.xml Mon Mar 18 19:18:42 2013 +0100 +++ b/make/build-graal.xml Thu Mar 21 11:09:19 2013 +0100 @@ -48,7 +48,7 @@ <src path="${src.dir}/com.oracle.graal.bytecode"/> <src path="${src.dir}/com.oracle.graal.java"/> <src path="${src.dir}/com.oracle.graal.word"/> - <src path="${src.dir}/com.oracle.graal.snippets"/> + <src path="${src.dir}/com.oracle.graal.replacements"/> <src path="${src.dir}/com.oracle.graal.api.runtime"/> <src path="${src.dir}/com.oracle.graal.printer"/> <src path="${src.dir}/com.oracle.graal.hotspot"/> @@ -56,7 +56,7 @@ <src path="${src.dir}/com.oracle.graal.asm.amd64"/> <src path="${src.dir}/com.oracle.graal.lir.amd64"/> <src path="${src.dir}/com.oracle.graal.compiler.amd64"/> - <src path="${src.dir}/com.oracle.graal.snippets.amd64"/> + <src path="${src.dir}/com.oracle.graal.replacements.amd64"/> <src path="${src.dir}/com.oracle.graal.hotspot.amd64"/> <src path="${src.dir}/com.oracle.graal.sparc"/> <src path="${src.dir}/com.oracle.graal.asm.sparc"/>
--- a/mx/projects Mon Mar 18 19:18:42 2013 +0100 +++ b/mx/projects Thu Mar 21 11:09:19 2013 +0100 @@ -82,14 +82,14 @@ # graal.hotspot project@com.oracle.graal.hotspot@subDir=graal project@com.oracle.graal.hotspot@sourceDirs=src -project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.snippets,com.oracle.graal.api.runtime,com.oracle.graal.printer +project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.api.runtime,com.oracle.graal.printer project@com.oracle.graal.hotspot@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot@javaCompliance=1.7 # graal.hotspot.amd64 project@com.oracle.graal.hotspot.amd64@subDir=graal project@com.oracle.graal.hotspot.amd64@sourceDirs=src -project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.hotspot,com.oracle.graal.compiler.amd64,com.oracle.graal.snippets.amd64 +project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.hotspot,com.oracle.graal.compiler.amd64,com.oracle.graal.replacements.amd64 project@com.oracle.graal.hotspot.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.amd64@javaCompliance=1.7 @@ -182,26 +182,26 @@ project@com.oracle.graal.word@checkstyle=com.oracle.graal.graph project@com.oracle.graal.word@javaCompliance=1.7 -# graal.snippets -project@com.oracle.graal.snippets@subDir=graal -project@com.oracle.graal.snippets@sourceDirs=src -project@com.oracle.graal.snippets@dependencies=com.oracle.graal.compiler,com.oracle.graal.java,com.oracle.graal.word -project@com.oracle.graal.snippets@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.snippets@javaCompliance=1.7 +# graal.replacements +project@com.oracle.graal.replacements@subDir=graal +project@com.oracle.graal.replacements@sourceDirs=src +project@com.oracle.graal.replacements@dependencies=com.oracle.graal.compiler,com.oracle.graal.java,com.oracle.graal.word +project@com.oracle.graal.replacements@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.replacements@javaCompliance=1.7 -# graal.snippets.amd64 -project@com.oracle.graal.snippets.amd64@subDir=graal -project@com.oracle.graal.snippets.amd64@sourceDirs=src -project@com.oracle.graal.snippets.amd64@dependencies=com.oracle.graal.snippets -project@com.oracle.graal.snippets.amd64@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.snippets.amd64@javaCompliance=1.7 +# graal.replacements.amd64 +project@com.oracle.graal.replacements.amd64@subDir=graal +project@com.oracle.graal.replacements.amd64@sourceDirs=src +project@com.oracle.graal.replacements.amd64@dependencies=com.oracle.graal.replacements +project@com.oracle.graal.replacements.amd64@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.replacements.amd64@javaCompliance=1.7 -# graal.snippets.test -project@com.oracle.graal.snippets.test@subDir=graal -project@com.oracle.graal.snippets.test@sourceDirs=src -project@com.oracle.graal.snippets.test@dependencies=com.oracle.graal.snippets,com.oracle.graal.compiler.test -project@com.oracle.graal.snippets.test@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.snippets.test@javaCompliance=1.7 +# graal.replacements.test +project@com.oracle.graal.replacements.test@subDir=graal +project@com.oracle.graal.replacements.test@sourceDirs=src +project@com.oracle.graal.replacements.test@dependencies=com.oracle.graal.replacements,com.oracle.graal.compiler.test +project@com.oracle.graal.replacements.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.replacements.test@javaCompliance=1.7 # graal.nodes project@com.oracle.graal.nodes@subDir=graal
--- a/src/share/vm/graal/graalRuntime.hpp Mon Mar 18 19:18:42 2013 +0100 +++ b/src/share/vm/graal/graalRuntime.hpp Thu Mar 21 11:09:19 2013 +0100 @@ -149,7 +149,7 @@ static jint identity_hash_code(JavaThread* thread, oopDesc* objd); static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte); - // Note: Must be kept in sync with constants in com.oracle.graal.snippets.Log + // Note: Must be kept in sync with constants in com.oracle.graal.replacements.Log enum { LOG_OBJECT_NEWLINE = 0x01, LOG_OBJECT_STRING = 0x02,