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}