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 }