001/*
002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.hotspot.meta;
024
025import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
026import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
027import static com.oracle.graal.java.BytecodeParser.Options.*;
028
029import java.lang.invoke.*;
030import java.util.zip.*;
031
032import jdk.internal.jvmci.hotspot.*;
033import jdk.internal.jvmci.meta.*;
034import jdk.internal.jvmci.options.*;
035import sun.reflect.*;
036
037import com.oracle.graal.api.replacements.*;
038import com.oracle.graal.compiler.common.spi.*;
039import com.oracle.graal.graphbuilderconf.*;
040import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
041import com.oracle.graal.graphbuilderconf.InvocationPlugin.Receiver;
042import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
043import com.oracle.graal.hotspot.nodes.*;
044import com.oracle.graal.hotspot.replacements.*;
045import com.oracle.graal.hotspot.replacements.arraycopy.*;
046import com.oracle.graal.hotspot.word.*;
047import com.oracle.graal.nodes.*;
048import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
049import com.oracle.graal.nodes.memory.address.*;
050import com.oracle.graal.nodes.spi.*;
051import com.oracle.graal.nodes.util.*;
052import com.oracle.graal.replacements.*;
053import com.oracle.graal.word.*;
054
055/**
056 * Defines the {@link Plugins} used when running on HotSpot.
057 */
058public class HotSpotGraphBuilderPlugins {
059
060    /**
061     * Creates a {@link Plugins} object that should be used when running on HotSpot.
062     *
063     * @param constantReflection
064     * @param snippetReflection
065     * @param foreignCalls
066     * @param stampProvider
067     */
068    public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
069                    SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements) {
070        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
071
072        Plugins plugins = new Plugins(invocationPlugins);
073        NodeIntrinsificationPhase nodeIntrinsificationPhase = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
074        NodeIntrinsificationPlugin nodeIntrinsificationPlugin = new NodeIntrinsificationPlugin(metaAccess, nodeIntrinsificationPhase, wordTypes, false);
075        HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
076        HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin, nodeIntrinsificationPlugin);
077
078        plugins.appendParameterPlugin(nodePlugin);
079        plugins.appendNodePlugin(nodePlugin);
080        plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess()));
081
082        plugins.appendInlineInvokePlugin(replacements);
083        if (InlineDuringParsing.getValue()) {
084            plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
085        }
086
087        registerObjectPlugins(invocationPlugins);
088        registerClassPlugins(plugins);
089        registerSystemPlugins(invocationPlugins, foreignCalls);
090        registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config);
091        registerCallSitePlugins(invocationPlugins);
092        registerReflectionPlugins(invocationPlugins);
093        registerStableOptionPlugins(invocationPlugins, snippetReflection);
094        registerAESPlugins(invocationPlugins, config);
095        registerCRC32Plugins(invocationPlugins, config);
096        StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, !config.useHeapProfiler);
097
098        return plugins;
099    }
100
101    private static void registerObjectPlugins(InvocationPlugins plugins) {
102        Registration r = new Registration(plugins, Object.class);
103        r.register1("clone", Receiver.class, new InvocationPlugin() {
104            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
105                ValueNode object = receiver.get();
106                b.addPush(Kind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
107                return true;
108            }
109
110            public boolean inlineOnly() {
111                return true;
112            }
113        });
114        r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class);
115    }
116
117    private static void registerClassPlugins(Plugins plugins) {
118        Registration r = new Registration(plugins.getInvocationPlugins(), Class.class);
119
120        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class);
121        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class);
122        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class);
123        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class);
124        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class);
125        r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class);
126
127        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
128            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
129                ValueNode javaClass = receiver.get();
130                ValueNode folded = ClassCastNode.tryFold(GraphUtil.originalValue(javaClass), object, b.getConstantReflection(), b.getAssumptions());
131                if (folded != null) {
132                    b.addPush(Kind.Object, folded);
133                } else {
134                    b.addPush(Kind.Object, new ClassCastNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), javaClass, object));
135                }
136                return true;
137            }
138
139            public boolean inlineOnly() {
140                return true;
141            }
142        });
143    }
144
145    private static void registerCallSitePlugins(InvocationPlugins plugins) {
146        InvocationPlugin plugin = new InvocationPlugin() {
147            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
148                ValueNode callSite = receiver.get();
149                ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite), b.getMetaAccess(), b.getAssumptions());
150                if (folded != null) {
151                    b.addPush(Kind.Object, folded);
152                } else {
153                    b.addPush(Kind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), callSite));
154                }
155                return true;
156            }
157
158            public boolean inlineOnly() {
159                return true;
160            }
161        };
162        plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
163        plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
164        plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
165    }
166
167    private static void registerReflectionPlugins(InvocationPlugins plugins) {
168        Registration r = new Registration(plugins, Reflection.class);
169        r.register0("getCallerClass", new InvocationPlugin() {
170            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
171                b.addPush(Kind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType()));
172                return true;
173            }
174
175            public boolean inlineOnly() {
176                return true;
177            }
178        });
179    }
180
181    private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
182        Registration r = new Registration(plugins, System.class);
183        r.register0("currentTimeMillis", new ForeignCallPlugin(foreignCalls, JAVA_TIME_MILLIS));
184        r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, JAVA_TIME_NANOS));
185        r.register1("identityHashCode", Object.class, new InvocationPlugin() {
186            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
187                b.addPush(Kind.Int, new IdentityHashCodeNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
188                return true;
189            }
190
191            public boolean inlineOnly() {
192                return true;
193            }
194        });
195        r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
196            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
197                b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length));
198                return true;
199            }
200
201            public boolean inlineOnly() {
202                return true;
203            }
204        });
205    }
206
207    private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, HotSpotVMConfig config) {
208        Registration r = new Registration(plugins, Thread.class);
209        r.register0("currentThread", new InvocationPlugin() {
210            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
211                CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
212                boolean compressible = false;
213                ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset));
214                AddressNode address = b.add(new OffsetAddressNode(thread, offset));
215                ValueNode javaThread = WordOperationPlugin.readOp(b, Kind.Object, address, JAVA_THREAD_THREAD_OBJECT_LOCATION, BarrierType.NONE, compressible);
216                boolean exactType = compressible;
217                boolean nonNull = true;
218                b.addPush(Kind.Object, new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull));
219                return true;
220            }
221        });
222    }
223
224    private static void registerStableOptionPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection) {
225        Registration r = new Registration(plugins, StableOptionValue.class);
226        r.register1("getValue", Receiver.class, new InvocationPlugin() {
227            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
228                if (receiver.isConstant()) {
229                    StableOptionValue<?> option = snippetReflection.asObject(StableOptionValue.class, (JavaConstant) receiver.get().asConstant());
230                    b.addPush(Kind.Object, ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), b.getMetaAccess()));
231                    return true;
232                }
233                return false;
234            }
235        });
236    }
237
238    private static void registerAESPlugins(InvocationPlugins plugins, HotSpotVMConfig config) {
239        if (config.useAESIntrinsics) {
240            assert config.aescryptEncryptBlockStub != 0L;
241            assert config.aescryptDecryptBlockStub != 0L;
242            assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
243            assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
244            Class<?> c = MethodSubstitutionPlugin.resolveClass("com.sun.crypto.provider.CipherBlockChaining", true);
245            if (c != null) {
246                Registration r = new Registration(plugins, c);
247                r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, "encrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
248                r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, "decrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
249            }
250            c = MethodSubstitutionPlugin.resolveClass("com.sun.crypto.provider.AESCrypt", true);
251            if (c != null) {
252                Registration r = new Registration(plugins, c);
253                r.registerMethodSubstitution(AESCryptSubstitutions.class, "encryptBlock", Receiver.class, byte[].class, int.class, byte[].class, int.class);
254                r.registerMethodSubstitution(AESCryptSubstitutions.class, "decryptBlock", Receiver.class, byte[].class, int.class, byte[].class, int.class);
255            }
256        }
257    }
258
259    private static void registerCRC32Plugins(InvocationPlugins plugins, HotSpotVMConfig config) {
260        if (config.useCRC32Intrinsics) {
261            assert config.aescryptEncryptBlockStub != 0L;
262            assert config.aescryptDecryptBlockStub != 0L;
263            assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
264            assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
265            Registration r = new Registration(plugins, CRC32.class);
266            r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
267            r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
268            r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
269        }
270    }
271}