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