Property.java revision 1115:a723569d0559
1156230Smux/*
2156230Smux * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3156230Smux * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4156230Smux *
5156230Smux * This code is free software; you can redistribute it and/or modify it
6156230Smux * under the terms of the GNU General Public License version 2 only, as
7156230Smux * published by the Free Software Foundation.  Oracle designates this
8156230Smux * particular file as subject to the "Classpath" exception as provided
9156230Smux * by Oracle in the LICENSE file that accompanied this code.
10156230Smux *
11156230Smux * This code is distributed in the hope that it will be useful, but WITHOUT
12156230Smux * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13156230Smux * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14156230Smux * version 2 for more details (a copy is included in the LICENSE file that
15156230Smux * accompanied this code).
16156230Smux *
17156230Smux * You should have received a copy of the GNU General Public License version
18156230Smux * 2 along with this work; if not, write to the Free Software Foundation,
19156230Smux * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20156230Smux *
21156230Smux * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22156230Smux * or visit www.oracle.com if you need additional information or have any
23156230Smux * questions.
24156230Smux */
25156230Smux
26156230Smuxpackage jdk.nashorn.internal.runtime;
27156230Smux
28156230Smuximport static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
29156230Smuximport static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
30156230Smuximport static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
31228857Smariusimport java.io.Serializable;
32228857Smariusimport java.lang.invoke.MethodHandle;
33228857Smariusimport java.lang.invoke.SwitchPoint;
34228857Smariusimport java.util.Objects;
35228857Smariusimport jdk.nashorn.internal.codegen.ObjectClassGenerator;
36228857Smarius
37228857Smarius/**
38228857Smarius * This is the abstract superclass representing a JavaScript Property.
39228857Smarius * The {@link PropertyMap} map links keys to properties, and consequently
40156230Smux * instances of this class make up the values in the PropertyMap
41228857Smarius *
42156230Smux * @see PropertyMap
43156230Smux * @see AccessorProperty
44156230Smux * @see UserAccessorProperty
45156230Smux */
46156230Smuxpublic abstract class Property implements Serializable {
47156230Smux    /*
48156230Smux     * ECMA 8.6.1 Property Attributes
49156230Smux     *
50156230Smux     * We use negative flags because most properties are expected to
51156230Smux     * be 'writable', 'configurable' and 'enumerable'. With negative flags,
52156230Smux     * we can use leave flag byte initialized with (the default) zero value.
53156230Smux     */
54156230Smux
55156230Smux    /** Mask for property being both writable, enumerable and configurable */
56156230Smux    public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000;
57156230Smux
58156230Smux    /** ECMA 8.6.1 - Is this property not writable? */
59156230Smux    public static final int NOT_WRITABLE     = 1 << 0;
60156230Smux
61156230Smux    /** ECMA 8.6.1 - Is this property not enumerable? */
62156230Smux    public static final int NOT_ENUMERABLE   = 1 << 1;
63156230Smux
64156230Smux    /** ECMA 8.6.1 - Is this property not configurable? */
65156230Smux    public static final int NOT_CONFIGURABLE = 1 << 2;
66156230Smux
67156230Smux    private static final int MODIFY_MASK     = NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE;
68156230Smux
69156230Smux    /** Is this a function parameter? */
70156230Smux    public static final int IS_PARAMETER     = 1 << 3;
71156230Smux
72156230Smux    /** Is parameter accessed thru arguments? */
73156230Smux    public static final int HAS_ARGUMENTS    = 1 << 4;
74156230Smux
75156230Smux    /** Is this a function declaration property ? */
76156230Smux    public static final int IS_FUNCTION_DECLARATION = 1 << 5;
77156230Smux
78156230Smux    /**
79156230Smux     * Is this is a primitive field given to us by Nasgen, i.e.
80156230Smux     * something we can be sure remains a constant whose type
81156230Smux     * is narrower than object, e.g. Math.PI which is declared
82156230Smux     * as a double
83156230Smux     */
84156230Smux    public static final int IS_NASGEN_PRIMITIVE     = 1 << 6;
85156230Smux
86156230Smux    /** Is this a builtin property, e.g. Function.prototype.apply */
87156230Smux    public static final int IS_BUILTIN              = 1 << 7;
88156230Smux
89156230Smux    /** Is this property bound to a receiver? This means get/set operations will be delegated to
90156230Smux     *  a statically defined object instead of the object passed as callsite parameter. */
91156230Smux    public static final int IS_BOUND                = 1 << 8;
92156230Smux
93156230Smux    /** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */
94156230Smux    public static final int NEEDS_DECLARATION       = 1 << 9;
95156230Smux
96156230Smux    /** Is this property an ES6 lexical binding? */
97156230Smux    public static final int IS_LEXICAL_BINDING      = 1 << 10;
98156230Smux
99156230Smux    /** Property key. */
100156230Smux    private final String key;
101156230Smux
102156230Smux    /** Property flags. */
103156230Smux    private int flags;
104156230Smux
105156230Smux    /** Property field number or spill slot. */
106156230Smux    private final int slot;
107156230Smux
108156230Smux    /**
109156230Smux     * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode
110186781Slulf     * null means undefined, and primitive types are allowed. The reason a special type is used for
111186781Slulf     * undefined, is that are no bits left to represent it in primitive types
112186781Slulf     */
113186781Slulf    private Class<?> type;
114186781Slulf
115186781Slulf    /** SwitchPoint that is invalidated when property is changed, optional */
116186781Slulf    protected transient SwitchPoint builtinSwitchPoint;
117186781Slulf
118186781Slulf    private static final long serialVersionUID = 2099814273074501176L;
119186781Slulf
120186781Slulf    /**
121186781Slulf     * Constructor
122186781Slulf     *
123186781Slulf     * @param key   property key
124186781Slulf     * @param flags property flags
125186781Slulf     * @param slot  property field number or spill slot
126186781Slulf     */
127186781Slulf    Property(final String key, final int flags, final int slot) {
128186781Slulf        assert key != null;
129186781Slulf        this.key   = key;
130186781Slulf        this.flags = flags;
131186781Slulf        this.slot  = slot;
132186781Slulf    }
133186781Slulf
134156230Smux    /**
135156230Smux     * Copy constructor
136156230Smux     *
137156230Smux     * @param property source property
138156230Smux     */
139156230Smux    Property(final Property property, final int flags) {
140156230Smux        this.key                = property.key;
141156230Smux        this.slot               = property.slot;
142156230Smux        this.builtinSwitchPoint = property.builtinSwitchPoint;
143156230Smux        this.flags              = flags;
144156230Smux    }
145156701Smux
146156230Smux    /**
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}
729