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