92 * <li>If the map is modified then it must be cloned and replaced. This notifies
93 * any code that made assumptions about the object that things have changed.
94 * Ex. CallSites that have been validated must check to see if the map has
95 * changed (or a map from a different object type) and hence relink the method
96 * to call.</li>
97 * <li>Modifications of the map include adding/deleting attributes or changing a
98 * function field value.</li>
99 * </ul>
100 */
101
102 public abstract class ScriptObject implements PropertyAccess, Cloneable {
103 /** __proto__ special property name inside object literals. ES6 draft. */
104 public static final String PROTO_PROPERTY_NAME = "__proto__";
105
106 /** Search fall back routine name for "no such method" */
107 public static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__";
108
109 /** Search fall back routine name for "no such property" */
110 public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
111
112 /** Per ScriptObject flag - is this a scope object? */
113 public static final int IS_SCOPE = 1 << 0;
114
115 /** Per ScriptObject flag - is this an array object? */
116 public static final int IS_ARRAY = 1 << 1;
117
118 /** Per ScriptObject flag - is this an arguments object? */
119 public static final int IS_ARGUMENTS = 1 << 2;
120
121 /** Is length property not-writable? */
122 public static final int IS_LENGTH_NOT_WRITABLE = 1 << 3;
123
124 /** Is this a builtin object? */
125 public static final int IS_BUILTIN = 1 << 4;
126
127 /**
128 * Spill growth rate - by how many elements does {@link ScriptObject#primitiveSpill} and
129 * {@link ScriptObject#objectSpill} when full
130 */
131 public static final int SPILL_RATE = 8;
132
133 /** Map to property information and accessor functions. Ordered by insertion. */
134 private PropertyMap map;
135
136 /** objects proto. */
137 private ScriptObject proto;
138
139 /** Object flags. */
140 private int flags;
141
142 /** Area for primitive properties added to object after instantiation, see {@link AccessorProperty} */
143 protected long[] primitiveSpill;
144
145 /** Area for reference properties added to object after instantiation, see {@link AccessorProperty} */
1613 while (true) {
1614 final PropertyMap newMap = getMap().freeze();
1615
1616 if (!compareAndSetMap(oldMap, newMap)) {
1617 oldMap = getMap();
1618 } else {
1619 setArray(ArrayData.freeze(getArray()));
1620 return this;
1621 }
1622 }
1623 }
1624
1625 /**
1626 * Check whether this ScriptObject is frozen
1627 * @return true if frozen
1628 */
1629 public boolean isFrozen() {
1630 return getMap().isFrozen();
1631 }
1632
1633
1634 /**
1635 * Flag this ScriptObject as scope
1636 */
1637 public final void setIsScope() {
1638 if (Context.DEBUG) {
1639 scopeCount++;
1640 }
1641 flags |= IS_SCOPE;
1642 }
1643
1644 /**
1645 * Check whether this ScriptObject is scope
1646 * @return true if scope
1647 */
1648 public final boolean isScope() {
1649 return (flags & IS_SCOPE) != 0;
1650 }
1651
1652 /**
1653 * Tag this script object as built in
1654 */
1655 public final void setIsBuiltin() {
1656 flags |= IS_BUILTIN;
1657 }
1658
1659 /**
1660 * Check if this script object is built in
1661 * @return true if build in
1662 */
1663 public final boolean isBuiltin() {
1664 return (flags & IS_BUILTIN) != 0;
1665 }
1666
1667 /**
1668 * Clears the properties from a ScriptObject
1669 * (java.util.Map-like method to help ScriptObjectMirror implementation)
1904 */
1905 protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
1906 // R(P0, P1, ...)
1907 final MethodType callType = desc.getMethodType();
1908 // use type Object(P0) for the getter
1909 final CallSiteDescriptor getterType = desc.changeMethodType(MethodType.methodType(Object.class, callType.parameterType(0)));
1910 final GuardedInvocation getter = findGetMethod(getterType, request, "getMethod");
1911
1912 // Object(P0) => Object(P0, P1, ...)
1913 final MethodHandle argDroppingGetter = MH.dropArguments(getter.getInvocation(), 1, callType.parameterList().subList(1, callType.parameterCount()));
1914 // R(Object, P0, P1, ...)
1915 final MethodHandle invoker = Bootstrap.createDynamicInvoker("dyn:call", callType.insertParameterTypes(0, argDroppingGetter.type().returnType()));
1916 // Fold Object(P0, P1, ...) into R(Object, P0, P1, ...) => R(P0, P1, ...)
1917 return getter.replaceMethods(MH.foldArguments(invoker, argDroppingGetter), getter.getGuard());
1918 }
1919
1920 /**
1921 * Test whether this object contains in its prototype chain or is itself a with-object.
1922 * @return true if a with-object was found
1923 */
1924 final boolean hasWithScope() {
1925 if (isScope()) {
1926 for (ScriptObject obj = this; obj != null; obj = obj.getProto()) {
1927 if (obj instanceof WithObject) {
1928 return true;
1929 }
1930 }
1931 }
1932 return false;
1933 }
1934
1935 /**
1936 * Add a filter to the first argument of {@code methodHandle} that calls its {@link #getProto()} method
1937 * {@code depth} times.
1938 * @param methodHandle a method handle
1939 * @param depth distance to target prototype
1940 * @return the filtered method handle
1941 */
1942 static MethodHandle addProtoFilter(final MethodHandle methodHandle, final int depth) {
1943 if (depth == 0) {
1944 return methodHandle;
1945 }
1946 final int listIndex = depth - 1; // We don't need 0-deep walker
1947 MethodHandle filter = listIndex < PROTO_FILTERS.size() ? PROTO_FILTERS.get(listIndex) : null;
1948
1949 if (filter == null) {
1950 filter = addProtoFilter(GETPROTO, depth - 1);
1951 PROTO_FILTERS.add(null);
3800 if (self instanceof ScriptObject && ((ScriptObject)self).getMap() == map) {
3801 final ScriptObject proto = getProto((ScriptObject)self, depth);
3802 if (proto == null) {
3803 return false;
3804 }
3805 try {
3806 return getter.invokeExact((Object)proto) == func;
3807 } catch (final RuntimeException | Error e) {
3808 throw e;
3809 } catch (final Throwable t) {
3810 throw new RuntimeException(t);
3811 }
3812 }
3813
3814 return false;
3815 }
3816
3817 /** This is updated only in debug mode - counts number of {@code ScriptObject} instances created */
3818 private static int count;
3819
3820 /** This is updated only in debug mode - counts number of {@code ScriptObject} instances created that are scope */
3821 private static int scopeCount;
3822
3823 /**
3824 * Get number of {@code ScriptObject} instances created. If not running in debug
3825 * mode this is always 0
3826 *
3827 * @return number of ScriptObjects created
3828 */
3829 public static int getCount() {
3830 return count;
3831 }
3832
3833 /**
3834 * Get number of scope {@code ScriptObject} instances created. If not running in debug
3835 * mode this is always 0
3836 *
3837 * @return number of scope ScriptObjects created
3838 */
3839 public static int getScopeCount() {
3840 return scopeCount;
3841 }
3842
3843 }
|
92 * <li>If the map is modified then it must be cloned and replaced. This notifies
93 * any code that made assumptions about the object that things have changed.
94 * Ex. CallSites that have been validated must check to see if the map has
95 * changed (or a map from a different object type) and hence relink the method
96 * to call.</li>
97 * <li>Modifications of the map include adding/deleting attributes or changing a
98 * function field value.</li>
99 * </ul>
100 */
101
102 public abstract class ScriptObject implements PropertyAccess, Cloneable {
103 /** __proto__ special property name inside object literals. ES6 draft. */
104 public static final String PROTO_PROPERTY_NAME = "__proto__";
105
106 /** Search fall back routine name for "no such method" */
107 public static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__";
108
109 /** Search fall back routine name for "no such property" */
110 public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
111
112 /** Per ScriptObject flag - is this an array object? */
113 public static final int IS_ARRAY = 1 << 0;
114
115 /** Per ScriptObject flag - is this an arguments object? */
116 public static final int IS_ARGUMENTS = 1 << 1;
117
118 /** Is length property not-writable? */
119 public static final int IS_LENGTH_NOT_WRITABLE = 1 << 2;
120
121 /** Is this a builtin object? */
122 public static final int IS_BUILTIN = 1 << 3;
123
124 /**
125 * Spill growth rate - by how many elements does {@link ScriptObject#primitiveSpill} and
126 * {@link ScriptObject#objectSpill} when full
127 */
128 public static final int SPILL_RATE = 8;
129
130 /** Map to property information and accessor functions. Ordered by insertion. */
131 private PropertyMap map;
132
133 /** objects proto. */
134 private ScriptObject proto;
135
136 /** Object flags. */
137 private int flags;
138
139 /** Area for primitive properties added to object after instantiation, see {@link AccessorProperty} */
140 protected long[] primitiveSpill;
141
142 /** Area for reference properties added to object after instantiation, see {@link AccessorProperty} */
1610 while (true) {
1611 final PropertyMap newMap = getMap().freeze();
1612
1613 if (!compareAndSetMap(oldMap, newMap)) {
1614 oldMap = getMap();
1615 } else {
1616 setArray(ArrayData.freeze(getArray()));
1617 return this;
1618 }
1619 }
1620 }
1621
1622 /**
1623 * Check whether this ScriptObject is frozen
1624 * @return true if frozen
1625 */
1626 public boolean isFrozen() {
1627 return getMap().isFrozen();
1628 }
1629
1630 /**
1631 * Check whether this ScriptObject is scope
1632 * @return true if scope
1633 */
1634 public boolean isScope() {
1635 return false;
1636 }
1637
1638 /**
1639 * Tag this script object as built in
1640 */
1641 public final void setIsBuiltin() {
1642 flags |= IS_BUILTIN;
1643 }
1644
1645 /**
1646 * Check if this script object is built in
1647 * @return true if build in
1648 */
1649 public final boolean isBuiltin() {
1650 return (flags & IS_BUILTIN) != 0;
1651 }
1652
1653 /**
1654 * Clears the properties from a ScriptObject
1655 * (java.util.Map-like method to help ScriptObjectMirror implementation)
1890 */
1891 protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
1892 // R(P0, P1, ...)
1893 final MethodType callType = desc.getMethodType();
1894 // use type Object(P0) for the getter
1895 final CallSiteDescriptor getterType = desc.changeMethodType(MethodType.methodType(Object.class, callType.parameterType(0)));
1896 final GuardedInvocation getter = findGetMethod(getterType, request, "getMethod");
1897
1898 // Object(P0) => Object(P0, P1, ...)
1899 final MethodHandle argDroppingGetter = MH.dropArguments(getter.getInvocation(), 1, callType.parameterList().subList(1, callType.parameterCount()));
1900 // R(Object, P0, P1, ...)
1901 final MethodHandle invoker = Bootstrap.createDynamicInvoker("dyn:call", callType.insertParameterTypes(0, argDroppingGetter.type().returnType()));
1902 // Fold Object(P0, P1, ...) into R(Object, P0, P1, ...) => R(P0, P1, ...)
1903 return getter.replaceMethods(MH.foldArguments(invoker, argDroppingGetter), getter.getGuard());
1904 }
1905
1906 /**
1907 * Test whether this object contains in its prototype chain or is itself a with-object.
1908 * @return true if a with-object was found
1909 */
1910 boolean hasWithScope() {
1911 return false;
1912 }
1913
1914 /**
1915 * Add a filter to the first argument of {@code methodHandle} that calls its {@link #getProto()} method
1916 * {@code depth} times.
1917 * @param methodHandle a method handle
1918 * @param depth distance to target prototype
1919 * @return the filtered method handle
1920 */
1921 static MethodHandle addProtoFilter(final MethodHandle methodHandle, final int depth) {
1922 if (depth == 0) {
1923 return methodHandle;
1924 }
1925 final int listIndex = depth - 1; // We don't need 0-deep walker
1926 MethodHandle filter = listIndex < PROTO_FILTERS.size() ? PROTO_FILTERS.get(listIndex) : null;
1927
1928 if (filter == null) {
1929 filter = addProtoFilter(GETPROTO, depth - 1);
1930 PROTO_FILTERS.add(null);
3779 if (self instanceof ScriptObject && ((ScriptObject)self).getMap() == map) {
3780 final ScriptObject proto = getProto((ScriptObject)self, depth);
3781 if (proto == null) {
3782 return false;
3783 }
3784 try {
3785 return getter.invokeExact((Object)proto) == func;
3786 } catch (final RuntimeException | Error e) {
3787 throw e;
3788 } catch (final Throwable t) {
3789 throw new RuntimeException(t);
3790 }
3791 }
3792
3793 return false;
3794 }
3795
3796 /** This is updated only in debug mode - counts number of {@code ScriptObject} instances created */
3797 private static int count;
3798
3799 /**
3800 * Get number of {@code ScriptObject} instances created. If not running in debug
3801 * mode this is always 0
3802 *
3803 * @return number of ScriptObjects created
3804 */
3805 public static int getCount() {
3806 return count;
3807 }
3808 }
|