NativeJSAdapter.java revision 1033:c1f651636d9c
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 */
25
26package jdk.nashorn.internal.objects;
27
28import static jdk.nashorn.internal.lookup.Lookup.MH;
29import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
31import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
32
33import java.lang.invoke.MethodHandle;
34import java.lang.invoke.MethodHandles;
35import java.lang.invoke.MethodType;
36import java.util.ArrayList;
37import java.util.Iterator;
38import java.util.List;
39import jdk.internal.dynalink.CallSiteDescriptor;
40import jdk.internal.dynalink.linker.GuardedInvocation;
41import jdk.internal.dynalink.linker.LinkRequest;
42import jdk.nashorn.internal.lookup.Lookup;
43import jdk.nashorn.internal.objects.annotations.Constructor;
44import jdk.nashorn.internal.objects.annotations.ScriptClass;
45import jdk.nashorn.internal.runtime.FindProperty;
46import jdk.nashorn.internal.runtime.JSType;
47import jdk.nashorn.internal.runtime.PropertyMap;
48import jdk.nashorn.internal.runtime.ScriptFunction;
49import jdk.nashorn.internal.runtime.ScriptObject;
50import jdk.nashorn.internal.runtime.ScriptRuntime;
51import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
52import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
53import jdk.nashorn.internal.scripts.JO;
54
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")
108public 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__";
127
128    // the new extensibility, sealing and freezing operations
129
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__";
142
143    private final ScriptObject adaptee;
144    private final boolean overrides;
145
146    private static final MethodHandle IS_JSADAPTOR = findOwnMH("isJSAdaptor", boolean.class, Object.class, Object.class, MethodHandle.class, Object.class, ScriptFunction.class);
147
148    // initialized by nasgen
149    private static PropertyMap $nasgenmap$;
150
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    }
162
163    private static ScriptObject wrapAdaptee(final ScriptObject adaptee) {
164        return new JO(adaptee, JO.getInitialMap());
165    }
166
167    @Override
168    public String getClassName() {
169        return "JSAdapter";
170    }
171
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    }
176
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    }
181
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    }
186
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    }
191
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    }
196
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    }
201
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    }
206
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    }
211
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    }
216
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    }
221
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    }
226
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    }
231
232    @Override
233    public Object get(final Object key) {
234        return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
235    }
236
237    @Override
238    public Object get(final double key) {
239        return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
240    }
241
242    @Override
243    public Object get(final long key) {
244        return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
245    }
246
247    @Override
248    public Object get(final int key) {
249        return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key);
250    }
251
252    @Override
253    public void set(final Object key, final int value, final int flags) {
254        if (overrides && super.hasOwnProperty(key)) {
255            super.set(key, value, flags);
256        } else {
257            callAdaptee(__put__, key, value, flags);
258        }
259    }
260
261    @Override
262    public void set(final Object key, final long value, final int flags) {
263        if (overrides && super.hasOwnProperty(key)) {
264            super.set(key, value, flags);
265        } else {
266            callAdaptee(__put__, key, value, flags);
267        }
268    }
269
270    @Override
271    public void set(final Object key, final double value, final int flags) {
272        if (overrides && super.hasOwnProperty(key)) {
273            super.set(key, value, flags);
274        } else {
275            callAdaptee(__put__, key, value, flags);
276        }
277    }
278
279    @Override
280    public void set(final Object key, final Object value, final int flags) {
281        if (overrides && super.hasOwnProperty(key)) {
282            super.set(key, value, flags);
283        } else {
284            callAdaptee(__put__, key, value, flags);
285        }
286    }
287
288    @Override
289    public void set(final double key, final int value, final int flags) {
290        if (overrides && super.hasOwnProperty(key)) {
291            super.set(key, value, flags);
292        } else {
293            callAdaptee(__put__, key, value, flags);
294        }
295    }
296
297    @Override
298    public void set(final double key, final long value, final int flags) {
299        if (overrides && super.hasOwnProperty(key)) {
300            super.set(key, value, flags);
301        } else {
302            callAdaptee(__put__, key, value, flags);
303        }
304    }
305
306    @Override
307    public void set(final double key, final double value, final int flags) {
308        if (overrides && super.hasOwnProperty(key)) {
309            super.set(key, value, flags);
310        } else {
311            callAdaptee(__put__, key, value, flags);
312        }
313    }
314
315    @Override
316    public void set(final double key, final Object value, final int flags) {
317        if (overrides && super.hasOwnProperty(key)) {
318            super.set(key, value, flags);
319        } else {
320            callAdaptee(__put__, key, value, flags);
321        }
322    }
323
324    @Override
325    public void set(final long key, final int value, final int flags) {
326        if (overrides && super.hasOwnProperty(key)) {
327            super.set(key, value, flags);
328        } else {
329            callAdaptee(__put__, key, value, flags);
330        }
331    }
332
333    @Override
334    public void set(final long key, final long value, final int flags) {
335        if (overrides && super.hasOwnProperty(key)) {
336            super.set(key, value, flags);
337        } else {
338            callAdaptee(__put__, key, value, flags);
339        }
340    }
341
342    @Override
343    public void set(final long key, final double value, final int flags) {
344        if (overrides && super.hasOwnProperty(key)) {
345            super.set(key, value, flags);
346        } else {
347            callAdaptee(__put__, key, value, flags);
348        }
349    }
350
351    @Override
352    public void set(final long key, final Object value, final int flags) {
353        if (overrides && super.hasOwnProperty(key)) {
354            super.set(key, value, flags);
355        } else {
356            callAdaptee(__put__, key, value, flags);
357        }
358    }
359
360    @Override
361    public void set(final int key, final int value, final int flags) {
362        if (overrides && super.hasOwnProperty(key)) {
363            super.set(key, value, flags);
364        } else {
365            callAdaptee(__put__, key, value, flags);
366        }
367    }
368
369    @Override
370    public void set(final int key, final long value, final int flags) {
371        if (overrides && super.hasOwnProperty(key)) {
372            super.set(key, value, flags);
373        } else {
374            callAdaptee(__put__, key, value, flags);
375        }
376    }
377
378    @Override
379    public void set(final int key, final double value, final int flags) {
380        if (overrides && super.hasOwnProperty(key)) {
381            super.set(key, value, flags);
382        } else {
383            callAdaptee(__put__, key, value, flags);
384        }
385    }
386
387    @Override
388    public void set(final int key, final Object value, final int flags) {
389        if (overrides && super.hasOwnProperty(key)) {
390            super.set(key, value, flags);
391        } else {
392            callAdaptee(__put__, key, value, flags);
393        }
394    }
395
396    @Override
397    public boolean has(final Object key) {
398        if (overrides && super.hasOwnProperty(key)) {
399            return true;
400        }
401
402        return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
403    }
404
405    @Override
406    public boolean has(final int key) {
407        if (overrides && super.hasOwnProperty(key)) {
408            return true;
409        }
410
411        return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
412    }
413
414    @Override
415    public boolean has(final long key) {
416        if (overrides && super.hasOwnProperty(key)) {
417            return true;
418        }
419
420        return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
421    }
422
423    @Override
424    public boolean has(final double key) {
425        if (overrides && super.hasOwnProperty(key)) {
426            return true;
427        }
428
429        return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key));
430    }
431
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        }
437
438        return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
439    }
440
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        }
446
447        return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
448    }
449
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        }
455
456        return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
457    }
458
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        }
464
465        return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict));
466    }
467
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        }
476
477        Object obj;
478        if (func instanceof ScriptFunction) {
479            obj = ScriptRuntime.apply((ScriptFunction)func, adaptee);
480        } else {
481            obj = new NativeArray(0);
482        }
483
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        }
488
489        return array.iterator();
490    }
491
492
493    @Override
494    public Iterator<Object> valueIterator() {
495        final Object obj = callAdaptee(new NativeArray(0), __getValues__);
496        return ArrayLikeIterator.arrayLikeIterator(obj);
497    }
498
499    @Override
500    public ScriptObject preventExtensions() {
501        callAdaptee(__preventExtensions__);
502        return this;
503    }
504
505    @Override
506    public boolean isExtensible() {
507        return JSType.toBoolean(callAdaptee(Boolean.TRUE, __isExtensible__));
508    }
509
510    @Override
511    public ScriptObject seal() {
512        callAdaptee(__seal__);
513        return this;
514    }
515
516    @Override
517    public boolean isSealed() {
518        return JSType.toBoolean(callAdaptee(Boolean.FALSE, __isSealed__));
519    }
520
521    @Override
522    public ScriptObject freeze() {
523        callAdaptee(__freeze__);
524        return this;
525    }
526
527    @Override
528    public boolean isFrozen() {
529        return JSType.toBoolean(callAdaptee(Boolean.FALSE, __isFrozen__));
530    }
531
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;
545
546        if (args == null || args.length == 0) {
547            throw typeError("not.an.object", "null");
548        }
549
550        switch (args.length) {
551        case 1:
552            adaptee = args[0];
553            break;
554
555        case 2:
556            overrides = args[0];
557            adaptee   = args[1];
558            break;
559
560        default:
561            //fallthru
562        case 3:
563            proto = args[0];
564            overrides = args[1];
565            adaptee = args[2];
566            break;
567        }
568
569        if (!(adaptee instanceof ScriptObject)) {
570            throw typeError("not.an.object", ScriptRuntime.safeToString(adaptee));
571        }
572
573        final Global global = Global.instance();
574        if (proto != null && !(proto instanceof ScriptObject)) {
575            proto = global.getJSAdapterPrototype();
576        }
577
578        return new NativeJSAdapter(overrides, (ScriptObject)adaptee, (ScriptObject)proto, $nasgenmap$);
579    }
580
581    @Override
582    protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
583        return findHook(desc, __new__, false);
584    }
585
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        }
598
599        return findHook(desc, __call__);
600    }
601
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        }
615
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        }
638
639        throw new AssertionError("should not reach here");
640    }
641
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        }
654
655        return findHook(desc, __put__);
656    }
657
658    // -- Internals only below this point
659    private Object callAdaptee(final String name, final Object... args) {
660        return callAdaptee(UNDEFINED, name, args);
661    }
662
663    private double callAdapteeDouble(final int programPoint, final String name, final Object... args) {
664        return JSType.toNumberMaybeOptimistic(callAdaptee(name, args), programPoint);
665    }
666
667    private long callAdapteeLong(final int programPoint, final String name, final Object... args) {
668        return JSType.toLongMaybeOptimistic(callAdaptee(name, args), programPoint);
669    }
670
671    private int callAdapteeInt(final int programPoint, final String name, final Object... args) {
672        return JSType.toInt32MaybeOptimistic(callAdaptee(name, args), programPoint);
673    }
674
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    }
682
683    private GuardedInvocation findHook(final CallSiteDescriptor desc, final String hook) {
684        return findHook(desc, hook, true);
685    }
686
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;
695
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        }
706
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    }
717
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    }
721
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        }
734
735        return res;
736    }
737
738    /**
739     * Get the adaptee
740     * @return adaptee ScriptObject
741     */
742    public ScriptObject getAdaptee() {
743        return adaptee;
744    }
745
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}
750