nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ChainedCallSite.java
changeset 33006 99298bc38e28
parent 32941 be82ab9eb287
child 33330 35531ae624ef
equal deleted inserted replaced
33005:19c2fe67d821 33006:99298bc38e28
    83 
    83 
    84 package jdk.internal.dynalink;
    84 package jdk.internal.dynalink;
    85 
    85 
    86 import java.lang.invoke.MethodHandle;
    86 import java.lang.invoke.MethodHandle;
    87 import java.lang.invoke.MethodHandles;
    87 import java.lang.invoke.MethodHandles;
       
    88 import java.util.Arrays;
    88 import java.util.Iterator;
    89 import java.util.Iterator;
    89 import java.util.LinkedList;
    90 import java.util.LinkedList;
    90 import java.util.concurrent.atomic.AtomicReference;
       
    91 import jdk.internal.dynalink.linker.GuardedInvocation;
    91 import jdk.internal.dynalink.linker.GuardedInvocation;
    92 import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
    92 import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
    93 import jdk.internal.dynalink.support.Lookup;
    93 import jdk.internal.dynalink.support.Lookup;
    94 
    94 
    95 /**
    95 /**
   110                 MethodHandle.class, boolean.class);
   110                 MethodHandle.class, boolean.class);
   111         PRUNE_CATCHES      = MethodHandles.insertArguments(PRUNE, 2, true);
   111         PRUNE_CATCHES      = MethodHandles.insertArguments(PRUNE, 2, true);
   112         PRUNE_SWITCHPOINTS = MethodHandles.insertArguments(PRUNE, 2, false);
   112         PRUNE_SWITCHPOINTS = MethodHandles.insertArguments(PRUNE, 2, false);
   113     }
   113     }
   114 
   114 
   115     private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>();
   115     /**
       
   116      * Contains the invocations currently linked into this call site's target. They are used when we are
       
   117      * relinking to rebuild the guardWithTest chain. Valid values for this field are: {@code null} if there's
       
   118      * no linked invocations, or an instance of {@link GuardedInvocation} if there is exactly one previous
       
   119      * invocation, or an instance of {@code GuardedInvocation[]} if there is more than one previous
       
   120      * invocation.
       
   121      */
       
   122     private Object invocations;
   116 
   123 
   117     /**
   124     /**
   118      * Creates a new chained call site.
   125      * Creates a new chained call site.
   119      * @param descriptor the descriptor for the call site.
   126      * @param descriptor the descriptor for the call site.
   120      */
   127      */
   140     public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) {
   147     public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) {
   141         relinkInternal(guardedInvocation, fallback, true, false);
   148         relinkInternal(guardedInvocation, fallback, true, false);
   142     }
   149     }
   143 
   150 
   144     private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) {
   151     private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) {
   145         final LinkedList<GuardedInvocation> currentInvocations = invocations.get();
   152         final Object currentInvocations = invocations;
   146         @SuppressWarnings({ "unchecked", "rawtypes" })
   153         final LinkedList<GuardedInvocation> newInvocations;
   147         final LinkedList<GuardedInvocation> newInvocations =
   154         if (currentInvocations == null || reset) {
   148             currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone();
   155             newInvocations = new LinkedList<>();
       
   156         } else if (currentInvocations instanceof GuardedInvocation) {
       
   157             newInvocations = new LinkedList<>();
       
   158             newInvocations.add((GuardedInvocation)currentInvocations);
       
   159         } else if (currentInvocations instanceof GuardedInvocation[]) {
       
   160             newInvocations = new LinkedList<>(Arrays.asList(((GuardedInvocation[])currentInvocations)));
       
   161         } else {
       
   162             throw new AssertionError();
       
   163         }
   149 
   164 
   150         // First, prune the chain of invalidated switchpoints, we always do this
   165         // First, prune the chain of invalidated switchpoints, we always do this
   151         // We also remove any catches if the remove catches flag is set
   166         // We also remove any catches if the remove catches flag is set
   152         for(final Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) {
   167         for(final Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) {
   153             final GuardedInvocation inv = it.next();
   168             final GuardedInvocation inv = it.next();
   175         MethodHandle target = relink;
   190         MethodHandle target = relink;
   176         for(final GuardedInvocation inv: newInvocations) {
   191         for(final GuardedInvocation inv: newInvocations) {
   177             target = inv.compose(target, pruneAndInvokeSwitchPoints, pruneAndInvokeCatches);
   192             target = inv.compose(target, pruneAndInvokeSwitchPoints, pruneAndInvokeCatches);
   178         }
   193         }
   179 
   194 
   180         // If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case
   195         switch (newInvocations.size()) {
   181         // we lost the race for multithreaded update, just do nothing. Either the other thread installed the same thing
   196             case 0:
   182         // we wanted to install, or otherwise, we'll be asked to relink again.
   197                 invocations = null;
   183         if(invocations.compareAndSet(currentInvocations, newInvocations)) {
   198                 break;
   184             setTarget(target);
   199             case 1:
   185         }
   200                 invocations = newInvocations.getFirst();
       
   201                 break;
       
   202             default:
       
   203                 invocations = newInvocations.toArray(new GuardedInvocation[newInvocations.size()]);
       
   204         }
       
   205         setTarget(target);
   186         return target;
   206         return target;
   187     }
   207     }
   188 
   208 
   189     /**
   209     /**
   190      * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
   210      * Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that