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