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 static PropertyMap getInitialMap() { 150 return $nasgenmap$; 151 } 152 153 NativeJSAdapter(final Object overrides, final ScriptObject adaptee, final ScriptObject proto, final PropertyMap map) { 154 super(proto, map); 155 this.adaptee = wrapAdaptee(adaptee); 156 if (overrides instanceof ScriptObject) { 157 this.overrides = true; 158 final ScriptObject sobj = (ScriptObject)overrides; 159 this.addBoundProperties(sobj); 160 } else { 161 this.overrides = false; 162 } 163 } 164 165 private static ScriptObject wrapAdaptee(final ScriptObject adaptee) { 166 return new JO(adaptee, JO.getInitialMap()); 167 } 168 169 @Override 170 public String getClassName() { 171 return "JSAdapter"; 172 } 173 174 @Override 175 public int getInt(final Object key) { 176 return (overrides && super.hasOwnProperty(key)) ? super.getInt(key) : callAdapteeInt(__get__, key); 177 } 178 179 @Override 180 public int getInt(final double key) { 181 return (overrides && super.hasOwnProperty(key)) ? super.getInt(key) : callAdapteeInt(__get__, key); 182 } 183 184 @Override 185 public int getInt(final long key) { 186 return (overrides && super.hasOwnProperty(key)) ? super.getInt(key) : callAdapteeInt(__get__, key); 187 } 188 189 @Override 190 public int getInt(final int key) { 191 return (overrides && super.hasOwnProperty(key)) ? super.getInt(key) : callAdapteeInt(__get__, key); 192 } 193 194 @Override 195 public long getLong(final Object key) { 196 return (overrides && super.hasOwnProperty(key)) ? super.getLong(key) : callAdapteeLong(__get__, key); 197 } 198 199 @Override 200 public long getLong(final double key) { 201 return (overrides && super.hasOwnProperty(key)) ? super.getLong(key) : callAdapteeLong(__get__, key); 202 } 203 204 @Override 205 public long getLong(final long key) { 206 return (overrides && super.hasOwnProperty(key)) ? super.getLong(key) : callAdapteeLong(__get__, key); 207 } 208 209 @Override 210 public long getLong(final int key) { 211 return (overrides && super.hasOwnProperty(key)) ? super.getLong(key) : callAdapteeLong(__get__, key); 212 } 213 214 @Override 215 public double getDouble(final Object key) { 216 return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key) : callAdapteeDouble(__get__, key); 217 } 218 219 @Override 220 public double getDouble(final double key) { 221 return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key) : callAdapteeDouble(__get__, key); 222 } 223 224 @Override 225 public double getDouble(final long key) { 226 return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key) : callAdapteeDouble(__get__, key); 227 } 228 229 @Override 230 public double getDouble(final int key) { 231 return (overrides && super.hasOwnProperty(key)) ? super.getDouble(key) : callAdapteeDouble(__get__, key); 232 } 233 234 @Override 235 public Object get(final Object key) { 236 return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key); 237 } 238 239 @Override 240 public Object get(final double key) { 241 return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key); 242 } 243 244 @Override 245 public Object get(final long key) { 246 return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key); 247 } 248 249 @Override 250 public Object get(final int key) { 251 return (overrides && super.hasOwnProperty(key)) ? super.get(key) : callAdaptee(__get__, key); 252 } 253 254 @Override 255 public void set(final Object key, final int value, final boolean strict) { 256 if (overrides && super.hasOwnProperty(key)) { 257 super.set(key, value, strict); 258 } else { 259 callAdaptee(__put__, key, value, strict); 260 } 261 } 262 263 @Override 264 public void set(final Object key, final long value, final boolean strict) { 265 if (overrides && super.hasOwnProperty(key)) { 266 super.set(key, value, strict); 267 } else { 268 callAdaptee(__put__, key, value, strict); 269 } 270 } 271 272 @Override 273 public void set(final Object key, final double value, final boolean strict) { 274 if (overrides && super.hasOwnProperty(key)) { 275 super.set(key, value, strict); 276 } else { 277 callAdaptee(__put__, key, value, strict); 278 } 279 } 280 281 @Override 282 public void set(final Object key, final Object value, final boolean strict) { 283 if (overrides && super.hasOwnProperty(key)) { 284 super.set(key, value, strict); 285 } else { 286 callAdaptee(__put__, key, value, strict); 287 } 288 } 289 290 @Override 291 public void set(final double key, final int value, final boolean strict) { 292 if (overrides && super.hasOwnProperty(key)) { 293 super.set(key, value, strict); 294 } else { 295 callAdaptee(__put__, key, value, strict); 296 } 297 } 298 299 @Override 300 public void set(final double key, final long value, final boolean strict) { 301 if (overrides && super.hasOwnProperty(key)) { 302 super.set(key, value, strict); 303 } else { 304 callAdaptee(__put__, key, value, strict); 305 } 306 } 307 308 @Override 309 public void set(final double key, final double value, final boolean strict) { 310 if (overrides && super.hasOwnProperty(key)) { 311 super.set(key, value, strict); 312 } else { 313 callAdaptee(__put__, key, value, strict); 314 } 315 } 316 317 @Override 318 public void set(final double key, final Object value, final boolean strict) { 319 if (overrides && super.hasOwnProperty(key)) { 320 super.set(key, value, strict); 321 } else { 322 callAdaptee(__put__, key, value, strict); 323 } 324 } 325 326 @Override 327 public void set(final long key, final int value, final boolean strict) { 328 if (overrides && super.hasOwnProperty(key)) { 329 super.set(key, value, strict); 330 } else { 331 callAdaptee(__put__, key, value, strict); 332 } 333 } 334 335 @Override 336 public void set(final long key, final long value, final boolean strict) { 337 if (overrides && super.hasOwnProperty(key)) { 338 super.set(key, value, strict); 339 } else { 340 callAdaptee(__put__, key, value, strict); 341 } 342 } 343 344 @Override 345 public void set(final long key, final double value, final boolean strict) { 346 if (overrides && super.hasOwnProperty(key)) { 347 super.set(key, value, strict); 348 } else { 349 callAdaptee(__put__, key, value, strict); 350 } 351 } 352 353 @Override 354 public void set(final long key, final Object value, final boolean strict) { 355 if (overrides && super.hasOwnProperty(key)) { 356 super.set(key, value, strict); 357 } else { 358 callAdaptee(__put__, key, value, strict); 359 } 360 } 361 362 @Override 363 public void set(final int key, final int value, final boolean strict) { 364 if (overrides && super.hasOwnProperty(key)) { 365 super.set(key, value, strict); 366 } else { 367 callAdaptee(__put__, key, value, strict); 368 } 369 } 370 371 @Override 372 public void set(final int key, final long value, final boolean strict) { 373 if (overrides && super.hasOwnProperty(key)) { 374 super.set(key, value, strict); 375 } else { 376 callAdaptee(__put__, key, value, strict); 377 } 378 } 379 380 @Override 381 public void set(final int key, final double value, final boolean strict) { 382 if (overrides && super.hasOwnProperty(key)) { 383 super.set(key, value, strict); 384 } else { 385 callAdaptee(__put__, key, value, strict); 386 } 387 } 388 389 @Override 390 public void set(final int key, final Object value, final boolean strict) { 391 if (overrides && super.hasOwnProperty(key)) { 392 super.set(key, value, strict); 393 } else { 394 callAdaptee(__put__, key, value, strict); 395 } 396 } 397 398 @Override 399 public boolean has(final Object key) { 400 if (overrides && super.hasOwnProperty(key)) { 401 return true; 402 } 403 404 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key)); 405 } 406 407 @Override 408 public boolean has(final int key) { 409 if (overrides && super.hasOwnProperty(key)) { 410 return true; 411 } 412 413 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key)); 414 } 415 416 @Override 417 public boolean has(final long key) { 418 if (overrides && super.hasOwnProperty(key)) { 419 return true; 420 } 421 422 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key)); 423 } 424 425 @Override 426 public boolean has(final double key) { 427 if (overrides && super.hasOwnProperty(key)) { 428 return true; 429 } 430 431 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __has__, key)); 432 } 433 434 @Override 435 public boolean delete(final int key, final boolean strict) { 436 if (overrides && super.hasOwnProperty(key)) { 437 return super.delete(key, strict); 438 } 439 440 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict)); 441 } 442 443 @Override 444 public boolean delete(final long key, final boolean strict) { 445 if (overrides && super.hasOwnProperty(key)) { 446 return super.delete(key, strict); 447 } 448 449 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict)); 450 } 451 452 @Override 453 public boolean delete(final double key, final boolean strict) { 454 if (overrides && super.hasOwnProperty(key)) { 455 return super.delete(key, strict); 456 } 457 458 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict)); 459 } 460 461 @Override 462 public boolean delete(final Object key, final boolean strict) { 463 if (overrides && super.hasOwnProperty(key)) { 464 return super.delete(key, strict); 465 } 466 467 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __delete__, key, strict)); 468 } 469 470 @Override 471 public Iterator<String> propertyIterator() { 472 // Try __getIds__ first, if not found then try __getKeys__ 473 // In jdk6, we had added "__getIds__" so this is just for compatibility. 474 Object func = adaptee.get(__getIds__); 475 if (!(func instanceof ScriptFunction)) { 476 func = adaptee.get(__getKeys__); 477 } 478 479 Object obj; 480 if (func instanceof ScriptFunction) { 481 obj = ScriptRuntime.apply((ScriptFunction)func, adaptee); 482 } else { 483 obj = new NativeArray(0); 484 } 485 486 final List<String> array = new ArrayList<>(); 487 for (final Iterator<Object> iter = ArrayLikeIterator.arrayLikeIterator(obj); iter.hasNext(); ) { 488 array.add((String)iter.next()); 489 } 490 491 return array.iterator(); 492 } 493 494 495 @Override 496 public Iterator<Object> valueIterator() { 497 final Object obj = callAdaptee(new NativeArray(0), __getValues__); 498 return ArrayLikeIterator.arrayLikeIterator(obj); 499 } 500 501 @Override 502 public ScriptObject preventExtensions() { 503 callAdaptee(__preventExtensions__); 504 return this; 505 } 506 507 @Override 508 public boolean isExtensible() { 509 return JSType.toBoolean(callAdaptee(Boolean.TRUE, __isExtensible__)); 510 } 511 512 @Override 513 public ScriptObject seal() { 514 callAdaptee(__seal__); 515 return this; 516 } 517 518 @Override 519 public boolean isSealed() { 520 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __isSealed__)); 521 } 522 523 @Override 524 public ScriptObject freeze() { 525 callAdaptee(__freeze__); 526 return this; 527 } 528 529 @Override 530 public boolean isFrozen() { 531 return JSType.toBoolean(callAdaptee(Boolean.FALSE, __isFrozen__)); 532 } 533 534 /** 535 * Constructor 536 * 537 * @param isNew is this NativeJSAdapter instantiated with the new operator 538 * @param self self reference 539 * @param args arguments ([adaptee], [overrides, adaptee] or [proto, overrides, adaptee] 540 * @return new NativeJSAdapter 541 */ 542 @Constructor 543 public static Object construct(final boolean isNew, final Object self, final Object... args) { 544 Object proto = UNDEFINED; 545 Object overrides = UNDEFINED; 546 Object adaptee; 547 548 if (args == null || args.length == 0) { 549 throw typeError("not.an.object", "null"); 550 } 551 552 switch (args.length) { 553 case 1: 554 adaptee = args[0]; 555 break; 556 557 case 2: 558 overrides = args[0]; 559 adaptee = args[1]; 560 break; 561 562 default: 563 //fallthru 564 case 3: 565 proto = args[0]; 566 overrides = args[1]; 567 adaptee = args[2]; 568 break; 569 } 570 571 if (!(adaptee instanceof ScriptObject)) { 572 throw typeError("not.an.object", ScriptRuntime.safeToString(adaptee)); 573 } 574 575 final Global global = Global.instance(); 576 if (proto != null && !(proto instanceof ScriptObject)) { 577 proto = global.getJSAdapterPrototype(); 578 } 579 580 return new NativeJSAdapter(overrides, (ScriptObject)adaptee, (ScriptObject)proto, getInitialMap()); 581 } 582 583 @Override 584 protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) { 585 return findHook(desc, __new__, false); 586 } 587 588 @Override 589 protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) { 590 if (overrides && super.hasOwnProperty(desc.getNameToken(2))) { 591 try { 592 final GuardedInvocation inv = super.findCallMethodMethod(desc, request); 593 if (inv != null) { 594 return inv; 595 } 596 } catch (final Exception e) { 597 //ignored 598 } 599 } 600 601 return findHook(desc, __call__); 602 } 603 604 @Override 605 protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operation) { 606 final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); 607 if (overrides && super.hasOwnProperty(name)) { 608 try { 609 final GuardedInvocation inv = super.findGetMethod(desc, request, operation); 610 if (inv != null) { 611 return inv; 612 } 613 } catch (final Exception e) { 614 //ignored 615 } 616 } 617 618 switch(operation) { 619 case "getProp": 620 case "getElem": 621 return findHook(desc, __get__); 622 case "getMethod": 623 final FindProperty find = adaptee.findProperty(__call__, true); 624 if (find != null) { 625 final Object value = find.getObjectValue(); 626 if (value instanceof ScriptFunction) { 627 final ScriptFunctionImpl func = (ScriptFunctionImpl)value; 628 // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound 629 // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice. 630 return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class, 631 func.makeBoundFunction(this, new Object[] { name })), 0, Object.class), 632 adaptee.getProtoSwitchPoint(__call__, find.getOwner()), 633 testJSAdaptor(adaptee, null, null, null)); 634 } 635 } 636 throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this)); 637 default: 638 break; 639 } 640 641 throw new AssertionError("should not reach here"); 642 } 643 644 @Override 645 protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { 646 if (overrides && super.hasOwnProperty(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) { 647 try { 648 final GuardedInvocation inv = super.findSetMethod(desc, request); 649 if (inv != null) { 650 return inv; 651 } 652 } catch (final Exception e) { 653 //ignored 654 } 655 } 656 657 return findHook(desc, __put__); 658 } 659 660 // -- Internals only below this point 661 private Object callAdaptee(final String name, final Object... args) { 662 return callAdaptee(UNDEFINED, name, args); 663 } 664 665 private double callAdapteeDouble(final String name, final Object... args) { 666 return JSType.toNumber(callAdaptee(name, args)); 667 } 668 669 private long callAdapteeLong(final String name, final Object... args) { 670 return JSType.toLong(callAdaptee(name, args)); 671 } 672 673 private int callAdapteeInt(final String name, final Object... args) { 674 return JSType.toInt32(callAdaptee(name, args)); 675 } 676 677 private Object callAdaptee(final Object retValue, final String name, final Object... args) { 678 final Object func = adaptee.get(name); 679 if (func instanceof ScriptFunction) { 680 return ScriptRuntime.apply((ScriptFunction)func, adaptee, args); 681 } 682 return retValue; 683 } 684 685 private GuardedInvocation findHook(final CallSiteDescriptor desc, final String hook) { 686 return findHook(desc, hook, true); 687 } 688 689 private GuardedInvocation findHook(final CallSiteDescriptor desc, final String hook, final boolean useName) { 690 final FindProperty findData = adaptee.findProperty(hook, true); 691 final MethodType type = desc.getMethodType(); 692 if (findData != null) { 693 final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null; 694 final Object value = findData.getObjectValue(); 695 if (value instanceof ScriptFunction) { 696 final ScriptFunction func = (ScriptFunction)value; 697 698 final MethodHandle methodHandle = getCallMethodHandle(findData, type, 699 useName ? name : null); 700 if (methodHandle != null) { 701 return new GuardedInvocation( 702 methodHandle, 703 adaptee.getProtoSwitchPoint(hook, findData.getOwner()), 704 testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func)); 705 } 706 } 707 } 708 709 switch (hook) { 710 case __call__: 711 throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this)); 712 default: 713 final MethodHandle methodHandle = hook.equals(__put__) ? 714 MH.asType(Lookup.EMPTY_SETTER, type) : 715 Lookup.emptyGetter(type.returnType()); 716 return new GuardedInvocation(methodHandle, adaptee.getProtoSwitchPoint(hook, null), testJSAdaptor(adaptee, null, null, null)); 717 } 718 } 719 720 private static MethodHandle testJSAdaptor(final Object adaptee, final MethodHandle getter, final Object where, final ScriptFunction func) { 721 return MH.insertArguments(IS_JSADAPTOR, 1, adaptee, getter, where, func); 722 } 723 724 @SuppressWarnings("unused") 725 private static boolean isJSAdaptor(final Object self, final Object adaptee, final MethodHandle getter, final Object where, final ScriptFunction func) { 726 final boolean res = self instanceof NativeJSAdapter && ((NativeJSAdapter)self).getAdaptee() == adaptee; 727 if (res && getter != null) { 728 try { 729 return getter.invokeExact(where) == func; 730 } catch (final RuntimeException | Error e) { 731 throw e; 732 } catch (final Throwable t) { 733 throw new RuntimeException(t); 734 } 735 } 736 737 return res; 738 } 739 740 /** 741 * Get the adaptee 742 * @return adaptee ScriptObject 743 */ 744 public ScriptObject getAdaptee() { 745 return adaptee; 746 } 747 748 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 749 return MH.findStatic(MethodHandles.lookup(), NativeJSAdapter.class, name, MH.type(rtype, types)); 750 } 751 }