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 
  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.dynalink.CallSiteDescriptor;
  40 import jdk.dynalink.StandardOperation;
  41 import jdk.dynalink.linker.GuardedInvocation;
  42 import jdk.dynalink.linker.LinkRequest;
  43 import jdk.nashorn.internal.lookup.Lookup;
  44 import jdk.nashorn.internal.objects.annotations.Constructor;
  45 import jdk.nashorn.internal.objects.annotations.ScriptClass;
  46 import jdk.nashorn.internal.runtime.FindProperty;
  47 import jdk.nashorn.internal.runtime.JSType;
  48 import jdk.nashorn.internal.runtime.PropertyMap;
  49 import jdk.nashorn.internal.runtime.ScriptFunction;
  50 import jdk.nashorn.internal.runtime.ScriptObject;
  51 import jdk.nashorn.internal.runtime.ScriptRuntime;
  52 import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
  53 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  54 import 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")
 113 public 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 }
--- EOF ---