src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java

Tue, 14 Oct 2014 16:16:12 +0530

author
sundar
date
Tue, 14 Oct 2014 16:16:12 +0530
changeset 1053
a35c8136c045
parent 1017
e83ceda86582
child 1088
b49b6786afad
permissions
-rw-r--r--

8050977: Java8 Javascript Nashorn exception: no current Global instance for nashorn
Reviewed-by: attila, lagergren, hannesw

     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  */
    26 package jdk.nashorn.internal.runtime.linker;
    28 import java.lang.invoke.MethodHandle;
    29 import java.lang.invoke.MethodHandles;
    30 import java.lang.invoke.MethodType;
    31 import jdk.internal.dynalink.beans.BeansLinker;
    32 import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
    33 import jdk.internal.dynalink.linker.GuardedInvocation;
    34 import jdk.internal.dynalink.linker.GuardingDynamicLinker;
    35 import jdk.internal.dynalink.linker.LinkRequest;
    36 import jdk.internal.dynalink.linker.LinkerServices;
    37 import jdk.internal.dynalink.support.Lookup;
    38 import jdk.nashorn.api.scripting.ScriptUtils;
    39 import jdk.nashorn.internal.objects.NativeArray;
    40 import jdk.nashorn.internal.runtime.ConsString;
    41 import jdk.nashorn.internal.runtime.ScriptObject;
    42 import jdk.nashorn.internal.runtime.options.Options;
    44 /**
    45  * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
    46  * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
    47  * observable (currently ConsString and ScriptObject) to Java APIs, but rather that we flatten it into a String. We can't just add
    48  * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
    49  * the target method handle parameter signature is {@code Object}.
    50  */
    51 public class NashornBeansLinker implements GuardingDynamicLinker {
    52     // System property to control whether to wrap ScriptObject->ScriptObjectMirror for
    53     // Object type arguments of Java method calls, field set and array set.
    54     private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
    56     private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
    57     private static final MethodHandle EXPORT_NATIVE_ARRAY = new Lookup(MethodHandles.lookup()).findOwnStatic("exportNativeArray", Object.class, NativeArray.class);
    58     private static final MethodHandle EXPORT_SCRIPT_OBJECT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportScriptObject", Object.class, ScriptObject.class);
    59     private static final MethodHandle IMPORT_RESULT = new Lookup(MethodHandles.lookup()).findOwnStatic("importResult", Object.class, Object.class);
    61     private final BeansLinker beansLinker = new BeansLinker();
    63     @Override
    64     public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
    65         return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
    66     }
    68     /**
    69      * Delegates to the specified linker but injects its linker services wrapper so that it will apply all special
    70      * conversions that this class does.
    71      * @param delegateLinker the linker to which the actual work is delegated to.
    72      * @param linkRequest the delegated link request
    73      * @param linkerServices the original link services that will be augmented with special conversions
    74      * @return the guarded invocation from the delegate, possibly augmented with special conversions
    75      * @throws Exception if the delegate throws an exception
    76      */
    77     public static GuardedInvocation getGuardedInvocation(final GuardingDynamicLinker delegateLinker, final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
    78         return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
    79     }
    81     @SuppressWarnings("unused")
    82     private static Object exportArgument(final Object arg) {
    83         return exportArgument(arg, MIRROR_ALWAYS);
    84     }
    86     @SuppressWarnings("unused")
    87     private static Object exportNativeArray(final NativeArray arg) {
    88         return exportArgument(arg, MIRROR_ALWAYS);
    89     }
    91     @SuppressWarnings("unused")
    92     private static Object exportScriptObject(final ScriptObject arg) {
    93         return exportArgument(arg, MIRROR_ALWAYS);
    94     }
    96     @SuppressWarnings("unused")
    97     private static Object exportScriptArray(final NativeArray arg) {
    98         return exportArgument(arg, MIRROR_ALWAYS);
    99     }
   101     static Object exportArgument(final Object arg, final boolean mirrorAlways) {
   102         if (arg instanceof ConsString) {
   103             return arg.toString();
   104         } else if (mirrorAlways && arg instanceof ScriptObject) {
   105             return ScriptUtils.wrap((ScriptObject)arg);
   106         } else {
   107             return arg;
   108         }
   109     }
   111     @SuppressWarnings("unused")
   112     private static Object importResult(final Object arg) {
   113         return ScriptUtils.unwrap(arg);
   114     }
   116     private static class NashornBeansLinkerServices implements LinkerServices {
   117         private final LinkerServices linkerServices;
   119         NashornBeansLinkerServices(final LinkerServices linkerServices) {
   120             this.linkerServices = linkerServices;
   121         }
   123         @Override
   124         public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
   125             final MethodType handleType = handle.type();
   126             final int paramCount = handleType.parameterCount();
   127             assert fromType.parameterCount() == handleType.parameterCount();
   129             MethodType newFromType = fromType;
   130             MethodHandle[] filters = null;
   131             for(int i = 0; i < paramCount; ++i) {
   132                 final MethodHandle filter = argConversionFilter(handleType.parameterType(i), fromType.parameterType(i));
   133                 if (filter != null) {
   134                     if (filters == null) {
   135                         filters = new MethodHandle[paramCount];
   136                     }
   137                     // "erase" specific type with Object type or else we'll get filter mismatch
   138                     newFromType = newFromType.changeParameterType(i, Object.class);
   139                     filters[i] = filter;
   140                 }
   141             }
   143             final MethodHandle typed = linkerServices.asType(handle, newFromType);
   144             MethodHandle result = filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
   145             // Filter Object typed return value for possible ScriptObjectMirror. We convert
   146             // ScriptObjectMirror as ScriptObject (if it is mirror from current global).
   147             if (MIRROR_ALWAYS && areBothObjects(handleType.returnType(), fromType.returnType())) {
   148                 result = MethodHandles.filterReturnValue(result, IMPORT_RESULT);
   149             }
   151             return result;
   152         }
   154         private static MethodHandle argConversionFilter(final Class<?> handleType, final Class<?> fromType) {
   155             if (handleType == Object.class) {
   156                 if (fromType == Object.class) {
   157                     return EXPORT_ARGUMENT;
   158                 } else if (fromType == NativeArray.class) {
   159                     return EXPORT_NATIVE_ARRAY;
   160                 } else if (fromType == ScriptObject.class) {
   161                     return EXPORT_SCRIPT_OBJECT;
   162                 }
   163             }
   164             return null;
   165         }
   167         private static boolean areBothObjects(final Class<?> handleType, final Class<?> fromType) {
   168             return handleType == Object.class && fromType == Object.class;
   169         }
   171         @Override
   172         public MethodHandle asTypeLosslessReturn(final MethodHandle handle, final MethodType fromType) {
   173             return Implementation.asTypeLosslessReturn(this, handle, fromType);
   174         }
   176         @Override
   177         public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
   178             return linkerServices.getTypeConverter(sourceType, targetType);
   179         }
   181         @Override
   182         public boolean canConvert(final Class<?> from, final Class<?> to) {
   183             return linkerServices.canConvert(from, to);
   184         }
   186         @Override
   187         public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
   188             return linkerServices.getGuardedInvocation(linkRequest);
   189         }
   191         @Override
   192         public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
   193             if (sourceType == ConsString.class) {
   194                 if (String.class == targetType1 || CharSequence.class == targetType1) {
   195                     return Comparison.TYPE_1_BETTER;
   196                 }
   198                 if (String.class == targetType2 || CharSequence.class == targetType2) {
   199                     return Comparison.TYPE_2_BETTER;
   200                 }
   201             }
   202             return linkerServices.compareConversion(sourceType, targetType1, targetType2);
   203         }
   204     }
   205 }

mercurial