Thu, 11 Sep 2014 18:04:54 +0200
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 }