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