nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java
changeset 34456 84eaea8d0574
parent 34096 5ac6287ec71a
parent 34455 cc9f05d3caf0
child 34457 81a65a2faef3
equal deleted inserted replaced
34096:5ac6287ec71a 34456:84eaea8d0574
     1 /*
       
     2  * Copyright (c) 2010, 2013, 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 
       
    84 package jdk.internal.dynalink.linker.support;
       
    85 
       
    86 import java.util.Collections;
       
    87 import java.util.LinkedList;
       
    88 import java.util.List;
       
    89 import java.util.Objects;
       
    90 import jdk.internal.dynalink.linker.GuardedInvocation;
       
    91 import jdk.internal.dynalink.linker.GuardingDynamicLinker;
       
    92 import jdk.internal.dynalink.linker.LinkRequest;
       
    93 import jdk.internal.dynalink.linker.LinkerServices;
       
    94 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
       
    95 
       
    96 /**
       
    97  * A composite type-based guarding dynamic linker. When a receiver of a not yet
       
    98  * seen class is encountered, all linkers are queried sequentially on their
       
    99  * {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} method. The linkers
       
   100  * returning true are then bound to the class, and next time a receiver of same
       
   101  * type is encountered, the linking is delegated to those linkers only, speeding
       
   102  * up dispatch.
       
   103  */
       
   104 public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker {
       
   105     // Using a separate static class instance so there's no strong reference from the class value back to the composite
       
   106     // linker.
       
   107     private static class ClassToLinker extends ClassValue<List<TypeBasedGuardingDynamicLinker>> {
       
   108         private static final List<TypeBasedGuardingDynamicLinker> NO_LINKER = Collections.emptyList();
       
   109         private final TypeBasedGuardingDynamicLinker[] linkers;
       
   110         private final List<TypeBasedGuardingDynamicLinker>[] singletonLinkers;
       
   111 
       
   112         @SuppressWarnings({"unchecked", "rawtypes"})
       
   113         ClassToLinker(final TypeBasedGuardingDynamicLinker[] linkers) {
       
   114             this.linkers = linkers;
       
   115             singletonLinkers = new List[linkers.length];
       
   116             for(int i = 0; i < linkers.length; ++i) {
       
   117                 singletonLinkers[i] = Collections.singletonList(linkers[i]);
       
   118             }
       
   119         }
       
   120 
       
   121         @SuppressWarnings("fallthrough")
       
   122         @Override
       
   123         protected List<TypeBasedGuardingDynamicLinker> computeValue(final Class<?> clazz) {
       
   124             List<TypeBasedGuardingDynamicLinker> list = NO_LINKER;
       
   125             for(int i = 0; i < linkers.length; ++i) {
       
   126                 final TypeBasedGuardingDynamicLinker linker = linkers[i];
       
   127                 if(linker.canLinkType(clazz)) {
       
   128                     switch(list.size()) {
       
   129                         case 0: {
       
   130                             list = singletonLinkers[i];
       
   131                             break;
       
   132                         }
       
   133                         case 1: {
       
   134                             list = new LinkedList<>(list);
       
   135                         }
       
   136                         default: {
       
   137                             list.add(linker);
       
   138                         }
       
   139                     }
       
   140                 }
       
   141             }
       
   142             return list;
       
   143         }
       
   144     }
       
   145 
       
   146     private final ClassValue<List<TypeBasedGuardingDynamicLinker>> classToLinker;
       
   147 
       
   148     /**
       
   149      * Creates a new composite type-based linker.
       
   150      *
       
   151      * @param linkers the component linkers
       
   152      * @throws NullPointerException if {@code linkers} or any of its elements
       
   153      * are null.
       
   154      */
       
   155     public CompositeTypeBasedGuardingDynamicLinker(final Iterable<? extends TypeBasedGuardingDynamicLinker> linkers) {
       
   156         final List<TypeBasedGuardingDynamicLinker> l = new LinkedList<>();
       
   157         for(final TypeBasedGuardingDynamicLinker linker: linkers) {
       
   158             l.add(Objects.requireNonNull(linker));
       
   159         }
       
   160         this.classToLinker = new ClassToLinker(l.toArray(new TypeBasedGuardingDynamicLinker[l.size()]));
       
   161     }
       
   162 
       
   163     /**
       
   164      * Returns true if at least one of the composite linkers returns true from
       
   165      * {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} for the type.
       
   166      * @param type the type to link
       
   167      * @return true true if at least one of the composite linkers returns true
       
   168      * from {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)}, false
       
   169      * otherwise.
       
   170      */
       
   171     @Override
       
   172     public boolean canLinkType(final Class<?> type) {
       
   173         return !classToLinker.get(type).isEmpty();
       
   174     }
       
   175 
       
   176     @Override
       
   177     public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
       
   178             throws Exception {
       
   179         final Object obj = linkRequest.getReceiver();
       
   180         if(obj == null) {
       
   181             return null;
       
   182         }
       
   183         for(final TypeBasedGuardingDynamicLinker linker: classToLinker.get(obj.getClass())) {
       
   184             final GuardedInvocation invocation = linker.getGuardedInvocation(linkRequest, linkerServices);
       
   185             if(invocation != null) {
       
   186                 return invocation;
       
   187             }
       
   188         }
       
   189         return null;
       
   190     }
       
   191 
       
   192     /**
       
   193      * Optimizes a list of type-based linkers. If a group of adjacent linkers in
       
   194      * the list all implement {@link TypeBasedGuardingDynamicLinker}, they will
       
   195      * be replaced with a single instance of
       
   196      * {@link CompositeTypeBasedGuardingDynamicLinker} that contains them.
       
   197      *
       
   198      * @param linkers the list of linkers to optimize
       
   199      * @return the optimized list
       
   200      * @throws NullPointerException if {@code linkers} or any of its elements
       
   201      * are null.
       
   202      */
       
   203     public static List<GuardingDynamicLinker> optimize(final Iterable<? extends GuardingDynamicLinker> linkers) {
       
   204         final List<GuardingDynamicLinker> llinkers = new LinkedList<>();
       
   205         final List<TypeBasedGuardingDynamicLinker> tblinkers = new LinkedList<>();
       
   206         for(final GuardingDynamicLinker linker: linkers) {
       
   207             Objects.requireNonNull(linker);
       
   208             if(linker instanceof TypeBasedGuardingDynamicLinker) {
       
   209                 tblinkers.add((TypeBasedGuardingDynamicLinker)linker);
       
   210             } else {
       
   211                 addTypeBased(llinkers, tblinkers);
       
   212                 llinkers.add(linker);
       
   213             }
       
   214         }
       
   215         addTypeBased(llinkers, tblinkers);
       
   216         return llinkers;
       
   217     }
       
   218 
       
   219     private static void addTypeBased(final List<GuardingDynamicLinker> llinkers,
       
   220             final List<TypeBasedGuardingDynamicLinker> tblinkers) {
       
   221         switch(tblinkers.size()) {
       
   222             case 0: {
       
   223                 break;
       
   224             }
       
   225             case 1: {
       
   226                 llinkers.addAll(tblinkers);
       
   227                 tblinkers.clear();
       
   228                 break;
       
   229             }
       
   230             default: {
       
   231                 llinkers.add(new CompositeTypeBasedGuardingDynamicLinker(tblinkers));
       
   232                 tblinkers.clear();
       
   233                 break;
       
   234             }
       
   235         }
       
   236     }
       
   237 }