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.runtime;
  27 
  28 import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
  29 import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
  30 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
  31 import java.io.Serializable;
  32 import java.lang.invoke.MethodHandle;
  33 import java.lang.invoke.SwitchPoint;
  34 import java.util.Objects;
  35 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
  36 
  37 /**
  38  * This is the abstract superclass representing a JavaScript Property.
  39  * The {@link PropertyMap} map links keys to properties, and consequently
  40  * instances of this class make up the values in the PropertyMap
  41  *
  42  * @see PropertyMap
  43  * @see AccessorProperty
  44  * @see UserAccessorProperty
  45  */
  46 public abstract class Property implements Serializable {
  47     /*
  48      * ECMA 8.6.1 Property Attributes
  49      *
  50      * We use negative flags because most properties are expected to
  51      * be 'writable', 'configurable' and 'enumerable'. With negative flags,
  52      * we can use leave flag byte initialized with (the default) zero value.
  53      */
  54 
  55     /** Mask for property being both writable, enumerable and configurable */
  56     public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000;
  57 
  58     /** ECMA 8.6.1 - Is this property not writable? */
  59     public static final int NOT_WRITABLE     = 1 << 0;
  60 
  61     /** ECMA 8.6.1 - Is this property not enumerable? */
  62     public static final int NOT_ENUMERABLE   = 1 << 1;
  63 
  64     /** ECMA 8.6.1 - Is this property not configurable? */
  65     public static final int NOT_CONFIGURABLE = 1 << 2;
  66 
  67     private static final int MODIFY_MASK     = NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE;
  68 
  69     /** Is this a function parameter? */
  70     public static final int IS_PARAMETER     = 1 << 3;
  71 
  72     /** Is parameter accessed thru arguments? */
  73     public static final int HAS_ARGUMENTS    = 1 << 4;
  74 
  75     /** Is this a function declaration property ? */
  76     public static final int IS_FUNCTION_DECLARATION = 1 << 5;
  77 
  78     /**
  79      * Is this is a primitive field given to us by Nasgen, i.e.
  80      * something we can be sure remains a constant whose type
  81      * is narrower than object, e.g. Math.PI which is declared
  82      * as a double
  83      */
  84     public static final int IS_NASGEN_PRIMITIVE     = 1 << 6;
  85 
  86     /** Is this a builtin property, e.g. Function.prototype.apply */
  87     public static final int IS_BUILTIN              = 1 << 7;
  88 
  89     /** Is this property bound to a receiver? This means get/set operations will be delegated to
  90      *  a statically defined object instead of the object passed as callsite parameter. */
  91     public static final int IS_BOUND                = 1 << 8;
  92 
  93     /** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */
  94     public static final int NEEDS_DECLARATION       = 1 << 9;
  95 
  96     /** Is this property an ES6 lexical binding? */
  97     public static final int IS_LEXICAL_BINDING      = 1 << 10;
  98 
  99     /** Does this property support dual field representation? */
 100     public static final int DUAL_FIELDS             = 1 << 11;
 101 
 102     /** Property key. */
 103     private final Object key;
 104 
 105     /** Property flags. */
 106     private int flags;
 107 
 108     /** Property field number or spill slot. */
 109     private final int slot;
 110 
 111     /**
 112      * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode
 113      * null means undefined, and primitive types are allowed. The reason a special type is used for
 114      * undefined, is that are no bits left to represent it in primitive types
 115      */
 116     private Class<?> type;
 117 
 118     /** SwitchPoint that is invalidated when property is changed, optional */
 119     protected transient SwitchPoint builtinSwitchPoint;
 120 
 121     private static final long serialVersionUID = 2099814273074501176L;
 122 
 123     /**
 124      * Constructor
 125      *
 126      * @param key   property key
 127      * @param flags property flags
 128      * @param slot  property field number or spill slot
 129      */
 130     Property(final Object key, final int flags, final int slot) {
 131         assert key != null;
 132         this.key   = key;
 133         this.flags = flags;
 134         this.slot  = slot;
 135     }
 136 
 137     /**
 138      * Copy constructor
 139      *
 140      * @param property source property
 141      */
 142     Property(final Property property, final int flags) {
 143         this.key                = property.key;
 144         this.slot               = property.slot;
 145         this.builtinSwitchPoint = property.builtinSwitchPoint;
 146         this.flags              = flags;
 147     }
 148 
 149     /**
 150      * Copy function
 151      *
 152      * @return cloned property
 153      */
 154     public abstract Property copy();
 155 
 156     /**
 157      * Copy function
 158      *
 159      * @param  newType new type
 160      * @return cloned property with new type
 161      */
 162     public abstract Property copy(final Class<?> newType);
 163 
 164     /**
 165      * Property flag utility method for {@link PropertyDescriptor}s. Given two property descriptors,
 166      * return the result of merging their flags.
 167      *
 168      * @param oldDesc  first property descriptor
 169      * @param newDesc  second property descriptor
 170      * @return merged flags.
 171      */
 172     static int mergeFlags(final PropertyDescriptor oldDesc, final PropertyDescriptor newDesc) {
 173         int     propFlags = 0;
 174         boolean value;
 175 
 176         value = newDesc.has(CONFIGURABLE) ? newDesc.isConfigurable() : oldDesc.isConfigurable();
 177         if (!value) {
 178             propFlags |= NOT_CONFIGURABLE;
 179         }
 180 
 181         value = newDesc.has(ENUMERABLE) ? newDesc.isEnumerable() : oldDesc.isEnumerable();
 182         if (!value) {
 183             propFlags |= NOT_ENUMERABLE;
 184         }
 185 
 186         value = newDesc.has(WRITABLE) ? newDesc.isWritable() : oldDesc.isWritable();
 187         if (!value) {
 188             propFlags |= NOT_WRITABLE;
 189         }
 190 
 191         return propFlags;
 192     }
 193 
 194     /**
 195      * Set the change callback for this property, i.e. a SwitchPoint
 196      * that will be invalidated when the value of the property is
 197      * changed
 198      * @param sp SwitchPoint to use for change callback
 199      */
 200     public final void setBuiltinSwitchPoint(final SwitchPoint sp) {
 201         this.builtinSwitchPoint = sp;
 202     }
 203 
 204     /**
 205      * Builtin properties have an invalidation switchpoint that is
 206      * invalidated when they are set, this is a getter for it
 207      * @return builtin switchpoint, or null if none
 208      */
 209     public final SwitchPoint getBuiltinSwitchPoint() {
 210         return builtinSwitchPoint;
 211     }
 212 
 213     /**
 214      * Checks if this is a builtin property, this means that it has
 215      * a builtin switchpoint that hasn't been invalidated by a setter
 216      * @return true if builtin, untouched (unset) property
 217      */
 218     public boolean isBuiltin() {
 219         return builtinSwitchPoint != null && !builtinSwitchPoint.hasBeenInvalidated();
 220     }
 221 
 222     /**
 223      * Property flag utility method for {@link PropertyDescriptor}. Get the property flags
 224      * conforming to any Property using this PropertyDescriptor
 225      *
 226      * @param desc property descriptor
 227      * @return flags for properties that conform to property descriptor
 228      */
 229     static int toFlags(final PropertyDescriptor desc) {
 230         int propFlags = 0;
 231 
 232         if (!desc.isConfigurable()) {
 233             propFlags |= NOT_CONFIGURABLE;
 234         }
 235         if (!desc.isEnumerable()) {
 236             propFlags |= NOT_ENUMERABLE;
 237         }
 238         if (!desc.isWritable()) {
 239             propFlags |= NOT_WRITABLE;
 240         }
 241 
 242         return propFlags;
 243     }
 244 
 245     /**
 246      * Check whether this property has a user defined getter function. See {@link UserAccessorProperty}
 247      * @param obj object containing getter
 248      * @return true if getter function exists, false is default
 249      */
 250     public boolean hasGetterFunction(final ScriptObject obj) {
 251         return false;
 252     }
 253 
 254     /**
 255      * Check whether this property has a user defined setter function. See {@link UserAccessorProperty}
 256      * @param obj object containing setter
 257      * @return true if getter function exists, false is default
 258      */
 259     public boolean hasSetterFunction(final ScriptObject obj) {
 260         return false;
 261     }
 262 
 263     /**
 264      * Check whether this property is writable (see ECMA 8.6.1)
 265      * @return true if writable
 266      */
 267     public boolean isWritable() {
 268         return (flags & NOT_WRITABLE) == 0;
 269     }
 270 
 271     /**
 272      * Check whether this property is writable (see ECMA 8.6.1)
 273      * @return true if configurable
 274      */
 275     public boolean isConfigurable() {
 276         return (flags & NOT_CONFIGURABLE) == 0;
 277     }
 278 
 279     /**
 280      * Check whether this property is enumerable (see ECMA 8.6.1)
 281      * @return true if enumerable
 282      */
 283     public boolean isEnumerable() {
 284         return (flags & NOT_ENUMERABLE) == 0;
 285     }
 286 
 287     /**
 288      * Check whether this property is used as a function parameter
 289      * @return true if parameter
 290      */
 291     public boolean isParameter() {
 292         return (flags & IS_PARAMETER) != 0;
 293     }
 294 
 295     /**
 296      * Check whether this property is in an object with arguments field
 297      * @return true if has arguments
 298      */
 299     public boolean hasArguments() {
 300         return (flags & HAS_ARGUMENTS) != 0;
 301     }
 302 
 303     /**
 304      * Check whether this is a spill property, i.e. one that will not
 305      * be stored in a specially generated field in the property class.
 306      * The spill pool is maintained separately, as a growing Object array
 307      * in the {@link ScriptObject}.
 308      *
 309      * @return true if spill property
 310      */
 311     public boolean isSpill() {
 312         return false;
 313     }
 314 
 315     /**
 316      * Is this property bound to a receiver? If this method returns {@code true} get and set operations
 317      * will be delegated to a statically bound object instead of the object passed as parameter.
 318      *
 319      * @return true if this is a bound property
 320      */
 321     public boolean isBound() {
 322         return (flags & IS_BOUND) != 0;
 323     }
 324 
 325     /**
 326      * Is this a LET or CONST property that needs to see its declaration before being usable?
 327      *
 328      * @return true if this is a block-scoped variable
 329      */
 330     public boolean needsDeclaration() {
 331         return (flags & NEEDS_DECLARATION) != 0;
 332     }
 333 
 334     /**
 335      * Add more property flags to the property. Properties are immutable here,
 336      * so any property change that results in a larger flag set results in the
 337      * property being cloned. Use only the return value
 338      *
 339      * @param propertyFlags flags to be OR:ed to the existing property flags
 340      * @return new property if property set was changed, {@code this} otherwise
 341      */
 342     public Property addFlags(final int propertyFlags) {
 343         if ((this.flags & propertyFlags) != propertyFlags) {
 344             final Property cloned = this.copy();
 345             cloned.flags |= propertyFlags;
 346             return cloned;
 347         }
 348         return this;
 349     }
 350 
 351     /**
 352      * Get the flags for this property
 353      * @return property flags
 354      */
 355     public int getFlags() {
 356         return flags;
 357     }
 358 
 359     /**
 360      * Remove property flags from the property. Properties are immutable here,
 361      * so any property change that results in a smaller flag set results in the
 362      * property being cloned. Use only the return value
 363      *
 364      * @param propertyFlags flags to be subtracted from the existing property flags
 365      * @return new property if property set was changed, {@code this} otherwise
 366      */
 367     public Property removeFlags(final int propertyFlags) {
 368         if ((this.flags & propertyFlags) != 0) {
 369             final Property cloned = this.copy();
 370             cloned.flags &= ~propertyFlags;
 371             return cloned;
 372         }
 373         return this;
 374     }
 375 
 376     /**
 377      * Reset the property for this property. Properties are immutable here,
 378      * so any property change that results in a different flag sets results in the
 379      * property being cloned. Use only the return value
 380      *
 381      * @param propertyFlags flags that are replacing from the existing property flags
 382      * @return new property if property set was changed, {@code this} otherwise
 383      */
 384     public Property setFlags(final int propertyFlags) {
 385         if (this.flags != propertyFlags) {
 386             final Property cloned = this.copy();
 387             cloned.flags &= ~MODIFY_MASK;
 388             cloned.flags |= propertyFlags & MODIFY_MASK;
 389             return cloned;
 390         }
 391         return this;
 392     }
 393 
 394     /**
 395      * Abstract method for retrieving the getter for the property. We do not know
 396      * anything about the internal representation when we request the getter, we only
 397      * know that the getter will return the property as the given type.
 398      *
 399      * @param type getter return value type
 400      * @return a getter for this property as {@code type}
 401      */
 402     public abstract MethodHandle getGetter(final Class<?> type);
 403 
 404     /**
 405      * Get an optimistic getter that throws an exception if type is not the known given one
 406      * @param type          type
 407      * @param programPoint  program point
 408      * @return getter
 409      */
 410     public abstract MethodHandle getOptimisticGetter(final Class<?> type, final int programPoint);
 411 
 412     /**
 413      * Hook to initialize method handles after deserialization.
 414      *
 415      * @param structure the structure class
 416      */
 417     abstract void initMethodHandles(final Class<?> structure);
 418 
 419     /**
 420      * Get the key for this property. This key is an ordinary string. The "name".
 421      * @return key for property
 422      */
 423     public Object getKey() {
 424         return key;
 425     }
 426 
 427     /**
 428      * Get the field number or spill slot
 429      * @return number/slot, -1 if none exists
 430      */
 431     public int getSlot() {
 432         return slot;
 433     }
 434 
 435     /**
 436      * get the Object value of this property from {@code owner}. This allows to bypass creation of the
 437      * getter MethodHandle for spill and user accessor properties.
 438      *
 439      * @param self the this object
 440      * @param owner the owner of the property
 441      * @return  the property value
 442      */
 443     public abstract int getIntValue(final ScriptObject self, final ScriptObject owner);
 444 
 445     /**
 446      * get the Object value of this property from {@code owner}. This allows to bypass creation of the
 447      * getter MethodHandle for spill and user accessor properties.
 448      *
 449      * @param self the this object
 450      * @param owner the owner of the property
 451      * @return  the property value
 452      */
 453     public abstract long getLongValue(final ScriptObject self, final ScriptObject owner);
 454 
 455     /**
 456      * get the Object value of this property from {@code owner}. This allows to bypass creation of the
 457      * getter MethodHandle for spill and user accessor properties.
 458      *
 459      * @param self the this object
 460      * @param owner the owner of the property
 461      * @return  the property value
 462      */
 463     public abstract double getDoubleValue(final ScriptObject self, final ScriptObject owner);
 464 
 465     /**
 466      * get the Object value of this property from {@code owner}. This allows to bypass creation of the
 467      * getter MethodHandle for spill and user accessor properties.
 468      *
 469      * @param self the this object
 470      * @param owner the owner of the property
 471      * @return  the property value
 472      */
 473     public abstract Object getObjectValue(final ScriptObject self, final ScriptObject owner);
 474 
 475     /**
 476      * Set the value of this property in {@code owner}. This allows to bypass creation of the
 477      * setter MethodHandle for spill and user accessor properties.
 478      *
 479      * @param self the this object
 480      * @param owner the owner object
 481      * @param value the new property value
 482      * @param strict is this a strict setter?
 483      */
 484     public abstract void setValue(final ScriptObject self, final ScriptObject owner, final int value, final boolean strict);
 485 
 486     /**
 487      * Set the value of this property in {@code owner}. This allows to bypass creation of the
 488      * setter MethodHandle for spill and user accessor properties.
 489      *
 490      * @param self the this object
 491      * @param owner the owner object
 492      * @param value the new property value
 493      * @param strict is this a strict setter?
 494      */
 495     public abstract void setValue(final ScriptObject self, final ScriptObject owner, final long value, final boolean strict);
 496 
 497     /**
 498      * Set the value of this property in {@code owner}. This allows to bypass creation of the
 499      * setter MethodHandle for spill and user accessor properties.
 500      *
 501      * @param self the this object
 502      * @param owner the owner object
 503      * @param value the new property value
 504      * @param strict is this a strict setter?
 505      */
 506     public abstract void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict);
 507 
 508     /**
 509      * Set the value of this property in {@code owner}. This allows to bypass creation of the
 510      * setter MethodHandle for spill and user accessor properties.
 511      *
 512      * @param self the this object
 513      * @param owner the owner object
 514      * @param value the new property value
 515      * @param strict is this a strict setter?
 516      */
 517     public abstract void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict);
 518 
 519     /**
 520      * Abstract method for retrieving the setter for the property. We do not know
 521      * anything about the internal representation when we request the setter, we only
 522      * know that the setter will take the property as a parameter of the given type.
 523      * <p>
 524      * Note that we have to pass the current property map from which we retrieved
 525      * the property here. This is necessary for map guards if, e.g. the internal
 526      * representation of the field, and consequently also the setter, changes. Then
 527      * we automatically get a map guard that relinks the call site so that the
 528      * older setter will never be used again.
 529      * <p>
 530      * see {@link ObjectClassGenerator#createSetter(Class, Class, MethodHandle, MethodHandle)}
 531      * if you are interested in the internal details of this. Note that if you
 532      * are running with {@code -Dnashorn.fields.objects=true}, the setters
 533      * will currently never change, as all properties are represented as Object field,
 534      * the Object fields are Initialized to {@code ScriptRuntime.UNDEFINED} and primitives are
 535      * boxed/unboxed upon every access, which is not necessarily optimal
 536      *
 537      * @param type setter parameter type
 538      * @param currentMap current property map for property
 539      * @return a getter for this property as {@code type}
 540      */
 541     public abstract MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap);
 542 
 543     /**
 544      * Get the user defined getter function if one exists. Only {@link UserAccessorProperty} instances
 545      * can have user defined getters
 546      * @param obj the script object
 547      * @return user defined getter function, or {@code null} if none exists
 548      */
 549     public ScriptFunction getGetterFunction(final ScriptObject obj) {
 550         return null;
 551     }
 552 
 553     /**
 554      * Get the user defined setter function if one exists. Only {@link UserAccessorProperty} instances
 555      * can have user defined getters
 556      * @param obj the script object
 557      * @return user defined getter function, or {@code null} if none exists
 558      */
 559     public ScriptFunction getSetterFunction(final ScriptObject obj) {
 560         return null;
 561     }
 562 
 563     @Override
 564     public int hashCode() {
 565         final Class<?> t = getLocalType();
 566         return Objects.hashCode(this.key) ^ flags ^ getSlot() ^ (t == null ? 0 : t.hashCode());
 567     }
 568 
 569     @Override
 570     public boolean equals(final Object other) {
 571         if (this == other) {
 572             return true;
 573         }
 574 
 575         if (other == null || this.getClass() != other.getClass()) {
 576             return false;
 577         }
 578 
 579         final Property otherProperty = (Property)other;
 580 
 581         return equalsWithoutType(otherProperty) &&
 582                 getLocalType() == otherProperty.getLocalType();
 583     }
 584 
 585     boolean equalsWithoutType(final Property otherProperty) {
 586         return getFlags() == otherProperty.getFlags() &&
 587                 getSlot() == otherProperty.getSlot() &&
 588                 getKey().equals(otherProperty.getKey());
 589     }
 590 
 591     private static String type(final Class<?> type) {
 592         if (type == null) {
 593             return "undef";
 594         } else if (type == int.class) {
 595             return "i";
 596         } else if (type == long.class) {
 597             return "j";
 598         } else if (type == double.class) {
 599             return "d";
 600         } else {
 601             return "o";
 602         }
 603     }
 604 
 605     /**
 606      * Short toString version
 607      * @return short toString
 608      */
 609     public final String toStringShort() {
 610         final StringBuilder sb   = new StringBuilder();
 611         final Class<?>      t = getLocalType();
 612         sb.append(getKey()).append(" (").append(type(t)).append(')');
 613         return sb.toString();
 614     }
 615 
 616     private static String indent(final String str, final int indent) {
 617         final StringBuilder sb = new StringBuilder();
 618         sb.append(str);
 619         for (int i = 0; i < indent - str.length(); i++) {
 620             sb.append(' ');
 621         }
 622         return sb.toString();
 623      }
 624 
 625     @Override
 626     public String toString() {
 627         final StringBuilder sb   = new StringBuilder();
 628         final Class<?>      t = getLocalType();
 629 
 630         sb.append(indent(getKey().toString(), 20)).
 631             append(" id=").
 632             append(Debug.id(this)).
 633             append(" (0x").
 634             append(indent(Integer.toHexString(flags), 4)).
 635             append(") ").
 636             append(getClass().getSimpleName()).
 637             append(" {").
 638             append(indent(type(t), 5)).
 639             append('}');
 640 
 641         if (slot != -1) {
 642             sb.append(" [").
 643                append("slot=").
 644                append(slot).
 645                append(']');
 646         }
 647 
 648         return sb.toString();
 649     }
 650 
 651     /**
 652      * Get the current type of this property. If you are running with object fields enabled,
 653      * this will always be Object.class. See the value representation explanation in
 654      * {@link Property#getSetter(Class, PropertyMap)} and {@link ObjectClassGenerator}
 655      * for more information.
 656      *
 657      * <p>Note that for user accessor properties, this returns the type of the last observed
 658      * value passed to or returned by a user accessor. Use {@link #getLocalType()} to always get
 659      * the type of the actual value stored in the property slot.</p>
 660      *
 661      * @return current type of property, null means undefined
 662      */
 663     public final Class<?> getType() {
 664         return type;
 665     }
 666 
 667     /**
 668      * Set the type of this property.
 669      * @param type new type
 670      */
 671     public final void setType(final Class<?> type) {
 672         assert type != boolean.class : "no boolean storage support yet - fix this";
 673         this.type = type == null ? null : type.isPrimitive() ? type : Object.class;
 674     }
 675 
 676     /**
 677      * Get the type of the value in the local property slot. This returns the same as
 678      * {@link #getType()} for normal properties, but always returns {@code Object.class}
 679      * for {@link UserAccessorProperty}s as their local type is a pair of accessor references.
 680      *
 681      * @return the local property type
 682      */
 683     protected Class<?> getLocalType() {
 684         return getType();
 685     }
 686 
 687     /**
 688      * Check whether this Property can ever change its type. The default is false, and if
 689      * you are not running with dual fields, the type is always object and can never change
 690      * @return true if this property can change types
 691      */
 692     public boolean canChangeType() {
 693         return false;
 694     }
 695 
 696     /**
 697      * Check whether this property represents a function declaration.
 698      * @return whether this property is a function declaration or not.
 699      */
 700     public boolean isFunctionDeclaration() {
 701         return (flags & IS_FUNCTION_DECLARATION) != 0;
 702     }
 703 
 704     /**
 705      * Is this a property defined by ES6 let or const?
 706      * @return true if this property represents a lexical binding.
 707      */
 708     public boolean isLexicalBinding() {
 709         return (flags & IS_LEXICAL_BINDING) != 0;
 710     }
 711 
 712     /**
 713      * Does this property support dual fields for both primitive and object values?
 714      * @return true if supports dual fields
 715      */
 716     public boolean hasDualFields() {
 717         return (flags & DUAL_FIELDS) != 0;
 718     }
 719 }