--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java 2020-04-15 18:51:02.000000000 +0530 +++ /dev/null 2020-04-15 18:51:02.000000000 +0530 @@ -1,333 +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.internal.org.objectweb.asm.Opcodes.ACC_FINAL; -import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; -import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; -import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; -import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; -import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; - -import java.lang.invoke.CallSite; -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.CodeSigner; -import java.security.CodeSource; -import java.security.Permissions; -import java.security.PrivilegedAction; -import java.security.ProtectionDomain; -import java.security.SecureClassLoader; -import java.util.Objects; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; -import jdk.internal.org.objectweb.asm.commons.InstructionAdapter; -import jdk.nashorn.api.scripting.ScriptObjectMirror; -import jdk.nashorn.internal.objects.Global; -import jdk.nashorn.internal.runtime.Context; -import jdk.nashorn.internal.runtime.ECMAException; -import jdk.nashorn.internal.runtime.JSType; -import jdk.nashorn.internal.runtime.ScriptFunction; -import jdk.nashorn.internal.runtime.ScriptObject; -import jdk.nashorn.internal.runtime.ScriptRuntime; - -/** - * Provides static utility services to generated Java adapter classes. - */ -public final class JavaAdapterServices { - private static final ThreadLocal classOverrides = new ThreadLocal<>(); - private static final MethodHandle NO_PERMISSIONS_INVOKER = createNoPermissionsInvoker(); - - private JavaAdapterServices() { - } - - /** - * Given a script function used as a delegate for a SAM adapter, figure out - * the right object to use as its "this" when called. - * @param delegate the delegate function - * @param global the current global of the adapter - * @return either the passed global, or UNDEFINED if the function is strict. - */ - public static Object getCallThis(final ScriptFunction delegate, final Object global) { - return delegate.isStrict() ? ScriptRuntime.UNDEFINED : global; - } - - /** - * Throws a "not.an.object" type error. Used when the delegate passed to the - * adapter constructor is not a script object. - * @param obj the object that is not a script object. - */ - public static void notAnObject(final Object obj) { - throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); - } - - /** - * Checks if the passed object, which is supposed to be a callee retrieved - * through applying the GET_METHOD_PROPERTY operation on the delegate, is - * a ScriptFunction, or null or undefined. These are the only allowed values - * for adapter method implementations, so in case it is neither, it throws - * a type error. Note that this restriction is somewhat artificial; as the - * CALL dynamic operation could invoke any Nashorn callable. We are - * restricting adapters to actual ScriptFunction objects for now though. - * @param callee the callee to check - * @param name the name of the function - * @return the callee cast to a ScriptFunction, or null if it was null or undefined. - * @throws ECMAException representing a JS TypeError with "not.a.function" - * message if the passed callee is neither a script function, nor null, nor - * undefined. - */ - public static ScriptFunction checkFunction(final Object callee, final String name) { - if (callee instanceof ScriptFunction) { - return (ScriptFunction)callee; - } else if (JSType.nullOrUndefined(callee)) { - return null; - } - throw typeError("not.a.function.value", name, ScriptRuntime.safeToString(callee)); - } - - /** - * Returns a thread-local JS object used to define methods for the adapter class being initialized on the current - * thread. This method is public solely for implementation reasons, so the adapter classes can invoke it from their - * static initializers. - * @return the thread-local JS object used to define methods for the class being initialized. - */ - public static ScriptObject getClassOverrides() { - final ScriptObject overrides = classOverrides.get(); - assert overrides != null; - return overrides; - } - - /** - * Takes a method handle and an argument to it, and invokes the method handle passing it the argument. Basically - * equivalent to {@code method.invokeExact(arg)}, except that the method handle will be invoked in a protection - * domain with absolutely no permissions. - * @param method the method handle to invoke. The handle must have the exact type of {@code void(Object)}. - * @param arg the argument to pass to the handle. - * @throws Throwable if anything goes wrong. - */ - public static void invokeNoPermissions(final MethodHandle method, final Object arg) throws Throwable { - NO_PERMISSIONS_INVOKER.invokeExact(method, arg); - } - - /** - * Set the current global scope to that of the adapter global - * @param adapterGlobal the adapter's global scope - * @return a Runnable that when invoked restores the previous global - */ - public static Runnable setGlobal(final ScriptObject adapterGlobal) { - final Global currentGlobal = Context.getGlobal(); - if (adapterGlobal != currentGlobal) { - Context.setGlobal(adapterGlobal); - return ()->Context.setGlobal(currentGlobal); - } - return ()->{}; - } - - /** - * Get the current non-null global scope - * @return the current global scope - * @throws NullPointerException if the current global scope is null. - */ - public static ScriptObject getNonNullGlobal() { - return Objects.requireNonNull(Context.getGlobal(), "Current global is null"); - } - - /** - * Returns true if the object has its own toString function. Used - * when implementing toString for adapters. Since every JS Object has a - * toString function, we only override "String toString()" in adapters if - * it is explicitly specified and not inherited from a prototype. - * @param sobj the object - * @return true if the object has its own toString function. - */ - public static boolean hasOwnToString(final ScriptObject sobj) { - // NOTE: we could just use ScriptObject.hasOwnProperty("toString"), but - // its logic is more complex and this is what it boils down to with a - // fixed "toString" argument. - return sobj.getMap().findProperty("toString") != null; - } - - /** - * Returns the ScriptObject or Global field value from a ScriptObjectMirror using reflection. - * - * @param mirror the mirror object - * @param getGlobal true if we want the global object, false to return the script object - * @return the script object or global object - */ - public static ScriptObject unwrapMirror(final Object mirror, final boolean getGlobal) { - assert mirror instanceof ScriptObjectMirror; - try { - final Field field = getGlobal ? MirrorFieldHolder.GLOBAL_FIELD : MirrorFieldHolder.SOBJ_FIELD; - return (ScriptObject) field.get(mirror); - } catch (final IllegalAccessException x) { - throw new RuntimeException(x); - } - } - - /** - * Delegate to {@link Bootstrap#bootstrap(Lookup, String, MethodType, int)}. - * @param lookup MethodHandle lookup. - * @param opDesc Dynalink dynamic operation descriptor. - * @param type Method type. - * @param flags flags for call type, trace/profile etc. - * @return CallSite with MethodHandle to appropriate method or null if not found. - */ - public static CallSite bootstrap(final Lookup lookup, final String opDesc, final MethodType type, final int flags) { - return Bootstrap.bootstrap(lookup, opDesc, type, flags); - } - - static void setClassOverrides(final ScriptObject overrides) { - classOverrides.set(overrides); - } - - private static MethodHandle createNoPermissionsInvoker() { - final String className = "NoPermissionsInvoker"; - - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER | ACC_FINAL, className, null, "java/lang/Object", null); - final Type objectType = Type.getType(Object.class); - final Type methodHandleType = Type.getType(MethodHandle.class); - final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "invoke", - Type.getMethodDescriptor(Type.VOID_TYPE, methodHandleType, objectType), null, null)); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.invokevirtual(methodHandleType.getInternalName(), "invokeExact", Type.getMethodDescriptor( - Type.VOID_TYPE, objectType), false); - mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - cw.visitEnd(); - final byte[] bytes = cw.toByteArray(); - - final ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public ClassLoader run() { - return new SecureClassLoader(null) { - @Override - protected Class findClass(final String name) throws ClassNotFoundException { - if(name.equals(className)) { - return defineClass(name, bytes, 0, bytes.length, new ProtectionDomain( - new CodeSource(null, (CodeSigner[])null), new Permissions())); - } - throw new ClassNotFoundException(name); - } - }; - } - }); - - try { - return MethodHandles.publicLookup().findStatic(Class.forName(className, true, loader), "invoke", - MethodType.methodType(void.class, MethodHandle.class, Object.class)); - } catch(final ReflectiveOperationException e) { - throw new AssertionError(e.getMessage(), e); - } - } - - /** - * Invoked when returning Object from an adapted method to filter out internal Nashorn objects that must not be seen - * by the callers. Currently only transforms {@code ConsString} into {@code String} and transforms {@code ScriptObject} into {@code ScriptObjectMirror}. - * @param obj the return value - * @return the filtered return value. - */ - public static Object exportReturnValue(final Object obj) { - return NashornBeansLinker.exportArgument(obj, true); - } - - /** - * Invoked to convert a return value of a delegate function to primitive char. There's no suitable conversion in - * {@code JSType}, so we provide our own to adapters. - * @param obj the return value. - * @return the character value of the return value - */ - public static char toCharPrimitive(final Object obj) { - return JavaArgumentConverters.toCharPrimitive(obj); - } - - /** - * Returns a new {@link RuntimeException} wrapping the passed throwable. - * Makes generated bytecode smaller by doing an INVOKESTATIC to this method - * rather than the NEW/DUP_X1/SWAP/INVOKESPECIAL <init> sequence. - * @param t the original throwable to wrap - * @return a newly created runtime exception wrapping the passed throwable. - */ - public static RuntimeException wrapThrowable(final Throwable t) { - return new RuntimeException(t); - } - - /** - * Creates and returns a new {@link UnsupportedOperationException}. Makes - * generated bytecode smaller by doing INVOKESTATIC to this method rather - * than the NEW/DUP/INVOKESPECIAL <init> sequence. - * @return a newly created {@link UnsupportedOperationException}. - */ - public static UnsupportedOperationException unsupported() { - return new UnsupportedOperationException(); - } - - /** - * A bootstrap method used to collect invocation arguments into an Object array. - * for variable arity invocation. - * @param lookup the adapter's lookup (not used). - * @param name the call site name (not used). - * @param type the method type - * @return a method that takes the input parameters and packs them into a - * newly allocated Object array. - */ - public static CallSite createArrayBootstrap(final MethodHandles.Lookup lookup, final String name, final MethodType type) { - return new ConstantCallSite( - MethodHandles.identity(Object[].class) - .asCollector(Object[].class, type.parameterCount()) - .asType(type)); - } - - // Initialization on demand holder for accessible ScriptObjectMirror fields - private static class MirrorFieldHolder { - - private static final Field SOBJ_FIELD = getMirrorField("sobj"); - private static final Field GLOBAL_FIELD = getMirrorField("global"); - - private static Field getMirrorField(final String fieldName) { - try { - final Field field = ScriptObjectMirror.class.getDeclaredField(fieldName); - AccessController.doPrivileged((PrivilegedAction) () -> { - field.setAccessible(true); - return null; - }); - return field; - } catch (final NoSuchFieldException e) { - throw new RuntimeException(e); - } - } - } -}