--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java 2020-04-15 18:51:11.000000000 +0530 +++ /dev/null 2020-04-15 18:51:11.000000000 +0530 @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.runtime.linker; - -import static jdk.nashorn.internal.lookup.Lookup.MH; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.function.Supplier; -import jdk.dynalink.linker.ConversionComparator; -import jdk.dynalink.linker.GuardedInvocation; -import jdk.dynalink.linker.GuardingTypeConverterFactory; -import jdk.dynalink.linker.LinkRequest; -import jdk.dynalink.linker.LinkerServices; -import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; -import jdk.dynalink.linker.support.TypeUtilities; -import jdk.nashorn.internal.objects.Global; -import jdk.nashorn.internal.runtime.ConsString; -import jdk.nashorn.internal.runtime.JSType; -import jdk.nashorn.internal.runtime.ScriptRuntime; -import jdk.nashorn.internal.runtime.Symbol; - -/** - * Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other - * engines. It is used for treatment of strings, boolean, and numbers as JavaScript primitives. Also provides ECMAScript - * primitive type conversions for these types when linking to Java methods. - */ -final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator { - private static final GuardedInvocation VOID_TO_OBJECT = - new GuardedInvocation(MethodHandles.constant(Object.class, ScriptRuntime.UNDEFINED)); - - @Override - public boolean canLinkType(final Class type) { - return canLinkTypeStatic(type); - } - - private static boolean canLinkTypeStatic(final Class type) { - return type == String.class || type == Boolean.class || type == ConsString.class || type == Integer.class - || type == Double.class || type == Float.class || type == Short.class || type == Byte.class - || type == Symbol.class; - } - - @Override - public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) - throws Exception { - final Object self = request.getReceiver(); - return Bootstrap.asTypeSafeReturn(Global.primitiveLookup(request, self), linkerServices, request.getCallSiteDescriptor()); - } - - /** - * This implementation of type converter factory will pretty much allow implicit conversions of anything to anything - * else that's allowed among JavaScript primitive types (string to number, boolean to string, etc.) - * @param sourceType the type to convert from - * @param targetType the type to convert to - * @return a conditional converter from source to target type - */ - @Override - public GuardedInvocation convertToType(final Class sourceType, final Class targetType, final Supplier lookupSupplier) { - final MethodHandle mh = JavaArgumentConverters.getConverter(targetType); - if (mh == null) { - if(targetType == Object.class && sourceType == void.class) { - return VOID_TO_OBJECT; - } - return null; - } - - return new GuardedInvocation(mh, canLinkTypeStatic(sourceType) ? null : GUARD_PRIMITIVE).asType(mh.type().changeParameterType(0, sourceType)); - } - - /** - * Implements the somewhat involved prioritization of JavaScript primitive types conversions. Instead of explaining - * it here in prose, just follow the source code comments. - * @param sourceType the source type to convert from - * @param targetType1 one candidate target type - * @param targetType2 another candidate target type - * @return one of {@link jdk.dynalink.linker.ConversionComparator.Comparison} values signifying which - * target type should be favored for conversion. - */ - @Override - public Comparison compareConversion(final Class sourceType, final Class targetType1, final Class targetType2) { - final Class wrapper1 = getWrapperTypeOrSelf(targetType1); - if (sourceType == wrapper1) { - // Source type exactly matches target 1 - return Comparison.TYPE_1_BETTER; - } - final Class wrapper2 = getWrapperTypeOrSelf(targetType2); - if (sourceType == wrapper2) { - // Source type exactly matches target 2 - return Comparison.TYPE_2_BETTER; - } - - if (Number.class.isAssignableFrom(sourceType)) { - // If exactly one of the targets is a number, pick it. - if (Number.class.isAssignableFrom(wrapper1)) { - if (!Number.class.isAssignableFrom(wrapper2)) { - return Comparison.TYPE_1_BETTER; - } - } else if (Number.class.isAssignableFrom(wrapper2)) { - return Comparison.TYPE_2_BETTER; - } - - // If exactly one of the targets is a character, pick it. Numbers can be reasonably converted to chars using - // the UTF-16 values. - if (Character.class == wrapper1) { - return Comparison.TYPE_1_BETTER; - } else if (Character.class == wrapper2) { - return Comparison.TYPE_2_BETTER; - } - - // For all other cases, we fall through to the next if statement - not that we repeat the condition in it - // too so if we entered this branch, we'll enter the below if statement too. - } - - if (sourceType == String.class || sourceType == Boolean.class || Number.class.isAssignableFrom(sourceType)) { - // Treat wrappers as primitives. - final Class primitiveType1 = getPrimitiveTypeOrSelf(targetType1); - final Class primitiveType2 = getPrimitiveTypeOrSelf(targetType2); - // Basically, choose the widest possible primitive type. (First "if" returning TYPE_2_BETTER is correct; - // when faced with a choice between double and int, choose double). - if (TypeUtilities.isMethodInvocationConvertible(primitiveType1, primitiveType2)) { - return Comparison.TYPE_2_BETTER; - } else if (TypeUtilities.isMethodInvocationConvertible(primitiveType2, primitiveType1)) { - return Comparison.TYPE_1_BETTER; - } - // Ok, at this point we're out of possible number conversions, so try strings. A String can represent any - // value without loss, so if one of the potential targets is string, go for it. - if (targetType1 == String.class) { - return Comparison.TYPE_1_BETTER; - } - if (targetType2 == String.class) { - return Comparison.TYPE_2_BETTER; - } - } - - return Comparison.INDETERMINATE; - } - - private static Class getPrimitiveTypeOrSelf(final Class type) { - final Class primitive = TypeUtilities.getPrimitiveType(type); - return primitive == null ? type : primitive; - } - - private static Class getWrapperTypeOrSelf(final Class type) { - final Class wrapper = TypeUtilities.getWrapperType(type); - return wrapper == null ? type : wrapper; - } - - @SuppressWarnings("unused") - private static boolean isJavaScriptPrimitive(final Object o) { - return JSType.isString(o) || o instanceof Boolean || JSType.isNumber(o) || o == null || o instanceof Symbol; - } - - private static final MethodHandle GUARD_PRIMITIVE = findOwnMH("isJavaScriptPrimitive", boolean.class, Object.class); - - private static MethodHandle findOwnMH(final String name, final Class rtype, final Class... types) { - return MH.findStatic(MethodHandles.lookup(), NashornPrimitiveLinker.class, name, MH.type(rtype, types)); - } -}