src/jdk/nashorn/internal/runtime/ScriptObject.java

Print this page




  49 import java.util.Arrays;
  50 import java.util.Collection;
  51 import java.util.Collections;
  52 import java.util.HashSet;
  53 import java.util.Iterator;
  54 import java.util.LinkedHashSet;
  55 import java.util.List;
  56 import java.util.Map;
  57 import java.util.Set;
  58 
  59 import jdk.internal.dynalink.CallSiteDescriptor;
  60 import jdk.internal.dynalink.linker.GuardedInvocation;
  61 import jdk.internal.dynalink.linker.LinkRequest;
  62 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
  63 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
  64 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
  65 import jdk.nashorn.internal.lookup.Lookup;
  66 import jdk.nashorn.internal.lookup.MethodHandleFactory;
  67 import jdk.nashorn.internal.objects.AccessorPropertyDescriptor;
  68 import jdk.nashorn.internal.objects.DataPropertyDescriptor;

  69 import jdk.nashorn.internal.runtime.arrays.ArrayData;
  70 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
  71 import jdk.nashorn.internal.runtime.linker.Bootstrap;
  72 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
  73 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  74 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  75 
  76 /**
  77  * Base class for generic JavaScript objects.
  78  * <p>
  79  * Notes:
  80  * <ul>
  81  * <li>The map is used to identify properties in the object.</li>
  82  * <li>If the map is modified then it must be cloned and replaced.  This notifies
  83  *     any code that made assumptions about the object that things have changed.
  84  *     Ex. CallSites that have been validated must check to see if the map has
  85  *     changed (or a map from a different object type) and hence relink the method
  86  *     to call.</li>
  87  * <li>Modifications of the map include adding/deleting attributes or changing a
  88  *     function field value.</li>


 114     /** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */
 115     public static final int SPILL_RATE = 8;
 116 
 117     /** Map to property information and accessor functions. Ordered by insertion. */
 118     private PropertyMap map;
 119 
 120     /** objects proto. */
 121     private ScriptObject proto;
 122 
 123     /** Object flags. */
 124     private int flags;
 125 
 126     /** Area for properties added to object after instantiation, see {@link AccessorProperty} */
 127     public Object[] spill;
 128 
 129     /** Indexed array data. */
 130     private ArrayData arrayData;
 131 
 132     static final MethodHandle GETPROTO           = findOwnMH("getProto", ScriptObject.class);
 133     static final MethodHandle SETPROTOCHECK      = findOwnMH("setProtoCheck", void.class, Object.class);
 134     static final MethodHandle MEGAMORPHIC_GET    = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class);
 135 
 136     static final MethodHandle SETFIELD           = findOwnMH("setField",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
 137     static final MethodHandle SETSPILL           = findOwnMH("setSpill",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
 138     static final MethodHandle SETSPILLWITHNEW    = findOwnMH("setSpillWithNew",  void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
 139     static final MethodHandle SETSPILLWITHGROW   = findOwnMH("setSpillWithGrow", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, int.class, Object.class, Object.class);

 140 
 141     private static final MethodHandle TRUNCATINGFILTER   = findOwnMH("truncatingFilter", Object[].class, int.class, Object[].class);
 142     private static final MethodHandle KNOWNFUNCPROPGUARD = findOwnMH("knownFunctionPropertyGuard", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, Object.class, ScriptFunction.class);
 143 
 144     private static final ArrayList<MethodHandle> protoFilters = new ArrayList<>();
 145 
 146     /** Method handle for getting a function argument at a given index. Used from MapCreator */
 147     public static final Call GET_ARGUMENT       = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArgument", Object.class, int.class);
 148 
 149     /** Method handle for setting a function argument at a given index. Used from MapCreator */
 150     public static final Call SET_ARGUMENT       = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class);
 151 
 152     /** Method handle for getting the proto of a ScriptObject */
 153     public static final Call GET_PROTO          = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class);
 154 
 155     /** Method handle for setting the proto of a ScriptObject */
 156     public static final Call SET_PROTO          = virtualCallNoLookup(ScriptObject.class, "setInitialProto", void.class, ScriptObject.class);
 157 
 158     /** Method handle for setting the proto of a ScriptObject after checking argument */
 159     public static final Call SET_PROTO_CHECK    = virtualCallNoLookup(ScriptObject.class, "setProtoCheck", void.class, Object.class);


1723             filter = addProtoFilter(GETPROTO, depth - 1);
1724             protoFilters.add(null);
1725             protoFilters.set(listIndex, filter);
1726         }
1727 
1728         return MH.filterArguments(methodHandle, 0, filter.asType(filter.type().changeReturnType(methodHandle.type().parameterType(0))));
1729     }
1730 
1731     /**
1732      * Find the appropriate GET method for an invoke dynamic call.
1733      *
1734      * @param desc     the call site descriptor
1735      * @param request  the link request
1736      * @param operator operator for get: getProp, getMethod, getElem etc
1737      *
1738      * @return GuardedInvocation to be invoked at call site.
1739      */
1740     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
1741         final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
1742         if (request.isCallSiteUnstable() || hasWithScope()) {
1743             return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
1744         }
1745 
1746         final FindProperty find = findProperty(name, true);
1747         MethodHandle methodHandle;
1748 
1749         if (find == null) {
1750             if (PROTO_PROPERTY_NAME.equals(name)) {
1751                 return new GuardedInvocation(GETPROTO, NashornGuards.getScriptObjectGuard());
1752             }
1753 
1754             if ("getProp".equals(operator)) {
1755                 return noSuchProperty(desc, request);
1756             } else if ("getMethod".equals(operator)) {
1757                 return noSuchMethod(desc, request);
1758             } else if ("getElem".equals(operator)) {
1759                 return createEmptyGetter(desc, name);
1760             }
1761             throw new AssertionError(); // never invoked with any other operation
1762         }
1763 
1764         final Class<?> returnType = desc.getMethodType().returnType();
1765         final Property property = find.getProperty();
1766         methodHandle = find.getGetter(returnType);
1767 
1768         final boolean noGuard = ObjectClassGenerator.OBJECT_FIELDS_ONLY && NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
1769         // getMap() is fine as we have the prototype switchpoint depending on where the property was found
1770         final MethodHandle guard = noGuard ? null : NashornGuards.getMapGuard(getMap());
1771         final ScriptObject owner = find.getOwner();
1772 
1773         if (methodHandle != null) {
1774             assert methodHandle.type().returnType().equals(returnType);
1775             if (find.isSelf()) {
1776                 return new GuardedInvocation(methodHandle, guard);
1777             }
1778 
1779             if (!property.hasGetterFunction(owner)) {
1780                 // If not a scope bind to actual prototype as changing prototype will change the property map.
1781                 // For scopes we install a filter that replaces the self object with the prototype owning the property.
1782                 methodHandle = isScope() ?
1783                         addProtoFilter(methodHandle, find.getProtoChainLength()) :
1784                         bindTo(methodHandle, owner);
1785             }
1786             return new GuardedInvocation(methodHandle, noGuard ? null : getProtoSwitchPoint(name, owner), guard);
1787         }
1788 
1789         assert !NashornCallSiteDescriptor.isFastScope(desc);
1790         return new GuardedInvocation(Lookup.emptyGetter(returnType), getProtoSwitchPoint(name, owner), guard);
1791     }
1792 
1793     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
1794         final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);

1795         final MethodHandle guard = getScriptObjectGuard(desc.getMethodType());
1796         return new GuardedInvocation(invoker, guard);
1797     }
1798 
1799     @SuppressWarnings("unused")
1800     private Object megamorphicGet(final String key, final boolean isMethod) {
1801         final FindProperty find = findProperty(key, true);
1802 
1803         if (find != null) {
1804             return getObjectValue(find);
1805         }



1806 
1807         return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key);
1808     }
1809 
1810     /**
1811      * Find the appropriate GETINDEX method for an invoke dynamic call.
1812      *
1813      * @param desc    the call site descriptor
1814      * @param request the link request
1815      *
1816      * @return GuardedInvocation to be invoked at call site.
1817      */
1818     protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
1819         return findGetIndexMethod(desc.getMethodType());
1820     }
1821 
1822     /**
1823      * Find the appropriate GETINDEX method for an invoke dynamic call.
1824      *
1825      * @param callType the call site method type


1979     @SuppressWarnings("unused")
1980     private static void setSpillWithGrow(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final int newLength, final Object self, final Object value) {
1981         final ScriptObject obj      = (ScriptObject)self;
1982         final boolean      isStrict = NashornCallSiteDescriptor.isStrict(desc);
1983 
1984         if (!obj.isExtensible()) {
1985             if (isStrict) {
1986                 throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj));
1987             }
1988         } else if (obj.compareAndSetMap(oldMap, newMap)) {
1989             final int oldLength = obj.spill.length;
1990             final Object[] newSpill = new Object[newLength];
1991             System.arraycopy(obj.spill, 0, newSpill, 0, oldLength);
1992             obj.spill = newSpill;
1993             obj.spill[index] = value;
1994         } else {
1995             obj.set(desc.getNameToken(2), value, isStrict);
1996         }
1997     }
1998 









1999     private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
2000         final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
2001         final GuardedInvocation inv = findSetIndexMethod(type, NashornCallSiteDescriptor.isStrict(desc));
2002         return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
2003     }
2004 
2005     private static GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc) { // array, index, value
2006         return findSetIndexMethod(desc.getMethodType(), NashornCallSiteDescriptor.isStrict(desc));
2007     }
2008 
2009     /**
2010      * Find the appropriate SETINDEX method for an invoke dynamic call.
2011      *
2012      * @param callType the method type at the call site
2013      * @param isStrict are we in strict mode?
2014      *
2015      * @return GuardedInvocation to be invoked at call site.
2016      */
2017     private static GuardedInvocation findSetIndexMethod(final MethodType callType, final boolean isStrict) {
2018         assert callType.parameterCount() == 3;


2806             // Setting a property should not modify the property in prototype unless this is a scope object.
2807             f = null;
2808         }
2809 
2810         if (f != null) {
2811             if (!f.getProperty().isWritable()) {
2812                 if (strict) {
2813                     throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
2814                 }
2815 
2816                 return;
2817             }
2818 
2819             f.setObjectValue(value, strict);
2820 
2821         } else if (!isExtensible()) {
2822             if (strict) {
2823                 throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
2824             }
2825         } else {
2826             spill(key, value);








2827         }
2828     }
2829 
2830     private void spill(final String key, final Object value) {
2831         addSpillProperty(key, 0).setObjectValue(this, this, value, false);
2832     }
2833 
2834 
2835     @Override
2836     public void set(final Object key, final int value, final boolean strict) {
2837         final Object primitiveKey = JSType.toPrimitive(key, String.class);
2838         final int index = getArrayIndex(primitiveKey);
2839 
2840         if (isValidArrayIndex(index)) {
2841             if (getArray().has(index)) {
2842                 setArray(getArray().set(index, value, strict));
2843             } else {
2844                 doesNotHave(index, value, strict);
2845             }
2846 




  49 import java.util.Arrays;
  50 import java.util.Collection;
  51 import java.util.Collections;
  52 import java.util.HashSet;
  53 import java.util.Iterator;
  54 import java.util.LinkedHashSet;
  55 import java.util.List;
  56 import java.util.Map;
  57 import java.util.Set;
  58 
  59 import jdk.internal.dynalink.CallSiteDescriptor;
  60 import jdk.internal.dynalink.linker.GuardedInvocation;
  61 import jdk.internal.dynalink.linker.LinkRequest;
  62 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
  63 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
  64 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
  65 import jdk.nashorn.internal.lookup.Lookup;
  66 import jdk.nashorn.internal.lookup.MethodHandleFactory;
  67 import jdk.nashorn.internal.objects.AccessorPropertyDescriptor;
  68 import jdk.nashorn.internal.objects.DataPropertyDescriptor;
  69 import jdk.nashorn.internal.objects.Global;
  70 import jdk.nashorn.internal.runtime.arrays.ArrayData;
  71 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
  72 import jdk.nashorn.internal.runtime.linker.Bootstrap;
  73 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
  74 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  75 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  76 
  77 /**
  78  * Base class for generic JavaScript objects.
  79  * <p>
  80  * Notes:
  81  * <ul>
  82  * <li>The map is used to identify properties in the object.</li>
  83  * <li>If the map is modified then it must be cloned and replaced.  This notifies
  84  *     any code that made assumptions about the object that things have changed.
  85  *     Ex. CallSites that have been validated must check to see if the map has
  86  *     changed (or a map from a different object type) and hence relink the method
  87  *     to call.</li>
  88  * <li>Modifications of the map include adding/deleting attributes or changing a
  89  *     function field value.</li>


 115     /** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */
 116     public static final int SPILL_RATE = 8;
 117 
 118     /** Map to property information and accessor functions. Ordered by insertion. */
 119     private PropertyMap map;
 120 
 121     /** objects proto. */
 122     private ScriptObject proto;
 123 
 124     /** Object flags. */
 125     private int flags;
 126 
 127     /** Area for properties added to object after instantiation, see {@link AccessorProperty} */
 128     public Object[] spill;
 129 
 130     /** Indexed array data. */
 131     private ArrayData arrayData;
 132 
 133     static final MethodHandle GETPROTO           = findOwnMH("getProto", ScriptObject.class);
 134     static final MethodHandle SETPROTOCHECK      = findOwnMH("setProtoCheck", void.class, Object.class);
 135     static final MethodHandle MEGAMORPHIC_GET    = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class, boolean.class);
 136 
 137     static final MethodHandle SETFIELD           = findOwnMH("setField",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
 138     static final MethodHandle SETSPILL           = findOwnMH("setSpill",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
 139     static final MethodHandle SETSPILLWITHNEW    = findOwnMH("setSpillWithNew",  void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
 140     static final MethodHandle SETSPILLWITHGROW   = findOwnMH("setSpillWithGrow", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, int.class, Object.class, Object.class);
 141     static final MethodHandle GLOBALFILTER       = findOwnMH("globalFilter", Object.class, Object.class);
 142 
 143     private static final MethodHandle TRUNCATINGFILTER   = findOwnMH("truncatingFilter", Object[].class, int.class, Object[].class);
 144     private static final MethodHandle KNOWNFUNCPROPGUARD = findOwnMH("knownFunctionPropertyGuard", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, Object.class, ScriptFunction.class);
 145 
 146     private static final ArrayList<MethodHandle> protoFilters = new ArrayList<>();
 147 
 148     /** Method handle for getting a function argument at a given index. Used from MapCreator */
 149     public static final Call GET_ARGUMENT       = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArgument", Object.class, int.class);
 150 
 151     /** Method handle for setting a function argument at a given index. Used from MapCreator */
 152     public static final Call SET_ARGUMENT       = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class);
 153 
 154     /** Method handle for getting the proto of a ScriptObject */
 155     public static final Call GET_PROTO          = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class);
 156 
 157     /** Method handle for setting the proto of a ScriptObject */
 158     public static final Call SET_PROTO          = virtualCallNoLookup(ScriptObject.class, "setInitialProto", void.class, ScriptObject.class);
 159 
 160     /** Method handle for setting the proto of a ScriptObject after checking argument */
 161     public static final Call SET_PROTO_CHECK    = virtualCallNoLookup(ScriptObject.class, "setProtoCheck", void.class, Object.class);


1725             filter = addProtoFilter(GETPROTO, depth - 1);
1726             protoFilters.add(null);
1727             protoFilters.set(listIndex, filter);
1728         }
1729 
1730         return MH.filterArguments(methodHandle, 0, filter.asType(filter.type().changeReturnType(methodHandle.type().parameterType(0))));
1731     }
1732 
1733     /**
1734      * Find the appropriate GET method for an invoke dynamic call.
1735      *
1736      * @param desc     the call site descriptor
1737      * @param request  the link request
1738      * @param operator operator for get: getProp, getMethod, getElem etc
1739      *
1740      * @return GuardedInvocation to be invoked at call site.
1741      */
1742     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
1743         final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
1744         if (request.isCallSiteUnstable() || hasWithScope()) {
1745             return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator), isScope() && NashornCallSiteDescriptor.isScope(desc));
1746         }
1747 
1748         final FindProperty find = findProperty(name, true);
1749         MethodHandle methodHandle;
1750 
1751         if (find == null) {
1752             if (PROTO_PROPERTY_NAME.equals(name)) {
1753                 return new GuardedInvocation(GETPROTO, NashornGuards.getScriptObjectGuard());
1754             }
1755 
1756             if ("getProp".equals(operator)) {
1757                 return noSuchProperty(desc, request);
1758             } else if ("getMethod".equals(operator)) {
1759                 return noSuchMethod(desc, request);
1760             } else if ("getElem".equals(operator)) {
1761                 return createEmptyGetter(desc, name);
1762             }
1763             throw new AssertionError(); // never invoked with any other operation
1764         }
1765 
1766         final Class<?> returnType = desc.getMethodType().returnType();
1767         final Property property = find.getProperty();
1768         methodHandle = find.getGetter(returnType);
1769 
1770         // Get the appropriate guard for this callsite and property.
1771         final MethodHandle guard = NashornGuards.getGuard(this, property, desc);

1772         final ScriptObject owner = find.getOwner();
1773 
1774         if (methodHandle != null) {
1775             assert methodHandle.type().returnType().equals(returnType);
1776             if (find.isSelf()) {
1777                 return new GuardedInvocation(methodHandle, guard);
1778             }
1779 
1780             if (!property.hasGetterFunction(owner)) {
1781                 // Add a filter that replaces the self object with the prototype owning the property.
1782                 methodHandle = addProtoFilter(methodHandle, find.getProtoChainLength());



1783             }
1784             return new GuardedInvocation(methodHandle, guard == null ? null : getProtoSwitchPoint(name, owner), guard);
1785         }
1786 
1787         assert !NashornCallSiteDescriptor.isFastScope(desc);
1788         return new GuardedInvocation(Lookup.emptyGetter(returnType), getProtoSwitchPoint(name, owner), guard);
1789     }
1790 
1791     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name,
1792                                                               final boolean isMethod, final boolean isScope) {
1793         final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, isScope);
1794         final MethodHandle guard = getScriptObjectGuard(desc.getMethodType());
1795         return new GuardedInvocation(invoker, guard);
1796     }
1797 
1798     @SuppressWarnings("unused")
1799     private Object megamorphicGet(final String key, final boolean isMethod, final boolean isScope) {
1800         final FindProperty find = findProperty(key, true);
1801 
1802         if (find != null) {
1803             return getObjectValue(find);
1804         }
1805         if (isScope) {
1806             throw referenceError("not.defined", key);
1807         }
1808 
1809         return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key);
1810     }
1811 
1812     /**
1813      * Find the appropriate GETINDEX method for an invoke dynamic call.
1814      *
1815      * @param desc    the call site descriptor
1816      * @param request the link request
1817      *
1818      * @return GuardedInvocation to be invoked at call site.
1819      */
1820     protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
1821         return findGetIndexMethod(desc.getMethodType());
1822     }
1823 
1824     /**
1825      * Find the appropriate GETINDEX method for an invoke dynamic call.
1826      *
1827      * @param callType the call site method type


1981     @SuppressWarnings("unused")
1982     private static void setSpillWithGrow(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final int newLength, final Object self, final Object value) {
1983         final ScriptObject obj      = (ScriptObject)self;
1984         final boolean      isStrict = NashornCallSiteDescriptor.isStrict(desc);
1985 
1986         if (!obj.isExtensible()) {
1987             if (isStrict) {
1988                 throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj));
1989             }
1990         } else if (obj.compareAndSetMap(oldMap, newMap)) {
1991             final int oldLength = obj.spill.length;
1992             final Object[] newSpill = new Object[newLength];
1993             System.arraycopy(obj.spill, 0, newSpill, 0, oldLength);
1994             obj.spill = newSpill;
1995             obj.spill[index] = value;
1996         } else {
1997             obj.set(desc.getNameToken(2), value, isStrict);
1998         }
1999     }
2000 
2001     @SuppressWarnings("unused")
2002     private static Object globalFilter(final Object object) {
2003         ScriptObject sobj = (ScriptObject) object;
2004         while (sobj != null && !(sobj instanceof Global)) {
2005             sobj = sobj.getProto();
2006         }
2007         return sobj;
2008     }
2009 
2010     private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
2011         final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
2012         final GuardedInvocation inv = findSetIndexMethod(type, NashornCallSiteDescriptor.isStrict(desc));
2013         return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
2014     }
2015 
2016     private static GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc) { // array, index, value
2017         return findSetIndexMethod(desc.getMethodType(), NashornCallSiteDescriptor.isStrict(desc));
2018     }
2019 
2020     /**
2021      * Find the appropriate SETINDEX method for an invoke dynamic call.
2022      *
2023      * @param callType the method type at the call site
2024      * @param isStrict are we in strict mode?
2025      *
2026      * @return GuardedInvocation to be invoked at call site.
2027      */
2028     private static GuardedInvocation findSetIndexMethod(final MethodType callType, final boolean isStrict) {
2029         assert callType.parameterCount() == 3;


2817             // Setting a property should not modify the property in prototype unless this is a scope object.
2818             f = null;
2819         }
2820 
2821         if (f != null) {
2822             if (!f.getProperty().isWritable()) {
2823                 if (strict) {
2824                     throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
2825                 }
2826 
2827                 return;
2828             }
2829 
2830             f.setObjectValue(value, strict);
2831 
2832         } else if (!isExtensible()) {
2833             if (strict) {
2834                 throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
2835             }
2836         } else {
2837             ScriptObject sobj = this;
2838             // undefined scope properties are set in the global object.
2839             if (isScope()) {
2840                 while (sobj != null && !(sobj instanceof Global)) {
2841                     sobj = sobj.getProto();
2842                 }
2843                 assert sobj != null : "no parent global object in scope";
2844             }
2845             sobj.spill(key, value);
2846         }
2847     }
2848 
2849     private void spill(final String key, final Object value) {
2850         addSpillProperty(key, 0).setObjectValue(this, this, value, false);
2851     }
2852 
2853 
2854     @Override
2855     public void set(final Object key, final int value, final boolean strict) {
2856         final Object primitiveKey = JSType.toPrimitive(key, String.class);
2857         final int index = getArrayIndex(primitiveKey);
2858 
2859         if (isValidArrayIndex(index)) {
2860             if (getArray().has(index)) {
2861                 setArray(getArray().set(index, value, strict));
2862             } else {
2863                 doesNotHave(index, value, strict);
2864             }
2865