100 private int flags; |
100 private int flags; |
101 |
101 |
102 /** Property field number or spill slot. */ |
102 /** Property field number or spill slot. */ |
103 private final int slot; |
103 private final int slot; |
104 |
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 |
105 /** SwitchPoint that is invalidated when property is changed, optional */ |
112 /** SwitchPoint that is invalidated when property is changed, optional */ |
106 protected transient SwitchPoint builtinSwitchPoint; |
113 protected transient SwitchPoint builtinSwitchPoint; |
107 |
114 |
108 private static final long serialVersionUID = 2099814273074501176L; |
115 private static final long serialVersionUID = 2099814273074501176L; |
109 |
116 |
534 * we automatically get a map guard that relinks the call site so that the |
541 * we automatically get a map guard that relinks the call site so that the |
535 * older setter will never be used again. |
542 * older setter will never be used again. |
536 * <p> |
543 * <p> |
537 * see {@link ObjectClassGenerator#createSetter(Class, Class, MethodHandle, MethodHandle)} |
544 * see {@link ObjectClassGenerator#createSetter(Class, Class, MethodHandle, MethodHandle)} |
538 * if you are interested in the internal details of this. Note that if you |
545 * if you are interested in the internal details of this. Note that if you |
539 * are running in default mode, with {@code -Dnashorn.fields.dual=true}, disabled, the setters |
546 * are running with {@code -Dnashorn.fields.objects=true}, the setters |
540 * will currently never change, as all properties are represented as Object field, |
547 * will currently never change, as all properties are represented as Object field, |
541 * the Object fields are Initialized to {@code ScriptRuntime.UNDEFINED} and primitives are |
548 * the Object fields are Initialized to {@code ScriptRuntime.UNDEFINED} and primitives are |
542 * boxed/unboxed upon every access, which is not necessarily optimal |
549 * boxed/unboxed upon every access, which is not necessarily optimal |
543 * |
550 * |
544 * @param type setter parameter type |
551 * @param type setter parameter type |
584 } |
591 } |
585 |
592 |
586 final Property otherProperty = (Property)other; |
593 final Property otherProperty = (Property)other; |
587 |
594 |
588 return equalsWithoutType(otherProperty) && |
595 return equalsWithoutType(otherProperty) && |
589 getCurrentType() == otherProperty.getCurrentType(); |
596 getLocalType() == otherProperty.getLocalType(); |
590 } |
597 } |
591 |
598 |
592 boolean equalsWithoutType(final Property otherProperty) { |
599 boolean equalsWithoutType(final Property otherProperty) { |
593 return getFlags() == otherProperty.getFlags() && |
600 return getFlags() == otherProperty.getFlags() && |
594 getSlot() == otherProperty.getSlot() && |
601 getSlot() == otherProperty.getSlot() && |
613 * Short toString version |
620 * Short toString version |
614 * @return short toString |
621 * @return short toString |
615 */ |
622 */ |
616 public final String toStringShort() { |
623 public final String toStringShort() { |
617 final StringBuilder sb = new StringBuilder(); |
624 final StringBuilder sb = new StringBuilder(); |
618 final Class<?> type = getCurrentType(); |
625 final Class<?> type = getLocalType(); |
619 sb.append(getKey()).append(" (").append(type(type)).append(')'); |
626 sb.append(getKey()).append(" (").append(type(type)).append(')'); |
620 return sb.toString(); |
627 return sb.toString(); |
621 } |
628 } |
622 |
629 |
623 private static String indent(final String str, final int indent) { |
630 private static String indent(final String str, final int indent) { |
630 } |
637 } |
631 |
638 |
632 @Override |
639 @Override |
633 public String toString() { |
640 public String toString() { |
634 final StringBuilder sb = new StringBuilder(); |
641 final StringBuilder sb = new StringBuilder(); |
635 final Class<?> type = getCurrentType(); |
642 final Class<?> type = getLocalType(); |
636 |
643 |
637 sb.append(indent(getKey(), 20)). |
644 sb.append(indent(getKey(), 20)). |
638 append(" id="). |
645 append(" id="). |
639 append(Debug.id(this)). |
646 append(Debug.id(this)). |
640 append(" (0x"). |
647 append(" (0x"). |
654 |
661 |
655 return sb.toString(); |
662 return sb.toString(); |
656 } |
663 } |
657 |
664 |
658 /** |
665 /** |
659 * Get the current type of this field. If you are not running with dual fields enabled, |
666 * Get the current type of this property. If you are running with object fields enabled, |
660 * this will always be Object.class. See the value representation explanation in |
667 * this will always be Object.class. See the value representation explanation in |
661 * {@link Property#getSetter(Class, PropertyMap)} and {@link ObjectClassGenerator} |
668 * {@link Property#getSetter(Class, PropertyMap)} and {@link ObjectClassGenerator} |
662 * for more information. |
669 * for more information. |
663 * |
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 * |
664 * @return current type of property, null means undefined |
675 * @return current type of property, null means undefined |
665 */ |
676 */ |
666 public abstract Class<?> getCurrentType(); |
677 public final Class<?> getType() { |
667 |
678 return type; |
668 /** |
679 } |
669 * Reset the current type of this property |
680 |
670 * @param currentType new current type |
681 /** |
671 */ |
682 * Set the type of this property. |
672 public abstract void setCurrentType(final Class<?> currentType); |
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 } |
673 |
700 |
674 /** |
701 /** |
675 * Check whether this Property can ever change its type. The default is false, and if |
702 * Check whether this Property can ever change its type. The default is false, and if |
676 * you are not running with dual fields, the type is always object and can never change |
703 * you are not running with dual fields, the type is always object and can never change |
677 * @return true if this property can change types |
704 * @return true if this property can change types |