changeset 79:8742be332c8a

8006222: Move slot from SpillProperty to Property Reviewed-by: hannesw, lagergren Contributed-by: james.laskey@oracle.com
author jlaskey
date Fri, 08 Feb 2013 09:19:38 -0400
parents d5130a5803d1
children 5ead5333fa59
files src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java src/jdk/nashorn/internal/codegen/objects/MapCreator.java src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java src/jdk/nashorn/internal/runtime/AccessorProperty.java src/jdk/nashorn/internal/runtime/FindProperty.java src/jdk/nashorn/internal/runtime/Property.java src/jdk/nashorn/internal/runtime/PropertyMap.java src/jdk/nashorn/internal/runtime/ScriptObject.java src/jdk/nashorn/internal/runtime/SpillProperty.java src/jdk/nashorn/internal/runtime/UserAccessorProperty.java src/jdk/nashorn/internal/runtime/linker/Lookup.java
diffstat 12 files changed, 187 insertions(+), 289 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/codegen/objects/FieldObjectCreator.java	Fri Feb 08 09:19:38 2013 -0400
@@ -75,7 +75,7 @@
      * @param symbols      symbols for fields in object
      * @param values       values (or null where no value) to be written to the fields
      * @param isScope      is this a scope object
-     * @param hasArguments does the created object have an "arguments" object
+     * @param hasArguments does the created object have an "arguments" property
      */
     public FieldObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final List<T> values, final boolean isScope, final boolean hasArguments) {
         super(codegen, keys, symbols, isScope, hasArguments);
@@ -106,7 +106,7 @@
         if (isScope()) {
             loadScope(method);
 
-            if (isVarArg()) {
+            if (hasArguments()) {
                 method.loadArguments();
                 method.invoke(constructorNoLookup(getClassName(), PropertyMap.class, ScriptObject.class, ARGUMENTS.type()));
             } else {
--- a/src/jdk/nashorn/internal/codegen/objects/MapCreator.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/codegen/objects/MapCreator.java	Fri Feb 08 09:19:38 2013 -0400
@@ -25,20 +25,12 @@
 
 package jdk.nashorn.internal.codegen.objects;
 
-import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
-import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.PRIMITIVE_TYPE;
-import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.List;
-import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.runtime.AccessorProperty;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
 
 /**
@@ -72,11 +64,11 @@
     /**
      * Constructs a property map based on a set of fields.
      *
-     * @param isVarArg is this a vararg object map
+     * @param hasArguments does the created object have an "arguments" property
      *
      * @return New map populated with accessor properties.
      */
-    public PropertyMap makeMap(final boolean isVarArg) {
+    public PropertyMap makeMap(final boolean hasArguments) {
         final List<Property> properties = new ArrayList<>();
 
         assert keys != null;
@@ -86,63 +78,31 @@
             final Symbol symbol = symbols[i];
 
             if (symbol != null && !ArrayIndex.isIndexKey(key)) {
-                final Property property = initHandle(key, symbol.getFieldIndex(), symbol, isVarArg);
-                properties.add(property);
+                properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), structure, symbol.getFieldIndex()));
             }
         }
 
         return PropertyMap.newMap(structure, properties);
     }
 
-    private Property initHandle(final String key, final int fieldIndex, final Symbol symbol, final boolean isVarArg) {
-        assert symbol != null;
-        final boolean isParam = symbol.isParam();
-
-        final String fieldNameObject    = ObjectClassGenerator.getFieldName(fieldIndex, Type.OBJECT);
-        final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(fieldIndex, ObjectClassGenerator.PRIMITIVE_TYPE);
-
-        MethodHandle primitiveGetter = null;
-        MethodHandle primitiveSetter = null;
-        MethodHandle objectGetter;
-        MethodHandle objectSetter;
-
-        final MethodHandles.Lookup lookup = MethodHandles.lookup();
-
-        if (isParam && isVarArg) {
-            final MethodHandle arguments   = MH.getter(MethodHandles.lookup(), structure, "arguments", Object.class);
-            final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class));
-            objectGetter = MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, fieldIndex);
-            objectSetter = MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, fieldIndex);
-        } else {
-            objectGetter = MH.getter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
-            objectSetter = MH.setter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
-            if (!OBJECT_FIELDS_ONLY) {
-                primitiveGetter = MH.getter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
-                primitiveSetter = MH.setter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
-            }
-        }
-
-        return new AccessorProperty(key, getPropertyFlags(symbol, isVarArg), objectGetter, objectSetter, primitiveGetter, primitiveSetter);
-    }
-
     /**
      * Compute property flags given local state of a field. Maybe be overridden and extended,
      * as is the case in {@link ObjectMapCreator}
      *
-     * @param symbol   symbol to check
-     * @param isVarArg is this a vararg
+     * @param symbol       symbol to check
+     * @param hasArguments does the created object have an "arguments" property
      *
      * @return flags to use for fields
      */
-    protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) {
-        final boolean isParam = symbol.isParam();
+    protected int getPropertyFlags(final Symbol symbol, final boolean hasArguments) {
         int flags = 0;
 
-        if (isParam || isVarArg) {
-            flags |= Property.IS_ALWAYS_OBJECT;
-            if (isParam) {
-                flags |= Property.IS_PARAMETER;
-            }
+        if (symbol.isParam()) {
+            flags |= Property.IS_ALWAYS_OBJECT | Property.IS_PARAMETER;
+        }
+
+        if (hasArguments) {
+            flags |= Property.IS_ALWAYS_OBJECT | Property.HAS_ARGUMENTS;
         }
 
         if (symbol.isScope()) {
--- a/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/codegen/objects/ObjectCreator.java	Fri Feb 08 09:19:38 2013 -0400
@@ -52,7 +52,7 @@
     protected final CodeGenerator codegen;
 
     private   final boolean       isScope;
-    private   final boolean       isVarArg;
+    private   final boolean       hasArguments;
     private         int           fieldCount;
     private         int           paramCount;
     private         String        fieldObjectClassName;
@@ -62,19 +62,19 @@
     /**
      * Constructor
      *
-     * @param codegen  the code generator
-     * @param keys     the keys
-     * @param symbols  the symbols corresponding to keys, same index
-     * @param isScope  is this object scope
-     * @param isVarArg is this object var arg
+     * @param codegen      the code generator
+     * @param keys         the keys
+     * @param symbols      the symbols corresponding to keys, same index
+     * @param isScope      is this object scope
+     * @param hasArguments does the created object have an "arguments" property
      */
-    protected ObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final boolean isScope, final boolean isVarArg) {
+    protected ObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final boolean isScope, final boolean hasArguments) {
         this.codegen       = codegen;
         this.compileUnit   = codegen.getCurrentCompileUnit();
         this.keys          = keys;
         this.symbols       = symbols;
         this.isScope       = isScope;
-        this.isVarArg      = isVarArg;
+        this.hasArguments  = hasArguments;
 
         countFields();
         findClass();
@@ -86,7 +86,7 @@
     private void countFields() {
         for (final Symbol symbol : this.symbols) {
             if (symbol != null) {
-                if (isVarArg() && symbol.isParam()) {
+                if (hasArguments() && symbol.isParam()) {
                     symbol.setFieldIndex(paramCount++);
                 } else {
                     symbol.setFieldIndex(fieldCount++);
@@ -133,7 +133,7 @@
         if (keys.isEmpty()) { //empty map
             propertyMap = PropertyMap.newMap(fieldObjectClass);
         } else {
-            propertyMap = newMapCreator(fieldObjectClass).makeMap(isVarArg());
+            propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments());
         }
         return propertyMap;
     }
@@ -167,10 +167,10 @@
     }
 
     /**
-     * Is this a vararg object
-     * @return true if vararg
+     * Does the created object have an "arguments" property
+     * @return true if has an "arguments" property
      */
-    protected boolean isVarArg() {
-        return isVarArg;
+    protected boolean hasArguments() {
+        return hasArguments;
     }
 }
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Fri Feb 08 09:19:38 2013 -0400
@@ -139,7 +139,7 @@
 
     // add a new property that throws TypeError on get as well as set
     static synchronized PropertyMap newThrowerProperty(final PropertyMap map, final String name, final int flags) {
-        return map.newProperty(name, flags, Lookup.TYPE_ERROR_THROWER_GETTER, Lookup.TYPE_ERROR_THROWER_SETTER);
+        return map.newProperty(name, flags, -1, Lookup.TYPE_ERROR_THROWER_GETTER, Lookup.TYPE_ERROR_THROWER_SETTER);
     }
 
     // property map for strict mode functions - lazily initialized
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Fri Feb 08 09:19:38 2013 -0400
@@ -29,6 +29,7 @@
 import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.DEBUG_FIELDS;
 import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.LOG;
 import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
+import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.PRIMITIVE_TYPE;
 import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.createGetter;
 import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.createGuardBoxedPrimitiveSetter;
 import static jdk.nashorn.internal.codegen.objects.ObjectClassGenerator.createSetter;
@@ -41,6 +42,7 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import jdk.nashorn.internal.codegen.objects.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.linker.Lookup;
 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
@@ -90,49 +92,6 @@
     }
 
     /**
-     * Constructor
-     *
-     * primitiveGetter and setter are only used in dual fields mode. Setting them to null also
-     * works in dual field mode, it only means that the property never has a primitive
-     * representation
-     *
-     * @param key              property key
-     * @param flags            property flags
-     * @param objectGetter     seed getter for object field
-     * @param objectSetter     seed setter for object field
-     * @param primitiveGetter  seed getter for primitive field (in dual field mode)
-     * @param primitiveSetter  seed setter for primitive field (in dual field mode)
-     */
-    public AccessorProperty(final String key, final int flags, final MethodHandle objectGetter, final MethodHandle objectSetter, final MethodHandle primitiveGetter, final MethodHandle primitiveSetter) {
-        super(key, flags);
-
-        this.objectGetter    = objectGetter;
-        this.objectSetter    = objectSetter;
-        this.primitiveGetter = primitiveGetter;
-        this.primitiveSetter = primitiveSetter;
-
-        Class<?> initialType = null;
-
-        if (OBJECT_FIELDS_ONLY || isAlwaysObject()) {
-            initialType = Object.class;
-        } else {
-            if (!canBePrimitive()) {
-                info(key + " cannot be primitive");
-                initialType = Object.class;
-            } else {
-                info(key + " CAN be primitive");
-                if (!canBeUndefined()) {
-                    info(key + " is always defined");
-                    initialType = int.class; //double works too for less type invalidation, but this requires experimentation, e.g. var x = 17; x += 2 will turn it into double now because of lack of range analysis
-                }
-            }
-        }
-
-        // is always object means "is never initialized to undefined, and always of object type
-        setCurrentType(initialType);
-    }
-
-    /**
      * Delegate constructor. This is used when adding properties to the Global scope, which
      * is necessary for outermost levels in a script (the ScriptObject is represented by
      * a JO$-prefixed ScriptObject class, but the properties need to be in the Global scope
@@ -161,11 +120,12 @@
      *
      * @param key    the property key
      * @param flags  the property flags
+     * @param slot   the property field number or spill slot
      * @param getter the property getter
      * @param setter the property setter or null if non writable, non configurable
      */
-    public AccessorProperty(final String key, final int flags, final MethodHandle getter, final MethodHandle setter) {
-        super(key, flags);
+    public AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
+        super(key, flags, slot);
 
         // we don't need to prep the setters these will never be invalidated as this is a nasgen
         // or known type getter/setter. No invalidations will take place
@@ -193,6 +153,66 @@
     }
 
     /**
+     * Constructor for dual field AccessorPropertys.
+     *
+     * @param key              property key
+     * @param flags            property flags
+     * @param structure        structure for objects associated with this property
+     * @param slot             property field number or spill slot
+     */
+    public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot) {
+        super(key, flags, slot);
+
+        /*
+         *
+         * primitiveGetter and primitiveSetter are only used in dual fields mode. Setting them to null also
+         * works in dual field mode, it only means that the property never has a primitive
+         * representation.
+         */
+        primitiveGetter = null;
+        primitiveSetter = null;
+
+        final MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+        if (isParameter() && hasArguments()) {
+            final MethodHandle arguments   = MH.getter(MethodHandles.lookup(), structure, "arguments", Object.class);
+            final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class));
+
+            objectGetter = MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot);
+            objectSetter = MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot);
+        } else {
+            final String fieldNameObject    = ObjectClassGenerator.getFieldName(slot, Type.OBJECT);
+            final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(slot, ObjectClassGenerator.PRIMITIVE_TYPE);
+
+            objectGetter = MH.getter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
+            objectSetter = MH.setter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
+
+            if (!OBJECT_FIELDS_ONLY) {
+                primitiveGetter = MH.getter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
+                primitiveSetter = MH.setter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
+            }
+        }
+
+        Class<?> initialType = null;
+
+        if (OBJECT_FIELDS_ONLY || isAlwaysObject()) {
+            initialType = Object.class;
+        } else if (!canBePrimitive()) {
+            info(key + " cannot be primitive");
+            initialType = Object.class;
+        } else {
+            info(key + " CAN be primitive");
+            if (!canBeUndefined()) {
+                info(key + " is always defined");
+                initialType = int.class; //double works too for less type invalidation, but this requires experimentation, e.g. var x = 17; x += 2 will turn it into double now because of lack of range analysis
+            }
+        }
+
+        // is always object means "is never initialized to undefined, and always of object type
+        setCurrentType(initialType);
+    }
+
+    /**
      * Copy constructor
      *
      * @param property  source property
--- a/src/jdk/nashorn/internal/runtime/FindProperty.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/runtime/FindProperty.java	Fri Feb 08 09:19:38 2013 -0400
@@ -34,53 +34,26 @@
  * This class represents the result from a find property search.
  */
 public final class FindProperty {
+    /** Object where search began. */
     private final ScriptObject self;
+    ;
+    /** Object where search finish. */
     private final ScriptObject prototype;
-    private final PropertyMap  map;
+
+    /** Found property. */
     private final Property     property;
-    private final int          depth;
-    private final boolean      isScope;
 
     /**
      * Constructor
      *
-     * @param self      script object where property was found
+     * @param self      script object where search began
      * @param prototype prototype where property was found, may be {@code self} if not inherited
-     * @param map       property map for script object
      * @param property  property that was search result
-     * @param depth     depth walked in property chain to find result
      */
-    public FindProperty(final ScriptObject self, final ScriptObject prototype, final PropertyMap map, final Property property, final int depth) {
+    public FindProperty(final ScriptObject self, final ScriptObject prototype, final Property property) {
         this.self      = self;
         this.prototype = prototype;
-        this.map       = map;
         this.property  = property;
-        this.depth     = depth;
-        this.isScope   = prototype.isScope();
-    }
-
-    /**
-     * Get ScriptObject for search
-     * @return script object
-     */
-    public ScriptObject getSelf() {
-        return self;
-    }
-
-    /**
-     * Get search depth
-     * @return depth
-     */
-    public int getDepth() {
-        return depth;
-    }
-
-    /**
-     * Get flags for property that was found
-     * @return property flags for property returned in {@link FindProperty#getProperty()}
-     */
-    public int getFlags() {
-        return property.getFlags();
     }
 
     /**
@@ -102,20 +75,33 @@
     }
 
     /**
-     * In certain properties, such as {@link UserAccessorProperty}, getter and setter functions
-     * are present. This function gets the getter function as a {@code ScriptFunction}
-     * @return getter function, or null if not present
+     * Ask for a setter that sets the given type. The type has nothing to do with the
+     * internal representation of the property. It may be an Object (boxing primitives) or
+     * a primitive (primitive fields with -Dnashorn.fields.dual=true)
+     * @see ObjectClassGenerator
+     *
+     * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature
+     * @param strict are we in strict mode
+     *
+     * @return method handle for the getter
      */
-    public ScriptFunction getGetterFunction() {
-        return property.getGetterFunction(getOwner());
+    public MethodHandle getSetter(final Class<?> type, final boolean strict) {
+        MethodHandle setter = property.getSetter(type, getOwner().getMap());
+        if (property instanceof UserAccessorProperty) {
+            final UserAccessorProperty uc = (UserAccessorProperty) property;
+            setter = MH.insertArguments(setter, 0, (isInherited() ? getOwner() : null),
+                    uc.getSetterSlot(), strict? property.getKey() : null);
+        }
+
+        return setter;
     }
 
     /**
-     * Return the property map where the property was found
-     * @return property map
+     * Return the {@code ScriptObject} owning of the property:  this means the prototype.
+     * @return owner of property
      */
-    public PropertyMap getMap() {
-        return map;
+    public ScriptObject getOwner() {
+        return prototype;
     }
 
     /**
@@ -148,62 +134,8 @@
      * @return true if on scope
      */
     public boolean isScope() {
-        return isScope;
-    }
-
-    /**
-     * Return the {@code ScriptObject} owning of the property:  this means the prototype.
-     * @return owner of property
-     */
-    public ScriptObject getOwner() {
-        return prototype;
+        return prototype.isScope();
     }
 
-    /**
-     * Ask for a setter that sets the given type. The type has nothing to do with the
-     * internal representation of the property. It may be an Object (boxing primitives) or
-     * a primitive (primitive fields with -Dnashorn.fields.dual=true)
-     * @see ObjectClassGenerator
-     *
-     * @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature
-     * @param strict are we in strict mode
-     *
-     * @return method handle for the getter
-     */
-    public MethodHandle getSetter(final Class<?> type, final boolean strict) {
-        MethodHandle setter = property.getSetter(type, getOwner().getMap());
-        if (property instanceof UserAccessorProperty) {
-            final UserAccessorProperty uc = (UserAccessorProperty) property;
-            setter = MH.insertArguments(setter, 0, (isInherited() ? getOwner() : null),
-                    uc.getSetterSlot(), strict? property.getKey() : null);
-        }
-
-        return setter;
-    }
-
-    /**
-     * In certain properties, such as {@link UserAccessorProperty}, getter and setter functions
-     * are present. This function gets the setter function as a {@code ScriptFunction}
-     * @return setter function, or null if not present
-     */
-    public ScriptFunction getSetterFunction() {
-        return property.getSetterFunction(getOwner());
-    }
-
-    /**
-     * Check if the property found is configurable
-     * @return true if configurable
-     */
-    public boolean isConfigurable() {
-        return property.isConfigurable();
-    }
-
-    /**
-     * Check if the property found is writable
-     * @return true if writable
-     */
-    public boolean isWritable() {
-        return property.isWritable();
-    }
 }
 
--- a/src/jdk/nashorn/internal/runtime/Property.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/runtime/Property.java	Fri Feb 08 09:19:38 2013 -0400
@@ -67,17 +67,20 @@
     /** Is this a spill property? See {@link SpillProperty} */
     public static final int IS_SPILL         = 0b0000_0001_0000;
 
-    /** Is this a function parameter ? */
+    /** Is this a function parameter? */
     public static final int IS_PARAMETER     = 0b0000_0010_0000;
 
+    /** Is parameter accessed thru arguments? */
+    public static final int HAS_ARGUMENTS    = 0b0000_0100_0000;
+
     /** Is this property always represented as an Object? See {@link ObjectClassGenerator} and dual fields flag. */
-    public static final int IS_ALWAYS_OBJECT = 0b0000_0100_0000;
+    public static final int IS_ALWAYS_OBJECT = 0b0000_1000_0000;
 
     /** Can this property be primitive? */
-    public static final int CAN_BE_PRIMITIVE = 0b0000_1000_0000;
+    public static final int CAN_BE_PRIMITIVE = 0b0001_0000_0000;
 
     /** Can this property be undefined? */
-    public static final int CAN_BE_UNDEFINED = 0b0001_0000_0000;
+    public static final int CAN_BE_UNDEFINED = 0b0010_0000_0000;
 
     /** Property key. */
     private final String key;
@@ -85,15 +88,21 @@
     /** Property flags. */
     protected int flags;
 
+    /** Property field number or spill slot */
+    private final int slot;
+
     /**
      * Constructor
      *
      * @param key   property key
      * @param flags property flags
+     * @param slot  property field number or spill slot
      */
-    public Property(final String key, final int flags) {
+    public Property(final String key, final int flags, final int slot) {
+        assert key != null;
         this.key   = key;
         this.flags = flags;
+        this.slot  = slot;
     }
 
     /**
@@ -104,6 +113,7 @@
     protected Property(final Property property) {
         this.key   = property.key;
         this.flags = property.flags;
+        this.slot  = property.slot;
     }
 
     /**
@@ -215,6 +225,14 @@
     }
 
     /**
+     * Check whether this property is in an object with arguments field
+     * @return true if has arguments
+     */
+    public boolean hasArguments() {
+        return (flags & HAS_ARGUMENTS) == HAS_ARGUMENTS;
+    }
+
+    /**
      * Check whether this is a spill property, i.e. one that will not
      * be stored in a specially generated field in the property class.
      * The spill pool is maintained separately, as a growing Object array
@@ -371,17 +389,17 @@
     }
 
     /**
-     * Get the spill slot as described in {@link Property#getSpillCount()}.
-     * @return spill slot, -1 if none exists
+     * Get the field number or spill slot
+     * @return number/slot, -1 if none exists
      */
     public int getSlot() {
-        return -1;
+        return slot;
     }
 
     @Override
     public int hashCode() {
         final Class<?> type = getCurrentType();
-        return Objects.hashCode(this.key) ^ flags ^ (type == null ? 0 : type.hashCode());
+        return Objects.hashCode(this.key) ^ flags ^ getSlot() ^ (type == null ? 0 : type.hashCode());
     }
 
     @Override
@@ -390,17 +408,16 @@
             return true;
         }
 
-        if (!(other instanceof Property)) {
+        if (other == null || this.getClass() != other.getClass()) {
             return false;
         }
 
         final Property otherProperty = (Property)other;
-        final Object otherKey = otherProperty.key;
-        final Class<?> otherType = otherProperty.getCurrentType();
 
-        return flags == otherProperty.flags &&
-               (key == null ? otherKey == null : key.equals(otherKey)) &&
-               (getCurrentType() == otherType);
+        return getFlags()       == otherProperty.getFlags() &&
+               getSlot()        == otherProperty.getSlot() &&
+               getCurrentType() == otherProperty.getCurrentType() &&
+               getKey().equals(otherProperty.getKey());
     }
 
     @Override
@@ -417,6 +434,12 @@
             append(type == null ? "UNDEFINED" : Type.typeFor(type).getDescriptor()).
             append('}');
 
+        if (slot != -1) {
+            sb.append('[');
+            sb.append(slot);
+            sb.append(']');
+        }
+
         return sb.toString();
     }
 
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Fri Feb 08 09:19:38 2013 -0400
@@ -271,13 +271,14 @@
      *
      * @param key           {@link Property} key.
      * @param propertyFlags {@link Property} flags.
+     * @param slot          {@link Property} slot.
      * @param getter        {@link Property} get accessor method.
      * @param setter        {@link Property} set accessor method.
      *
      * @return  New {@link PropertyMap} with {@link AccessorProperty} added.
      */
-    public PropertyMap newProperty(final String key, final int propertyFlags, final MethodHandle getter, final MethodHandle setter) {
-        return newProperty(new AccessorProperty(key, propertyFlags, getter, setter));
+    public PropertyMap newProperty(final String key, final int propertyFlags, final int slot, final MethodHandle getter, final MethodHandle setter) {
+        return newProperty(new AccessorProperty(key, propertyFlags, slot, getter, setter));
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Feb 08 09:19:38 2013 -0400
@@ -650,24 +650,23 @@
      * @return FindPropertyData or null if not found.
      */
     public final FindProperty findProperty(final String key, final boolean deep, final boolean stopOnNonScope) {
-        int depth = 0;
-
         for (ScriptObject self = this; self != null; self = self.getProto()) {
             // if doing deep search, stop search on the first non-scope object if asked to do so
-            if (stopOnNonScope && depth != 0 && !self.isScope()) {
-                break;
+            if (stopOnNonScope && self != this && !self.isScope()) {
+                return null;
             }
+
             final PropertyMap selfMap  = self.getMap();
             final Property    property = selfMap.findProperty(key);
 
             if (property != null) {
-                return new FindProperty(this, self, selfMap, property, depth);
-            } else if (!deep) {
+                return new FindProperty(this, self, property);
+            }
+
+            if (!deep) {
                 return null;
             }
-
-            depth++;
-        }
+         }
 
         return null;
     }
@@ -999,7 +998,7 @@
      * @return Value of property.
      */
     public final Object getWithProperty(final Property property) {
-        return getObjectValue(new FindProperty(this, this, getMap(), property, 0));
+        return getObjectValue(new FindProperty(this, this, property));
     }
 
     /**
@@ -1793,7 +1792,7 @@
         // If it's not a scope search, then we don't want any inherited properties except those with user defined accessors.
         if (!scope && find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
             // We should still check if inherited data property is not writable
-            if (isExtensible() && !find.isWritable()) {
+            if (isExtensible() && !find.getProperty().isWritable()) {
                 return createEmptySetMethod(desc, "property.not.writable", false);
             }
             // Otherwise, forget the found property
@@ -1801,7 +1800,7 @@
         }
 
         if (find != null) {
-            if(!find.isWritable()) {
+            if(!find.getProperty().isWritable()) {
                 // Existing, non-writable property
                 return createEmptySetMethod(desc, "property.not.writable", true);
             }
@@ -2617,7 +2616,7 @@
         MethodHandle setter;
 
         if (f != null) {
-            if (!f.isWritable()) {
+            if (!f.getProperty().isWritable()) {
                 if (strict) {
                     typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
                 }
@@ -3120,7 +3119,7 @@
             return true;
         }
 
-        if (!find.isConfigurable()) {
+        if (!find.getProperty().isConfigurable()) {
             if (strict) {
                 typeError("cant.delete.property", propName, ScriptRuntime.safeToString(this));
             }
--- a/src/jdk/nashorn/internal/runtime/SpillProperty.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java	Fri Feb 08 09:19:38 2013 -0400
@@ -42,9 +42,6 @@
 public final class SpillProperty extends AccessorProperty {
     private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE);
 
-    /** Property slot in spill */
-    private final int slot;
-
     /**
      * Constructor
      *
@@ -55,14 +52,11 @@
      * @param setter setter for property, or null if not configurable and writable
      */
     public SpillProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
-        super(key, flags, getter, setter);
-        this.slot = slot;
+        super(key, flags, slot, getter, setter);
     }
 
     private SpillProperty(final SpillProperty property) {
         super(property);
-
-        this.slot = property.slot;
     }
 
     @Override
@@ -88,31 +82,4 @@
         return super.getSetter(type, currentMap);
     }
 
-    @Override
-    public int getSlot() {
-        return slot;
-    }
-
-    @Override
-    public String toString() {
-        return super.toString() + '[' + slot + ']';
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ slot;
-    }
-
-    @Override
-    public boolean equals(final Object other) {
-        if (this == other) {
-            return true;
-        }
-
-        if (other instanceof SpillProperty) {
-            return super.equals(other) && slot == ((SpillProperty) other).slot;
-        }
-
-        return false;
-    }
 }
--- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Fri Feb 08 09:19:38 2013 -0400
@@ -60,7 +60,7 @@
      * @param setterSlot setter slot, starting at first embed
      */
     public UserAccessorProperty(final String key, final int flags, final int getterSlot, final int setterSlot) {
-        super(key, flags);
+        super(key, flags, -1);
         this.getterSlot = getterSlot;
         this.setterSlot = setterSlot;
     }
@@ -95,17 +95,13 @@
 
     @Override
     public boolean equals(final Object other) {
-        if (this == other) {
-            return true;
+        if (!super.equals(other)) {
+            return false;
         }
 
-        if (other instanceof UserAccessorProperty) {
-            final UserAccessorProperty uc = (UserAccessorProperty) other;
-            return super.equals(other) && getterSlot == uc.getterSlot && setterSlot == uc.setterSlot;
-        }
-
-        return false;
-    }
+        final UserAccessorProperty uc = (UserAccessorProperty) other;
+        return getterSlot == uc.getterSlot && setterSlot == uc.setterSlot;
+     }
 
     @Override
     public int hashCode() {
@@ -158,6 +154,6 @@
     public ScriptFunction getSetterFunction(final ScriptObject obj) {
         final Object value = obj.getEmbedOrSpill(setterSlot);
         return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
+    }
 
-    }
 }
--- a/src/jdk/nashorn/internal/runtime/linker/Lookup.java	Thu Feb 07 15:33:17 2013 +0100
+++ b/src/jdk/nashorn/internal/runtime/linker/Lookup.java	Fri Feb 08 09:19:38 2013 -0400
@@ -160,7 +160,7 @@
             throw new IllegalArgumentException("getter/setter has wrong arguments");
         }
 
-        return map.newProperty(key, flags, getter, setter);
+        return map.newProperty(key, flags, -1, getter, setter);
     }
 
     /**