Path: blob/aarch64-shenandoah-jdk8u272-b10/nashorn/src/jdk/internal/dynalink/DynamicLinker.java
48580 views
/*1* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* This file is available under and governed by the GNU General Public27* License version 2 only, as published by the Free Software Foundation.28* However, the following notice accompanied the original version of this29* file, and Oracle licenses the original version of this file under the BSD30* license:31*/32/*33Copyright 2009-2013 Attila Szegedi3435Licensed under both the Apache License, Version 2.0 (the "Apache License")36and the BSD License (the "BSD License"), with licensee being free to37choose either of the two at their discretion.3839You may not use this file except in compliance with either the Apache40License or the BSD License.4142If you choose to use this file in compliance with the Apache License, the43following notice applies to you:4445You may obtain a copy of the Apache License at4647http://www.apache.org/licenses/LICENSE-2.04849Unless required by applicable law or agreed to in writing, software50distributed under the License is distributed on an "AS IS" BASIS,51WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or52implied. See the License for the specific language governing53permissions and limitations under the License.5455If you choose to use this file in compliance with the BSD License, the56following notice applies to you:5758Redistribution and use in source and binary forms, with or without59modification, are permitted provided that the following conditions are60met:61* Redistributions of source code must retain the above copyright62notice, this list of conditions and the following disclaimer.63* Redistributions in binary form must reproduce the above copyright64notice, this list of conditions and the following disclaimer in the65documentation and/or other materials provided with the distribution.66* Neither the name of the copyright holder nor the names of67contributors may be used to endorse or promote products derived from68this software without specific prior written permission.6970THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS71IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED72TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A73PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER74BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR75CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF76SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR77BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,78WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR79OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF80ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.81*/8283package jdk.internal.dynalink;8485import java.lang.invoke.MethodHandle;86import java.lang.invoke.MethodHandles;87import java.lang.invoke.MethodType;88import java.lang.invoke.MutableCallSite;89import java.util.List;90import java.util.Objects;91import jdk.internal.dynalink.linker.GuardedInvocation;92import jdk.internal.dynalink.linker.GuardingDynamicLinker;93import jdk.internal.dynalink.linker.LinkRequest;94import jdk.internal.dynalink.linker.LinkerServices;95import jdk.internal.dynalink.support.CallSiteDescriptorFactory;96import jdk.internal.dynalink.support.LinkRequestImpl;97import jdk.internal.dynalink.support.Lookup;98import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;99100/**101* The linker for {@link RelinkableCallSite} objects. Users of it (scripting102* frameworks and language runtimes) have to create a linker using the103* {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic104* bootstrap methods to set the target of all the call sites in the code they105* generate. Usual usage would be to create one class per language runtime to106* contain one linker instance as:107*108* <pre>109* class MyLanguageRuntime {110* private static final GuardingDynamicLinker myLanguageLinker = new MyLanguageLinker();111* private static final DynamicLinker dynamicLinker = createDynamicLinker();112*113* private static DynamicLinker createDynamicLinker() {114* final DynamicLinkerFactory factory = new DynamicLinkerFactory();115* factory.setPrioritizedLinker(myLanguageLinker);116* return factory.createLinker();117* }118*119* public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {120* return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(lookup, name, type)));121* }122* }123* </pre>124*125* Note how there are three components you will need to provide here:126* <ul>127*128* <li>You're expected to provide a {@link GuardingDynamicLinker} for your own129* language. If your runtime doesn't have its own language and/or object model130* (i.e., it's a generic scripting shell), you don't need to implement a dynamic131* linker; you would simply not invoke the {@code setPrioritizedLinker} method132* on the factory, or even better, simply use {@link DefaultBootstrapper}.</li>133*134* <li>The performance of the programs can depend on your choice of the class to135* represent call sites. The above example used {@link MonomorphicCallSite}, but136* you might want to use {@link ChainedCallSite} instead. You'll need to137* experiment and decide what fits your language runtime the best. You can138* subclass either of these or roll your own if you need to.</li>139*140* <li>You also need to provide {@link CallSiteDescriptor}s to your call sites.141* They are immutable objects that contain all the information about the call142* site: the class performing the lookups, the name of the method being invoked,143* and the method signature. The library has a default {@link CallSiteDescriptorFactory}144* for descriptors that you can use, or you can create your own descriptor145* classes, especially if you need to add further information (values passed in146* additional parameters to the bootstrap method) to them.</li>147*148* </ul>149*150* @author Attila Szegedi151*/152public class DynamicLinker {153private static final String CLASS_NAME = DynamicLinker.class.getName();154private static final String RELINK_METHOD_NAME = "relink";155156private static final String INITIAL_LINK_CLASS_NAME = "java.lang.invoke.MethodHandleNatives";157private static final String INITIAL_LINK_METHOD_NAME = "linkCallSite";158159private final LinkerServices linkerServices;160private final GuardedInvocationFilter prelinkFilter;161private final int runtimeContextArgCount;162private final boolean syncOnRelink;163private final int unstableRelinkThreshold;164165/**166* Creates a new dynamic linker.167*168* @param linkerServices the linkerServices used by the linker, created by the factory.169* @param prelinkFilter see {@link DynamicLinkerFactory#setPrelinkFilter(GuardedInvocationFilter)}170* @param runtimeContextArgCount see {@link DynamicLinkerFactory#setRuntimeContextArgCount(int)}171*/172DynamicLinker(final LinkerServices linkerServices, final GuardedInvocationFilter prelinkFilter, final int runtimeContextArgCount,173final boolean syncOnRelink, final int unstableRelinkThreshold) {174if(runtimeContextArgCount < 0) {175throw new IllegalArgumentException("runtimeContextArgCount < 0");176}177if(unstableRelinkThreshold < 0) {178throw new IllegalArgumentException("unstableRelinkThreshold < 0");179}180this.linkerServices = linkerServices;181this.prelinkFilter = prelinkFilter;182this.runtimeContextArgCount = runtimeContextArgCount;183this.syncOnRelink = syncOnRelink;184this.unstableRelinkThreshold = unstableRelinkThreshold;185}186187/**188* Links an invokedynamic call site. It will install a method handle into189* the call site that invokes the relinking mechanism of this linker. Next190* time the call site is invoked, it will be linked for the actual arguments191* it was invoked with.192*193* @param <T> the particular subclass of {@link RelinkableCallSite} for194* which to create a link.195* @param callSite the call site to link.196*197* @return the callSite, for easy call chaining.198*/199public <T extends RelinkableCallSite> T link(final T callSite) {200callSite.initialize(createRelinkAndInvokeMethod(callSite, 0));201return callSite;202}203204/**205* Returns the object representing the lower level linker services of this206* class that are normally exposed to individual language-specific linkers.207* While as a user of this class you normally only care about the208* {@link #link(RelinkableCallSite)} method, in certain circumstances you209* might want to use the lower level services directly; either to lookup210* specific method handles, to access the type converters, and so on.211*212* @return the object representing the linker services of this class.213*/214public LinkerServices getLinkerServices() {215return linkerServices;216}217218private static final MethodHandle RELINK = Lookup.findOwnSpecial(MethodHandles.lookup(), RELINK_METHOD_NAME,219MethodHandle.class, RelinkableCallSite.class, int.class, Object[].class);220221private MethodHandle createRelinkAndInvokeMethod(final RelinkableCallSite callSite, final int relinkCount) {222// Make a bound MH of invoke() for this linker and call site223final MethodHandle boundRelinker = MethodHandles.insertArguments(RELINK, 0, this, callSite, Integer.valueOf(224relinkCount));225// Make a MH that gathers all arguments to the invocation into an Object[]226final MethodType type = callSite.getDescriptor().getMethodType();227final MethodHandle collectingRelinker = boundRelinker.asCollector(Object[].class, type.parameterCount());228return MethodHandles.foldArguments(MethodHandles.exactInvoker(type), collectingRelinker.asType(229type.changeReturnType(MethodHandle.class)));230}231232/**233* Relinks a call site conforming to the invocation arguments.234*235* @param callSite the call site itself236* @param arguments arguments to the invocation237*238* @return return the method handle for the invocation239*240* @throws Exception rethrows any exception thrown by the linkers241*/242@SuppressWarnings("unused")243private MethodHandle relink(final RelinkableCallSite callSite, final int relinkCount, final Object... arguments) throws Exception {244final CallSiteDescriptor callSiteDescriptor = callSite.getDescriptor();245final boolean unstableDetectionEnabled = unstableRelinkThreshold > 0;246final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold;247final LinkRequest linkRequest =248runtimeContextArgCount == 0 ?249new LinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments) :250new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments, runtimeContextArgCount);251252GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest);253254// None found - throw an exception255if(guardedInvocation == null) {256throw new NoSuchDynamicMethodException(callSiteDescriptor.toString());257}258259// If our call sites have a runtime context, and the linker produced a context-stripped invocation, adapt the260// produced invocation into contextual invocation (by dropping the context...)261if(runtimeContextArgCount > 0) {262final MethodType origType = callSiteDescriptor.getMethodType();263final MethodHandle invocation = guardedInvocation.getInvocation();264if(invocation.type().parameterCount() == origType.parameterCount() - runtimeContextArgCount) {265final List<Class<?>> prefix = origType.parameterList().subList(1, runtimeContextArgCount + 1);266final MethodHandle guard = guardedInvocation.getGuard();267guardedInvocation = guardedInvocation.dropArguments(1, prefix);268}269}270271// Make sure we filter the invocation before linking it into the call site. This is typically used to match the272// return type of the invocation to the call site.273guardedInvocation = prelinkFilter.filter(guardedInvocation, linkRequest, linkerServices);274Objects.requireNonNull(guardedInvocation);275276int newRelinkCount = relinkCount;277// Note that the short-circuited "&&" evaluation below ensures we'll increment the relinkCount until278// threshold + 1 but not beyond that. Threshold + 1 is treated as a special value to signal that resetAndRelink279// has already executed once for the unstable call site; we only want the call site to throw away its current280// linkage once, when it transitions to unstable.281if(unstableDetectionEnabled && newRelinkCount <= unstableRelinkThreshold && newRelinkCount++ == unstableRelinkThreshold) {282callSite.resetAndRelink(guardedInvocation, createRelinkAndInvokeMethod(callSite, newRelinkCount));283} else {284callSite.relink(guardedInvocation, createRelinkAndInvokeMethod(callSite, newRelinkCount));285}286if(syncOnRelink) {287MutableCallSite.syncAll(new MutableCallSite[] { (MutableCallSite)callSite });288}289return guardedInvocation.getInvocation();290}291292/**293* Returns a stack trace element describing the location of the call site294* currently being linked on the current thread. The operation internally295* creates a Throwable object and inspects its stack trace, so it's296* potentially expensive. The recommended usage for it is in writing297* diagnostics code.298*299* @return a stack trace element describing the location of the call site300* currently being linked, or null if it is not invoked while a call301* site is being linked.302*/303public static StackTraceElement getLinkedCallSiteLocation() {304final StackTraceElement[] trace = new Throwable().getStackTrace();305for(int i = 0; i < trace.length - 1; ++i) {306final StackTraceElement frame = trace[i];307if(isRelinkFrame(frame) || isInitialLinkFrame(frame)) {308return trace[i + 1];309}310}311return null;312}313314/**315* Deprecated because of imprecise name.316*317* @deprecated Use {@link #getLinkedCallSiteLocation()} instead.318*319* @return see non-deprecated method320*/321@Deprecated322public static StackTraceElement getRelinkedCallSiteLocation() {323return getLinkedCallSiteLocation();324}325326/**327* Returns {@code true} if the frame represents {@code MethodHandleNatives.linkCallSite()},328* the frame immediately on top of the call site frame when the call site is329* being linked for the first time.330*331* @param frame the frame332*333* @return {@code true} if this frame represents {@code MethodHandleNatives.linkCallSite()}.334*/335private static boolean isInitialLinkFrame(final StackTraceElement frame) {336return testFrame(frame, INITIAL_LINK_METHOD_NAME, INITIAL_LINK_CLASS_NAME);337}338339/**340* Returns {@code true} if the frame represents {@code DynamicLinker.relink()},341* the frame immediately on top of the call site frame when the call site is342* being relinked (linked for second and subsequent times).343*344* @param frame the frame345*346* @return {@code true} if this frame represents {@code DynamicLinker.relink()}.347*/348private static boolean isRelinkFrame(final StackTraceElement frame) {349return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME);350}351352private static boolean testFrame(final StackTraceElement frame, final String methodName, final String className) {353return methodName.equals(frame.getMethodName()) && className.equals(frame.getClassName());354}355}356357358