nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
author sundar
Tue, 12 Mar 2013 18:12:42 +0530
changeset 16522 d643e3ee819c
parent 16277 fd698c5ee684
child 16525 1409942e618e
permissions -rw-r--r--
8009757: Package access clean up and refactoring Reviewed-by: jlaskey, lagergren, attila
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
     1
/*
16151
97c1e756ae1e 8005663: Update copyright year to 2013
jlaskey
parents: 16147
diff changeset
     2
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
     4
 *
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    10
 *
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    15
 * accompanied this code).
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    16
 *
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    20
 *
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    23
 * questions.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    24
 */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    25
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    26
package jdk.nashorn.internal.runtime.linker;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    27
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    28
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    29
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    30
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    31
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    32
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    33
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    34
import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    35
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    36
import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    37
import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    38
import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    39
import static jdk.internal.org.objectweb.asm.Opcodes.IFNONNULL;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    40
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    41
import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    42
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    43
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
16277
fd698c5ee684 8009559: clean up method handle lookup code.
sundar
parents: 16272
diff changeset
    44
import static jdk.nashorn.internal.lookup.Lookup.MH;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    45
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    46
import java.lang.invoke.MethodHandle;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    47
import java.lang.invoke.MethodType;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    48
import java.lang.reflect.Constructor;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    49
import java.lang.reflect.Method;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    50
import java.lang.reflect.Modifier;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    51
import java.security.AccessController;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    52
import java.security.AllPermission;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    53
import java.security.CodeSigner;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    54
import java.security.CodeSource;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    55
import java.security.Permissions;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    56
import java.security.PrivilegedAction;
16522
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
    57
import java.security.PrivilegedExceptionAction;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    58
import java.security.ProtectionDomain;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    59
import java.security.SecureClassLoader;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    60
import java.security.SecureRandom;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    61
import java.util.ArrayList;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    62
import java.util.Arrays;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    63
import java.util.Collection;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    64
import java.util.Collections;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    65
import java.util.HashMap;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    66
import java.util.HashSet;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    67
import java.util.Iterator;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    68
import java.util.LinkedHashMap;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    69
import java.util.LinkedList;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    70
import java.util.List;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    71
import java.util.Map;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    72
import java.util.Random;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    73
import java.util.Set;
16234
86cb162cec6c 8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents: 16221
diff changeset
    74
import jdk.internal.dynalink.beans.StaticClass;
86cb162cec6c 8008085: Integrate Dynalink source code into Nashorn codebase
attila
parents: 16221
diff changeset
    75
import jdk.internal.dynalink.support.LinkRequestImpl;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    76
import jdk.internal.org.objectweb.asm.ClassWriter;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    77
import jdk.internal.org.objectweb.asm.Label;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    78
import jdk.internal.org.objectweb.asm.Opcodes;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    79
import jdk.internal.org.objectweb.asm.Type;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    80
import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    81
import jdk.nashorn.internal.objects.NativeJava;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    82
import jdk.nashorn.internal.runtime.Context;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    83
import jdk.nashorn.internal.runtime.ECMAErrors;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    84
import jdk.nashorn.internal.runtime.ECMAException;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    85
import jdk.nashorn.internal.runtime.ScriptFunction;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    86
import jdk.nashorn.internal.runtime.ScriptObject;
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
    87
import jdk.nashorn.internal.runtime.ScriptRuntime;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    88
import jdk.nashorn.internal.runtime.Undefined;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    89
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    90
/**
16272
675a0caf75bc 8009263: Fix all javadoc errors in nashorn code
sundar
parents: 16256
diff changeset
    91
 * <p>A factory class that generates adapter classes. Adapter classes allow implementation of Java interfaces and
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    92
 * extending of Java classes from JavaScript. For every combination of a superclass to extend and interfaces to
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    93
 * implement (collectively: "original types"), exactly one adapter class is generated that extends the specified
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    94
 * superclass and implements the specified interfaces.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    95
 * </p><p>
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
    96
 * The adapter class is generated in a new secure class loader that inherits Nashorn's protection domain, and has either
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    97
 * one of the original types' class loader or the Nashorn's class loader as its parent - the parent class loader
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    98
 * is chosen so that all the original types and the Nashorn core classes are visible from it (as the adapter will have
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
    99
 * constant pool references to ScriptObject and ScriptFunction classes). In case none of the candidate class loaders has
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   100
 * visibility of all the required types, an error is thrown.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   101
 * </p><p>
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   102
 * For every protected or public constructor in the extended class, the adapter class will have one or two public
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   103
 * constructors (visibility of protected constructors in the extended class is promoted to public). In every case, for
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   104
 * every original constructor, a new constructor taking a trailing ScriptObject argument preceded by original
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   105
 * constructor arguments is present on the adapter class. When such a constructor is invoked, the passed ScriptObject's
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   106
 * member functions are used to implement and/or override methods on the original class, dispatched by name. A single
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   107
 * JavaScript function will act as the implementation for all overloaded methods of the same name. When methods on an
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   108
 * adapter instance are invoked, the functions are invoked having the ScriptObject passed in the instance constructor as
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   109
 * their "this". Subsequent changes to the ScriptObject (reassignment or removal of its functions) are not reflected in
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   110
 * the adapter instance; the method implementations are bound to functions at constructor invocation time.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   111
 * {@code java.lang.Object} methods {@code equals}, {@code hashCode}, and {@code toString} can also be overridden. The
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   112
 * only restriction is that since every JavaScript object already has a {@code toString} function through the
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   113
 * {@code Object.prototype}, the {@code toString} in the adapter is only overridden if the passed ScriptObject has a
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   114
 * {@code toString} function as its own property, and not inherited from a prototype. All other adapter methods can be
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   115
 * implemented or overridden through a prototype-inherited function of the ScriptObject passed to the constructor too.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   116
 * </p><p>
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   117
 * If the original types collectively have only one abstract method, or have several of them, but all share the
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   118
 * same name, an additional constructor is provided for every original constructor; this one takes a ScriptFunction as
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   119
 * its last argument preceded by original constructor arguments. This constructor will use the passed function as the
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   120
 * implementation for all abstract methods. For consistency, any concrete methods sharing the single abstract method
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   121
 * name will also be overridden by the function. When methods on the adapter instance are invoked, the ScriptFunction is
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   122
 * invoked with {@code null} as its "this".
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   123
 * </p><p>
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   124
 * For adapter methods that return values, all the JavaScript-to-Java conversions supported by Nashorn will be in effect
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   125
 * to coerce the JavaScript function return value to the expected Java return type.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   126
 * </p><p>
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   127
 * Since we are adding a trailing argument to the generated constructors in the adapter class, they will never be
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   128
 * declared as variable arity, even if the original constructor in the superclass was declared as variable arity. The
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   129
 * reason we are passing the additional argument at the end of the argument list instead at the front is that the
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   130
 * source-level script expression <code>new X(a, b) { ... }</code> (which is a proprietary syntax extension Nashorn uses
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   131
 * to resemble Java anonymous classes) is actually equivalent to <code>new X(a, b, { ... })</code>.
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   132
 * </p><p>
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   133
 * You normally don't use this class directly, but rather either create adapters from script using
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   134
 * {@link NativeJava#extend(Object, Object...)}, using the {@code new} operator on abstract classes and interfaces (see
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   135
 * {@link NativeJava#type(Object, Object)}), or implicitly when passing script functions to Java methods expecting SAM
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   136
 * types.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   137
 * </p>
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   138
 */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   139
16185
893aabe8c800 8006635: Reduce access levels as much as possible
sundar
parents: 16178
diff changeset
   140
public final class JavaAdapterFactory {
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   141
    private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   142
    private static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   143
    private static final Type OBJECT_TYPE = Type.getType(Object.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   144
    private static final Type STRING_TYPE = Type.getType(String.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   145
    private static final Type CONTEXT_TYPE = Type.getType(Context.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   146
    private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   147
    private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   148
    private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   149
            OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE, Type.BOOLEAN_TYPE);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   150
    private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   151
            SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE, Type.BOOLEAN_TYPE);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   152
    private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   153
    private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   154
    private static final Type PRIVILEGED_ACTION_TYPE = Type.getType(PrivilegedAction.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   155
    private static final Type UNSUPPORTED_OPERATION_TYPE = Type.getType(UnsupportedOperationException.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   156
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   157
    private static final String THIS_CLASS_TYPE_NAME = Type.getInternalName(JavaAdapterFactory.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   158
    private static final String RUNTIME_EXCEPTION_TYPE_NAME = RUNTIME_EXCEPTION_TYPE.getInternalName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   159
    private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   160
    private static final String THROWABLE_TYPE_NAME = THROWABLE_TYPE.getInternalName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   161
    private static final String CONTEXT_TYPE_NAME = CONTEXT_TYPE.getInternalName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   162
    private static final String OBJECT_TYPE_NAME = OBJECT_TYPE.getInternalName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   163
    private static final String PRIVILEGED_ACTION_TYPE_NAME = PRIVILEGED_ACTION_TYPE.getInternalName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   164
    private static final String UNSUPPORTED_OPERATION_TYPE_NAME = UNSUPPORTED_OPERATION_TYPE.getInternalName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   165
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   166
    private static final String METHOD_HANDLE_TYPE_DESCRIPTOR = METHOD_HANDLE_TYPE.getDescriptor();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   167
    private static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   168
    private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   169
    private static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, SCRIPT_OBJECT_TYPE);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   170
    private static final String GET_CLASS_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Class.class));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   171
    private static final String PRIVILEGED_RUN_METHOD_DESCRIPTOR = Type.getMethodDescriptor(OBJECT_TYPE);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   172
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   173
    // Package used when the adapter can't be defined in the adaptee's package (either because it's sealed, or because
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   174
    // it's a java.* package.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   175
    private static final String ADAPTER_PACKAGE_PREFIX = "jdk/nashorn/internal/javaadapters/";
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   176
    // Class name suffix used to append to the adaptee class name, when it can be defined in the adaptee's package.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   177
    private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter";
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   178
    private static final String JAVA_PACKAGE_PREFIX = "java/";
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   179
    private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 238; //255 - 17; 17 is the maximum possible length for the global setter inner class suffix
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   180
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   181
    private static final String INIT = "<init>";
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   182
    private static final String VOID_NOARG = Type.getMethodDescriptor(Type.VOID_TYPE);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   183
    private static final String GLOBAL_FIELD_NAME = "global";
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   184
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   185
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   186
     * Contains various outcomes for attempting to generate an adapter class. These are stored in AdapterInfo instances.
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   187
     * We have a successful outcome (adapter class was generated) and four possible error outcomes: superclass is final,
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   188
     * superclass is not public, superclass has no public or protected constructor, more than one superclass was
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   189
     * specified. We don't throw exceptions when we try to generate the adapter, but rather just record these error
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   190
     * conditions as they are still useful as partial outcomes, as Nashorn's linker can still successfully check whether
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   191
     * the class can be autoconverted from a script function even when it is not possible to generate an adapter for it.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   192
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   193
    private enum AdaptationOutcome {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   194
        SUCCESS,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   195
        ERROR_FINAL_CLASS,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   196
        ERROR_NON_PUBLIC_CLASS,
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   197
        ERROR_NO_ACCESSIBLE_CONSTRUCTOR,
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   198
        ERROR_MULTIPLE_SUPERCLASSES,
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   199
        ERROR_NO_COMMON_LOADER
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   200
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   201
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   202
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   203
     * Collection of methods we never override: Object.clone(), Object.finalize().
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   204
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   205
    private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   206
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   207
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   208
     * A mapping from an original Class object to AdapterInfo representing the adapter for the class it represents.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   209
     */
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   210
    private static final ClassValue<Map<List<Class<?>>, AdapterInfo>> ADAPTER_INFO_MAPS = new ClassValue<Map<List<Class<?>>, AdapterInfo>>() {
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   211
        @Override
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   212
        protected Map<List<Class<?>>, AdapterInfo> computeValue(final Class<?> type) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   213
            return new HashMap<>();
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   214
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   215
    };
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   216
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   217
    private static final Random random = new SecureRandom();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   218
    private static final ProtectionDomain GENERATED_PROTECTION_DOMAIN = createGeneratedProtectionDomain();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   219
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   220
    // This is the superclass for our generated adapter.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   221
    private final Class<?> superClass;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   222
    // Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   223
    // loader that has the visibility of all original types (class to extend and interfaces to implement) and of the
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   224
    // Nashorn classes.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   225
    private final ClassLoader commonLoader;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   226
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   227
    // Binary name of the superClass
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   228
    private final String superClassName;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   229
    // Binary name of the generated class.
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   230
    private final String generatedClassName;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   231
    // Binary name of the PrivilegedAction inner class that is used to
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   232
    private final String globalSetterClassName;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   233
    private final Set<String> usedFieldNames = new HashSet<>();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   234
    private final Set<String> abstractMethodNames = new HashSet<>();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   235
    private final String samName;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   236
    private final Set<MethodInfo> finalMethods = new HashSet<>(EXCLUDED);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   237
    private final Set<MethodInfo> methodInfos = new HashSet<>();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   238
    private boolean autoConvertibleFromFunction = false;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   239
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   240
    private final ClassWriter cw;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   241
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   242
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   243
     * Creates a factory that will produce the adapter type for the specified original type.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   244
     * @param originalType the type for which this factory will generate the adapter type.
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   245
     * @param definingClassAndLoader the class in whose ClassValue we'll store the generated adapter, and its class loader.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   246
     * @throws AdaptationException if the adapter can not be generated for some reason.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   247
     */
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   248
    private JavaAdapterFactory(final Class<?> superType, final List<Class<?>> interfaces, final ClassAndLoader definingClassAndLoader) throws AdaptationException {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   249
        assert superType != null && !superType.isInterface();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   250
        assert interfaces != null;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   251
        assert definingClassAndLoader != null;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   252
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   253
        this.superClass = superType;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   254
        this.commonLoader = findCommonLoader(definingClassAndLoader);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   255
        cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   256
            @Override
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   257
            protected String getCommonSuperClass(final String type1, final String type2) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   258
                // We need to override ClassWriter.getCommonSuperClass to use this factory's commonLoader as a class
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   259
                // loader to find the common superclass of two types when needed.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   260
                return JavaAdapterFactory.this.getCommonSuperClass(type1, type2);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   261
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   262
        };
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   263
        superClassName = Type.getInternalName(superType);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   264
        generatedClassName = getGeneratedClassName(superType, interfaces);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   265
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   266
        // Randomize the name of the privileged global setter, to make it non-feasible to find.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   267
        final long l;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   268
        synchronized(random) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   269
            l = random.nextLong();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   270
        }
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   271
        // NOTE: they way this class name is calculated affects the value of MAX_GENERATED_TYPE_NAME_LENGTH constant. If
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   272
        // you change the calculation of globalSetterClassName, adjust the constant too.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   273
        globalSetterClassName = generatedClassName.concat("$" + Long.toHexString(l & Long.MAX_VALUE));
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   274
        cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER | ACC_FINAL, generatedClassName, null, superClassName, getInternalTypeNames(interfaces));
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   275
        cw.visitField(ACC_PRIVATE | ACC_FINAL, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   276
        usedFieldNames.add(GLOBAL_FIELD_NAME);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   277
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   278
        gatherMethods(superType);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   279
        gatherMethods(interfaces);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   280
        samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   281
        generateFields();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   282
        generateConstructors();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   283
        generateMethods();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   284
        // }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   285
        cw.visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   286
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   287
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   288
    private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   289
        // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're
16204
c53eef0eb729 8007140: Java.extend crashes when attempting to extend java.lang.Object
sundar
parents: 16188
diff changeset
   290
        // just implementing interfaces or extending Object), then the first implemented interface or Object.
c53eef0eb729 8007140: Java.extend crashes when attempting to extend java.lang.Object
sundar
parents: 16188
diff changeset
   291
        final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   292
        final Package pkg = namingType.getPackage();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   293
        final String namingTypeName = Type.getInternalName(namingType);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   294
        final StringBuilder buf = new StringBuilder();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   295
        if (namingTypeName.startsWith(JAVA_PACKAGE_PREFIX) || pkg == null || pkg.isSealed()) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   296
            // Can't define new classes in java.* packages
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   297
            buf.append(ADAPTER_PACKAGE_PREFIX).append(namingTypeName);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   298
        } else {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   299
            buf.append(namingTypeName).append(ADAPTER_CLASS_NAME_SUFFIX);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   300
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   301
        final Iterator<Class<?>> it = interfaces.iterator();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   302
        if(superType == Object.class && it.hasNext()) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   303
            it.next(); // Skip first interface, it was used to primarily name the adapter
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   304
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   305
        // Append interface names to the adapter name
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   306
        while(it.hasNext()) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   307
            buf.append("$$").append(it.next().getSimpleName());
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   308
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   309
        return buf.toString().substring(0, Math.min(MAX_GENERATED_TYPE_NAME_LENGTH, buf.length()));
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   310
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   311
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   312
    /**
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   313
     * Given a list of class objects, return an array with their binary names. Used to generate the array of interface
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   314
     * names to implement.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   315
     * @param classes the classes
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   316
     * @return an array of names
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   317
     */
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   318
    private static String[] getInternalTypeNames(final List<Class<?>> classes) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   319
        final int interfaceCount = classes.size();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   320
        final String[] interfaceNames = new String[interfaceCount];
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   321
        for(int i = 0; i < interfaceCount; ++i) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   322
            interfaceNames[i] = Type.getInternalName(classes.get(i));
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   323
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   324
        return interfaceNames;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   325
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   326
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   327
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   328
     * Utility method used by few other places in the code. Tests if the class has the abstract modifier and is not an
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   329
     * array class. For some reason, array classes have the abstract modifier set in HotSpot JVM, and we don't want to
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   330
     * treat array classes as abstract.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   331
     * @param clazz the inspected class
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   332
     * @return true if the class is abstract and is not an array type.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   333
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   334
    static boolean isAbstractClass(final Class<?> clazz) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   335
        return Modifier.isAbstract(clazz.getModifiers()) && !clazz.isArray();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   336
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   337
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   338
    /**
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   339
     * Returns an adapter class for the specified original types. The adapter class extends/implements the original
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   340
     * class/interfaces.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   341
     * @param types the original types. The caller must pass at least one Java type representing either a public
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   342
     * interface or a non-final public class with at least one public or protected constructor. If more than one type is
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   343
     * specified, at most one can be a class and the rest have to be interfaces. The class can be in any position in the
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   344
     * array. Invoking the method twice with exactly the same types in the same order will return the same adapter
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   345
     * class, any reordering of types or even addition or removal of redundant types (i.e. interfaces that other types
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   346
     * in the list already implement/extend, or {@code java.lang.Object} in a list of types consisting purely of
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   347
     * interfaces) will result in a different adapter class, even though those adapter classes are functionally
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   348
     * identical; we deliberately don't want to incur the additional processing cost of canonicalizing type lists.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   349
     * @return an adapter class. See this class' documentation for details on the generated adapter class.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   350
     * @throws ECMAException with a TypeError if the adapter class can not be generated because the original class is
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   351
     * final, non-public, or has no public or protected constructors.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   352
     */
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   353
    public static StaticClass getAdapterClassFor(final Class<?>[] types) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   354
        assert types != null && types.length > 0;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   355
        final AdapterInfo adapterInfo = getAdapterInfo(types);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   356
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   357
        final StaticClass clazz = adapterInfo.adapterClass;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   358
        if (clazz != null) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   359
            return clazz;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   360
        }
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   361
        adapterInfo.adaptationOutcome.typeError();
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   362
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   363
        throw new AssertionError();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   364
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   365
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   366
    private static AdapterInfo getAdapterInfo(final Class<?>[] types) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   367
        final ClassAndLoader definingClassAndLoader = getDefiningClassAndLoader(types);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   368
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   369
        final Map<List<Class<?>>, AdapterInfo> adapterInfoMap = ADAPTER_INFO_MAPS.get(definingClassAndLoader.clazz);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   370
        final List<Class<?>> typeList = types.length == 1 ? getSingletonClassList(types[0]) : Arrays.asList(types.clone());
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   371
        AdapterInfo adapterInfo;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   372
        synchronized(adapterInfoMap) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   373
            adapterInfo = adapterInfoMap.get(typeList);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   374
            if(adapterInfo == null) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   375
                adapterInfo = createAdapterInfo(types, definingClassAndLoader);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   376
                adapterInfoMap.put(typeList, adapterInfo);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   377
            }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   378
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   379
        return adapterInfo;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   380
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   381
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   382
    @SuppressWarnings({ "unchecked", "rawtypes" })
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   383
    private static List<Class<?>> getSingletonClassList(final Class<?> clazz) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   384
        return (List)Collections.singletonList(clazz);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   385
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   386
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   387
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   388
     * Returns whether an instance of the specified class/interface can be generated from a ScriptFunction. Returns true
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   389
     * iff: the adapter for the class/interface can be created, it is abstract (this includes interfaces), it has at
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   390
     * least one abstract method, all the abstract methods share the same name, and it has a public or protected default
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   391
     * constructor. Note that invoking this class will most likely result in the adapter class being defined in the JVM
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   392
     * if it hasn't been already.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   393
     * @param clazz the inspected class
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   394
     * @return true iff an instance of the specified class/interface can be generated from a ScriptFunction.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   395
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   396
    static boolean isAutoConvertibleFromFunction(final Class<?> clazz) {
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   397
        return getAdapterInfo(new Class<?>[] { clazz }).autoConvertibleFromFunction;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   398
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   399
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   400
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   401
     * Returns a method handle representing a constructor that takes a single argument of the source type (which,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   402
     * really, should be one of {@link ScriptObject}, {@link ScriptFunction}, or {@link Object}, and returns an instance
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   403
     * of the adapter for the target type. Used to implement the function autoconverters as well as the Nashorn's
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   404
     * JSR-223 script engine's {@code getInterface()} method.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   405
     * @param sourceType the source type; should be either {@link ScriptObject}, {@link ScriptFunction}, or
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   406
     * {@link Object}. In case of {@code Object}, it will return a method handle that dispatches to either the script
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   407
     * object or function constructor at invocation based on the actual argument.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   408
     * @param targetType the target type, for which adapter instances will be created
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   409
     * @return the constructor method handle.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   410
     * @throws Exception if anything goes wrong
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   411
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   412
    public static MethodHandle getConstructor(final Class<?> sourceType, final Class<?> targetType) throws Exception {
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   413
        final StaticClass adapterClass = getAdapterClassFor(new Class<?>[] { targetType });
16522
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   414
        return AccessController.doPrivileged(new PrivilegedExceptionAction<MethodHandle>() {
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   415
            public MethodHandle run() throws Exception {
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   416
                return  MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(NashornCallSiteDescriptor.get(
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   417
                    "dyn:new", MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false,
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   418
                    adapterClass, null)).getInvocation(), adapterClass);
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   419
            }
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   420
        });
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   421
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   422
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   423
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   424
     * Finishes the bytecode generation for the adapter class that was started in the constructor, and loads the
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   425
     * bytecode as a new class into the JVM.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   426
     * @return the generated adapter class
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   427
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   428
    private Class<?> generateClass() {
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   429
        final String binaryName = generatedClassName.replace('/', '.');
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   430
        try {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   431
            return Class.forName(binaryName, true, createClassLoader(commonLoader, binaryName, cw.toByteArray(),
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   432
                    globalSetterClassName.replace('/', '.')));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   433
        } catch (final ClassNotFoundException e) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   434
            throw new AssertionError(e); // cannot happen
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   435
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   436
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   437
16188
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   438
    /**
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   439
     * Tells if the given Class is an adapter or support class
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   440
     * @param clazz Class object
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   441
     * @return true if the Class given is adapter or support class
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   442
     */
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   443
    public static boolean isAdapterClass(Class<?> clazz) {
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   444
        return clazz.getClassLoader() instanceof AdapterLoader;
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   445
    }
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   446
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   447
    private static class AdapterLoader extends SecureClassLoader {
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   448
        AdapterLoader(ClassLoader parent) {
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   449
            super(parent);
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   450
        }
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   451
    }
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   452
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   453
    // Creation of class loader is in a separate static method so that it doesn't retain a reference to the factory
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   454
    // instance. Note that the adapter class is created in the protection domain of the class/interface being
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   455
    // extended/implemented, and only the privileged global setter action class is generated in the protection domain
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   456
    // of Nashorn itself. Also note that the creation and loading of the global setter is deferred until it is
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   457
    // required by JVM linker, which will only happen on first invocation of any of the adapted method. We could defer
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   458
    // it even more by separating its invocation into a separate static method on the adapter class, but then someone
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   459
    // with ability to introspect on the class and use setAccessible(true) on it could invoke the method. It's a
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   460
    // security tradeoff...
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   461
    private static ClassLoader createClassLoader(final ClassLoader parentLoader, final String className,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   462
            final byte[] classBytes, final String privilegedActionClassName) {
16188
d6390b0ea32a 8006678: Avoid too many Context.getGlobal() calls
sundar
parents: 16185
diff changeset
   463
        return new AdapterLoader(parentLoader) {
16522
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   464
            private final ClassLoader myLoader = getClass().getClassLoader();
16221
38ac51eba133 8007715: Make sure that not all tests run with AllPermission
sundar
parents: 16204
diff changeset
   465
            private final ProtectionDomain myProtectionDomain = getClass().getProtectionDomain();
38ac51eba133 8007715: Make sure that not all tests run with AllPermission
sundar
parents: 16204
diff changeset
   466
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   467
            @Override
16522
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   468
            public Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   469
                try {
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   470
                    return super.loadClass(name, resolve);
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   471
                } catch (final SecurityException se) {
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   472
                    // we may be implementing an interface or extending a class that was
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   473
                    // loaded by a loader that prevents package.access. If so, it'd throw
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   474
                    // SecurityException for nashorn's classes!. For adapter's to work, we
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   475
                    // should be able to refer to nashorn classes.
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   476
                    if (name.startsWith("jdk.nashorn.internal.")) {
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   477
                        return myLoader.loadClass(name);
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   478
                    }
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   479
                    throw se;
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   480
                }
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   481
            }
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   482
d643e3ee819c 8009757: Package access clean up and refactoring
sundar
parents: 16277
diff changeset
   483
            @Override
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   484
            protected Class<?> findClass(final String name) throws ClassNotFoundException {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   485
                if(name.equals(className)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   486
                    final byte[] bytes = classBytes;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   487
                    return defineClass(name, bytes, 0, bytes.length, GENERATED_PROTECTION_DOMAIN);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   488
                } else if(name.equals(privilegedActionClassName)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   489
                    final byte[] bytes = generatePrivilegedActionClassBytes(privilegedActionClassName.replace('.', '/'));
16221
38ac51eba133 8007715: Make sure that not all tests run with AllPermission
sundar
parents: 16204
diff changeset
   490
                    return defineClass(name, bytes, 0, bytes.length, myProtectionDomain);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   491
                } else {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   492
                    throw new ClassNotFoundException(name);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   493
                }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   494
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   495
        };
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   496
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   497
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   498
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   499
     * Generates a PrivilegedAction implementation class for invoking {@link Context#setGlobal(ScriptObject)} from the
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   500
     * adapter class.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   501
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   502
    private static byte[] generatePrivilegedActionClassBytes(final String className) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   503
        final ClassWriter w = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   504
        // class GlobalSetter implements PrivilegedAction {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   505
        w.visit(Opcodes.V1_7, ACC_SUPER | ACC_FINAL, className, null, OBJECT_TYPE_NAME, new String[] {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   506
                PRIVILEGED_ACTION_TYPE_NAME
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   507
        });
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   508
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   509
        // private final ScriptObject global;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   510
        w.visitField(ACC_PRIVATE | ACC_FINAL, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   511
16185
893aabe8c800 8006635: Reduce access levels as much as possible
sundar
parents: 16178
diff changeset
   512
        // private GlobalSetter(ScriptObject global) {
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   513
        InstructionAdapter mv = new InstructionAdapter(w.visitMethod(ACC_PRIVATE, INIT,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   514
                SET_GLOBAL_METHOD_DESCRIPTOR, null, new String[0]));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   515
        mv.visitCode();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   516
        // super();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   517
        mv.visitVarInsn(ALOAD, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   518
        mv.invokespecial(OBJECT_TYPE_NAME, INIT, VOID_NOARG);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   519
        // this.global = global;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   520
        mv.visitVarInsn(ALOAD, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   521
        mv.visitVarInsn(ALOAD, 1);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   522
        mv.putfield(className, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   523
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   524
        mv.visitInsn(RETURN);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   525
        mv.visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   526
        mv.visitMaxs(0, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   527
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   528
        // public Object run() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   529
        mv = new InstructionAdapter(w.visitMethod(ACC_PUBLIC, "run", PRIVILEGED_RUN_METHOD_DESCRIPTOR, null,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   530
                new String[0]));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   531
        mv.visitCode();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   532
        // Context.setGlobal(this.global);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   533
        mv.visitVarInsn(ALOAD, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   534
        mv.getfield(className, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   535
        mv.invokestatic(CONTEXT_TYPE_NAME, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   536
        // return null;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   537
        mv.visitInsn(ACONST_NULL);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   538
        mv.visitInsn(ARETURN);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   539
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   540
        mv.visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   541
        mv.visitMaxs(0, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   542
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   543
        // static void setGlobal(ScriptObject global) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   544
        mv = new InstructionAdapter(w.visitMethod(ACC_STATIC, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR, null,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   545
                new String[0]));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   546
        mv.visitCode();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   547
        // new GlobalSetter(ScriptObject global)
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   548
        mv.anew(Type.getType("L" + className + ";"));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   549
        mv.dup();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   550
        mv.visitVarInsn(ALOAD, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   551
        mv.invokespecial(className, INIT, SET_GLOBAL_METHOD_DESCRIPTOR);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   552
        // AccessController.doPrivileged(...)
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   553
        mv.invokestatic(Type.getInternalName(AccessController.class), "doPrivileged", Type.getMethodDescriptor(
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   554
                OBJECT_TYPE, PRIVILEGED_ACTION_TYPE));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   555
        mv.pop();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   556
        mv.visitInsn(RETURN);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   557
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   558
        mv.visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   559
        mv.visitMaxs(0, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   560
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   561
        return w.toByteArray();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   562
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   563
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   564
    private void generateFields() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   565
        for (final MethodInfo mi: methodInfos) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   566
            cw.visitField(ACC_PRIVATE | ACC_FINAL, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   567
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   568
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   569
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   570
    private void generateConstructors() throws AdaptationException {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   571
        boolean gotCtor = false;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   572
        for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) {
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   573
            final int modifier = ctor.getModifiers();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   574
            if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   575
                generateConstructor(ctor);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   576
                gotCtor = true;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   577
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   578
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   579
        if(!gotCtor) {
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   580
            throw new AdaptationException(AdaptationOutcome.ERROR_NO_ACCESSIBLE_CONSTRUCTOR, superClass.getCanonicalName());
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   581
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   582
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   583
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   584
    boolean isAutoConvertibleFromFunction() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   585
        return autoConvertibleFromFunction;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   586
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   587
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   588
    private void generateConstructor(final Constructor<?> ctor) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   589
        // Generate a constructor that delegates to ctor, but takes an additional ScriptObject parameter at the
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   590
        // beginning of its parameter list.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   591
        generateConstructor(ctor, false);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   592
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   593
        if (samName != null) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   594
            if (!autoConvertibleFromFunction && ctor.getParameterTypes().length == 0) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   595
                // If the original type only has a single abstract method name, as well as a default ctor, then it can
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   596
                // be automatically converted from JS function.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   597
                autoConvertibleFromFunction = true;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   598
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   599
            // If all our abstract methods have a single name, generate an additional constructor, one that takes a
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   600
            // ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   601
            generateConstructor(ctor, true);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   602
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   603
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   604
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   605
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   606
     * Generates a constructor for the adapter class. This constructor will take the same arguments as the supertype
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   607
     * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   608
     * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   609
     * all the method handle fields of the adapter instance with functions from the script object (or the script
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   610
     * function itself, if that's what's passed). There is one method handle field in the adapter class for every method
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   611
     * that can be implemented or overridden; the name of every field is same as the name of the method, with a number
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   612
     * suffix that makes it unique in case of overloaded methods. The generated constructor will invoke
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   613
     * {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType,
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   614
     * boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   615
     * adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}.
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   616
     * The constructor that takes a script function will only initialize the methods with the same name as the single
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   617
     * abstract method. The constructor will also store the Nashorn global that was current at the constructor
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   618
     * invocation time in a field named "global". The generated constructor will be public, regardless of whether the
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   619
     * supertype constructor was public or protected. The generated constructor will not be variable arity, even if the
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   620
     * supertype constructor was.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   621
     * @param ctor the supertype constructor that is serving as the base for the generated constructor.
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   622
     * @param fromFunction true if we're generating a constructor that initializes SAM types from a single
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   623
     * ScriptFunction passed to it, false if we're generating a constructor that initializes an arbitrary type from a
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   624
     * ScriptObject passed to it.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   625
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   626
    private void generateConstructor(final Constructor<?> ctor, final boolean fromFunction) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   627
        final Type originalCtorType = Type.getType(ctor);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   628
        final Type[] originalArgTypes = originalCtorType.getArgumentTypes();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   629
        final int argLen = originalArgTypes.length;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   630
        final Type[] newArgTypes = new Type[argLen + 1];
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   631
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   632
        // Insert ScriptFunction|Object as the last argument to the constructor
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   633
        final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : OBJECT_TYPE;
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   634
        newArgTypes[argLen] = extraArgumentType;
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   635
        System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   636
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   637
        // All constructors must be public, even if in the superclass they were protected.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   638
        // Existing super constructor <init>(this, args...) triggers generating <init>(this, scriptObj, args...).
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   639
        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   640
                Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   641
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   642
        mv.visitCode();
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   643
        // First, invoke super constructor with original arguments. If the form of the constructor we're generating is
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   644
        // <init>(this, args..., scriptFn), then we're invoking super.<init>(this, args...).
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   645
        mv.visitVarInsn(ALOAD, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   646
        final Class<?>[] argTypes = ctor.getParameterTypes();
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   647
        int offset = 1; // First arg is at position 1, after this.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   648
        for (int i = 0; i < argLen; ++i) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   649
            final Type argType = Type.getType(argTypes[i]);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   650
            mv.load(offset, argType);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   651
            offset += argType.getSize();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   652
        }
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   653
        mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor());
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   654
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   655
        // Get a descriptor to the appropriate "JavaAdapterFactory.getHandle" method.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   656
        final String getHandleDescriptor = fromFunction ? GET_HANDLE_FUNCTION_DESCRIPTOR : GET_HANDLE_OBJECT_DESCRIPTOR;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   657
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   658
        // Assign MethodHandle fields through invoking getHandle()
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   659
        for (final MethodInfo mi : methodInfos) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   660
            mv.visitVarInsn(ALOAD, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   661
            if (fromFunction && !mi.getName().equals(samName)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   662
                // Constructors initializing from a ScriptFunction only initialize methods with the SAM name.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   663
                // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overriden too. This
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   664
                // is a deliberate design choice. All other method handles are initialized to null.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   665
                mv.visitInsn(ACONST_NULL);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   666
            } else {
16167
d99db3541813 8005983: JavaAdapterFactory generated proxy classes should take extra constructor arguments at the end
attila
parents: 16151
diff changeset
   667
                mv.visitVarInsn(ALOAD, offset);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   668
                if(!fromFunction) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   669
                    mv.aconst(mi.getName());
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   670
                }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   671
                mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   672
                mv.iconst(mi.method.isVarArgs() ? 1 : 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   673
                mv.invokestatic(THIS_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   674
            }
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   675
            mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   676
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   677
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   678
        // Assign "this.global = Context.getGlobal()"
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   679
        mv.visitVarInsn(ALOAD, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   680
        invokeGetGlobal(mv);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   681
        mv.dup();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   682
        mv.invokevirtual(OBJECT_TYPE_NAME, "getClass", GET_CLASS_METHOD_DESCRIPTOR); // check against null Context
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   683
        mv.pop();
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   684
        mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   685
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   686
        // Wrap up
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   687
        mv.visitInsn(RETURN);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   688
        mv.visitMaxs(0, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   689
        mv.visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   690
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   691
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   692
    private static void invokeGetGlobal(final InstructionAdapter mv) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   693
        mv.invokestatic(CONTEXT_TYPE_NAME, "getGlobal", GET_GLOBAL_METHOD_DESCRIPTOR);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   694
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   695
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   696
    private void invokeSetGlobal(final InstructionAdapter mv) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   697
        mv.invokestatic(globalSetterClassName, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   698
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   699
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   700
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   701
     * Given a JS script function, binds it to null JS "this", and adapts its parameter types, return types, and arity
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   702
     * to the specified type and arity. This method is public mainly for implementation reasons, so the adapter classes
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   703
     * can invoke it from their constructors that take a ScriptFunction in its first argument to obtain the method
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   704
     * handles for their abstract method implementations.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   705
     * @param fn the script function
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   706
     * @param type the method type it has to conform to
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   707
     * @param varArg if the Java method for which the function is being adapted is a variable arity method
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   708
     * @return the appropriately adapted method handle for invoking the script function.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   709
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   710
    public static MethodHandle getHandle(final ScriptFunction fn, final MethodType type, final boolean varArg) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   711
        // JS "this" will be null for SAMs
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   712
        return adaptHandle(fn.getBoundInvokeHandle(null), type, varArg);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   713
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   714
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   715
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   716
     * Given a JS script object, retrieves a function from it by name, binds it to the script object as its "this", and
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   717
     * adapts its parameter types, return types, and arity to the specified type and arity. This method is public mainly
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   718
     * for implementation reasons, so the adapter classes can invoke it from their constructors that take a Object
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   719
     * in its first argument to obtain the method handles for their method implementations.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   720
     * @param obj the script obj
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   721
     * @param name the name of the property that contains the function
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   722
     * @param type the method type it has to conform to
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   723
     * @param varArg if the Java method for which the function is being adapted is a variable arity method
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   724
     * @return the appropriately adapted method handle for invoking the script function, or null if the value of the
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   725
     * property is either null or undefined, or "toString" was requested as the name, but the object doesn't directly
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   726
     * define it but just inherits it through prototype.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   727
     */
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   728
    public static MethodHandle getHandle(final Object obj, final String name, final MethodType type, final boolean varArg) {
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   729
        if (! (obj instanceof ScriptObject)) {
16256
f2d9a0c49914 8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
lagergren
parents: 16234
diff changeset
   730
            throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   731
        }
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   732
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   733
        final ScriptObject sobj = (ScriptObject)obj;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   734
        // Since every JS Object has a toString, we only override "String toString()" it if it's explicitly specified
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   735
        if ("toString".equals(name) && !sobj.hasOwnProperty("toString")) {
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   736
            return null;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   737
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   738
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   739
        final Object fnObj = sobj.get(name);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   740
        if (fnObj instanceof ScriptFunction) {
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   741
            return adaptHandle(((ScriptFunction)fnObj).getBoundInvokeHandle(sobj), type, varArg);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   742
        } else if(fnObj == null || fnObj instanceof Undefined) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   743
            return null;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   744
        } else {
16256
f2d9a0c49914 8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
lagergren
parents: 16234
diff changeset
   745
            throw typeError("not.a.function", name);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   746
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   747
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   748
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   749
    private static MethodHandle adaptHandle(final MethodHandle handle, final MethodType type, final boolean varArg) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   750
        return Bootstrap.getLinkerServices().asType(ScriptObject.pairArguments(handle, type, varArg), type);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   751
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   752
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   753
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   754
     * Encapsulation of the information used to generate methods in the adapter classes. Basically, a wrapper around the
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   755
     * reflective Method object, a cached MethodType, and the name of the field in the adapter class that will hold the
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   756
     * method handle serving as the implementation of this method in adapter instances.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   757
     *
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   758
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   759
    private static class MethodInfo {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   760
        private final Method method;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   761
        private final MethodType type;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   762
        private String methodHandleFieldName;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   763
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   764
        private MethodInfo(final Class<?> clazz, final String name, final Class<?>... argTypes) throws NoSuchMethodException {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   765
            this(clazz.getDeclaredMethod(name, argTypes));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   766
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   767
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   768
        private MethodInfo(final Method method) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   769
            this.method = method;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   770
            this.type   = MH.type(method.getReturnType(), method.getParameterTypes());
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   771
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   772
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   773
        @Override
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   774
        public boolean equals(final Object obj) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   775
            return obj instanceof MethodInfo && equals((MethodInfo)obj);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   776
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   777
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   778
        private boolean equals(final MethodInfo other) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   779
            // Only method name and type are used for comparison; method handle field name is not.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   780
            return getName().equals(other.getName()) && type.equals(other.type);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   781
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   782
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   783
        String getName() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   784
            return method.getName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   785
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   786
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   787
        @Override
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   788
        public int hashCode() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   789
            return getName().hashCode() ^ type.hashCode();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   790
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   791
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   792
        void setIsCanonical(final Set<String> usedFieldNames) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   793
            int i = 0;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   794
            String fieldName = getName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   795
            while(!usedFieldNames.add(fieldName)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   796
                fieldName = getName() + (i++);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   797
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   798
            methodHandleFieldName = fieldName;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   799
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   800
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   801
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   802
    private void generateMethods() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   803
        for(final MethodInfo mi: methodInfos) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   804
            generateMethod(mi);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   805
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   806
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   807
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   808
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   809
     * Generates a method in the adapter class that adapts a method from the original class. The generated methods will
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   810
     * inspect the method handle field assigned to them. If it is null (the JS object doesn't provide an implementation
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   811
     * for the method) then it will either invoke its version in the supertype, or if it is abstract, throw an
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   812
     * {@link UnsupportedOperationException}. Otherwise, if the method handle field's value is not null, the handle is
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   813
     * invoked using invokeExact (signature polymorphic invocation as per JLS 15.12.3). Before the invocation, the
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   814
     * current Nashorn {@link Context} is checked, and if it is different than the global used to create the adapter
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   815
     * instance, the creating global is set to be the current global. In this case, the previously current global is
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   816
     * restored after the invocation. If invokeExact results in a Throwable that is not one of the method's declared
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   817
     * exceptions, and is not an unchecked throwable, then it is wrapped into a {@link RuntimeException} and the runtime
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   818
     * exception is thrown. The method handle retrieved from the field is guaranteed to exactly match the signature of
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   819
     * the method; this is guaranteed by the way constructors of the adapter class obtain them using
16178
2704dd3b2691 8006424: Passing null or undefined to adapter class constructors results in NPE or ClassCastException
sundar
parents: 16171
diff changeset
   820
     * {@link #getHandle(Object, String, MethodType, boolean)}.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   821
     * @param mi the method info describing the method to be generated.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   822
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   823
    private void generateMethod(final MethodInfo mi) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   824
        final Method method = mi.method;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   825
        final int mod = method.getModifiers();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   826
        final int access = ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   827
        final Class<?>[] exceptions = method.getExceptionTypes();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   828
        final String[] exceptionNames = new String[exceptions.length];
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   829
        for (int i = 0; i < exceptions.length; ++i) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   830
            exceptionNames[i] = Type.getInternalName(exceptions[i]);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   831
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   832
        final MethodType type = mi.type;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   833
        final String methodDesc = type.toMethodDescriptorString();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   834
        final String name = mi.getName();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   835
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   836
        final Type asmType = Type.getMethodType(methodDesc);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   837
        final Type[] asmArgTypes = asmType.getArgumentTypes();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   838
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   839
        // Determine the first index for a local variable
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   840
        int nextLocalVar = 1; // this
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   841
        for(final Type t: asmArgTypes) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   842
            nextLocalVar += t.getSize();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   843
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   844
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   845
        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(access, name, methodDesc, null,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   846
                exceptionNames));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   847
        mv.visitCode();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   848
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   849
        final Label methodHandleNotNull = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   850
        final Label methodEnd = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   851
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   852
        final Type returnType = Type.getType(type.returnType());
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   853
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   854
        // Get the method handle
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   855
        mv.visitVarInsn(ALOAD, 0);
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   856
        mv.getfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   857
        mv.visitInsn(DUP); // It'll remain on the stack all the way until the invocation
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   858
        // Check if the method handle is null
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   859
        mv.visitJumpInsn(IFNONNULL, methodHandleNotNull);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   860
        if(Modifier.isAbstract(mod)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   861
            // If it's null, and the method is abstract, throw an exception
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   862
            mv.anew(UNSUPPORTED_OPERATION_TYPE);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   863
            mv.dup();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   864
            mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   865
            mv.athrow();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   866
        } else {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   867
            // If it's null, and the method is not abstract, delegate to super method.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   868
            mv.visitVarInsn(ALOAD, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   869
            int nextParam = 1;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   870
            for(final Type t: asmArgTypes) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   871
                mv.load(nextParam, t);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   872
                nextParam += t.getSize();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   873
            }
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   874
            mv.invokespecial(superClassName, name, methodDesc);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   875
            mv.areturn(returnType);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   876
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   877
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   878
        mv.visitLabel(methodHandleNotNull);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   879
        final int currentGlobalVar = nextLocalVar++;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   880
        final int globalsDifferVar = nextLocalVar++;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   881
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   882
        // Emit code for switching to the creating global
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   883
        // ScriptObject currentGlobal = Context.getGlobal();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   884
        invokeGetGlobal(mv);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   885
        mv.dup();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   886
        mv.visitVarInsn(ASTORE, currentGlobalVar);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   887
        // if(this.global == currentGlobal) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   888
        loadGlobalOnStack(mv);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   889
        final Label globalsDiffer = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   890
        mv.ifacmpne(globalsDiffer);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   891
        //     globalsDiffer = false
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   892
        mv.iconst(0); // false
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   893
        final Label proceed = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   894
        mv.goTo(proceed);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   895
        mv.visitLabel(globalsDiffer);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   896
        // } else {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   897
        //     Context.setGlobal(this.global);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   898
        loadGlobalOnStack(mv);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   899
        invokeSetGlobal(mv);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   900
        //     globalsDiffer = true
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   901
        mv.iconst(1);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   902
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   903
        mv.visitLabel(proceed);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   904
        mv.visitVarInsn(ISTORE, globalsDifferVar);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   905
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   906
        // Load all parameters back on stack for dynamic invocation.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   907
        int varOffset = 1;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   908
        for (final Type t : asmArgTypes) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   909
            mv.load(varOffset, t);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   910
            varOffset += t.getSize();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   911
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   912
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   913
        // Invoke the target method handle
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   914
        final Label tryBlockStart = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   915
        mv.visitLabel(tryBlockStart);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   916
        mv.invokevirtual(METHOD_HANDLE_TYPE.getInternalName(), "invokeExact", type.toMethodDescriptorString());
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   917
        final Label tryBlockEnd = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   918
        mv.visitLabel(tryBlockEnd);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   919
        emitFinally(mv, currentGlobalVar, globalsDifferVar);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   920
        mv.areturn(returnType);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   921
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   922
        // If Throwable is not declared, we need an adapter from Throwable to RuntimeException
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   923
        final boolean throwableDeclared = isThrowableDeclared(exceptions);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   924
        final Label throwableHandler;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   925
        if (!throwableDeclared) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   926
            // Add "throw new RuntimeException(Throwable)" handler for Throwable
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   927
            throwableHandler = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   928
            mv.visitLabel(throwableHandler);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   929
            mv.anew(RUNTIME_EXCEPTION_TYPE);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   930
            mv.dupX1();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   931
            mv.swap();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   932
            mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   933
            // Fall through to rethrow handler
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   934
        } else {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   935
            throwableHandler = null;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   936
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   937
        final Label rethrowHandler = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   938
        mv.visitLabel(rethrowHandler);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   939
        // Rethrow handler for RuntimeException, Error, and all declared exception types
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   940
        emitFinally(mv, currentGlobalVar, globalsDifferVar);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   941
        mv.athrow();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   942
        mv.visitLabel(methodEnd);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   943
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   944
        mv.visitLocalVariable("currentGlobal", SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, methodHandleNotNull, methodEnd, currentGlobalVar);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   945
        mv.visitLocalVariable("globalsDiffer", Type.INT_TYPE.getDescriptor(), null, methodHandleNotNull, methodEnd, globalsDifferVar);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   946
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   947
        if(throwableDeclared) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   948
            mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   949
            assert throwableHandler == null;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   950
        } else {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   951
            mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   952
            mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   953
            for(final String excName: exceptionNames) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   954
                mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   955
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   956
            mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   957
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   958
        mv.visitMaxs(0, 0);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   959
        mv.visitEnd();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   960
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   961
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   962
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   963
     * Emit code to restore the previous Nashorn Context when needed.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   964
     * @param mv the instruction adapter
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   965
     * @param currentGlobalVar index of the local variable holding the reference to the current global at method
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   966
     * entry.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   967
     * @param globalsDifferVar index of the boolean local variable that is true if the global needs to be restored.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   968
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   969
    private void emitFinally(final InstructionAdapter mv, final int currentGlobalVar, final int globalsDifferVar) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   970
        // Emit code to restore the previous Nashorn global if needed
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   971
        mv.visitVarInsn(ILOAD, globalsDifferVar);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   972
        final Label skip = new Label();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   973
        mv.ifeq(skip);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   974
        mv.visitVarInsn(ALOAD, currentGlobalVar);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   975
        invokeSetGlobal(mv);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   976
        mv.visitLabel(skip);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   977
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   978
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   979
    private void loadGlobalOnStack(final InstructionAdapter mv) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   980
        mv.visitVarInsn(ALOAD, 0);
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
   981
        mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   982
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   983
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   984
    private static boolean isThrowableDeclared(final Class<?>[] exceptions) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   985
        for (final Class<?> exception : exceptions) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   986
            if (exception == Throwable.class) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   987
                return true;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   988
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   989
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   990
        return false;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   991
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   992
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   993
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   994
     * Gathers methods that can be implemented or overridden from the specified type into this factory's
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   995
     * {@link #methodInfos} set. It will add all non-final, non-static methods that are either public or protected from
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   996
     * the type if the type itself is public. If the type is a class, the method will recursively invoke itself for its
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   997
     * superclass and the interfaces it implements, and add further methods that were not directly declared on the
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   998
     * class.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
   999
     * @param type the type defining the methods.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1000
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1001
    private void gatherMethods(final Class<?> type) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1002
        if (Modifier.isPublic(type.getModifiers())) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1003
            final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1004
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1005
            for (final Method typeMethod: typeMethods) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1006
                final int m = typeMethod.getModifiers();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1007
                if (Modifier.isStatic(m)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1008
                    continue;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1009
                }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1010
                if (Modifier.isPublic(m) || Modifier.isProtected(m)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1011
                    final MethodInfo mi = new MethodInfo(typeMethod);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1012
                    if (Modifier.isFinal(m)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1013
                        finalMethods.add(mi);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1014
                    } else if (!finalMethods.contains(mi) && methodInfos.add(mi)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1015
                        if (Modifier.isAbstract(m)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1016
                            abstractMethodNames.add(mi.getName());
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1017
                        }
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1018
                        mi.setIsCanonical(usedFieldNames);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1019
                    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1020
                }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1021
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1022
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1023
        // If the type is a class, visit its superclasses and declared interfaces. If it's an interface, we're done.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1024
        // Needing to invoke the method recursively for a non-interface Class object is the consequence of needing to
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1025
        // see all declared protected methods, and Class.getDeclaredMethods() doesn't provide those declared in a
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1026
        // superclass. For interfaces, we used Class.getMethods(), as we're only interested in public ones there, and
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1027
        // getMethods() does provide those declared in a superinterface.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1028
        if (!type.isInterface()) {
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1029
            final Class<?> superType = type.getSuperclass();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1030
            if (superType != null) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1031
                gatherMethods(superType);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1032
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1033
            for (final Class<?> itf: type.getInterfaces()) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1034
                gatherMethods(itf);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1035
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1036
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1037
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1038
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1039
    private void gatherMethods(final List<Class<?>> classes) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1040
        for(final Class<?> c: classes) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1041
            gatherMethods(c);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1042
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1043
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1044
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1045
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1046
     * Creates a collection of methods that are not final, but we still never allow them to be overridden in adapters,
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1047
     * as explicitly declaring them automatically is a bad idea. Currently, this means {@code Object.finalize()} and
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1048
     * {@code Object.clone()}.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1049
     * @return a collection of method infos representing those methods that we never override in adapter classes.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1050
     */
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1051
    private static Collection<MethodInfo> getExcludedMethods() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1052
        return AccessController.doPrivileged(new PrivilegedAction<Collection<MethodInfo>>() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1053
            @Override
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1054
            public Collection<MethodInfo> run() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1055
                try {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1056
                    return Arrays.asList(
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1057
                            new MethodInfo(Object.class, "finalize"),
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1058
                            new MethodInfo(Object.class, "clone"));
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1059
                } catch (final NoSuchMethodException e) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1060
                    throw new AssertionError(e);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1061
                }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1062
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1063
        });
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1064
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1065
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1066
    private static ProtectionDomain createGeneratedProtectionDomain() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1067
        // Generated classes need to have AllPermission. Since we require the "createClassLoader" RuntimePermission, we
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1068
        // can create a class loader that'll load new classes with any permissions. Our generated classes are just
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1069
        // delegating adapters, so having AllPermission can't cause anything wrong; the effective set of permissions for
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1070
        // the executing script functions will still be limited by the permissions of the caller and the permissions of
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1071
        // the script.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1072
        final Permissions permissions = new Permissions();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1073
        permissions.add(new AllPermission());
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1074
        return new ProtectionDomain(new CodeSource(null, (CodeSigner[])null), permissions);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1075
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1076
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1077
    private static class AdapterInfo {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1078
        final StaticClass adapterClass;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1079
        final boolean autoConvertibleFromFunction;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1080
        final AnnotatedAdaptationOutcome adaptationOutcome;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1081
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1082
        AdapterInfo(final StaticClass adapterClass, final boolean autoConvertibleFromFunction) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1083
            this.adapterClass = adapterClass;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1084
            this.autoConvertibleFromFunction = autoConvertibleFromFunction;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1085
            this.adaptationOutcome = AnnotatedAdaptationOutcome.SUCCESS;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1086
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1087
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1088
        AdapterInfo(final AdaptationOutcome outcome, final String classList) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1089
            this(new AnnotatedAdaptationOutcome(outcome, classList));
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1090
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1091
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1092
        AdapterInfo(final AnnotatedAdaptationOutcome adaptationOutcome) {
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1093
            this.adapterClass = null;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1094
            this.autoConvertibleFromFunction = false;
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1095
            this.adaptationOutcome = adaptationOutcome;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1096
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1097
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1098
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1099
    /**
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1100
     * An adaptation outcome accompanied with a name of a class (or a list of multiple class names) that are the reason
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1101
     * an adapter could not be generated.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1102
     */
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1103
    private static class AnnotatedAdaptationOutcome {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1104
        static final AnnotatedAdaptationOutcome SUCCESS = new AnnotatedAdaptationOutcome(AdaptationOutcome.SUCCESS, "");
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1105
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1106
        private final AdaptationOutcome adaptationOutcome;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1107
        private final String classList;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1108
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1109
        AnnotatedAdaptationOutcome(final AdaptationOutcome adaptationOutcome, final String classList) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1110
            this.adaptationOutcome = adaptationOutcome;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1111
            this.classList = classList;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1112
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1113
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1114
        void typeError() {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1115
            assert adaptationOutcome != AdaptationOutcome.SUCCESS;
16256
f2d9a0c49914 8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
lagergren
parents: 16234
diff changeset
  1116
            throw ECMAErrors.typeError("extend." + adaptationOutcome, classList);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1117
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1118
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1119
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1120
    /**
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1121
     * For a given class, create its adapter class and associated info.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1122
     * @param type the class for which the adapter is created
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1123
     * @return the adapter info for the class.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1124
     */
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1125
    private static AdapterInfo createAdapterInfo(final Class<?>[] types, final ClassAndLoader definingClassAndLoader) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1126
        Class<?> superClass = null;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1127
        final List<Class<?>> interfaces = new ArrayList<>(types.length);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1128
        for(final Class<?> t: types) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1129
            final int mod = t.getModifiers();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1130
            if(!t.isInterface()) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1131
                if(superClass != null) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1132
                    return new AdapterInfo(AdaptationOutcome.ERROR_MULTIPLE_SUPERCLASSES, t.getCanonicalName() + " and " + superClass.getCanonicalName());
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1133
                }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1134
                if (Modifier.isFinal(mod)) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1135
                    return new AdapterInfo(AdaptationOutcome.ERROR_FINAL_CLASS, t.getCanonicalName());
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1136
                }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1137
                superClass = t;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1138
            } else {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1139
                interfaces.add(t);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1140
            }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1141
            if(!Modifier.isPublic(mod)) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1142
                return new AdapterInfo(AdaptationOutcome.ERROR_NON_PUBLIC_CLASS, t.getCanonicalName());
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1143
            }
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1144
        }
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1145
        final Class<?> effectiveSuperClass = superClass == null ? Object.class : superClass;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1146
        return AccessController.doPrivileged(new PrivilegedAction<AdapterInfo>() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1147
            @Override
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1148
            public AdapterInfo run() {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1149
                try {
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1150
                    final JavaAdapterFactory factory = new JavaAdapterFactory(effectiveSuperClass, interfaces, definingClassAndLoader);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1151
                    return new AdapterInfo(StaticClass.forClass(factory.generateClass()),
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1152
                            factory.isAutoConvertibleFromFunction());
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1153
                } catch (final AdaptationException e) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1154
                    return new AdapterInfo(e.outcome);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1155
                }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1156
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1157
        });
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1158
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1159
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1160
    @SuppressWarnings("serial")
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1161
    private static class AdaptationException extends Exception {
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1162
        private final AnnotatedAdaptationOutcome outcome;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1163
        AdaptationException(final AdaptationOutcome outcome, final String classList) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1164
            this.outcome = new AnnotatedAdaptationOutcome(outcome, classList);
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1165
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1166
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1167
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1168
    private String getCommonSuperClass(final String type1, final String type2) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1169
        try {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1170
            final Class<?> c1 = Class.forName(type1.replace('/', '.'), false, commonLoader);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1171
            final Class<?> c2 = Class.forName(type2.replace('/', '.'), false, commonLoader);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1172
            if (c1.isAssignableFrom(c2)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1173
                return type1;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1174
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1175
            if (c2.isAssignableFrom(c1)) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1176
                return type2;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1177
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1178
            if (c1.isInterface() || c2.isInterface()) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1179
                return "java/lang/Object";
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1180
            }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1181
            return assignableSuperClass(c1, c2).getName().replace('.', '/');
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1182
        } catch(final ClassNotFoundException e) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1183
            throw new RuntimeException(e);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1184
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1185
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1186
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1187
    private static Class<?> assignableSuperClass(final Class<?> c1, final Class<?> c2) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1188
        final Class<?> superClass = c1.getSuperclass();
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1189
        return superClass.isAssignableFrom(c2) ? superClass : assignableSuperClass(superClass, c2);
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1190
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1191
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1192
    /**
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1193
     * Choose between the passed class loader and the class loader that defines the ScriptObject class, based on which
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1194
     * of the two can see the classes in both.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1195
     * @param classAndLoader the loader and a representative class from it that will be used to add the generated
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1196
     * adapter to its ADAPTER_INFO_MAPS.
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1197
     * @return the class loader that sees both the specified class and Nashorn classes.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1198
     * @throws IllegalStateException if no such class loader is found.
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1199
     */
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1200
    private static ClassLoader findCommonLoader(final ClassAndLoader classAndLoader) throws AdaptationException {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1201
        final ClassLoader loader = classAndLoader.getLoader();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1202
        if (canSeeClass(loader, ScriptObject.class)) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1203
            return loader;
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1204
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1205
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1206
        final ClassLoader nashornLoader = ScriptObject.class.getClassLoader();
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1207
        if(canSeeClass(nashornLoader, classAndLoader.clazz)) {
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1208
            return nashornLoader;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1209
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1210
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1211
        throw new AdaptationException(AdaptationOutcome.ERROR_NO_COMMON_LOADER, classAndLoader.clazz.getCanonicalName());
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1212
    }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1213
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1214
    private static boolean canSeeClass(final ClassLoader cl, final Class<?> clazz) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1215
        try {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1216
            return Class.forName(clazz.getName(), false, cl) == clazz;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1217
        } catch (final ClassNotFoundException e) {
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1218
            return false;
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1219
        }
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1220
    }
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1221
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1222
    /**
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1223
     * Given a list of types that define the superclass/interfaces for an adapter class, returns a single type from the
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1224
     * list that will be used to attach the adapter to its ClassValue. The first type in the array that is defined in a
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1225
     * class loader that can also see all other types is returned. If there is no such loader, an exception is thrown.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1226
     * @param types the input types
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1227
     * @return the first type from the array that is defined in a class loader that can also see all other types.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1228
     */
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1229
    private static ClassAndLoader getDefiningClassAndLoader(final Class<?>[] types) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1230
        // Short circuit the cheap case
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1231
        if(types.length == 1) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1232
            return new ClassAndLoader(types[0], false);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1233
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1234
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1235
        return AccessController.doPrivileged(new PrivilegedAction<ClassAndLoader>() {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1236
            @Override
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1237
            public ClassAndLoader run() {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1238
                return getDefiningClassAndLoaderPrivileged(types);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1239
            }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1240
        });
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1241
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1242
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1243
    private static ClassAndLoader getDefiningClassAndLoaderPrivileged(final Class<?>[] types) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1244
        final Collection<ClassAndLoader> maximumVisibilityLoaders = getMaximumVisibilityLoaders(types);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1245
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1246
        final Iterator<ClassAndLoader> it = maximumVisibilityLoaders.iterator();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1247
        if(maximumVisibilityLoaders.size() == 1) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1248
            // Fortunate case - single maximally specific class loader; return its representative class.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1249
            return it.next();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1250
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1251
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1252
        // Ambiguity; throw an error.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1253
        assert maximumVisibilityLoaders.size() > 1; // basically, can't be zero
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1254
        final StringBuilder b = new StringBuilder();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1255
        b.append(it.next().clazz.getCanonicalName());
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1256
        while(it.hasNext()) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1257
            b.append(", ").append(it.next().clazz.getCanonicalName());
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1258
        }
16256
f2d9a0c49914 8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
lagergren
parents: 16234
diff changeset
  1259
        throw typeError("extend.ambiguous.defining.class", b.toString());
16171
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1260
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1261
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1262
    /**
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1263
     * Given an array of types, return a subset of their class loaders that are maximal according to the
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1264
     * "can see other loaders' classes" relation, which is presumed to be a partial ordering.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1265
     * @param types types
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1266
     * @return a collection of maximum visibility class loaders. It is guaranteed to have at least one element.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1267
     */
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1268
    private static Collection<ClassAndLoader> getMaximumVisibilityLoaders(final Class<?>[] types) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1269
        final List<ClassAndLoader> maximumVisibilityLoaders = new LinkedList<>();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1270
        outer:  for(final ClassAndLoader maxCandidate: getClassLoadersForTypes(types)) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1271
            final Iterator<ClassAndLoader> it = maximumVisibilityLoaders.iterator();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1272
            while(it.hasNext()) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1273
                final ClassAndLoader existingMax = it.next();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1274
                final boolean candidateSeesExisting = canSeeClass(maxCandidate.getRetrievedLoader(), existingMax.clazz);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1275
                final boolean exitingSeesCandidate = canSeeClass(existingMax.getRetrievedLoader(), maxCandidate.clazz);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1276
                if(candidateSeesExisting) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1277
                    if(!exitingSeesCandidate) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1278
                        // The candidate sees the the existing maximum, so drop the existing one as it's no longer maximal.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1279
                        it.remove();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1280
                    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1281
                    // NOTE: there's also the anomalous case where both loaders see each other. Not sure what to do
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1282
                    // about that one, as two distinct class loaders both seeing each other's classes is weird and
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1283
                    // violates the assumption that the relation "sees others' classes" is a partial ordering. We'll
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1284
                    // just not do anything, and treat them as incomparable; hopefully some later class loader that
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1285
                    // comes along can eliminate both of them, if it can not, we'll end up with ambiguity anyway and
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1286
                    // throw an error at the end.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1287
                } else if(exitingSeesCandidate) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1288
                    // Existing sees the candidate, so drop the candidate.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1289
                    continue outer;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1290
                }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1291
            }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1292
            // If we get here, no existing maximum visibility loader could see the candidate, so the candidate is a new
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1293
            // maximum.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1294
            maximumVisibilityLoaders.add(maxCandidate);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1295
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1296
        return maximumVisibilityLoaders;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1297
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1298
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1299
    private static Collection<ClassAndLoader> getClassLoadersForTypes(final Class<?>[] types) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1300
        final Map<ClassAndLoader, ClassAndLoader> classesAndLoaders = new LinkedHashMap<>();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1301
        for(final Class<?> c: types) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1302
            final ClassAndLoader cl = new ClassAndLoader(c, true);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1303
            if(!classesAndLoaders.containsKey(cl)) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1304
                classesAndLoaders.put(cl, cl);
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1305
            }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1306
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1307
        return classesAndLoaders.keySet();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1308
    }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1309
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1310
    /**
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1311
     * A tuple of a class loader and a single class representative of the classes that can be loaded through it. Its
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1312
     * equals/hashCode is defined in terms of the identity of the class loader.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1313
     */
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1314
    private static final class ClassAndLoader {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1315
        private final Class<?> clazz;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1316
        // Don't access this directly; most of the time, use getRetrievedLoader(), or if you know what you're doing,
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1317
        // getLoader().
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1318
        private ClassLoader loader;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1319
        // We have mild affinity against eagerly retrieving the loader, as we need to do it in a privileged block. For
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1320
        // the most basic case of looking up an already-generated adapter info for a single type, we avoid it.
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1321
        private boolean loaderRetrieved;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1322
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1323
        ClassAndLoader(final Class<?> clazz, final boolean retrieveLoader) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1324
            this.clazz = clazz;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1325
            if(retrieveLoader) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1326
                retrieveLoader();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1327
            }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1328
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1329
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1330
        ClassLoader getLoader() {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1331
            if(!loaderRetrieved) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1332
                retrieveLoader();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1333
            }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1334
            return getRetrievedLoader();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1335
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1336
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1337
        ClassLoader getRetrievedLoader() {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1338
            assert loaderRetrieved;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1339
            return loader;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1340
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1341
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1342
        private void retrieveLoader() {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1343
            loader = clazz.getClassLoader();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1344
            loaderRetrieved = true;
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1345
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1346
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1347
        @Override
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1348
        public boolean equals(final Object obj) {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1349
            return obj instanceof ClassAndLoader && ((ClassAndLoader)obj).getRetrievedLoader() == getRetrievedLoader();
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1350
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1351
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1352
        @Override
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1353
        public int hashCode() {
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1354
            return System.identityHashCode(getRetrievedLoader());
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1355
        }
90dcd4fc42f0 8006168: ability to generate multi-type Java adapters
attila
parents: 16167
diff changeset
  1356
    }
16147
e63b63819133 8005403: Open-source Nashorn
jlaskey
parents:
diff changeset
  1357
}