Tue, 30 Apr 2013 10:05:42 -0300
8006220: Simplify PropertyMaps
Reviewed-by: hannesw, lagergren
Contributed-by: james.laskey@oracle.com
1.1 --- a/src/jdk/nashorn/internal/codegen/MapCreator.java Tue Apr 30 09:42:13 2013 +0200 1.2 +++ b/src/jdk/nashorn/internal/codegen/MapCreator.java Tue Apr 30 10:05:42 2013 -0300 1.3 @@ -65,10 +65,12 @@ 1.4 * Constructs a property map based on a set of fields. 1.5 * 1.6 * @param hasArguments does the created object have an "arguments" property 1.7 + * @param fieldCount Number of fields in use. 1.8 + * @param fieldMaximum Number of fields available. 1.9 * 1.10 * @return New map populated with accessor properties. 1.11 */ 1.12 - PropertyMap makeMap(final boolean hasArguments) { 1.13 + PropertyMap makeMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) { 1.14 final List<Property> properties = new ArrayList<>(); 1.15 1.16 assert keys != null; 1.17 @@ -82,7 +84,7 @@ 1.18 } 1.19 } 1.20 1.21 - return PropertyMap.newMap(structure, properties); 1.22 + return PropertyMap.newMap(structure, properties, fieldCount, fieldMaximum); 1.23 } 1.24 1.25 /**
2.1 --- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Tue Apr 30 09:42:13 2013 +0200 2.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Tue Apr 30 10:05:42 2013 -0300 2.3 @@ -69,6 +69,16 @@ 2.4 static final String SCOPE_MARKER = "P"; 2.5 2.6 /** 2.7 + * Minimum number of extra fields in an object. 2.8 + */ 2.9 + static final int FIELD_PADDING = 4; 2.10 + 2.11 + /** 2.12 + * Rounding when calculating the number of fields. 2.13 + */ 2.14 + static final int FIELD_ROUNDING = 4; 2.15 + 2.16 + /** 2.17 * Debug field logger 2.18 * Should we print debugging information for fields when they are generated and getters/setters are called? 2.19 */
3.1 --- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java Tue Apr 30 09:42:13 2013 +0200 3.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java Tue Apr 30 10:05:42 2013 -0300 3.3 @@ -26,6 +26,8 @@ 3.4 package jdk.nashorn.internal.codegen; 3.5 3.6 import java.util.List; 3.7 +import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING; 3.8 +import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_ROUNDING; 3.9 import jdk.nashorn.internal.ir.Symbol; 3.10 import jdk.nashorn.internal.runtime.Context; 3.11 import jdk.nashorn.internal.runtime.PropertyMap; 3.12 @@ -50,6 +52,7 @@ 3.13 private final boolean isScope; 3.14 private final boolean hasArguments; 3.15 private int fieldCount; 3.16 + private int paddedFieldCount; 3.17 private int paramCount; 3.18 private String fieldObjectClassName; 3.19 private Class<?> fieldObjectClass; 3.20 @@ -88,6 +91,8 @@ 3.21 } 3.22 } 3.23 } 3.24 + 3.25 + paddedFieldCount = (fieldCount + FIELD_PADDING + FIELD_ROUNDING - 1) / FIELD_ROUNDING * FIELD_ROUNDING; 3.26 } 3.27 3.28 /** 3.29 @@ -96,7 +101,7 @@ 3.30 private void findClass() { 3.31 fieldObjectClassName = isScope() ? 3.32 ObjectClassGenerator.getClassName(fieldCount, paramCount) : 3.33 - ObjectClassGenerator.getClassName(fieldCount); 3.34 + ObjectClassGenerator.getClassName(paddedFieldCount); 3.35 3.36 try { 3.37 this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName)); 3.38 @@ -125,11 +130,7 @@ 3.39 * @return the newly created property map 3.40 */ 3.41 protected PropertyMap makeMap() { 3.42 - if (keys.isEmpty()) { //empty map 3.43 - propertyMap = PropertyMap.newMap(fieldObjectClass); 3.44 - } else { 3.45 - propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments()); 3.46 - } 3.47 + propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments(), fieldCount, paddedFieldCount); 3.48 return propertyMap; 3.49 } 3.50
4.1 --- a/src/jdk/nashorn/internal/objects/NativeDebug.java Tue Apr 30 09:42:13 2013 +0200 4.2 +++ b/src/jdk/nashorn/internal/objects/NativeDebug.java Tue Apr 30 10:05:42 2013 -0300 4.3 @@ -87,66 +87,6 @@ 4.4 } 4.5 4.6 /** 4.7 - * Nashorn extension: get embed0 from {@link ScriptObject} 4.8 - * 4.9 - * @param self self reference 4.10 - * @param obj script object 4.11 - * @return the embed0 property value for the given ScriptObject 4.12 - */ 4.13 - @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 4.14 - public static Object embed0(final Object self, final Object obj) { 4.15 - if (obj instanceof ScriptObject) { 4.16 - return ((ScriptObject)obj).embed0; 4.17 - } 4.18 - return UNDEFINED; 4.19 - } 4.20 - 4.21 - /** 4.22 - * Nashorn extension: get embed1 from {@link ScriptObject} 4.23 - * 4.24 - * @param self self reference 4.25 - * @param obj script object 4.26 - * @return the embed1 property value for the given ScriptObject 4.27 - */ 4.28 - @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 4.29 - public static Object embed1(final Object self, final Object obj) { 4.30 - if (obj instanceof ScriptObject) { 4.31 - return ((ScriptObject)obj).embed1; 4.32 - } 4.33 - return UNDEFINED; 4.34 - } 4.35 - 4.36 - /** 4.37 - * Nashorn extension: get embed2 from {@link ScriptObject} 4.38 - * 4.39 - * @param self self reference 4.40 - * @param obj script object 4.41 - * @return the embed2 property value for the given ScriptObject 4.42 - */ 4.43 - @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 4.44 - public static Object embed2(final Object self, final Object obj) { 4.45 - if (obj instanceof ScriptObject) { 4.46 - return ((ScriptObject)obj).embed2; 4.47 - } 4.48 - return UNDEFINED; 4.49 - } 4.50 - 4.51 - /** 4.52 - * Nashorn extension: get embed3 from {@link ScriptObject} 4.53 - * 4.54 - * @param self self reference 4.55 - * @param obj script object 4.56 - * @return the embed3 property value for the given ScriptObject 4.57 - */ 4.58 - @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 4.59 - public static Object embed3(final Object self, final Object obj) { 4.60 - if (obj instanceof ScriptObject) { 4.61 - return ((ScriptObject)obj).embed3; 4.62 - } 4.63 - return UNDEFINED; 4.64 - } 4.65 - 4.66 - /** 4.67 * Nashorn extension: get spill vector from {@link ScriptObject} 4.68 * 4.69 * @param self self reference
5.1 --- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Tue Apr 30 09:42:13 2013 +0200 5.2 +++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Tue Apr 30 10:05:42 2013 -0300 5.3 @@ -620,7 +620,7 @@ 5.4 // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice. 5.5 return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class, 5.6 func.makeBoundFunction(this, new Object[] { name })), 0, Object.class), 5.7 - adaptee.getMap().getProtoGetSwitchPoint(__call__), testJSAdaptor(adaptee, null, null, null)); 5.8 + adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null)); 5.9 } 5.10 throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this)); 5.11 default: 5.12 @@ -687,7 +687,7 @@ 5.13 if (methodHandle != null) { 5.14 return new GuardedInvocation( 5.15 methodHandle, 5.16 - adaptee.getMap().getProtoGetSwitchPoint(hook), 5.17 + adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook), 5.18 testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func)); 5.19 } 5.20 } 5.21 @@ -699,7 +699,7 @@ 5.22 final MethodHandle methodHandle = hook.equals(__put__) ? 5.23 MH.asType(Lookup.EMPTY_SETTER, type) : 5.24 Lookup.emptyGetter(type.returnType()); 5.25 - return new GuardedInvocation(methodHandle, adaptee.getMap().getProtoGetSwitchPoint(hook), testJSAdaptor(adaptee, null, null, null)); 5.26 + return new GuardedInvocation(methodHandle, adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook), testJSAdaptor(adaptee, null, null, null)); 5.27 } 5.28 } 5.29
6.1 --- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java Tue Apr 30 09:42:13 2013 +0200 6.2 +++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java Tue Apr 30 10:05:42 2013 -0300 6.3 @@ -50,8 +50,6 @@ 6.4 /** 6.5 * An AccessorProperty is the most generic property type. An AccessorProperty is 6.6 * represented as fields in a ScriptObject class. 6.7 - * 6.8 - * @see SpillProperty 6.9 */ 6.10 public class AccessorProperty extends Property { 6.11 private static final MethodHandles.Lookup lookup = MethodHandles.lookup(); 6.12 @@ -77,6 +75,7 @@ 6.13 6.14 private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES]; 6.15 private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES]; 6.16 + private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE); 6.17 6.18 /** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */ 6.19 private MethodHandle primitiveGetter; 6.20 @@ -285,7 +284,7 @@ 6.21 "get"); 6.22 } 6.23 6.24 - return getters[i]; 6.25 + return isSpill() ? MH.filterArguments(getters[i], 0, SPILLGETTER) : getters[i]; 6.26 } 6.27 6.28 private Property getWiderProperty(final Class<?> type) { 6.29 @@ -327,6 +326,7 @@ 6.30 final Class<?> forType = currentType == null ? type : currentType; 6.31 6.32 //if we are asking for an object setter, but are still a primitive type, we might try to box it 6.33 + MethodHandle mh; 6.34 6.35 if (needsInvalidator(i, ci)) { 6.36 final Property newProperty = getWiderProperty(type); 6.37 @@ -335,12 +335,15 @@ 6.38 final MethodHandle explodeTypeSetter = MH.filterArguments(widerSetter, 0, MH.insertArguments(REPLACE_MAP, 1, newMap, getKey(), currentType, type)); 6.39 if (currentType != null && currentType.isPrimitive() && type == Object.class) { 6.40 //might try a box check on this to avoid widening field to object storage 6.41 - return createGuardBoxedPrimitiveSetter(currentType, generateSetter(currentType, currentType), explodeTypeSetter); 6.42 + mh = createGuardBoxedPrimitiveSetter(currentType, generateSetter(currentType, currentType), explodeTypeSetter); 6.43 + } else { 6.44 + mh = explodeTypeSetter; 6.45 } 6.46 - return explodeTypeSetter; 6.47 + } else { 6.48 + mh = generateSetter(forType, type); 6.49 } 6.50 6.51 - return generateSetter(forType, type); 6.52 + return isSpill() ? MH.filterArguments(mh, 0, SPILLGETTER) : mh; 6.53 } 6.54 6.55 @Override
7.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Tue Apr 30 09:42:13 2013 +0200 7.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Tue Apr 30 10:05:42 2013 -0300 7.3 @@ -201,9 +201,6 @@ 7.4 /** Current error manager. */ 7.5 private final ErrorManager errors; 7.6 7.7 - /** Empty map used for seed map for JO objects */ 7.8 - final PropertyMap emptyMap = PropertyMap.newEmptyMap(this); 7.9 - 7.10 private static final ClassLoader myLoader = Context.class.getClassLoader(); 7.11 private static final StructureLoader sharedLoader; 7.12
8.1 --- a/src/jdk/nashorn/internal/runtime/Property.java Tue Apr 30 09:42:13 2013 +0200 8.2 +++ b/src/jdk/nashorn/internal/runtime/Property.java Tue Apr 30 10:05:42 2013 -0300 8.3 @@ -41,7 +41,6 @@ 8.4 * 8.5 * @see PropertyMap 8.6 * @see AccessorProperty 8.7 - * @see SpillProperty 8.8 * @see UserAccessorProperty 8.9 */ 8.10 public abstract class Property { 8.11 @@ -64,7 +63,7 @@ 8.12 8.13 private static final int MODIFY_MASK = 0b0000_0000_1111; 8.14 8.15 - /** Is this a spill property? See {@link SpillProperty} */ 8.16 + /** Is this a spill property? See {@link AccessorProperty} */ 8.17 public static final int IS_SPILL = 0b0000_0001_0000; 8.18 8.19 /** Is this a function parameter? */ 8.20 @@ -88,7 +87,7 @@ 8.21 /** Property flags. */ 8.22 protected int flags; 8.23 8.24 - /** Property field number or spill slot */ 8.25 + /** Property field number or spill slot. */ 8.26 private final int slot; 8.27 8.28 /** 8.29 @@ -248,7 +247,7 @@ 8.30 * Does this property use any slots in the spill array described in 8.31 * {@link Property#isSpill}? In that case how many. Currently a property 8.32 * only uses max one spill slot, but this may change in future representations 8.33 - * Only {@link SpillProperty} instances use spill slots 8.34 + * Only {@link AccessorProperty} instances use spill slots 8.35 * 8.36 * @return number of spill slots a property is using 8.37 */ 8.38 @@ -345,6 +344,14 @@ 8.39 } 8.40 8.41 /** 8.42 + * Get the field number or spill slot 8.43 + * @return number/slot, -1 if none exists 8.44 + */ 8.45 + public int getSlot() { 8.46 + return slot; 8.47 + } 8.48 + 8.49 + /** 8.50 * Abstract method for retrieving the setter for the property. We do not know 8.51 * anything about the internal representation when we request the setter, we only 8.52 * know that the setter will take the property as a parameter of the given type. 8.53 @@ -388,14 +395,6 @@ 8.54 return null; 8.55 } 8.56 8.57 - /** 8.58 - * Get the field number or spill slot 8.59 - * @return number/slot, -1 if none exists 8.60 - */ 8.61 - public int getSlot() { 8.62 - return slot; 8.63 - } 8.64 - 8.65 @Override 8.66 public int hashCode() { 8.67 final Class<?> type = getCurrentType();
9.1 --- a/src/jdk/nashorn/internal/runtime/PropertyHashMap.java Tue Apr 30 09:42:13 2013 +0200 9.2 +++ b/src/jdk/nashorn/internal/runtime/PropertyHashMap.java Tue Apr 30 10:05:42 2013 -0300 9.3 @@ -110,7 +110,7 @@ 9.4 private static final int LIST_THRESHOLD = 8; 9.5 9.6 /** Initial map. */ 9.7 - public static final PropertyHashMap EMPTY_MAP = new PropertyHashMap(); 9.8 + public static final PropertyHashMap EMPTY_HASHMAP = new PropertyHashMap(); 9.9 9.10 /** Number of properties in the map. */ 9.11 private final int size; 9.12 @@ -246,7 +246,7 @@ 9.13 } 9.14 } else if (findElement(list, key) != null) { 9.15 final int newSize = size - 1; 9.16 - return newSize != 0 ? new PropertyHashMap(newSize, null, removeFromList(list, key)) : EMPTY_MAP; 9.17 + return newSize != 0 ? new PropertyHashMap(newSize, null, removeFromList(list, key)) : EMPTY_HASHMAP; 9.18 } 9.19 return this; 9.20 }
10.1 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java Tue Apr 30 09:42:13 2013 +0200 10.2 +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java Tue Apr 30 10:05:42 2013 -0300 10.3 @@ -25,7 +25,7 @@ 10.4 10.5 package jdk.nashorn.internal.runtime; 10.6 10.7 -import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_MAP; 10.8 +import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP; 10.9 10.10 import java.lang.invoke.MethodHandle; 10.11 import java.lang.invoke.SwitchPoint; 10.12 @@ -49,29 +49,27 @@ 10.13 * will return a new map. 10.14 */ 10.15 public final class PropertyMap implements Iterable<Object>, PropertyListener { 10.16 - /** Is this a prototype PropertyMap? */ 10.17 - public static final int IS_PROTOTYPE = 0b0000_0001; 10.18 /** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */ 10.19 - public static final int NOT_EXTENSIBLE = 0b0000_0010; 10.20 + public static final int NOT_EXTENSIBLE = 0b0000_0001; 10.21 /** This mask is used to preserve certain flags when cloning the PropertyMap. Others should not be copied */ 10.22 private static final int CLONEABLE_FLAGS_MASK = 0b0000_1111; 10.23 /** Has a listener been added to this property map. This flag is not copied when cloning a map. See {@link PropertyListener} */ 10.24 public static final int IS_LISTENER_ADDED = 0b0001_0000; 10.25 10.26 + /** Empty map used for seed map for JO$ objects */ 10.27 + private static final PropertyMap EMPTY_MAP = new PropertyMap(EMPTY_HASHMAP); 10.28 + 10.29 /** Map status flags. */ 10.30 private int flags; 10.31 10.32 - /** Class of object referenced.*/ 10.33 - private final Class<?> structure; 10.34 - 10.35 - /** Context associated with this {@link PropertyMap}. */ 10.36 - private final Context context; 10.37 - 10.38 /** Map of properties. */ 10.39 private final PropertyHashMap properties; 10.40 10.41 - /** objects proto. */ 10.42 - private ScriptObject proto; 10.43 + /** Number of fields in use. */ 10.44 + private int fieldCount; 10.45 + 10.46 + /** Number of fields available. */ 10.47 + private int fieldMaximum; 10.48 10.49 /** Length of spill in use. */ 10.50 private int spillLength; 10.51 @@ -91,15 +89,15 @@ 10.52 /** 10.53 * Constructor. 10.54 * 10.55 - * @param structure Class the map's {@link AccessorProperty}s apply to. 10.56 - * @param context Context associated with this {@link PropertyMap}. 10.57 - * @param properties A {@link PropertyHashMap} with initial contents. 10.58 + * @param properties A {@link PropertyHashMap} with initial contents. 10.59 + * @param fieldCount Number of fields in use. 10.60 + * @param fieldMaximum Number of fields available. 10.61 */ 10.62 - PropertyMap(final Class<?> structure, final Context context, final PropertyHashMap properties) { 10.63 - this.structure = structure; 10.64 - this.context = context; 10.65 - this.properties = properties; 10.66 - this.hashCode = computeHashCode(); 10.67 + private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum) { 10.68 + this.properties = properties; 10.69 + this.hashCode = computeHashCode(); 10.70 + this.fieldCount = fieldCount; 10.71 + this.fieldMaximum = fieldMaximum; 10.72 10.73 if (Context.DEBUG) { 10.74 count++; 10.75 @@ -107,19 +105,27 @@ 10.76 } 10.77 10.78 /** 10.79 + * Constructor. 10.80 + * 10.81 + * @param properties A {@link PropertyHashMap} with initial contents. 10.82 + */ 10.83 + private PropertyMap(final PropertyHashMap properties) { 10.84 + this(properties, 0, 0); 10.85 + } 10.86 + 10.87 + /** 10.88 * Cloning constructor. 10.89 * 10.90 * @param propertyMap Existing property map. 10.91 * @param properties A {@link PropertyHashMap} with a new set of properties. 10.92 */ 10.93 private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) { 10.94 - this.structure = propertyMap.structure; 10.95 - this.context = propertyMap.context; 10.96 - this.properties = properties; 10.97 - this.flags = propertyMap.getClonedFlags(); 10.98 - this.proto = propertyMap.proto; 10.99 - this.spillLength = propertyMap.spillLength; 10.100 - this.hashCode = computeHashCode(); 10.101 + this.properties = properties; 10.102 + this.flags = propertyMap.getClonedFlags(); 10.103 + this.spillLength = propertyMap.spillLength; 10.104 + this.fieldCount = propertyMap.fieldCount; 10.105 + this.fieldMaximum = propertyMap.fieldMaximum; 10.106 + this.hashCode = computeHashCode(); 10.107 10.108 if (Context.DEBUG) { 10.109 count++; 10.110 @@ -128,6 +134,15 @@ 10.111 } 10.112 10.113 /** 10.114 + * Cloning constructor. 10.115 + * 10.116 + * @param propertyMap Existing property map. 10.117 + */ 10.118 + private PropertyMap(final PropertyMap propertyMap) { 10.119 + this(propertyMap, propertyMap.properties); 10.120 + } 10.121 + 10.122 + /** 10.123 * Duplicates this PropertyMap instance. This is used by nasgen generated 10.124 * prototype and constructor classes. {@link PropertyMap} used for singletons 10.125 * like these (and global instance) are duplicated using this method and used. 10.126 @@ -138,7 +153,7 @@ 10.127 * @return Duplicated {@link PropertyMap}. 10.128 */ 10.129 public PropertyMap duplicate() { 10.130 - return new PropertyMap(this.structure, this.context, this.properties); 10.131 + return new PropertyMap(this.properties); 10.132 } 10.133 10.134 /** 10.135 @@ -146,20 +161,20 @@ 10.136 * 10.137 * @param structure Class the map's {@link AccessorProperty}s apply to. 10.138 * @param properties Collection of initial properties. 10.139 + * @param fieldCount Number of fields in use. 10.140 + * @param fieldMaximum Number of fields available. 10.141 * 10.142 * @return New {@link PropertyMap}. 10.143 */ 10.144 - public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties) { 10.145 - final Context context = Context.fromClass(structure); 10.146 - 10.147 + public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties, final int fieldCount, final int fieldMaximum) { 10.148 // Reduce the number of empty maps in the context. 10.149 if (structure == jdk.nashorn.internal.scripts.JO.class) { 10.150 - return context.emptyMap; 10.151 + return EMPTY_MAP; 10.152 } 10.153 10.154 - PropertyHashMap newProperties = EMPTY_MAP.immutableAdd(properties); 10.155 + PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties); 10.156 10.157 - return new PropertyMap(structure, context, newProperties); 10.158 + return new PropertyMap(newProperties, fieldCount, fieldMaximum); 10.159 } 10.160 10.161 /** 10.162 @@ -170,7 +185,7 @@ 10.163 * @return New {@link PropertyMap}. 10.164 */ 10.165 public static PropertyMap newMap(final Class<?> structure) { 10.166 - return newMap(structure, null); 10.167 + return newMap(structure, null, 0, 0); 10.168 } 10.169 10.170 /** 10.171 @@ -180,7 +195,7 @@ 10.172 * @return New empty {@link PropertyMap}. 10.173 */ 10.174 public static PropertyMap newEmptyMap(final Context context) { 10.175 - return new PropertyMap(jdk.nashorn.internal.scripts.JO.class, context, EMPTY_MAP); 10.176 + return new PropertyMap(EMPTY_HASHMAP); 10.177 } 10.178 10.179 /** 10.180 @@ -195,11 +210,12 @@ 10.181 /** 10.182 * Return a SwitchPoint used to track changes of a property in a prototype. 10.183 * 10.184 - * @param key {@link Property} key. 10.185 + * @param proto Object prototype. 10.186 + * @param key {@link Property} key. 10.187 * 10.188 * @return A shared {@link SwitchPoint} for the property. 10.189 */ 10.190 - public SwitchPoint getProtoGetSwitchPoint(final String key) { 10.191 + public SwitchPoint getProtoGetSwitchPoint(final ScriptObject proto, final String key) { 10.192 if (proto == null) { 10.193 return null; 10.194 } 10.195 @@ -295,6 +311,11 @@ 10.196 final PropertyHashMap newProperties = properties.immutableAdd(property); 10.197 newMap = new PropertyMap(this, newProperties); 10.198 addToHistory(property, newMap); 10.199 + 10.200 + if(!property.isSpill()) { 10.201 + newMap.fieldCount = Math.max(newMap.fieldCount, property.getSlot() + 1); 10.202 + } 10.203 + 10.204 newMap.spillLength += property.getSpillCount(); 10.205 } 10.206 10.207 @@ -355,7 +376,6 @@ 10.208 newProperty instanceof UserAccessorProperty) : "arbitrary replaceProperty attempted"; 10.209 10.210 newMap.flags = getClonedFlags(); 10.211 - newMap.proto = proto; 10.212 10.213 /* 10.214 * spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need 10.215 @@ -411,7 +431,7 @@ 10.216 * @return New map with {@link #NOT_EXTENSIBLE} flag set. 10.217 */ 10.218 PropertyMap preventExtensions() { 10.219 - final PropertyMap newMap = new PropertyMap(this, this.properties); 10.220 + final PropertyMap newMap = new PropertyMap(this); 10.221 newMap.flags |= NOT_EXTENSIBLE; 10.222 return newMap; 10.223 } 10.224 @@ -423,7 +443,7 @@ 10.225 * {@link Property#NOT_CONFIGURABLE} set. 10.226 */ 10.227 PropertyMap seal() { 10.228 - PropertyHashMap newProperties = EMPTY_MAP; 10.229 + PropertyHashMap newProperties = EMPTY_HASHMAP; 10.230 10.231 for (final Property oldProperty : properties.getProperties()) { 10.232 newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE)); 10.233 @@ -442,7 +462,7 @@ 10.234 * {@link Property#NOT_CONFIGURABLE} and {@link Property#NOT_WRITABLE} set. 10.235 */ 10.236 PropertyMap freeze() { 10.237 - PropertyHashMap newProperties = EMPTY_MAP; 10.238 + PropertyHashMap newProperties = EMPTY_HASHMAP; 10.239 10.240 for (Property oldProperty : properties.getProperties()) { 10.241 int propertyFlags = Property.NOT_CONFIGURABLE; 10.242 @@ -578,11 +598,7 @@ 10.243 * @return Computed hash code. 10.244 */ 10.245 private int computeHashCode() { 10.246 - int hash = structure.hashCode(); 10.247 - 10.248 - if (proto != null) { 10.249 - hash ^= proto.hashCode(); 10.250 - } 10.251 + int hash = 0; 10.252 10.253 for (final Property property : getProperties()) { 10.254 hash = hash << 7 ^ hash >> 7; 10.255 @@ -605,9 +621,7 @@ 10.256 10.257 final PropertyMap otherMap = (PropertyMap)other; 10.258 10.259 - if (structure != otherMap.structure || 10.260 - proto != otherMap.proto || 10.261 - properties.size() != otherMap.properties.size()) { 10.262 + if (properties.size() != otherMap.properties.size()) { 10.263 return false; 10.264 } 10.265 10.266 @@ -659,31 +673,6 @@ 10.267 } 10.268 10.269 /** 10.270 - * Return map's {@link Context}. 10.271 - * 10.272 - * @return The {@link Context} where the map originated. 10.273 - */ 10.274 - Context getContext() { 10.275 - return context; 10.276 - } 10.277 - 10.278 - /** 10.279 - * Check if this map is a prototype 10.280 - * 10.281 - * @return {@code true} if is prototype 10.282 - */ 10.283 - public boolean isPrototype() { 10.284 - return (flags & IS_PROTOTYPE) != 0; 10.285 - } 10.286 - 10.287 - /** 10.288 - * Flag this map as having a prototype. 10.289 - */ 10.290 - private void setIsPrototype() { 10.291 - flags |= IS_PROTOTYPE; 10.292 - } 10.293 - 10.294 - /** 10.295 * Check whether a {@link PropertyListener} has been added to this map. 10.296 * 10.297 * @return {@code true} if {@link PropertyListener} exists 10.298 @@ -720,6 +709,22 @@ 10.299 boolean isFrozen() { 10.300 return !isExtensible() && allFrozen(); 10.301 } 10.302 + /** 10.303 + * Get the number of fields allocated for this {@link PropertyMap}. 10.304 + * 10.305 + * @return Number of fields allocated. 10.306 + */ 10.307 + int getFieldCount() { 10.308 + return fieldCount; 10.309 + } 10.310 + /** 10.311 + * Get maximum number of fields available for this {@link PropertyMap}. 10.312 + * 10.313 + * @return Number of fields available. 10.314 + */ 10.315 + int getFieldMaximum() { 10.316 + return fieldMaximum; 10.317 + } 10.318 10.319 /** 10.320 * Get length of spill area associated with this {@link PropertyMap}. 10.321 @@ -731,25 +736,20 @@ 10.322 } 10.323 10.324 /** 10.325 - * Return the prototype of objects associated with this {@link PropertyMap}. 10.326 + * Change the prototype of objects associated with this {@link PropertyMap}. 10.327 * 10.328 - * @return Prototype object. 10.329 - */ 10.330 - ScriptObject getProto() { 10.331 - return proto; 10.332 - } 10.333 - 10.334 - /** 10.335 - * Set the prototype of objects associated with this {@link PropertyMap}. 10.336 - * 10.337 - * @param newProto Prototype object to use. 10.338 + * @param oldProto Current prototype object. 10.339 + * @param newProto New prototype object to replace oldProto. 10.340 * 10.341 * @return New {@link PropertyMap} with prototype changed. 10.342 */ 10.343 - PropertyMap setProto(final ScriptObject newProto) { 10.344 - final ScriptObject oldProto = this.proto; 10.345 - 10.346 - if (oldProto == newProto) { 10.347 + PropertyMap changeProto(final ScriptObject oldProto, final ScriptObject newProto) { 10.348 + if ((oldProto == newProto) || 10.349 + (size() == 0 && 10.350 + oldProto == null && 10.351 + protoGetSwitches == null && 10.352 + history == null && 10.353 + protoHistory == null)) { 10.354 return this; 10.355 } 10.356 10.357 @@ -761,19 +761,10 @@ 10.358 if (Context.DEBUG) { 10.359 incrementSetProtoNewMapCount(); 10.360 } 10.361 - final PropertyMap newMap = new PropertyMap(this, this.properties); 10.362 + 10.363 + final PropertyMap newMap = new PropertyMap(this); 10.364 addToProtoHistory(newProto, newMap); 10.365 10.366 - newMap.proto = newProto; 10.367 - 10.368 - if (oldProto != null && newMap.isListenerAdded()) { 10.369 - oldProto.removePropertyListener(newMap); 10.370 - } 10.371 - 10.372 - if (newProto != null) { 10.373 - newProto.getMap().setIsPrototype(); 10.374 - } 10.375 - 10.376 return newMap; 10.377 } 10.378 10.379 @@ -927,4 +918,3 @@ 10.380 setProtoNewMapCount++; 10.381 } 10.382 } 10.383 -
11.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Tue Apr 30 09:42:13 2013 +0200 11.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Tue Apr 30 10:05:42 2013 -0300 11.3 @@ -104,34 +104,31 @@ 11.4 /** Per ScriptObject flag - is this an arguments object? */ 11.5 public static final int IS_ARGUMENTS = 0b0000_0100; 11.6 11.7 + /** Is this a prototype PropertyMap? */ 11.8 + public static final int IS_PROTOTYPE = 0b0000_1000; 11.9 + 11.10 /** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */ 11.11 public static final int SPILL_RATE = 8; 11.12 11.13 /** Map to property information and accessor functions. Ordered by insertion. */ 11.14 private PropertyMap map; 11.15 11.16 + /** objects proto. */ 11.17 + private ScriptObject proto; 11.18 + 11.19 + /** Context of the object, lazily cached. */ 11.20 + private Context context; 11.21 + 11.22 /** Object flags. */ 11.23 private int flags; 11.24 11.25 - /** Area for properties added to object after instantiation, see {@link SpillProperty} */ 11.26 + /** Area for properties added to object after instantiation, see {@link AccessorProperty} */ 11.27 public Object[] spill; 11.28 11.29 - /** Local embed area position 0 - used for {@link SpillProperty} before {@link ScriptObject#spill} */ 11.30 - public Object embed0; 11.31 - 11.32 - /** Local embed area position 1 - used for {@link SpillProperty} before {@link ScriptObject#spill} */ 11.33 - public Object embed1; 11.34 - 11.35 - /** Local embed area position 2 - used for {@link SpillProperty} before {@link ScriptObject#spill} */ 11.36 - public Object embed2; 11.37 - 11.38 - /** Local embed area position 3 - used for {@link SpillProperty} before {@link ScriptObject#spill} */ 11.39 - public Object embed3; 11.40 - 11.41 /** Indexed array data. */ 11.42 private ArrayData arrayData; 11.43 11.44 - static final MethodHandle SETEMBED = findOwnMH("setEmbed", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, int.class, Object.class, Object.class); 11.45 + static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class); 11.46 static final MethodHandle SETSPILL = findOwnMH("setSpill", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class); 11.47 static final MethodHandle SETSPILLWITHNEW = findOwnMH("setSpillWithNew", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class); 11.48 static final MethodHandle SETSPILLWITHGROW = findOwnMH("setSpillWithGrow", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, int.class, Object.class, Object.class); 11.49 @@ -783,8 +780,8 @@ 11.50 // delete getter and setter function references so that we don't leak 11.51 if (property instanceof UserAccessorProperty) { 11.52 final UserAccessorProperty uc = (UserAccessorProperty) property; 11.53 - setEmbedOrSpill(uc.getGetterSlot(), null); 11.54 - setEmbedOrSpill(uc.getSetterSlot(), null); 11.55 + setSpill(uc.getGetterSlot(), null); 11.56 + setSpill(uc.getSetterSlot(), null); 11.57 } 11.58 return true; 11.59 } 11.60 @@ -809,7 +806,7 @@ 11.61 11.62 int getterSlot = uc.getGetterSlot(); 11.63 // clear the old getter and set the new getter 11.64 - setEmbedOrSpill(getterSlot, getter); 11.65 + setSpill(getterSlot, getter); 11.66 // if getter function is null, flag the slot to be negative (less by 1) 11.67 if (getter == null) { 11.68 getterSlot = -getterSlot - 1; 11.69 @@ -817,7 +814,7 @@ 11.70 11.71 int setterSlot = uc.getSetterSlot(); 11.72 // clear the old setter and set the new setter 11.73 - setEmbedOrSpill(setterSlot, setter); 11.74 + setSpill(setterSlot, setter); 11.75 // if setter function is null, flag the slot to be negative (less by 1) 11.76 if (setter == null) { 11.77 setterSlot = -setterSlot - 1; 11.78 @@ -1056,8 +1053,11 @@ 11.79 * Return the current context from the object's map. 11.80 * @return Current context. 11.81 */ 11.82 - final Context getContext() { 11.83 - return getMap().getContext(); 11.84 + protected final Context getContext() { 11.85 + if (context == null) { 11.86 + context = Context.fromClass(getClass()); 11.87 + } 11.88 + return context; 11.89 } 11.90 11.91 /** 11.92 @@ -1097,44 +1097,30 @@ 11.93 * @return __proto__ object. 11.94 */ 11.95 public final ScriptObject getProto() { 11.96 - return getMap().getProto(); 11.97 - } 11.98 - 11.99 - /** 11.100 - * Check if this is a prototype 11.101 - * @return true if {@link PropertyMap#isPrototype()} is true for this ScriptObject 11.102 - */ 11.103 - public final boolean isPrototype() { 11.104 - return getMap().isPrototype(); 11.105 + return proto; 11.106 } 11.107 11.108 /** 11.109 * Set the __proto__ of an object. 11.110 * @param newProto new __proto__ to set. 11.111 */ 11.112 - public final void setProto(final ScriptObject newProto) { 11.113 - PropertyMap oldMap = getMap(); 11.114 - ScriptObject oldProto = getProto(); 11.115 - 11.116 - while (oldProto != newProto) { 11.117 - final PropertyMap newMap = oldMap.setProto(newProto); 11.118 - 11.119 - if (!compareAndSetMap(oldMap, newMap)) { 11.120 - oldMap = getMap(); 11.121 - oldProto = getProto(); 11.122 - } else { 11.123 - if (isPrototype()) { 11.124 - 11.125 - if (oldProto != null) { 11.126 - oldProto.removePropertyListener(this); 11.127 - } 11.128 - 11.129 - if (newProto != null) { 11.130 - newProto.addPropertyListener(this); 11.131 - } 11.132 - } 11.133 - 11.134 - return; 11.135 + public synchronized final void setProto(final ScriptObject newProto) { 11.136 + final ScriptObject oldProto = proto; 11.137 + map = map.changeProto(oldProto, newProto); 11.138 + 11.139 + if (newProto != null) { 11.140 + newProto.setIsPrototype(); 11.141 + } 11.142 + 11.143 + proto = newProto; 11.144 + 11.145 + if (isPrototype()) { 11.146 + if (oldProto != null) { 11.147 + oldProto.removePropertyListener(this); 11.148 + } 11.149 + 11.150 + if (newProto != null) { 11.151 + newProto.addPropertyListener(this); 11.152 } 11.153 } 11.154 } 11.155 @@ -1327,6 +1313,22 @@ 11.156 } 11.157 11.158 /** 11.159 + * Check if this object is a prototype 11.160 + * 11.161 + * @return {@code true} if is prototype 11.162 + */ 11.163 + public boolean isPrototype() { 11.164 + return (flags & IS_PROTOTYPE) != 0; 11.165 + } 11.166 + 11.167 + /** 11.168 + * Flag this object as having a prototype. 11.169 + */ 11.170 + public void setIsPrototype() { 11.171 + flags |= IS_PROTOTYPE; 11.172 + } 11.173 + 11.174 + /** 11.175 * Get the {@link ArrayData} for this ScriptObject if it is an array 11.176 * @return array data 11.177 */ 11.178 @@ -1719,11 +1721,11 @@ 11.179 if (!property.hasGetterFunction()) { 11.180 methodHandle = bindTo(methodHandle, prototype); 11.181 } 11.182 - return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(name), guard); 11.183 + return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(proto, name), guard); 11.184 } 11.185 11.186 assert !NashornCallSiteDescriptor.isFastScope(desc); 11.187 - return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(name), guard); 11.188 + return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard); 11.189 } 11.190 11.191 private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) { 11.192 @@ -1822,27 +1824,31 @@ 11.193 } 11.194 assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc); 11.195 final PropertyMap myMap = getMap(); 11.196 - return new GuardedInvocation(Lookup.EMPTY_SETTER, myMap.getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(myMap)); 11.197 + return new GuardedInvocation(Lookup.EMPTY_SETTER, myMap.getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(myMap)); 11.198 } 11.199 11.200 @SuppressWarnings("unused") 11.201 - private static void setEmbed(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final MethodHandle setter, final int i, final Object self, final Object value) throws Throwable { 11.202 + private static void setField(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final MethodHandle setter, final Object self, final Object value) throws Throwable { 11.203 final ScriptObject obj = (ScriptObject)self; 11.204 - if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) { 11.205 - obj.useEmbed(i); 11.206 + final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc); 11.207 + if (!obj.isExtensible()) { 11.208 + throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj)); 11.209 + } else if (obj.compareAndSetMap(oldMap, newMap)) { 11.210 setter.invokeExact(self, value); 11.211 + } else { 11.212 + obj.set(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND), value, isStrict); 11.213 } 11.214 } 11.215 11.216 @SuppressWarnings("unused") 11.217 private static void setSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final Object self, final Object value) { 11.218 final ScriptObject obj = (ScriptObject)self; 11.219 - if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) { 11.220 + if (obj.trySetSpill(desc, oldMap, newMap, value)) { 11.221 obj.spill[index] = value; 11.222 } 11.223 } 11.224 11.225 - private boolean trySetEmbedOrSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final Object value) { 11.226 + private boolean trySetSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final Object value) { 11.227 final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc); 11.228 if (!isExtensible() && isStrict) { 11.229 throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(this)); 11.230 @@ -1964,7 +1970,7 @@ 11.231 methodHandle = bindTo(methodHandle, UNDEFINED); 11.232 } 11.233 return new GuardedInvocation(methodHandle, 11.234 - find.isInherited()? getMap().getProtoGetSwitchPoint(NO_SUCH_PROPERTY_NAME) : null, 11.235 + find.isInherited()? getMap().getProtoGetSwitchPoint(proto, NO_SUCH_PROPERTY_NAME) : null, 11.236 getKnownFunctionPropertyGuard(getMap(), find.getGetter(Object.class), find.getOwner(), func)); 11.237 } 11.238 } 11.239 @@ -1995,7 +2001,7 @@ 11.240 } 11.241 11.242 private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) { 11.243 - return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(getMap())); 11.244 + return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(getMap())); 11.245 } 11.246 11.247 private abstract static class ScriptObjectIterator <T extends Object> implements Iterator<T> { 11.248 @@ -2070,36 +2076,39 @@ 11.249 * @return Added property. 11.250 */ 11.251 private Property addSpillProperty(final String key, final int propertyFlags) { 11.252 - int i = findEmbed(); 11.253 - Property spillProperty; 11.254 - 11.255 - if (i >= EMBED_SIZE) { 11.256 - i = getMap().getSpillLength(); 11.257 + int fieldCount = getMap().getFieldCount(); 11.258 + int fieldMaximum = getMap().getFieldMaximum(); 11.259 + Property property; 11.260 + 11.261 + if (fieldCount < fieldMaximum) { 11.262 + property = new AccessorProperty(key, propertyFlags & ~Property.IS_SPILL, getClass(), fieldCount); 11.263 + notifyPropertyAdded(this, property); 11.264 + property = addOwnProperty(property); 11.265 + } else { 11.266 + int i = getMap().getSpillLength(); 11.267 MethodHandle getter = MH.arrayElementGetter(Object[].class); 11.268 MethodHandle setter = MH.arrayElementSetter(Object[].class); 11.269 getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE); 11.270 setter = MH.asType(MH.insertArguments(setter, 1, i), Lookup.SET_OBJECT_TYPE); 11.271 - spillProperty = new SpillProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter); 11.272 - notifyPropertyAdded(this, spillProperty); 11.273 - spillProperty = addOwnProperty(spillProperty); 11.274 - i = spillProperty.getSlot(); 11.275 + property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter); 11.276 + notifyPropertyAdded(this, property); 11.277 + property = addOwnProperty(property); 11.278 + i = property.getSlot(); 11.279 11.280 final int newLength = (i + SPILL_RATE) / SPILL_RATE * SPILL_RATE; 11.281 - final Object[] newSpill = new Object[newLength]; 11.282 - 11.283 - if (spill != null) { 11.284 - System.arraycopy(spill, 0, newSpill, 0, spill.length); 11.285 + 11.286 + if (spill == null || newLength > spill.length) { 11.287 + final Object[] newSpill = new Object[newLength]; 11.288 + 11.289 + if (spill != null) { 11.290 + System.arraycopy(spill, 0, newSpill, 0, spill.length); 11.291 + } 11.292 + 11.293 + spill = newSpill; 11.294 } 11.295 - 11.296 - spill = newSpill; 11.297 - } else { 11.298 - useEmbed(i); 11.299 - spillProperty = new SpillProperty(key, propertyFlags, i, GET_EMBED[i], SET_EMBED[i]); 11.300 - notifyPropertyAdded(this, spillProperty); 11.301 - spillProperty = addOwnProperty(spillProperty); 11.302 } 11.303 11.304 - return spillProperty; 11.305 + return property; 11.306 } 11.307 11.308 11.309 @@ -3159,67 +3168,22 @@ 11.310 } 11.311 11.312 /* 11.313 - * Embed management 11.314 - */ 11.315 - 11.316 - /** Number of embed slots */ 11.317 - public static final int EMBED_SIZE = 4; 11.318 - /** Embed offset */ 11.319 - public static final int EMBED_OFFSET = 32 - EMBED_SIZE; 11.320 - 11.321 - static final MethodHandle[] GET_EMBED; 11.322 - static final MethodHandle[] SET_EMBED; 11.323 - 11.324 - static { 11.325 - GET_EMBED = new MethodHandle[EMBED_SIZE]; 11.326 - SET_EMBED = new MethodHandle[EMBED_SIZE]; 11.327 - 11.328 - for (int i = 0; i < EMBED_SIZE; i++) { 11.329 - final String name = "embed" + i; 11.330 - GET_EMBED[i] = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, name, Object.class), Lookup.GET_OBJECT_TYPE); 11.331 - SET_EMBED[i] = MH.asType(MH.setter(MethodHandles.lookup(), ScriptObject.class, name, Object.class), Lookup.SET_OBJECT_TYPE); 11.332 - } 11.333 - } 11.334 - 11.335 - void useEmbed(final int i) { 11.336 - flags |= 1 << (EMBED_OFFSET + i); 11.337 - } 11.338 - 11.339 - int findEmbed() { 11.340 - final int bits = ~(flags >>> EMBED_OFFSET); 11.341 - final int least = bits ^ -bits; 11.342 - final int index = Integer.numberOfTrailingZeros(least) - 1; 11.343 - 11.344 - return index; 11.345 - } 11.346 - 11.347 - /* 11.348 * Make a new UserAccessorProperty property. getter and setter functions are stored in 11.349 * this ScriptObject and slot values are used in property object. 11.350 */ 11.351 private UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) { 11.352 int oldSpillLength = getMap().getSpillLength(); 11.353 11.354 - int getterSlot = findEmbed(); 11.355 - if (getterSlot >= EMBED_SIZE) { 11.356 - getterSlot = oldSpillLength + EMBED_SIZE; 11.357 - ++oldSpillLength; 11.358 - } else { 11.359 - useEmbed(getterSlot); 11.360 - } 11.361 - setEmbedOrSpill(getterSlot, getter); 11.362 + int getterSlot = oldSpillLength++; 11.363 + setSpill(getterSlot, getter); 11.364 // if getter function is null, flag the slot to be negative (less by 1) 11.365 if (getter == null) { 11.366 getterSlot = -getterSlot - 1; 11.367 } 11.368 11.369 - int setterSlot = findEmbed(); 11.370 - if (setterSlot >= EMBED_SIZE) { 11.371 - setterSlot = oldSpillLength + EMBED_SIZE; 11.372 - } else { 11.373 - useEmbed(setterSlot); 11.374 - } 11.375 - setEmbedOrSpill(setterSlot, setter); 11.376 + int setterSlot = oldSpillLength++; 11.377 + 11.378 + setSpill(setterSlot, setter); 11.379 // if setter function is null, flag the slot to be negative (less by 1) 11.380 if (setter == null) { 11.381 setterSlot = -setterSlot - 1; 11.382 @@ -3228,56 +3192,28 @@ 11.383 return new UserAccessorProperty(key, propertyFlags, getterSlot, setterSlot); 11.384 } 11.385 11.386 - private void setEmbedOrSpill(final int slot, final Object value) { 11.387 - switch (slot) { 11.388 - case 0: 11.389 - embed0 = value; 11.390 - break; 11.391 - case 1: 11.392 - embed1 = value; 11.393 - break; 11.394 - case 2: 11.395 - embed2 = value; 11.396 - break; 11.397 - case 3: 11.398 - embed3 = value; 11.399 - break; 11.400 - default: 11.401 - if (slot >= 0) { 11.402 - final int index = (slot - EMBED_SIZE); 11.403 - if (spill == null) { 11.404 - // create new spill. 11.405 - spill = new Object[Math.max(index + 1, SPILL_RATE)]; 11.406 - } else if (index >= spill.length) { 11.407 - // grow spill as needed 11.408 - final Object[] newSpill = new Object[index + 1]; 11.409 - System.arraycopy(spill, 0, newSpill, 0, spill.length); 11.410 - spill = newSpill; 11.411 - } 11.412 - 11.413 - spill[index] = value; 11.414 + private void setSpill(final int slot, final Object value) { 11.415 + if (slot >= 0) { 11.416 + final int index = slot; 11.417 + if (spill == null) { 11.418 + // create new spill. 11.419 + spill = new Object[Math.max(index + 1, SPILL_RATE)]; 11.420 + } else if (index >= spill.length) { 11.421 + // grow spill as needed 11.422 + final Object[] newSpill = new Object[index + 1]; 11.423 + System.arraycopy(spill, 0, newSpill, 0, spill.length); 11.424 + spill = newSpill; 11.425 } 11.426 - break; 11.427 + 11.428 + spill[index] = value; 11.429 } 11.430 } 11.431 11.432 - // user accessors are either stored in embed fields or spill array slots 11.433 - // get the accessor value using slot number. Note that slot is either embed 11.434 - // field number or (spill array index + embedSize). 11.435 - Object getEmbedOrSpill(final int slot) { 11.436 - switch (slot) { 11.437 - case 0: 11.438 - return embed0; 11.439 - case 1: 11.440 - return embed1; 11.441 - case 2: 11.442 - return embed2; 11.443 - case 3: 11.444 - return embed3; 11.445 - default: 11.446 - final int index = (slot - EMBED_SIZE); 11.447 - return (index < 0 || (index >= spill.length)) ? null : spill[index]; 11.448 - } 11.449 + // user accessors are either stored in spill array slots 11.450 + // get the accessor value using slot number. Note that slot is spill array index. 11.451 + Object getSpill(final int slot) { 11.452 + final int index = slot; 11.453 + return (index < 0 || (index >= spill.length)) ? null : spill[index]; 11.454 } 11.455 11.456 // User defined getter and setter are always called by "dyn:call". Note that the user 11.457 @@ -3287,7 +3223,7 @@ 11.458 @SuppressWarnings("unused") 11.459 private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) { 11.460 final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; 11.461 - final Object func = container.getEmbedOrSpill(slot); 11.462 + final Object func = container.getSpill(slot); 11.463 11.464 if (func instanceof ScriptFunction) { 11.465 try { 11.466 @@ -3305,7 +3241,7 @@ 11.467 @SuppressWarnings("unused") 11.468 private static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) { 11.469 final ScriptObject container = (proto != null) ? proto : (ScriptObject)self; 11.470 - final Object func = container.getEmbedOrSpill(slot); 11.471 + final Object func = container.getSpill(slot); 11.472 11.473 if (func instanceof ScriptFunction) { 11.474 try {
12.1 --- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Tue Apr 30 09:42:13 2013 +0200 12.2 +++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Tue Apr 30 10:05:42 2013 -0300 12.3 @@ -166,18 +166,20 @@ 12.4 } 12.5 12.6 private SetMethod createNewPropertySetter() { 12.7 - final int nextEmbed = sobj.findEmbed(); 12.8 - final SetMethod sm; 12.9 - if (nextEmbed >= ScriptObject.EMBED_SIZE) { 12.10 - sm = createNewSpillPropertySetter(); 12.11 - } else { 12.12 - sm = createNewEmbedPropertySetter(nextEmbed); 12.13 - } 12.14 - 12.15 + final SetMethod sm = map.getFieldCount() < map.getFieldMaximum() ? createNewFieldSetter() : createNewSpillPropertySetter(); 12.16 sobj.notifyPropertyAdded(sobj, sm.property); 12.17 return sm; 12.18 } 12.19 12.20 + private SetMethod createNewFieldSetter() { 12.21 + final PropertyMap oldMap = getMap(); 12.22 + final Property property = new AccessorProperty(getName(), 0, sobj.getClass(), oldMap.getFieldCount()); 12.23 + final PropertyMap newMap = oldMap.addProperty(property); 12.24 + MethodHandle setter = MH.insertArguments(ScriptObject.SETFIELD, 0, desc, oldMap, newMap, property.getSetter(Object.class, newMap)); 12.25 + 12.26 + return new SetMethod(MH.asType(setter, Lookup.SET_OBJECT_TYPE), property); 12.27 + } 12.28 + 12.29 private SetMethod createNewSpillPropertySetter() { 12.30 final int nextSpill = getMap().getSpillLength(); 12.31 12.32 @@ -189,7 +191,7 @@ 12.33 final MethodHandle getter = MH.asType(MH.insertArguments(MH.arrayElementGetter(Object[].class), 1, nextSpill), Lookup.GET_OBJECT_TYPE); 12.34 final MethodHandle setter = MH.asType(MH.insertArguments(MH.arrayElementSetter(Object[].class), 1, nextSpill), Lookup.SET_OBJECT_TYPE); 12.35 12.36 - return new SpillProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter); 12.37 + return new AccessorProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter); 12.38 } 12.39 12.40 private MethodHandle createSpillMethodHandle(final int nextSpill, Property property) { 12.41 @@ -207,14 +209,6 @@ 12.42 } 12.43 } 12.44 12.45 - private SetMethod createNewEmbedPropertySetter(final int nextEmbed) { 12.46 - sobj.useEmbed(nextEmbed); 12.47 - final Property property = new SpillProperty(getName(), 0, nextEmbed, ScriptObject.GET_EMBED[nextEmbed], ScriptObject.SET_EMBED[nextEmbed]); 12.48 - //TODO specfields 12.49 - final MethodHandle methodHandle = MH.insertArguments(ScriptObject.SETEMBED, 0, desc, getMap(), getNewMap(property), property.getSetter(Object.class, getMap()), nextEmbed); 12.50 - return new SetMethod(methodHandle, property); 12.51 - } 12.52 - 12.53 private PropertyMap getNewMap(Property property) { 12.54 return getMap().addProperty(property); 12.55 }
13.1 --- a/src/jdk/nashorn/internal/runtime/SpillProperty.java Tue Apr 30 09:42:13 2013 +0200 13.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 13.3 @@ -1,85 +0,0 @@ 13.4 -/* 13.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 13.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.7 - * 13.8 - * This code is free software; you can redistribute it and/or modify it 13.9 - * under the terms of the GNU General Public License version 2 only, as 13.10 - * published by the Free Software Foundation. Oracle designates this 13.11 - * particular file as subject to the "Classpath" exception as provided 13.12 - * by Oracle in the LICENSE file that accompanied this code. 13.13 - * 13.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 13.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13.17 - * version 2 for more details (a copy is included in the LICENSE file that 13.18 - * accompanied this code). 13.19 - * 13.20 - * You should have received a copy of the GNU General Public License version 13.21 - * 2 along with this work; if not, write to the Free Software Foundation, 13.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 13.23 - * 13.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 13.25 - * or visit www.oracle.com if you need additional information or have any 13.26 - * questions. 13.27 - */ 13.28 - 13.29 -package jdk.nashorn.internal.runtime; 13.30 - 13.31 -import static jdk.nashorn.internal.lookup.Lookup.MH; 13.32 - 13.33 -import java.lang.invoke.MethodHandle; 13.34 -import java.lang.invoke.MethodHandles; 13.35 -import jdk.nashorn.internal.lookup.Lookup; 13.36 - 13.37 -/** 13.38 - * The SpillProperty is a subclass of AccessorProperties. Anything not in the initial property map 13.39 - * will end up in the embed fields of the ScriptObject or in the Spill, which currently is a growing 13.40 - * Object only array in ScriptObject 13.41 - * 13.42 - * @see AccessorProperty 13.43 - * @see ScriptObject 13.44 - */ 13.45 -public final class SpillProperty extends AccessorProperty { 13.46 - private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE); 13.47 - 13.48 - /** 13.49 - * Constructor 13.50 - * 13.51 - * @param key property key 13.52 - * @param flags property flags 13.53 - * @param slot property slot/index 13.54 - * @param getter getter for property 13.55 - * @param setter setter for property, or null if not configurable and writable 13.56 - */ 13.57 - public SpillProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) { 13.58 - super(key, flags, slot, getter, setter); 13.59 - } 13.60 - 13.61 - private SpillProperty(final SpillProperty property) { 13.62 - super(property); 13.63 - } 13.64 - 13.65 - @Override 13.66 - protected Property copy() { 13.67 - return new SpillProperty(this); 13.68 - } 13.69 - 13.70 - @Override 13.71 - public MethodHandle getGetter(final Class<?> type) { 13.72 - if (isSpill()) { 13.73 - return MH.filterArguments(super.getGetter(type), 0, SPILLGETTER); 13.74 - } 13.75 - 13.76 - return super.getGetter(type); 13.77 - } 13.78 - 13.79 - @Override 13.80 - public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) { 13.81 - if (isSpill()) { 13.82 - return MH.filterArguments(super.getSetter(type, currentMap), 0, SPILLGETTER); 13.83 - } 13.84 - 13.85 - return super.getSetter(type, currentMap); 13.86 - } 13.87 - 13.88 -}
14.1 --- a/src/jdk/nashorn/internal/runtime/StructureLoader.java Tue Apr 30 09:42:13 2013 +0200 14.2 +++ b/src/jdk/nashorn/internal/runtime/StructureLoader.java Tue Apr 30 10:05:42 2013 -0300 14.3 @@ -110,8 +110,7 @@ 14.4 @Override 14.5 protected Class<?> findClass(final String name) throws ClassNotFoundException { 14.6 if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) { 14.7 - final int start = name.indexOf(JS_OBJECT_PREFIX.symbolName()) + JS_OBJECT_PREFIX.symbolName().length(); 14.8 - return generateClass(name, name.substring(start, name.length())); 14.9 + return generateClass(name, name.substring(JS_OBJECT_PREFIX_EXTERNAL.length())); 14.10 } 14.11 return super.findClass(name); 14.12 }
15.1 --- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Tue Apr 30 09:42:13 2013 +0200 15.2 +++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java Tue Apr 30 10:05:42 2013 -0300 15.3 @@ -67,7 +67,6 @@ 15.4 15.5 private UserAccessorProperty(final UserAccessorProperty property) { 15.6 super(property); 15.7 - 15.8 this.getterSlot = property.getterSlot; 15.9 this.setterSlot = property.setterSlot; 15.10 } 15.11 @@ -115,10 +114,10 @@ 15.12 public int getSpillCount() { 15.13 // calculate how many spill array slots used by this propery. 15.14 int count = 0; 15.15 - if (getGetterSlot() >= ScriptObject.EMBED_SIZE) { 15.16 + if (getGetterSlot() >= 0) { 15.17 count++; 15.18 } 15.19 - if (getSetterSlot() >= ScriptObject.EMBED_SIZE) { 15.20 + if (getSetterSlot() >= 0) { 15.21 count++; 15.22 } 15.23 return count; 15.24 @@ -141,7 +140,7 @@ 15.25 15.26 @Override 15.27 public ScriptFunction getGetterFunction(final ScriptObject obj) { 15.28 - final Object value = obj.getEmbedOrSpill(getterSlot); 15.29 + final Object value = obj.getSpill(getterSlot); 15.30 return (value instanceof ScriptFunction) ? (ScriptFunction) value : null; 15.31 } 15.32 15.33 @@ -152,7 +151,7 @@ 15.34 15.35 @Override 15.36 public ScriptFunction getSetterFunction(final ScriptObject obj) { 15.37 - final Object value = obj.getEmbedOrSpill(setterSlot); 15.38 + final Object value = obj.getSpill(setterSlot); 15.39 return (value instanceof ScriptFunction) ? (ScriptFunction) value : null; 15.40 } 15.41
16.1 --- a/src/jdk/nashorn/internal/scripts/JO.java Tue Apr 30 09:42:13 2013 +0200 16.2 +++ b/src/jdk/nashorn/internal/scripts/JO.java Tue Apr 30 10:05:42 2013 -0300 16.3 @@ -32,12 +32,11 @@ 16.4 * Empty object class. 16.5 */ 16.6 public class JO extends ScriptObject { 16.7 - 16.8 /** 16.9 * Constructor 16.10 */ 16.11 public JO() { 16.12 - super(); 16.13 + super(PropertyMap.newMap(JO.class)); 16.14 } 16.15 16.16 /**
17.1 --- a/src/jdk/nashorn/tools/Shell.java Tue Apr 30 09:42:13 2013 +0200 17.2 +++ b/src/jdk/nashorn/tools/Shell.java Tue Apr 30 10:05:42 2013 -0300 17.3 @@ -343,7 +343,7 @@ 17.4 * @return error code 17.5 * @throws IOException when any script file read results in I/O error 17.6 */ 17.7 - private int runFXScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException { 17.8 + private static int runFXScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException { 17.9 final ScriptObject oldGlobal = Context.getGlobal(); 17.10 final boolean globalChanged = (oldGlobal != global); 17.11 try {