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 
  31 import java.lang.invoke.MethodHandle;
  32 import java.lang.invoke.MethodHandles;
  33 import java.lang.invoke.MethodType;
  34 import java.util.ArrayList;
  35 import java.util.Collection;
  36 import java.util.HashSet;
  37 import java.util.List;
  38 import java.util.Set;
  39 import java.util.concurrent.Callable;
  40 import jdk.internal.dynalink.beans.BeansLinker;
  41 import jdk.internal.dynalink.beans.StaticClass;
  42 import jdk.internal.dynalink.linker.GuardedInvocation;
  43 import jdk.internal.dynalink.linker.GuardingDynamicLinker;
  44 import jdk.internal.dynalink.linker.LinkRequest;
  45 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
  46 import jdk.internal.dynalink.support.LinkRequestImpl;
  47 import jdk.nashorn.api.scripting.ScriptObjectMirror;
  48 import jdk.nashorn.internal.lookup.Lookup;
  49 import jdk.nashorn.internal.objects.annotations.Attribute;
  50 import jdk.nashorn.internal.objects.annotations.Constructor;
  51 import jdk.nashorn.internal.objects.annotations.Function;
  52 import jdk.nashorn.internal.objects.annotations.ScriptClass;
  53 import jdk.nashorn.internal.objects.annotations.Where;
  54 import jdk.nashorn.internal.runtime.AccessorProperty;
  55 import jdk.nashorn.internal.runtime.ECMAException;
  56 import jdk.nashorn.internal.runtime.JSType;
  57 import jdk.nashorn.internal.runtime.Property;
  58 import jdk.nashorn.internal.runtime.PropertyMap;
  59 import jdk.nashorn.internal.runtime.ScriptObject;
  60 import jdk.nashorn.internal.runtime.ScriptRuntime;
  61 import jdk.nashorn.internal.runtime.linker.Bootstrap;
  62 import jdk.nashorn.internal.runtime.linker.InvokeByName;
  63 import jdk.nashorn.internal.runtime.linker.NashornBeansLinker;
  64 
  65 /**
  66  * ECMA 15.2 Object objects
  67  *
  68  * JavaScript Object constructor/prototype. Note: instances of this class are
  69  * never created. This class is not even a subclass of ScriptObject. But, we use
  70  * this class to generate prototype and constructor for "Object".
  71  *
  72  */
  73 @ScriptClass("Object")
  74 public final class NativeObject {
  75     private static final Object TO_STRING = new Object();
  76 
  77     private static InvokeByName getTO_STRING() {
  78         return Global.instance().getInvokeByName(TO_STRING,
  79                 new Callable<InvokeByName>() {
  80                     @Override
  81                     public InvokeByName call() {
  82                         return new InvokeByName("toString", ScriptObject.class);
  83                     }
  84                 });
  85     }
  86 
  87     private static final MethodType MIRROR_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class);
  88     private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.class);
  89 
  90     // initialized by nasgen
  91     @SuppressWarnings("unused")
  92     private static PropertyMap $nasgenmap$;
  93 
  94     private NativeObject() {
  95         // don't create me!
  96         throw new UnsupportedOperationException();
  97     }
  98 
  99     private static ECMAException notAnObject(final Object obj) {
 100         return typeError("not.an.object", ScriptRuntime.safeToString(obj));
 101     }
 102 
 103     /**
 104      * ECMA 15.2.3.2 Object.getPrototypeOf ( O )
 105      *
 106      * @param  self self reference
 107      * @param  obj object to get prototype from
 108      * @return the prototype of an object
 109      */
 110     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 111     public static Object getPrototypeOf(final Object self, final Object obj) {
 112         if (obj instanceof ScriptObject) {
 113             return ((ScriptObject)obj).getProto();
 114         } else if (obj instanceof ScriptObjectMirror) {
 115             return ((ScriptObjectMirror)obj).getProto();
 116         } else {
 117             final JSType type = JSType.of(obj);
 118             if (type == JSType.OBJECT) {
 119                 // host (Java) objects have null __proto__
 120                 return null;
 121             }
 122 
 123             // must be some JS primitive
 124             throw notAnObject(obj);
 125         }
 126     }
 127 
 128     /**
 129      * Nashorn extension: Object.setPrototypeOf ( O, proto )
 130      * Also found in ES6 draft specification.
 131      *
 132      * @param  self self reference
 133      * @param  obj object to set prototype for
 134      * @param  proto prototype object to be used
 135      * @return object whose prototype is set
 136      */
 137     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 138     public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) {
 139         if (obj instanceof ScriptObject) {
 140             ((ScriptObject)obj).setProtoCheck(proto);
 141             return obj;
 142         } else if (obj instanceof ScriptObjectMirror) {
 143             ((ScriptObjectMirror)obj).setProto(proto);
 144             return obj;
 145         }
 146 
 147         throw notAnObject(obj);
 148     }
 149 
 150     /**
 151      * ECMA 15.2.3.3 Object.getOwnPropertyDescriptor ( O, P )
 152      *
 153      * @param self  self reference
 154      * @param obj   object from which to get property descriptor for {@code ToString(prop)}
 155      * @param prop  property descriptor
 156      * @return property descriptor
 157      */
 158     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 159     public static Object getOwnPropertyDescriptor(final Object self, final Object obj, final Object prop) {
 160         if (obj instanceof ScriptObject) {
 161             final String       key  = JSType.toString(prop);
 162             final ScriptObject sobj = (ScriptObject)obj;
 163 
 164             return sobj.getOwnPropertyDescriptor(key);
 165         } else if (obj instanceof ScriptObjectMirror) {
 166             final String       key  = JSType.toString(prop);
 167             final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj;
 168 
 169             return sobjMirror.getOwnPropertyDescriptor(key);
 170         } else {
 171             throw notAnObject(obj);
 172         }
 173     }
 174 
 175     /**
 176      * ECMA 15.2.3.4 Object.getOwnPropertyNames ( O )
 177      *
 178      * @param self self reference
 179      * @param obj  object to query for property names
 180      * @return array of property names
 181      */
 182     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 183     public static Object getOwnPropertyNames(final Object self, final Object obj) {
 184         if (obj instanceof ScriptObject) {
 185             return new NativeArray(((ScriptObject)obj).getOwnKeys(true));
 186         } else if (obj instanceof ScriptObjectMirror) {
 187             return new NativeArray(((ScriptObjectMirror)obj).getOwnKeys(true));
 188         } else {
 189             throw notAnObject(obj);
 190         }
 191     }
 192 
 193     /**
 194      * ECMA 15.2.3.5 Object.create ( O [, Properties] )
 195      *
 196      * @param self  self reference
 197      * @param proto prototype object
 198      * @param props properties to define
 199      * @return object created
 200      */
 201     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 202     public static Object create(final Object self, final Object proto, final Object props) {
 203         if (proto != null) {
 204             Global.checkObject(proto);
 205         }
 206 
 207         // FIXME: should we create a proper object with correct number of
 208         // properties?
 209         final ScriptObject newObj = Global.newEmptyInstance();
 210         newObj.setProto((ScriptObject)proto);
 211         if (props != UNDEFINED) {
 212             NativeObject.defineProperties(self, newObj, props);
 213         }
 214 
 215         return newObj;
 216     }
 217 
 218     /**
 219      * ECMA 15.2.3.6 Object.defineProperty ( O, P, Attributes )
 220      *
 221      * @param self self reference
 222      * @param obj  object in which to define a property
 223      * @param prop property to define
 224      * @param attr attributes for property descriptor
 225      * @return object
 226      */
 227     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 228     public static Object defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
 229         Global.checkObject(obj);
 230         ((ScriptObject)obj).defineOwnProperty(JSType.toString(prop), attr, true);
 231         return obj;
 232     }
 233 
 234     /**
 235      * ECMA 5.2.3.7 Object.defineProperties ( O, Properties )
 236      *
 237      * @param self  self reference
 238      * @param obj   object in which to define properties
 239      * @param props properties
 240      * @return object
 241      */
 242     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 243     public static Object defineProperties(final Object self, final Object obj, final Object props) {
 244         Global.checkObject(obj);
 245 
 246         final ScriptObject sobj     = (ScriptObject)obj;
 247         final Object       propsObj = Global.toObject(props);
 248 
 249         if (propsObj instanceof ScriptObject) {
 250             final Object[] keys = ((ScriptObject)propsObj).getOwnKeys(false);
 251             for (final Object key : keys) {
 252                 final String prop = JSType.toString(key);
 253                 sobj.defineOwnProperty(prop, ((ScriptObject)propsObj).get(prop), true);
 254             }
 255         }
 256         return sobj;
 257     }
 258 
 259     /**
 260      * ECMA 15.2.3.8 Object.seal ( O )
 261      *
 262      * @param self self reference
 263      * @param obj  object to seal
 264      * @return sealed object
 265      */
 266     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 267     public static Object seal(final Object self, final Object obj) {
 268         if (obj instanceof ScriptObject) {
 269             return ((ScriptObject)obj).seal();
 270         } else if (obj instanceof ScriptObjectMirror) {
 271             return ((ScriptObjectMirror)obj).seal();
 272         } else {
 273             throw notAnObject(obj);
 274         }
 275     }
 276 
 277 
 278     /**
 279      * ECMA 15.2.3.9 Object.freeze ( O )
 280      *
 281      * @param self self reference
 282      * @param obj object to freeze
 283      * @return frozen object
 284      */
 285     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 286     public static Object freeze(final Object self, final Object obj) {
 287         if (obj instanceof ScriptObject) {
 288             return ((ScriptObject)obj).freeze();
 289         } else if (obj instanceof ScriptObjectMirror) {
 290             return ((ScriptObjectMirror)obj).freeze();
 291         } else {
 292             throw notAnObject(obj);
 293         }
 294     }
 295 
 296     /**
 297      * ECMA 15.2.3.10 Object.preventExtensions ( O )
 298      *
 299      * @param self self reference
 300      * @param obj  object, for which to set the internal extensible property to false
 301      * @return object
 302      */
 303     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 304     public static Object preventExtensions(final Object self, final Object obj) {
 305         if (obj instanceof ScriptObject) {
 306             return ((ScriptObject)obj).preventExtensions();
 307         } else if (obj instanceof ScriptObjectMirror) {
 308             return ((ScriptObjectMirror)obj).preventExtensions();
 309         } else {
 310             throw notAnObject(obj);
 311         }
 312     }
 313 
 314     /**
 315      * ECMA 15.2.3.11 Object.isSealed ( O )
 316      *
 317      * @param self self reference
 318      * @param obj check whether an object is sealed
 319      * @return true if sealed, false otherwise
 320      */
 321     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 322     public static Object isSealed(final Object self, final Object obj) {
 323         if (obj instanceof ScriptObject) {
 324             return ((ScriptObject)obj).isSealed();
 325         } else if (obj instanceof ScriptObjectMirror) {
 326             return ((ScriptObjectMirror)obj).isSealed();
 327         } else {
 328             throw notAnObject(obj);
 329         }
 330     }
 331 
 332     /**
 333      * ECMA 15.2.3.12 Object.isFrozen ( O )
 334      *
 335      * @param self self reference
 336      * @param obj check whether an object
 337      * @return true if object is frozen, false otherwise
 338      */
 339     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 340     public static Object isFrozen(final Object self, final Object obj) {
 341         if (obj instanceof ScriptObject) {
 342             return ((ScriptObject)obj).isFrozen();
 343         } else if (obj instanceof ScriptObjectMirror) {
 344             return ((ScriptObjectMirror)obj).isFrozen();
 345         } else {
 346             throw notAnObject(obj);
 347         }
 348     }
 349 
 350     /**
 351      * ECMA 15.2.3.13 Object.isExtensible ( O )
 352      *
 353      * @param self self reference
 354      * @param obj check whether an object is extensible
 355      * @return true if object is extensible, false otherwise
 356      */
 357     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 358     public static Object isExtensible(final Object self, final Object obj) {
 359         if (obj instanceof ScriptObject) {
 360             return ((ScriptObject)obj).isExtensible();
 361         } else if (obj instanceof ScriptObjectMirror) {
 362             return ((ScriptObjectMirror)obj).isExtensible();
 363         } else {
 364             throw notAnObject(obj);
 365         }
 366     }
 367 
 368     /**
 369      * ECMA 15.2.3.14 Object.keys ( O )
 370      *
 371      * @param self self reference
 372      * @param obj  object from which to extract keys
 373      * @return array of keys in object
 374      */
 375     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 376     public static Object keys(final Object self, final Object obj) {
 377         if (obj instanceof ScriptObject) {
 378             final ScriptObject sobj = (ScriptObject)obj;
 379             return new NativeArray(sobj.getOwnKeys(false));
 380         } else if (obj instanceof ScriptObjectMirror) {
 381             final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj;
 382             return new NativeArray(sobjMirror.getOwnKeys(false));
 383         } else {
 384             throw notAnObject(obj);
 385         }
 386     }
 387 
 388     /**
 389      * ECMA 15.2.2.1 , 15.2.1.1 new Object([value]) and Object([value])
 390      *
 391      * Constructor
 392      *
 393      * @param newObj is the new object instantiated with the new operator
 394      * @param self   self reference
 395      * @param value  value of object to be instantiated
 396      * @return the new NativeObject
 397      */
 398     @Constructor
 399     public static Object construct(final boolean newObj, final Object self, final Object value) {
 400         final JSType type = JSType.of(value);
 401 
 402         // Object(null), Object(undefined), Object() are same as "new Object()"
 403 
 404         if (newObj || (type == JSType.NULL || type == JSType.UNDEFINED)) {
 405             switch (type) {
 406             case BOOLEAN:
 407             case NUMBER:
 408             case STRING:
 409                 return Global.toObject(value);
 410             case OBJECT:
 411             case FUNCTION:
 412                 return value;
 413             case NULL:
 414             case UNDEFINED:
 415                 // fall through..
 416             default:
 417                 break;
 418             }
 419 
 420             return Global.newEmptyInstance();
 421         }
 422 
 423         return Global.toObject(value);
 424     }
 425 
 426     /**
 427      * ECMA 15.2.4.2 Object.prototype.toString ( )
 428      *
 429      * @param self self reference
 430      * @return ToString of object
 431      */
 432     @Function(attributes = Attribute.NOT_ENUMERABLE)
 433     public static Object toString(final Object self) {
 434         return ScriptRuntime.builtinObjectToString(self);
 435     }
 436 
 437     /**
 438      * ECMA 15.2.4.3 Object.prototype.toLocaleString ( )
 439      *
 440      * @param self self reference
 441      * @return localized ToString
 442      */
 443     @Function(attributes = Attribute.NOT_ENUMERABLE)
 444     public static Object toLocaleString(final Object self) {
 445         final Object obj = JSType.toScriptObject(self);
 446         if (obj instanceof ScriptObject) {
 447             final InvokeByName toStringInvoker = getTO_STRING();
 448             final ScriptObject sobj = (ScriptObject)self;
 449             try {
 450                 final Object toString = toStringInvoker.getGetter().invokeExact(sobj);
 451 
 452                 if (Bootstrap.isCallable(toString)) {
 453                     return toStringInvoker.getInvoker().invokeExact(toString, sobj);
 454                 }
 455             } catch (final RuntimeException | Error e) {
 456                 throw e;
 457             } catch (final Throwable t) {
 458                 throw new RuntimeException(t);
 459             }
 460 
 461             throw typeError("not.a.function", "toString");
 462         }
 463 
 464         return ScriptRuntime.builtinObjectToString(self);
 465     }
 466 
 467     /**
 468      * ECMA 15.2.4.4 Object.prototype.valueOf ( )
 469      *
 470      * @param self self reference
 471      * @return value of object
 472      */
 473     @Function(attributes = Attribute.NOT_ENUMERABLE)
 474     public static Object valueOf(final Object self) {
 475         return Global.toObject(self);
 476     }
 477 
 478     /**
 479      * ECMA 15.2.4.5 Object.prototype.hasOwnProperty (V)
 480      *
 481      * @param self self reference
 482      * @param v property to check for
 483      * @return true if property exists in object
 484      */
 485     @Function(attributes = Attribute.NOT_ENUMERABLE)
 486     public static Object hasOwnProperty(final Object self, final Object v) {
 487         // Convert ScriptObjects to primitive with String.class hint
 488         // but no need to convert other primitives to string.
 489         final Object key = JSType.toPrimitive(v, String.class);
 490         final Object obj = Global.toObject(self);
 491 
 492         return (obj instanceof ScriptObject) && ((ScriptObject)obj).hasOwnProperty(key);
 493     }
 494 
 495     /**
 496      * ECMA 15.2.4.6 Object.prototype.isPrototypeOf (V)
 497      *
 498      * @param self self reference
 499      * @param v v prototype object to check against
 500      * @return true if object is prototype of v
 501      */
 502     @Function(attributes = Attribute.NOT_ENUMERABLE)
 503     public static Object isPrototypeOf(final Object self, final Object v) {
 504         if (!(v instanceof ScriptObject)) {
 505             return false;
 506         }
 507 
 508         final Object obj   = Global.toObject(self);
 509         ScriptObject proto = (ScriptObject)v;
 510 
 511         do {
 512             proto = proto.getProto();
 513             if (proto == obj) {
 514                 return true;
 515             }
 516         } while (proto != null);
 517 
 518         return false;
 519     }
 520 
 521     /**
 522      * ECMA 15.2.4.7 Object.prototype.propertyIsEnumerable (V)
 523      *
 524      * @param self self reference
 525      * @param v property to check if enumerable
 526      * @return true if property is enumerable
 527      */
 528     @Function(attributes = Attribute.NOT_ENUMERABLE)
 529     public static Object propertyIsEnumerable(final Object self, final Object v) {
 530         final String str = JSType.toString(v);
 531         final Object obj = Global.toObject(self);
 532 
 533         if (obj instanceof ScriptObject) {
 534             final jdk.nashorn.internal.runtime.Property property = ((ScriptObject)obj).getMap().findProperty(str);
 535             return property != null && property.isEnumerable();
 536         }
 537 
 538         return false;
 539     }
 540 
 541     /**
 542      * Nashorn extension: Object.bindProperties
 543      *
 544      * Binds the source object's properties to the target object. Binding
 545      * properties allows two-way read/write for the properties of the source object.
 546      *
 547      * Example:
 548      * <pre>
 549      * var obj = { x: 34, y: 100 };
 550      * var foo = {}
 551      *
 552      * // bind properties of "obj" to "foo" object
 553      * Object.bindProperties(foo, obj);
 554      *
 555      * // now, we can access/write on 'foo' properties
 556      * print(foo.x); // prints obj.x which is 34
 557      *
 558      * // update obj.x via foo.x
 559      * foo.x = "hello";
 560      * print(obj.x); // prints "hello" now
 561      *
 562      * obj.x = 42;   // foo.x also becomes 42
 563      * print(foo.x); // prints 42
 564      * </pre>
 565      * <p>
 566      * The source object bound can be a ScriptObject or a ScriptOjectMirror.
 567      * null or undefined source object results in TypeError being thrown.
 568      * </p>
 569      * Example:
 570      * <pre>
 571      * var obj = loadWithNewGlobal({
 572      *    name: "test",
 573      *    script: "obj = { x: 33, y: 'hello' }"
 574      * });
 575      *
 576      * // bind 'obj's properties to global scope 'this'
 577      * Object.bindProperties(this, obj);
 578      * print(x);         // prints 33
 579      * print(y);         // prints "hello"
 580      * x = Math.PI;      // changes obj.x to Math.PI
 581      * print(obj.x);     // prints Math.PI
 582      * </pre>
 583      *
 584      * Limitations of property binding:
 585      * <ul>
 586      * <li> Only enumerable, immediate (not proto inherited) properties of the source object are bound.
 587      * <li> If the target object already contains a property called "foo", the source's "foo" is skipped (not bound).
 588      * <li> Properties added to the source object after binding to the target are not bound.
 589      * <li> Property configuration changes on the source object (or on the target) is not propagated.
 590      * <li> Delete of property on the target (or the source) is not propagated -
 591      * only the property value is set to 'undefined' if the property happens to be a data property.
 592      * </ul>
 593      * <p>
 594      * It is recommended that the bound properties be treated as non-configurable
 595      * properties to avoid surprises.
 596      * </p>
 597      *
 598      * @param self self reference
 599      * @param target the target object to which the source object's properties are bound
 600      * @param source the source object whose properties are bound to the target
 601      * @return the target object after property binding
 602      */
 603     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 604     public static Object bindProperties(final Object self, final Object target, final Object source) {
 605         // target object has to be a ScriptObject
 606         Global.checkObject(target);
 607         // check null or undefined source object
 608         Global.checkObjectCoercible(source);
 609 
 610         final ScriptObject targetObj = (ScriptObject)target;
 611 
 612         if (source instanceof ScriptObject) {
 613             final ScriptObject sourceObj = (ScriptObject)source;
 614             final Property[] properties = sourceObj.getMap().getProperties();
 615 
 616             // filter non-enumerable properties
 617             final ArrayList<Property> propList = new ArrayList<>();
 618             for (Property prop : properties) {
 619                 if (prop.isEnumerable()) {
 620                     propList.add(prop);
 621                 }
 622             }
 623 
 624             if (! propList.isEmpty()) {
 625                 targetObj.addBoundProperties(sourceObj, propList.toArray(new Property[propList.size()]));
 626             }
 627         } else if (source instanceof ScriptObjectMirror) {
 628             // get enumerable, immediate properties of mirror
 629             final ScriptObjectMirror mirror = (ScriptObjectMirror)source;
 630             final String[] keys = mirror.getOwnKeys(false);
 631             if (keys.length == 0) {
 632                 // nothing to bind
 633                 return target;
 634             }
 635 
 636             // make accessor properties using dynamic invoker getters and setters
 637             final AccessorProperty[] props = new AccessorProperty[keys.length];
 638             for (int idx = 0; idx < keys.length; idx++) {
 639                 final String name = keys[idx];
 640                 final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, MIRROR_GETTER_TYPE);
 641                 final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, MIRROR_SETTER_TYPE);
 642                 props[idx] = (AccessorProperty.create(name, 0, getter, setter));
 643             }
 644 
 645             targetObj.addBoundProperties(source, props);
 646         } else if (source instanceof StaticClass) {
 647             final Class<?> clazz = ((StaticClass)source).getRepresentedClass();
 648             Bootstrap.checkReflectionAccess(clazz, true);
 649             bindBeanProperties(targetObj, source, BeansLinker.getReadableStaticPropertyNames(clazz),
 650                     BeansLinker.getWritableStaticPropertyNames(clazz), BeansLinker.getStaticMethodNames(clazz));
 651         } else {
 652             final Class<?> clazz = source.getClass();
 653             Bootstrap.checkReflectionAccess(clazz, false);
 654             bindBeanProperties(targetObj, source, BeansLinker.getReadableInstancePropertyNames(clazz),
 655                     BeansLinker.getWritableInstancePropertyNames(clazz), BeansLinker.getInstanceMethodNames(clazz));
 656         }
 657 
 658         return target;
 659     }
 660 
 661     private static void bindBeanProperties(final ScriptObject targetObj, final Object source,
 662             final Collection<String> readablePropertyNames, final Collection<String> writablePropertyNames,
 663             final Collection<String> methodNames) {
 664         final Set<String> propertyNames = new HashSet<>(readablePropertyNames);
 665         propertyNames.addAll(writablePropertyNames);
 666 
 667         final Class<?> clazz = source.getClass();
 668 
 669         final MethodType getterType = MethodType.methodType(Object.class, clazz);
 670         final MethodType setterType = MethodType.methodType(Object.class, clazz, Object.class);
 671 
 672         final GuardingDynamicLinker linker = BeansLinker.getLinkerForClass(clazz);
 673 
 674         final List<AccessorProperty> properties = new ArrayList<>(propertyNames.size() + methodNames.size());
 675         for(final String methodName: methodNames) {
 676             final MethodHandle method;
 677             try {
 678                 method = getBeanOperation(linker, "dyn:getMethod:" + methodName, getterType, source);
 679             } catch(final IllegalAccessError e) {
 680                 // Presumably, this was a caller sensitive method. Ignore it and carry on.
 681                 continue;
 682             }
 683             properties.add(AccessorProperty.create(methodName, Property.NOT_WRITABLE, getBoundBeanMethodGetter(source,
 684                     method), null));
 685         }
 686         for(final String propertyName: propertyNames) {
 687             MethodHandle getter;
 688             if(readablePropertyNames.contains(propertyName)) {
 689                 try {
 690                     getter = getBeanOperation(linker, "dyn:getProp:" + propertyName, getterType, source);
 691                 } catch(final IllegalAccessError e) {
 692                     // Presumably, this was a caller sensitive method. Ignore it and carry on.
 693                     getter = Lookup.EMPTY_GETTER;
 694                 }
 695             } else {
 696                 getter = Lookup.EMPTY_GETTER;
 697             }
 698             final boolean isWritable = writablePropertyNames.contains(propertyName);
 699             MethodHandle setter;
 700             if(isWritable) {
 701                 try {
 702                     setter = getBeanOperation(linker, "dyn:setProp:" + propertyName, setterType, source);
 703                 } catch(final IllegalAccessError e) {
 704                     // Presumably, this was a caller sensitive method. Ignore it and carry on.
 705                     setter = Lookup.EMPTY_SETTER;
 706                 }
 707             } else {
 708                 setter = Lookup.EMPTY_SETTER;
 709             }
 710             if(getter != Lookup.EMPTY_GETTER || setter != Lookup.EMPTY_SETTER) {
 711                 properties.add(AccessorProperty.create(propertyName, isWritable ? 0 : Property.NOT_WRITABLE, getter, setter));
 712             }
 713         }
 714 
 715         targetObj.addBoundProperties(source, properties.toArray(new AccessorProperty[properties.size()]));
 716     }
 717 
 718     private static MethodHandle getBoundBeanMethodGetter(Object source, MethodHandle methodGetter) {
 719         try {
 720             // NOTE: we're relying on the fact that "dyn:getMethod:..." return value is constant for any given method
 721             // name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is
 722             // constant for any given method name and object's class.)
 723             return MethodHandles.dropArguments(MethodHandles.constant(Object.class,
 724                     Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class);
 725         } catch(RuntimeException|Error e) {
 726             throw e;
 727         } catch(Throwable t) {
 728             throw new RuntimeException(t);
 729         }
 730     }
 731 
 732     private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final String operation,
 733             final MethodType methodType, final Object source) {
 734         final GuardedInvocation inv;
 735         try {
 736             inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation, methodType, source), Bootstrap.getLinkerServices());
 737             assert passesGuard(source, inv.getGuard());
 738         } catch(RuntimeException|Error e) {
 739             throw e;
 740         } catch(Throwable t) {
 741             throw new RuntimeException(t);
 742         }
 743         assert inv.getSwitchPoint() == null; // Linkers in Dynalink's beans package don't use switchpoints.
 744         // We discard the guard, as all method handles will be bound to a specific object.
 745         return inv.getInvocation();
 746     }
 747 
 748     private static boolean passesGuard(final Object obj, final MethodHandle guard) throws Throwable {
 749         return guard == null || (boolean)guard.invoke(obj);
 750     }
 751 
 752     private static LinkRequest createLinkRequest(String operation, MethodType methodType, Object source) {
 753         return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation,
 754                 methodType), false, source);
 755     }
 756 }