Path: blob/aarch64-shenandoah-jdk8u272-b10/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java
48579 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.util.Iterator;88import java.util.LinkedList;89import java.util.concurrent.atomic.AtomicReference;90import jdk.internal.dynalink.linker.GuardedInvocation;91import jdk.internal.dynalink.support.AbstractRelinkableCallSite;92import jdk.internal.dynalink.support.Lookup;9394/**95* A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method96* handles can be chained, cascading from one to the other through97* {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. When this call site has to link a new98* method handle and the length of the chain is already at the maximum, it will throw away the oldest method handle.99* Switchpoint-invalidated handles in the chain are removed eagerly (on each linking request, and whenever a100* switchpoint-invalidated method handle is traversed during invocation). There is currently no profiling101* attached to the handles in the chain, so they are never reordered based on usage; the most recently linked method102* handle is always at the start of the chain.103*/104public class ChainedCallSite extends AbstractRelinkableCallSite {105private static final MethodHandle PRUNE_CATCHES =106MethodHandles.insertArguments(107Lookup.findOwnSpecial(108MethodHandles.lookup(),109"prune",110MethodHandle.class,111MethodHandle.class,112boolean.class),1132,114true);115116private static final MethodHandle PRUNE_SWITCHPOINTS =117MethodHandles.insertArguments(118Lookup.findOwnSpecial(119MethodHandles.lookup(),120"prune",121MethodHandle.class,122MethodHandle.class,123boolean.class),1242,125false);126127private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>();128129/**130* Creates a new chained call site.131* @param descriptor the descriptor for the call site.132*/133public ChainedCallSite(final CallSiteDescriptor descriptor) {134super(descriptor);135}136137/**138* The maximum number of method handles in the chain. Defaults to 8. You can override it in a subclass if you need139* to change the value. If your override returns a value less than 1, the code will break.140* @return the maximum number of method handles in the chain.141*/142protected int getMaxChainLength() {143return 8;144}145146@Override147public void relink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) {148relinkInternal(guardedInvocation, fallback, false, false);149}150151@Override152public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) {153relinkInternal(guardedInvocation, fallback, true, false);154}155156private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) {157final LinkedList<GuardedInvocation> currentInvocations = invocations.get();158@SuppressWarnings({ "unchecked", "rawtypes" })159final LinkedList<GuardedInvocation> newInvocations =160currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone();161162// First, prune the chain of invalidated switchpoints, we always do this163// We also remove any catches if the remove catches flag is set164for(final Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) {165final GuardedInvocation inv = it.next();166if(inv.hasBeenInvalidated() || (removeCatches && inv.getException() != null)) {167it.remove();168}169}170171// prune() is allowed to invoke this method with invocation == null meaning we're just pruning the chain and not172// adding any new invocations to it.173if(invocation != null) {174// Remove oldest entry if we're at max length175if(newInvocations.size() == getMaxChainLength()) {176newInvocations.removeFirst();177}178newInvocations.addLast(invocation);179}180181// prune-and-invoke is used as the fallback for invalidated switchpoints. If a switchpoint gets invalidated, we182// rebuild the chain and get rid of all invalidated switchpoints instead of letting them linger.183final MethodHandle pruneAndInvokeSwitchPoints = makePruneAndInvokeMethod(relink, getPruneSwitchpoints());184final MethodHandle pruneAndInvokeCatches = makePruneAndInvokeMethod(relink, getPruneCatches());185186// Fold the new chain187MethodHandle target = relink;188for(final GuardedInvocation inv: newInvocations) {189target = inv.compose(target, pruneAndInvokeSwitchPoints, pruneAndInvokeCatches);190}191192// If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case193// we lost the race for multithreaded update, just do nothing. Either the other thread installed the same thing194// we wanted to install, or otherwise, we'll be asked to relink again.195if(invocations.compareAndSet(currentInvocations, newInvocations)) {196setTarget(target);197}198return target;199}200201/**202* Get the switchpoint pruning function for a chained call site203* @return function that removes invalidated switchpoints tied to callsite guard chain and relinks204*/205protected MethodHandle getPruneSwitchpoints() {206return PRUNE_SWITCHPOINTS;207}208209/**210* Get the catch pruning function for a chained call site211* @return function that removes all catches tied to callsite guard chain and relinks212*/213protected MethodHandle getPruneCatches() {214return PRUNE_CATCHES;215}216217/**218* Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that219* chain.220* @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).221* @return a method handle for prune-and-invoke222*/223private MethodHandle makePruneAndInvokeMethod(final MethodHandle relink, final MethodHandle prune) {224// Bind prune to (this, relink)225final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink);226// Make it ignore all incoming arguments227final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());228// Invoke prune, then invoke the call site target with original arguments229return MethodHandles.foldArguments(MethodHandles.exactInvoker(type()), ignoreArgsPrune);230}231232@SuppressWarnings("unused")233private MethodHandle prune(final MethodHandle relink, final boolean catches) {234return relinkInternal(null, relink, false, catches);235}236}237238239