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