DynamicLinker.java revision 1684:21421eec73d6
1/* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26/* 27 * This file is available under and governed by the GNU General Public 28 * License version 2 only, as published by the Free Software Foundation. 29 * However, the following notice accompanied the original version of this 30 * file, and Oracle licenses the original version of this file under the BSD 31 * license: 32 */ 33/* 34 Copyright 2009-2013 Attila Szegedi 35 36 Licensed under both the Apache License, Version 2.0 (the "Apache License") 37 and the BSD License (the "BSD License"), with licensee being free to 38 choose either of the two at their discretion. 39 40 You may not use this file except in compliance with either the Apache 41 License or the BSD License. 42 43 If you choose to use this file in compliance with the Apache License, the 44 following notice applies to you: 45 46 You may obtain a copy of the Apache License at 47 48 http://www.apache.org/licenses/LICENSE-2.0 49 50 Unless required by applicable law or agreed to in writing, software 51 distributed under the License is distributed on an "AS IS" BASIS, 52 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 53 implied. See the License for the specific language governing 54 permissions and limitations under the License. 55 56 If you choose to use this file in compliance with the BSD License, the 57 following notice applies to you: 58 59 Redistribution and use in source and binary forms, with or without 60 modification, are permitted provided that the following conditions are 61 met: 62 * Redistributions of source code must retain the above copyright 63 notice, this list of conditions and the following disclaimer. 64 * Redistributions in binary form must reproduce the above copyright 65 notice, this list of conditions and the following disclaimer in the 66 documentation and/or other materials provided with the distribution. 67 * Neither the name of the copyright holder nor the names of 68 contributors may be used to endorse or promote products derived from 69 this software without specific prior written permission. 70 71 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 72 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 73 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 74 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 75 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 76 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 77 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 78 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 79 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 80 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82*/ 83 84package jdk.dynalink; 85 86import java.lang.StackWalker.StackFrame; 87import java.lang.invoke.MethodHandle; 88import java.lang.invoke.MethodHandles; 89import java.lang.invoke.MethodType; 90import java.lang.invoke.MutableCallSite; 91import java.util.Objects; 92import jdk.dynalink.linker.GuardedInvocation; 93import jdk.dynalink.linker.GuardedInvocationTransformer; 94import jdk.dynalink.linker.GuardingDynamicLinker; 95import jdk.dynalink.linker.LinkRequest; 96import jdk.dynalink.linker.LinkerServices; 97import jdk.dynalink.linker.support.Lookup; 98import jdk.dynalink.linker.support.SimpleLinkRequest; 99import jdk.dynalink.support.ChainedCallSite; 100import jdk.dynalink.support.SimpleRelinkableCallSite; 101 102/** 103 * The linker for {@link RelinkableCallSite} objects. A dynamic linker is a main 104 * objects when using Dynalink, it coordinates linking of call sites with 105 * linkers of available language runtimes that are represented by 106 * {@link GuardingDynamicLinker} objects (you only need to deal with these if 107 * you are yourself implementing a language runtime with its own object model 108 * and/or type conversions). To use Dynalink, you have to create one or more 109 * dynamic linkers using a {@link DynamicLinkerFactory}. Subsequently, you need 110 * to invoke its {@link #link(RelinkableCallSite)} method from 111 * {@code invokedynamic} bootstrap methods to let it manage all the call sites 112 * they create. Usual usage would be to create at least one class per language 113 * runtime to contain one linker instance as: 114 * <pre> 115 * 116 * class MyLanguageRuntime { 117 * private static final GuardingDynamicLinker myLanguageLinker = new MyLanguageLinker(); 118 * private static final DynamicLinker dynamicLinker = createDynamicLinker(); 119 * 120 * private static DynamicLinker createDynamicLinker() { 121 * final DynamicLinkerFactory factory = new DynamicLinkerFactory(); 122 * factory.setPrioritizedLinker(myLanguageLinker); 123 * return factory.createLinker(); 124 * } 125 * 126 * public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) { 127 * return dynamicLinker.link( 128 * new SimpleRelinkableCallSite( 129 * new CallSiteDescriptor(lookup, parseOperation(name), type))); 130 * } 131 * 132 * private static Operation parseOperation(String name) { 133 * ... 134 * } 135 * } 136 * </pre> 137 * The above setup of one static linker instance is often too simple. You will 138 * often have your language runtime have a concept of some kind of 139 * "context class loader" and you will want to create one dynamic linker per 140 * such class loader, to ensure it incorporates linkers for all other language 141 * runtimes visible to that class loader (see 142 * {@link DynamicLinkerFactory#setClassLoader(ClassLoader)}). 143 * <p> 144 * There are three components you need to provide in the above example: 145 * <ul> 146 * 147 * <li>You are expected to provide a {@link GuardingDynamicLinker} for your own 148 * language. If your runtime doesn't have its own object model or type 149 * conversions, you don't need to implement a {@code GuardingDynamicLinker}; you 150 * would simply not invoke the {@code setPrioritizedLinker} method on the factory.</li> 151 * 152 * <li>The performance of the programs can depend on your choice of the class to 153 * represent call sites. The above example used 154 * {@link SimpleRelinkableCallSite}, but you might want to use 155 * {@link ChainedCallSite} instead. You'll need to experiment and decide what 156 * fits your runtime the best. You can further subclass either of these or 157 * implement your own.</li> 158 * 159 * <li>You also need to provide {@link CallSiteDescriptor}s to your call sites. 160 * They are immutable objects that contain all the information about the call 161 * site: the class performing the lookups, the operation being invoked, and the 162 * method signature. You will have to supply your own scheme to encode and 163 * decode operations in the call site name or static parameters, that is why 164 * in the above example the {@code parseOperation} method is left unimplemented.</li> 165 * 166 * </ul> 167 */ 168public final class DynamicLinker { 169 private static final String CLASS_NAME = DynamicLinker.class.getName(); 170 private static final String RELINK_METHOD_NAME = "relink"; 171 172 private static final String INITIAL_LINK_CLASS_NAME = "java.lang.invoke.MethodHandleNatives"; 173 private static final String INITIAL_LINK_METHOD_NAME = "linkCallSite"; 174 private static final String INVOKE_PACKAGE_PREFIX = "java.lang.invoke."; 175 176 private static final StackWalker stackWalker = StackWalker.getInstance(StackWalker.Option.SHOW_HIDDEN_FRAMES); 177 178 private final LinkerServices linkerServices; 179 private final GuardedInvocationTransformer prelinkTransformer; 180 private final boolean syncOnRelink; 181 private final int unstableRelinkThreshold; 182 183 /** 184 * Creates a new dynamic linker. 185 * 186 * @param linkerServices the linkerServices used by the linker, created by the factory. 187 * @param prelinkTransformer see {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer)} 188 * @param syncOnRelink see {@link DynamicLinkerFactory#setSyncOnRelink(boolean)} 189 * @param unstableRelinkThreshold see {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)} 190 */ 191 DynamicLinker(final LinkerServices linkerServices, final GuardedInvocationTransformer prelinkTransformer, 192 final boolean syncOnRelink, final int unstableRelinkThreshold) { 193 if(unstableRelinkThreshold < 0) { 194 throw new IllegalArgumentException("unstableRelinkThreshold < 0"); 195 } 196 this.linkerServices = linkerServices; 197 this.prelinkTransformer = prelinkTransformer; 198 this.syncOnRelink = syncOnRelink; 199 this.unstableRelinkThreshold = unstableRelinkThreshold; 200 } 201 202 /** 203 * Links an invokedynamic call site. It will install a method handle into 204 * the call site that invokes the relinking mechanism of this linker. Next 205 * time the call site is invoked, it will be linked for the actual arguments 206 * it was invoked with. 207 * 208 * @param <T> the particular subclass of {@link RelinkableCallSite} for 209 * which to create a link. 210 * @param callSite the call site to link. 211 * 212 * @return the callSite, for easy call chaining. 213 */ 214 public <T extends RelinkableCallSite> T link(final T callSite) { 215 callSite.initialize(createRelinkAndInvokeMethod(callSite, 0)); 216 return callSite; 217 } 218 219 /** 220 * Returns the object representing the linker services of this class that 221 * are normally exposed to individual {@link GuardingDynamicLinker 222 * language-specific linkers}. While as a user of this class you normally 223 * only care about the {@link #link(RelinkableCallSite)} method, in certain 224 * circumstances you might want to use the lower level services directly; 225 * either to lookup specific method handles, to access the type converters, 226 * and so on. 227 * 228 * @return the object representing the linker services of this class. 229 */ 230 public LinkerServices getLinkerServices() { 231 return linkerServices; 232 } 233 234 private static final MethodHandle RELINK = Lookup.findOwnSpecial(MethodHandles.lookup(), RELINK_METHOD_NAME, 235 MethodHandle.class, RelinkableCallSite.class, int.class, Object[].class); 236 237 private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, final int relinkCount) { 238 // Make a bound MH of invoke() for this linker and call site 239 final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf( 240 relinkCount)); 241 // Make a MH that gathers all arguments to the invocation into an Object[] 242 final MethodType type = callSite.getDescriptor().getMethodType(); 243 final MethodHandle collectingRelinker = boundRelinker.asCollector(Object[].class, type.parameterCount()); 244 return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), collectingRelinker.asType( 245 type.changeReturnType(MethodHandle.class))); 246 } 247 248 /** 249 * Relinks a call site conforming to the invocation arguments. 250 * 251 * @param callSite the call site itself 252 * @param arguments arguments to the invocation 253 * 254 * @return return the method handle for the invocation 255 * 256 * @throws Exception rethrows any exception thrown by the linkers 257 */ 258 @SuppressWarnings("unused") 259 private MethodHandle relink(final RelinkableCallSite callSite, final int relinkCount, final Object... arguments) throws Exception { 260 final CallSiteDescriptor callSiteDescriptor = callSite.getDescriptor(); 261 final boolean unstableDetectionEnabled = unstableRelinkThreshold > 0; 262 final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold; 263 final LinkRequest linkRequest = new SimpleLinkRequest(callSiteDescriptor, callSiteUnstable, arguments); 264 265 GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest); 266 267 // None found - throw an exception 268 if(guardedInvocation == null) { 269 throw new NoSuchDynamicMethodException(callSiteDescriptor.toString()); 270 } 271 272 // Make sure we transform the invocation before linking it into the call site. This is typically used to match the 273 // return type of the invocation to the call site. 274 guardedInvocation = prelinkTransformer.filter(guardedInvocation, linkRequest, linkerServices); 275 Objects.requireNonNull(guardedInvocation); 276 277 int newRelinkCount = relinkCount; 278 // Note that the short-circuited "&&" evaluation below ensures we'll increment the relinkCount until 279 // threshold + 1 but not beyond that. Threshold + 1 is treated as a special value to signal that resetAndRelink 280 // has already executed once for the unstable call site; we only want the call site to throw away its current 281 // linkage once, when it transitions to unstable. 282 if(unstableDetectionEnabled && newRelinkCount <= unstableRelinkThreshold && newRelinkCount++ == unstableRelinkThreshold) { 283 callSite.resetAndRelink(guardedInvocation, createRelinkAndInvokeMethod(callSite, newRelinkCount)); 284 } else { 285 callSite.relink(guardedInvocation, createRelinkAndInvokeMethod(callSite, newRelinkCount)); 286 } 287 if(syncOnRelink) { 288 MutableCallSite.syncAll(new MutableCallSite[] { (MutableCallSite)callSite }); 289 } 290 return guardedInvocation.getInvocation(); 291 } 292 293 /** 294 * Returns a stack trace element describing the location of the 295 * {@code invokedynamic} call site currently being linked on the current 296 * thread. The operation is potentially expensive as it needs to generate a 297 * stack trace to inspect it and is intended for use in diagnostics code. 298 * For "free-floating" call sites (not associated with an 299 * {@code invokedynamic} instruction), the result is not well-defined. 300 * 301 * @return a stack trace element describing the location of the call site 302 * currently being linked, or null if it is not invoked while a call 303 * site is being linked. 304 */ 305 public static StackTraceElement getLinkedCallSiteLocation() { 306 return stackWalker.walk(s -> s 307 // Find one of our linking entry points on the stack... 308 .dropWhile(f -> !(isRelinkFrame(f) || isInitialLinkFrame(f))) 309 .skip(1) 310 // ... then look for the first thing calling it that isn't j.l.invoke 311 .dropWhile(f -> f.getClassName().startsWith(INVOKE_PACKAGE_PREFIX)) 312 .findFirst() 313 .map(StackFrame::toStackTraceElement) 314 .orElse(null) 315 ); 316 } 317 318 /** 319 * Returns {@code true} if the frame represents {@code MethodHandleNatives.linkCallSite()}, 320 * the frame immediately on top of the call site frame when the call site is 321 * being linked for the first time. 322 * 323 * @param frame the frame 324 * 325 * @return {@code true} if this frame represents {@code MethodHandleNatives.linkCallSite()}. 326 */ 327 private static boolean isInitialLinkFrame(final StackFrame frame) { 328 return testFrame(frame, INITIAL_LINK_METHOD_NAME, INITIAL_LINK_CLASS_NAME); 329 } 330 331 /** 332 * Returns {@code true} if the frame represents {@code DynamicLinker.relink()}, 333 * the frame immediately on top of the call site frame when the call site is 334 * being relinked (linked for second and subsequent times). 335 * 336 * @param frame the frame 337 * 338 * @return {@code true} if this frame represents {@code DynamicLinker.relink()}. 339 */ 340 private static boolean isRelinkFrame(final StackFrame frame) { 341 return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME); 342 } 343 344 private static boolean testFrame(final StackFrame frame, final String methodName, final String className) { 345 return methodName.equals(frame.getMethodName()) && className.equals(frame.getClassName()); 346 } 347} 348