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