src/jdk/nashorn/internal/objects/NativeJSAdapter.java

Thu, 11 Sep 2014 18:04:54 +0200

author
hannesw
date
Thu, 11 Sep 2014 18:04:54 +0200
changeset 1006
e94bfa3c6c6c
parent 963
e2497b11a021
child 1020
9ee8fd4a7266
permissions
-rw-r--r--

8057021: UserAccessorProperty guards fail with multiple globals
Reviewed-by: attila, lagergren

     1 /*
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package jdk.nashorn.internal.objects;
    28 import static jdk.nashorn.internal.lookup.Lookup.MH;
    29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
    30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
    31 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
    33 import java.lang.invoke.MethodHandle;
    34 import java.lang.invoke.MethodHandles;
    35 import java.lang.invoke.MethodType;
    36 import java.util.ArrayList;
    37 import java.util.Iterator;
    38 import java.util.List;
    39 import jdk.internal.dynalink.CallSiteDescriptor;
    40 import jdk.internal.dynalink.linker.GuardedInvocation;
    41 import jdk.internal.dynalink.linker.LinkRequest;
    42 import jdk.nashorn.internal.lookup.Lookup;
    43 import jdk.nashorn.internal.objects.annotations.Constructor;
    44 import jdk.nashorn.internal.objects.annotations.ScriptClass;
    45 import jdk.nashorn.internal.runtime.FindProperty;
    46 import jdk.nashorn.internal.runtime.JSType;
    47 import jdk.nashorn.internal.runtime.PropertyMap;
    48 import jdk.nashorn.internal.runtime.ScriptFunction;
    49 import jdk.nashorn.internal.runtime.ScriptObject;
    50 import jdk.nashorn.internal.runtime.ScriptRuntime;
    51 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
    52 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
    53 import jdk.nashorn.internal.scripts.JO;
    55 /**
    56  * This class is the implementation of the Nashorn-specific global object named {@code JSAdapter}. It can be
    57  * thought of as the {@link java.lang.reflect.Proxy} equivalent for JavaScript. NativeJSAdapter calls specially named
    58  * JavaScript methods on an adaptee object when property access/update/call/new/delete is attempted on it. Example:
    59  *<pre>
    60  *    var y = {
    61  *                __get__    : function (name) { ... }
    62  *                __has__    : function (name) { ... }
    63  *                __put__    : function (name, value) {...}
    64  *                __call__   : function (name, arg1, arg2) {...}
    65  *                __new__    : function (arg1, arg2) {...}
    66  *                __delete__ : function (name) { ... }
    67  *                __getIds__ : function () { ... }
    68  *            };
    69  *
    70  *    var x = new JSAdapter(y);
    71  *
    72  *    x.i;                        // calls y.__get__
    73  *    x.foo();                    // calls y.__call__
    74  *    new x();                    // calls y.__new__
    75  *    i in x;                     // calls y.__has__
    76  *    x.p = 10;                   // calls y.__put__
    77  *    delete x.p;                 // calls y.__delete__
    78  *    for (i in x) { print(i); }  // calls y.__getIds__
    79  * </pre>
    80  * <p>
    81  * JavaScript caller of adapter object is isolated from the fact that the property access/mutation/deletion are really
    82  * calls to JavaScript methods on adaptee.
    83  * </p>
    84  * <p>
    85  * JSAdapter constructor can optionally receive an "overrides" object. Properties of overrides object is copied to
    86  * JSAdapter instance. When user accessed property is one of these, then adaptee's methods like {@code __get__},
    87  * {@code __put__} etc. are not called for those. This can be used to make certain "preferred" properties that can be
    88  * accessed in the usual/faster way avoiding proxy mechanism. Example:
    89  * </p>
    90  * <pre>
    91  *     var x = new JSAdapter({ foo: 444, bar: 6546 }) {
    92  *          __get__: function(name) { return name; }
    93  *      };
    94  *
    95  *     x.foo;           // 444 directly retrieved without __get__ call
    96  *     x.bar = 'hello'; // "bar" directly set without __put__ call
    97  *     x.prop           // calls __get__("prop") as 'prop' is not overridden
    98  * </pre>
    99  * It is possible to pass a specific prototype for JSAdapter instance by passing three arguments to JSAdapter
   100  * constructor. So exact signature of JSAdapter constructor is as follows:
   101  * <pre>
   102  *     JSAdapter([proto], [overrides], adaptee);
   103  * </pre>
   104  * Both proto and overrides are optional - but adaptee is not. When proto is not passed {@code JSAdapter.prototype} is
   105  * used.
   106  */
   107 @ScriptClass("JSAdapter")
   108 public final class NativeJSAdapter extends ScriptObject {
   109     /** object get operation */
   110     public static final String __get__       = "__get__";
   111     /** object out operation */
   112     public static final String __put__       = "__put__";
   113     /** object call operation */
   114     public static final String __call__      = "__call__";
   115     /** object new operation */
   116     public static final String __new__       = "__new__";
   117     /** object getIds operation */
   118     public static final String __getIds__    = "__getIds__";
   119     /** object getKeys operation */
   120     public static final String __getKeys__   = "__getKeys__";
   121     /** object getValues operation */
   122     public static final String __getValues__ = "__getValues__";
   123     /** object has operation */
   124     public static final String __has__       = "__has__";
   125     /** object delete operation */
   126     public static final String __delete__    = "__delete__";
   128     // the new extensibility, sealing and freezing operations
   130     /** prevent extensions operation */
   131     public static final String __preventExtensions__ = "__preventExtensions__";
   132     /** isExtensible extensions operation */
   133     public static final String __isExtensible__      = "__isExtensible__";
   134     /** seal operation */
   135     public static final String __seal__              = "__seal__";
   136     /** isSealed extensions operation */
   137     public static final String __isSealed__          = "__isSealed__";
   138     /** freeze operation */
   139     public static final String __freeze__            = "__freeze__";
   140     /** isFrozen extensions operation */
   141     public static final String __isFrozen__          = "__isFrozen__";
   143     private final ScriptObject adaptee;
   144     private final boolean overrides;
   146     private static final MethodHandle IS_JSADAPTOR = findOwnMH("isJSAdaptor", boolean.class, Object.class, Object.class, MethodHandle.class, Object.class, ScriptFunction.class);
   148     // initialized by nasgen
   149     private static PropertyMap $nasgenmap$;
   151     NativeJSAdapter(final Object overrides, final ScriptObject adaptee, final ScriptObject proto, final PropertyMap map) {
   152         super(proto, map);
   153         this.adaptee = wrapAdaptee(adaptee);
   154         if (overrides instanceof ScriptObject) {
   155             this.overrides = true;
   156             final ScriptObject sobj = (ScriptObject)overrides;
   157             this.addBoundProperties(sobj);
   158         } else {
   159             this.overrides = false;
   160         }
   161     }
   163     private static ScriptObject wrapAdaptee(final ScriptObject adaptee) {
   164         return new JO(adaptee, JO.getInitialMap());
   165     }
   167     @Override
   168     public String getClassName() {
   169         return "JSAdapter";
   170     }
   172     @Override
   173     public int getInt(final Object key, final int programPoint) {
   174         return (overrides && super.hasOwnProperty(key)) ? super.getInt(key, programPoint) : callAdapteeInt(programPoint, __get__, key);
   175     }
   177     @Override
   178     public int getInt(final double key, final int programPoint) {
   179         return (overrides && super.hasOwnProperty(key)) ? super.getInt(key, programPoint) : callAdapteeInt(programPoint, __get__, key);
   180     }
   182     @Override
   183     public int getInt(final long key, final int programPoint) {
   184         return (overrides && super.hasOwnProperty(key)) ? super.getInt(key, programPoint) : callAdapteeInt(programPoint, __get__, key);
   185     }
   187     @Override
   188     public int getInt(final int key, final int programPoint) {
   189         return (overrides && super.hasOwnProperty(key)) ? super.getInt(key, programPoint) : callAdapteeInt(programPoint, __get__, key);
   190     }
   192     @Override
   193     public long getLong(final Object key, final int programPoint) {
   194         return (overrides && super.hasOwnProperty(key)) ? super.getLong(key, programPoint) : callAdapteeLong(programPoint, __get__, key);
   195     }
   197     @Override
   198     public long getLong(final double key, final int programPoint) {
   199         return (overrides && super.hasOwnProperty(key)) ? super.getLong(key, programPoint) : callAdapteeLong(programPoint, __get__, key);
   200     }
   202     @Override
   203     public long getLong(final long key, final int programPoint) {
   204         return (overrides && super.hasOwnProperty(key)) ? super.getLong(key, programPoint) : callAdapteeLong(programPoint, __get__, key);
   205     }
   207     @Override
   208     public long getLong(final int key, final int programPoint) {
   209         return (overrides && super.hasOwnProperty(key)) ? super.getLong(key, programPoint) : callAdapteeLong(programPoint, __get__, key);
   210     }
   212     @Override
   213     public double getDouble(final Object key, final int programPoint) {
   214         return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key, programPoint) : callAdapteeDouble(programPoint, __get__, key);
   215     }
   217     @Override
   218     public double getDouble(final double key, final int programPoint) {
   219         return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key, programPoint) : callAdapteeDouble(programPoint, __get__, key);
   220     }
   222     @Override
   223     public double getDouble(final long key, final int programPoint) {
   224         return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key, programPoint) : callAdapteeDouble(programPoint, __get__, key);
   225     }
   227     @Override
   228     public double getDouble(final int key, final int programPoint) {
   229         return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key, programPoint) : callAdapteeDouble(programPoint, __get__, key);
   230     }
   232     @Override
   233     public Object get(final Object key) {
   234         return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
   235     }
   237     @Override
   238     public Object get(final double key) {
   239         return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
   240     }
   242     @Override
   243     public Object get(final long key) {
   244         return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
   245     }
   247     @Override
   248     public Object get(final int key) {
   249         return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
   250     }
   252     @Override
   253     public void set(final Object key, final int value, final boolean strict) {
   254         if (overrides && super.hasOwnProperty(key)) {
   255             super.set(key, value, strict);
   256         } else {
   257             callAdaptee(__put__, key, value, strict);
   258         }
   259     }
   261     @Override
   262     public void set(final Object key, final long value, final boolean strict) {
   263         if (overrides && super.hasOwnProperty(key)) {
   264             super.set(key, value, strict);
   265         } else {
   266             callAdaptee(__put__, key, value, strict);
   267         }
   268     }
   270     @Override
   271     public void set(final Object key, final double value, final boolean strict) {
   272         if (overrides && super.hasOwnProperty(key)) {
   273             super.set(key, value, strict);
   274         } else {
   275             callAdaptee(__put__, key, value, strict);
   276         }
   277     }
   279     @Override
   280     public void set(final Object key, final Object value, final boolean strict) {
   281         if (overrides && super.hasOwnProperty(key)) {
   282             super.set(key, value, strict);
   283         } else {
   284             callAdaptee(__put__, key, value, strict);
   285         }
   286     }
   288     @Override
   289     public void set(final double key, final int value, final boolean strict) {
   290         if (overrides && super.hasOwnProperty(key)) {
   291             super.set(key, value, strict);
   292         } else {
   293             callAdaptee(__put__, key, value, strict);
   294         }
   295     }
   297     @Override
   298     public void set(final double key, final long value, final boolean strict) {
   299         if (overrides && super.hasOwnProperty(key)) {
   300             super.set(key, value, strict);
   301         } else {
   302             callAdaptee(__put__, key, value, strict);
   303         }
   304     }
   306     @Override
   307     public void set(final double key, final double value, final boolean strict) {
   308         if (overrides && super.hasOwnProperty(key)) {
   309             super.set(key, value, strict);
   310         } else {
   311             callAdaptee(__put__, key, value, strict);
   312         }
   313     }
   315     @Override
   316     public void set(final double key, final Object value, final boolean strict) {
   317         if (overrides && super.hasOwnProperty(key)) {
   318             super.set(key, value, strict);
   319         } else {
   320             callAdaptee(__put__, key, value, strict);
   321         }
   322     }
   324     @Override
   325     public void set(final long key, final int value, final boolean strict) {
   326         if (overrides && super.hasOwnProperty(key)) {
   327             super.set(key, value, strict);
   328         } else {
   329             callAdaptee(__put__, key, value, strict);
   330         }
   331     }
   333     @Override
   334     public void set(final long key, final long value, final boolean strict) {
   335         if (overrides && super.hasOwnProperty(key)) {
   336             super.set(key, value, strict);
   337         } else {
   338             callAdaptee(__put__, key, value, strict);
   339         }
   340     }
   342     @Override
   343     public void set(final long key, final double value, final boolean strict) {
   344         if (overrides && super.hasOwnProperty(key)) {
   345             super.set(key, value, strict);
   346         } else {
   347             callAdaptee(__put__, key, value, strict);
   348         }
   349     }
   351     @Override
   352     public void set(final long key, final Object value, final boolean strict) {
   353         if (overrides && super.hasOwnProperty(key)) {
   354             super.set(key, value, strict);
   355         } else {
   356             callAdaptee(__put__, key, value, strict);
   357         }
   358     }
   360     @Override
   361     public void set(final int key, final int value, final boolean strict) {
   362         if (overrides && super.hasOwnProperty(key)) {
   363             super.set(key, value, strict);
   364         } else {
   365             callAdaptee(__put__, key, value, strict);
   366         }
   367     }
   369     @Override
   370     public void set(final int key, final long value, final boolean strict) {
   371         if (overrides && super.hasOwnProperty(key)) {
   372             super.set(key, value, strict);
   373         } else {
   374             callAdaptee(__put__, key, value, strict);
   375         }
   376     }
   378     @Override
   379     public void set(final int key, final double value, final boolean strict) {
   380         if (overrides && super.hasOwnProperty(key)) {
   381             super.set(key, value, strict);
   382         } else {
   383             callAdaptee(__put__, key, value, strict);
   384         }
   385     }
   387     @Override
   388     public void set(final int key, final Object value, final boolean strict) {
   389         if (overrides && super.hasOwnProperty(key)) {
   390             super.set(key, value, strict);
   391         } else {
   392             callAdaptee(__put__, key, value, strict);
   393         }
   394     }
   396     @Override
   397     public boolean has(final Object key) {
   398         if (overrides && super.hasOwnProperty(key)) {
   399             return true;
   400         }
   402         return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
   403     }
   405     @Override
   406     public boolean has(final int key) {
   407         if (overrides && super.hasOwnProperty(key)) {
   408             return true;
   409         }
   411         return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
   412     }
   414     @Override
   415     public boolean has(final long key) {
   416         if (overrides && super.hasOwnProperty(key)) {
   417             return true;
   418         }
   420         return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
   421     }
   423     @Override
   424     public boolean has(final double key) {
   425         if (overrides && super.hasOwnProperty(key)) {
   426             return true;
   427         }
   429         return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
   430     }
   432     @Override
   433     public boolean delete(final int key, final boolean strict) {
   434         if (overrides && super.hasOwnProperty(key)) {
   435             return super.delete(key, strict);
   436         }
   438         return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
   439     }
   441     @Override
   442     public boolean delete(final long key, final boolean strict) {
   443         if (overrides && super.hasOwnProperty(key)) {
   444             return super.delete(key, strict);
   445         }
   447         return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
   448     }
   450     @Override
   451     public boolean delete(final double key, final boolean strict) {
   452         if (overrides && super.hasOwnProperty(key)) {
   453             return super.delete(key, strict);
   454         }
   456         return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
   457     }
   459     @Override
   460     public boolean delete(final Object key, final boolean strict) {
   461         if (overrides && super.hasOwnProperty(key)) {
   462             return super.delete(key, strict);
   463         }
   465         return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
   466     }
   468     @Override
   469     public Iterator<String> propertyIterator() {
   470         // Try __getIds__ first, if not found then try __getKeys__
   471         // In jdk6, we had added "__getIds__" so this is just for compatibility.
   472         Object func = adaptee.get(__getIds__);
   473         if (!(func instanceof ScriptFunction)) {
   474             func = adaptee.get(__getKeys__);
   475         }
   477         Object obj;
   478         if (func instanceof ScriptFunction) {
   479             obj = ScriptRuntime.apply((ScriptFunction)func, adaptee);
   480         } else {
   481             obj = new NativeArray(0);
   482         }
   484         final List<String> array = new ArrayList<>();
   485         for (final Iterator<Object> iter = ArrayLikeIterator.arrayLikeIterator(obj); iter.hasNext(); ) {
   486             array.add((String)iter.next());
   487         }
   489         return array.iterator();
   490     }
   493     @Override
   494     public Iterator<Object> valueIterator() {
   495         final Object obj = callAdaptee(new NativeArray(0), __getValues__);
   496         return ArrayLikeIterator.arrayLikeIterator(obj);
   497     }
   499     @Override
   500     public ScriptObject preventExtensions() {
   501         callAdaptee(__preventExtensions__);
   502         return this;
   503     }
   505     @Override
   506     public boolean isExtensible() {
   507         return JSType.toBoolean(callAdaptee(Boolean.TRUE, __isExtensible__));
   508     }
   510     @Override
   511     public ScriptObject seal() {
   512         callAdaptee(__seal__);
   513         return this;
   514     }
   516     @Override
   517     public boolean isSealed() {
   518         return JSType.toBoolean(callAdaptee(Boolean.FALSE, __isSealed__));
   519     }
   521     @Override
   522     public ScriptObject freeze() {
   523         callAdaptee(__freeze__);
   524         return this;
   525     }
   527     @Override
   528     public boolean isFrozen() {
   529         return JSType.toBoolean(callAdaptee(Boolean.FALSE, __isFrozen__));
   530     }
   532     /**
   533      * Constructor
   534      *
   535      * @param isNew is this NativeJSAdapter instantiated with the new operator
   536      * @param self  self reference
   537      * @param args  arguments ([adaptee], [overrides, adaptee] or [proto, overrides, adaptee]
   538      * @return new NativeJSAdapter
   539      */
   540     @Constructor
   541     public static NativeJSAdapter construct(final boolean isNew, final Object self, final Object... args) {
   542         Object proto     = UNDEFINED;
   543         Object overrides = UNDEFINED;
   544         Object adaptee;
   546         if (args == null || args.length == 0) {
   547             throw typeError("not.an.object", "null");
   548         }
   550         switch (args.length) {
   551         case 1:
   552             adaptee = args[0];
   553             break;
   555         case 2:
   556             overrides = args[0];
   557             adaptee   = args[1];
   558             break;
   560         default:
   561             //fallthru
   562         case 3:
   563             proto = args[0];
   564             overrides = args[1];
   565             adaptee = args[2];
   566             break;
   567         }
   569         if (!(adaptee instanceof ScriptObject)) {
   570             throw typeError("not.an.object", ScriptRuntime.safeToString(adaptee));
   571         }
   573         final Global global = Global.instance();
   574         if (proto != null && !(proto instanceof ScriptObject)) {
   575             proto = global.getJSAdapterPrototype();
   576         }
   578         return new NativeJSAdapter(overrides, (ScriptObject)adaptee, (ScriptObject)proto, $nasgenmap$);
   579     }
   581     @Override
   582     protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
   583         return findHook(desc, __new__, false);
   584     }
   586     @Override
   587     protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
   588         if (overrides && super.hasOwnProperty(desc.getNameToken(2))) {
   589             try {
   590                 final GuardedInvocation inv = super.findCallMethodMethod(desc, request);
   591                 if (inv != null) {
   592                     return inv;
   593                 }
   594             } catch (final Exception e) {
   595                 //ignored
   596             }
   597         }
   599         return findHook(desc, __call__);
   600     }
   602     @Override
   603     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operation) {
   604         final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
   605         if (overrides && super.hasOwnProperty(name)) {
   606             try {
   607                 final GuardedInvocation inv = super.findGetMethod(desc, request, operation);
   608                 if (inv != null) {
   609                     return inv;
   610                 }
   611             } catch (final Exception e) {
   612                 //ignored
   613             }
   614         }
   616         switch(operation) {
   617         case "getProp":
   618         case "getElem":
   619             return findHook(desc, __get__);
   620         case "getMethod":
   621             final FindProperty find = adaptee.findProperty(__call__, true);
   622             if (find != null) {
   623                 final Object value = find.getObjectValue();
   624                 if (value instanceof ScriptFunction) {
   625                     final ScriptFunctionImpl func = (ScriptFunctionImpl)value;
   626                     // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
   627                     // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
   628                     return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
   629                             func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
   630                             testJSAdaptor(adaptee, null, null, null),
   631                             adaptee.getProtoSwitchPoint(__call__, find.getOwner()));
   632                 }
   633             }
   634             throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
   635         default:
   636             break;
   637         }
   639         throw new AssertionError("should not reach here");
   640     }
   642     @Override
   643     protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
   644         if (overrides && super.hasOwnProperty(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
   645             try {
   646                 final GuardedInvocation inv = super.findSetMethod(desc, request);
   647                 if (inv != null) {
   648                     return inv;
   649                 }
   650             } catch (final Exception e) {
   651                 //ignored
   652             }
   653         }
   655         return findHook(desc, __put__);
   656     }
   658     // -- Internals only below this point
   659     private Object callAdaptee(final String name, final Object... args) {
   660         return callAdaptee(UNDEFINED, name, args);
   661     }
   663     private double callAdapteeDouble(final int programPoint, final String name, final Object... args) {
   664         return JSType.toNumberMaybeOptimistic(callAdaptee(name, args), programPoint);
   665     }
   667     private long callAdapteeLong(final int programPoint, final String name, final Object... args) {
   668         return JSType.toLongMaybeOptimistic(callAdaptee(name, args), programPoint);
   669     }
   671     private int callAdapteeInt(final int programPoint, final String name, final Object... args) {
   672         return JSType.toInt32MaybeOptimistic(callAdaptee(name, args), programPoint);
   673     }
   675     private Object callAdaptee(final Object retValue, final String name, final Object... args) {
   676         final Object func = adaptee.get(name);
   677         if (func instanceof ScriptFunction) {
   678             return ScriptRuntime.apply((ScriptFunction)func, adaptee, args);
   679         }
   680         return retValue;
   681     }
   683     private GuardedInvocation findHook(final CallSiteDescriptor desc, final String hook) {
   684         return findHook(desc, hook, true);
   685     }
   687     private GuardedInvocation findHook(final CallSiteDescriptor desc, final String hook, final boolean useName) {
   688         final FindProperty findData = adaptee.findProperty(hook, true);
   689         final MethodType type = desc.getMethodType();
   690         if (findData != null) {
   691             final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null;
   692             final Object value = findData.getObjectValue();
   693             if (value instanceof ScriptFunction) {
   694                 final ScriptFunction func = (ScriptFunction)value;
   696                 final MethodHandle methodHandle = getCallMethodHandle(findData, type,
   697                     useName ? name : null);
   698                 if (methodHandle != null) {
   699                     return new GuardedInvocation(
   700                             methodHandle,
   701                             testJSAdaptor(adaptee, findData.getGetter(Object.class, INVALID_PROGRAM_POINT, null), findData.getOwner(), func),
   702                             adaptee.getProtoSwitchPoint(hook, findData.getOwner()));
   703                 }
   704              }
   705         }
   707         switch (hook) {
   708         case __call__:
   709             throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
   710         default:
   711             final MethodHandle methodHandle = hook.equals(__put__) ?
   712             MH.asType(Lookup.EMPTY_SETTER, type) :
   713             Lookup.emptyGetter(type.returnType());
   714             return new GuardedInvocation(methodHandle, testJSAdaptor(adaptee, null, null, null), adaptee.getProtoSwitchPoint(hook, null));
   715         }
   716     }
   718     private static MethodHandle testJSAdaptor(final Object adaptee, final MethodHandle getter, final Object where, final ScriptFunction func) {
   719         return MH.insertArguments(IS_JSADAPTOR, 1, adaptee, getter, where, func);
   720     }
   722     @SuppressWarnings("unused")
   723     private static boolean isJSAdaptor(final Object self, final Object adaptee, final MethodHandle getter, final Object where, final ScriptFunction func) {
   724         final boolean res = self instanceof NativeJSAdapter && ((NativeJSAdapter)self).getAdaptee() == adaptee;
   725         if (res && getter != null) {
   726             try {
   727                 return getter.invokeExact(where) == func;
   728             } catch (final RuntimeException | Error e) {
   729                 throw e;
   730             } catch (final Throwable t) {
   731                 throw new RuntimeException(t);
   732             }
   733         }
   735         return res;
   736     }
   738     /**
   739      * Get the adaptee
   740      * @return adaptee ScriptObject
   741      */
   742     public ScriptObject getAdaptee() {
   743         return adaptee;
   744     }
   746     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
   747         return MH.findStatic(MethodHandles.lookup(), NativeJSAdapter.class, name, MH.type(rtype, types));
   748     }
   749 }

mercurial