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