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