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

Print this page




  29 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
  30 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
  31 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
  32 import static jdk.nashorn.internal.lookup.Lookup.MH;
  33 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
  34 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  35 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_DOUBLE;
  36 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_INT;
  37 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_LONG;
  38 import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
  39 import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
  40 import static jdk.nashorn.internal.runtime.PropertyDescriptor.GET;
  41 import static jdk.nashorn.internal.runtime.PropertyDescriptor.SET;
  42 import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
  43 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
  44 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
  45 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
  46 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
  47 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
  48 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;


  49 import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
  50 
  51 import java.lang.invoke.MethodHandle;
  52 import java.lang.invoke.MethodHandles;
  53 import java.lang.invoke.MethodType;
  54 import java.lang.invoke.SwitchPoint;
  55 import java.util.AbstractMap;
  56 import java.util.ArrayList;
  57 import java.util.Arrays;
  58 import java.util.Collection;
  59 import java.util.Collections;
  60 import java.util.HashSet;
  61 import java.util.Iterator;
  62 import java.util.LinkedHashSet;
  63 import java.util.List;
  64 import java.util.Map;
  65 import java.util.Set;
  66 import jdk.internal.dynalink.CallSiteDescriptor;
  67 import jdk.internal.dynalink.linker.GuardedInvocation;
  68 import jdk.internal.dynalink.linker.LinkRequest;


  81 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
  82 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  83 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  84 
  85 /**
  86  * Base class for generic JavaScript objects.
  87  * <p>
  88  * Notes:
  89  * <ul>
  90  * <li>The map is used to identify properties in the object.</li>
  91  * <li>If the map is modified then it must be cloned and replaced.  This notifies
  92  *     any code that made assumptions about the object that things have changed.
  93  *     Ex. CallSites that have been validated must check to see if the map has
  94  *     changed (or a map from a different object type) and hence relink the method
  95  *     to call.</li>
  96  * <li>Modifications of the map include adding/deleting attributes or changing a
  97  *     function field value.</li>
  98  * </ul>
  99  */
 100 
 101 public abstract class ScriptObject implements PropertyAccess {
 102     /** __proto__ special property name inside object literals. ES6 draft. */
 103     public static final String PROTO_PROPERTY_NAME   = "__proto__";
 104 
 105     /** Search fall back routine name for "no such method" */
 106     public static final String NO_SUCH_METHOD_NAME   = "__noSuchMethod__";
 107 
 108     /** Search fall back routine name for "no such property" */
 109     public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
 110 
 111     /** Per ScriptObject flag - is this a scope object? */
 112     public static final int IS_SCOPE       = 1 << 0;
 113 
 114     /** Per ScriptObject flag - is this an array object? */
 115     public static final int IS_ARRAY       = 1 << 1;
 116 
 117     /** Per ScriptObject flag - is this an arguments object? */
 118     public static final int IS_ARGUMENTS   = 1 << 2;
 119 
 120     /** Is length property not-writable? */
 121     public static final int IS_LENGTH_NOT_WRITABLE = 1 << 3;


2185          * we'll end up assigning it on it's proto - which is Object.prototype.toString !!
2186          *
2187          * toString = function() { print("global toString"); } // don't affect Object.prototype.toString
2188          */
2189         FindProperty find = findProperty(name, true, this);
2190 
2191         // If it's not a scope search, then we don't want any inherited properties except those with user defined accessors.
2192         if (find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
2193             // We should still check if inherited data property is not writable
2194             if (isExtensible() && !find.getProperty().isWritable()) {
2195                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
2196             }
2197             // Otherwise, forget the found property unless this is a scope callsite and the owner is a scope object as well.
2198             if (!NashornCallSiteDescriptor.isScope(desc) || !find.getOwner().isScope()) {
2199                 find = null;
2200             }
2201         }
2202 
2203         if (find != null) {
2204             if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) {



2205                 // Existing, non-writable property
2206                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
2207             }
2208         } else {
2209             if (!isExtensible()) {
2210                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "object.non.extensible", false);
2211             }
2212         }
2213 
2214         final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name));
2215 
2216         final GlobalConstants globalConstants = getGlobalConstants();
2217         if (globalConstants != null) {
2218             final GuardedInvocation cinv = globalConstants.findSetMethod(find, this, inv, desc, request);
2219             if (cinv != null) {
2220                 return cinv;
2221             }
2222         }
2223 
2224         return inv;


3086         }
3087         return false;
3088     }
3089 
3090     private boolean doesNotHaveCheckArrayKeys(final long longIndex, final Object value, final int callSiteFlags) {
3091         if (getMap().containsArrayKeys()) {
3092             final String       key  = JSType.toString(longIndex);
3093             final FindProperty find = findProperty(key, true);
3094             if (find != null) {
3095                 setObject(find, callSiteFlags, key, value);
3096                 return true;
3097             }
3098         }
3099         return false;
3100     }
3101 
3102     //value agnostic
3103     private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) {
3104         if (longIndex >= oldLength) {
3105             if (!isExtensible()) {
3106                 if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
3107                     throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
3108                 }
3109                 return true;
3110             }
3111             setArray(getArray().ensure(longIndex));
3112         }
3113         return false;
3114     }
3115 
3116     private void doesNotHaveEnsureDelete(final long longIndex, final long oldLength, final boolean strict) {
3117         if (longIndex > oldLength) {
3118             ArrayData array = getArray();
3119             if (array.canDelete(oldLength, longIndex - 1, strict)) {
3120                 array = array.delete(oldLength, longIndex - 1);
3121             }
3122             setArray(array);
3123         }
3124     }
3125 
3126     private void doesNotHave(final int index, final int value, final int callSiteFlags) {
3127         final long oldLength = getArray().length();
3128         final long longIndex = ArrayIndex.toLongIndex(index);
3129         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3130             final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
3131             setArray(getArray().set(index, value, strict));
3132             doesNotHaveEnsureDelete(longIndex, oldLength, strict);
3133         }
3134     }
3135 
3136     private void doesNotHave(final int index, final long value, final int callSiteFlags) {
3137         final long oldLength = getArray().length();
3138         final long longIndex = ArrayIndex.toLongIndex(index);
3139         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3140             final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
3141             setArray(getArray().set(index, value, strict));
3142             doesNotHaveEnsureDelete(longIndex, oldLength, strict);
3143         }
3144     }
3145 
3146     private void doesNotHave(final int index, final double value, final int callSiteFlags) {
3147         final long oldLength = getArray().length();
3148         final long longIndex = ArrayIndex.toLongIndex(index);
3149         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3150             final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
3151             setArray(getArray().set(index, value, strict));
3152             doesNotHaveEnsureDelete(longIndex, oldLength, strict);
3153         }
3154     }
3155 
3156     private void doesNotHave(final int index, final Object value, final int callSiteFlags) {
3157         final long oldLength = getArray().length();
3158         final long longIndex = ArrayIndex.toLongIndex(index);
3159         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3160             final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
3161             setArray(getArray().set(index, value, strict));
3162             doesNotHaveEnsureDelete(longIndex, oldLength, strict);
3163         }
3164     }
3165 
3166     /**
3167      * This is the most generic of all Object setters. Most of the others use this in some form.
3168      * TODO: should be further specialized
3169      *
3170      * @param find          found property
3171      * @param callSiteFlags callsite flags
3172      * @param key           property key
3173      * @param value         property value
3174      */
3175     public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) {
3176         FindProperty f = find;
3177 
3178         invalidateGlobalConstant(key);
3179 
3180         if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
3181             final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags);
3182             // If the start object of the find is not this object it means the property was found inside a
3183             // 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
3184             // to the 'with' object.
3185             // Note that although a 'set' operation involving a with statement follows scope rules outside
3186             // the 'with' expression (the 'set' operation is performed on the owning prototype if it exists),
3187             // it follows non-scope rules inside the 'with' expression (set is performed on the top level object).
3188             // This is why we clear the callsite flags and FindProperty in the forward call to the 'with' object.
3189             if (isScope && f.getSelf() != this) {
3190                 f.getSelf().setObject(null, 0, key, value);
3191                 return;
3192             }
3193             // Setting a property should not modify the property in prototype unless this is a scope callsite
3194             // and the owner is a scope object as well (with the exception of 'with' statement handled above).
3195             if (!isScope || !f.getOwner().isScope()) {
3196                 f = null;
3197             }
3198         }
3199 
3200         if (f != null) {
3201             if (!f.getProperty().isWritable()) {
3202                 if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {



3203                     throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
3204                 }
3205                 return;
3206             }
3207 
3208             f.setValue(value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags));
3209 
3210         } else if (!isExtensible()) {
3211             if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
3212                 throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
3213             }
3214         } else {
3215             ScriptObject sobj = this;
3216             // undefined scope properties are set in the global object.
3217             if (isScope()) {
3218                 while (sobj != null && !(sobj instanceof Global)) {
3219                     sobj = sobj.getProto();
3220                 }
3221                 assert sobj != null : "no parent global object in scope";
3222             }
3223             //this will unbox any Number object to its primitive type in case the
3224             //property supports primitive types, so it doesn't matter that it comes
3225             //in as an Object.
3226             sobj.addSpillProperty(key, 0, value, true);
3227         }
3228     }
3229 
3230     @Override
3231     public void set(final Object key, final int value, final int callSiteFlags) {
3232         final Object primitiveKey = JSType.toPrimitive(key, String.class);
3233         final int    index        = getArrayIndex(primitiveKey);
3234 
3235         if (isValidArrayIndex(index)) {
3236             final ArrayData data = getArray();
3237             if (data.has(index)) {
3238                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3239             } else {
3240                 doesNotHave(index, value, callSiteFlags);
3241             }
3242 
3243             return;
3244         }
3245 
3246         final String propName = JSType.toString(primitiveKey);
3247         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3248     }
3249 
3250     @Override
3251     public void set(final Object key, final long value, final int callSiteFlags) {
3252         final Object primitiveKey = JSType.toPrimitive(key, String.class);
3253         final int    index        = getArrayIndex(primitiveKey);
3254 
3255         if (isValidArrayIndex(index)) {
3256             final ArrayData data = getArray();
3257             if (data.has(index)) {
3258                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3259             } else {
3260                 doesNotHave(index, value, callSiteFlags);
3261             }
3262 
3263             return;
3264         }
3265 
3266         final String propName = JSType.toString(primitiveKey);
3267         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3268     }
3269 
3270     @Override
3271     public void set(final Object key, final double value, final int callSiteFlags) {
3272         final Object primitiveKey = JSType.toPrimitive(key, String.class);
3273         final int    index        = getArrayIndex(primitiveKey);
3274 
3275         if (isValidArrayIndex(index)) {
3276             final ArrayData data = getArray();
3277             if (data.has(index)) {
3278                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3279             } else {
3280                 doesNotHave(index, value, callSiteFlags);
3281             }
3282 
3283             return;
3284         }
3285 
3286         final String propName = JSType.toString(primitiveKey);
3287         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3288     }
3289 
3290     @Override
3291     public void set(final Object key, final Object value, final int callSiteFlags) {
3292         final Object primitiveKey = JSType.toPrimitive(key, String.class);
3293         final int    index        = getArrayIndex(primitiveKey);
3294 
3295         if (isValidArrayIndex(index)) {
3296             final ArrayData data = getArray();
3297             if (data.has(index)) {
3298                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3299             } else {
3300                 doesNotHave(index, value, callSiteFlags);
3301             }
3302 
3303             return;
3304         }
3305 
3306         final String propName = JSType.toString(primitiveKey);
3307         setObject(findProperty(propName, true), callSiteFlags, propName, value);
3308     }
3309 
3310     @Override
3311     public void set(final double key, final int value, final int callSiteFlags) {
3312         final int index = getArrayIndex(key);
3313 
3314         if (isValidArrayIndex(index)) {
3315             final ArrayData data = getArray();
3316             if (data.has(index)) {
3317                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3318             } else {
3319                 doesNotHave(index, value, callSiteFlags);
3320             }
3321 
3322             return;
3323         }
3324 
3325         final String propName = JSType.toString(key);
3326         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3327     }
3328 
3329     @Override
3330     public void set(final double key, final long value, final int callSiteFlags) {
3331         final int index = getArrayIndex(key);
3332 
3333         if (isValidArrayIndex(index)) {
3334             final ArrayData data = getArray();
3335             if (data.has(index)) {
3336                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3337             } else {
3338                 doesNotHave(index, value, callSiteFlags);
3339             }
3340 
3341             return;
3342         }
3343 
3344         final String propName = JSType.toString(key);
3345         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3346     }
3347 
3348     @Override
3349     public void set(final double key, final double value, final int callSiteFlags) {
3350         final int index = getArrayIndex(key);
3351 
3352         if (isValidArrayIndex(index)) {
3353             final ArrayData data = getArray();
3354             if (data.has(index)) {
3355                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3356             } else {
3357                 doesNotHave(index, value, callSiteFlags);
3358             }
3359 
3360             return;
3361         }
3362 
3363         final String propName = JSType.toString(key);
3364         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3365     }
3366 
3367     @Override
3368     public void set(final double key, final Object value, final int callSiteFlags) {
3369         final int index = getArrayIndex(key);
3370 
3371         if (isValidArrayIndex(index)) {
3372             final ArrayData data = getArray();
3373             if (data.has(index)) {
3374                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3375             } else {
3376                 doesNotHave(index, value, callSiteFlags);
3377             }
3378 
3379             return;
3380         }
3381 
3382         final String propName = JSType.toString(key);
3383         setObject(findProperty(propName, true), callSiteFlags, propName, value);
3384     }
3385 
3386     @Override
3387     public void set(final long key, final int value, final int callSiteFlags) {
3388         final int index = getArrayIndex(key);
3389 
3390         if (isValidArrayIndex(index)) {
3391             final ArrayData data = getArray();
3392             if (data.has(index)) {
3393                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3394             } else {
3395                 doesNotHave(index, value, callSiteFlags);
3396             }
3397 
3398             return;
3399         }
3400 
3401         final String propName = JSType.toString(key);
3402         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3403     }
3404 
3405     @Override
3406     public void set(final long key, final long value, final int callSiteFlags) {
3407         final int index = getArrayIndex(key);
3408 
3409         if (isValidArrayIndex(index)) {
3410             final ArrayData data = getArray();
3411             if (data.has(index)) {
3412                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3413             } else {
3414                 doesNotHave(index, value, callSiteFlags);
3415             }
3416 
3417             return;
3418         }
3419 
3420         final String propName = JSType.toString(key);
3421         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3422     }
3423 
3424     @Override
3425     public void set(final long key, final double value, final int callSiteFlags) {
3426         final int index = getArrayIndex(key);
3427 
3428         if (isValidArrayIndex(index)) {
3429             final ArrayData data = getArray();
3430             if (data.has(index)) {
3431                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3432             } else {
3433                 doesNotHave(index, value, callSiteFlags);
3434             }
3435 
3436             return;
3437         }
3438 
3439         final String propName = JSType.toString(key);
3440         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3441     }
3442 
3443     @Override
3444     public void set(final long key, final Object value, final int callSiteFlags) {
3445         final int index = getArrayIndex(key);
3446 
3447         if (isValidArrayIndex(index)) {
3448             final ArrayData data = getArray();
3449             if (data.has(index)) {
3450                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3451             } else {
3452                 doesNotHave(index, value, callSiteFlags);
3453             }
3454 
3455             return;
3456         }
3457 
3458         final String propName = JSType.toString(key);
3459         setObject(findProperty(propName, true), callSiteFlags, propName, value);
3460     }
3461 
3462     @Override
3463     public void set(final int key, final int value, final int callSiteFlags) {
3464         final int index = getArrayIndex(key);
3465         if (isValidArrayIndex(index)) {
3466             if (getArray().has(index)) {
3467                 final ArrayData data = getArray();
3468                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3469             } else {
3470                 doesNotHave(index, value, callSiteFlags);
3471             }
3472             return;
3473         }
3474 
3475         final String propName = JSType.toString(key);
3476         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3477     }
3478 
3479     @Override
3480     public void set(final int key, final long value, final int callSiteFlags) {
3481         final int index = getArrayIndex(key);
3482 
3483         if (isValidArrayIndex(index)) {
3484             final ArrayData data = getArray();
3485             if (data.has(index)) {
3486                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3487             } else {
3488                 doesNotHave(index, value, callSiteFlags);
3489             }
3490 
3491             return;
3492         }
3493 
3494         final String propName = JSType.toString(key);
3495         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3496     }
3497 
3498     @Override
3499     public void set(final int key, final double value, final int callSiteFlags) {
3500         final int index = getArrayIndex(key);
3501 
3502         if (isValidArrayIndex(index)) {
3503             final ArrayData data = getArray();
3504             if (data.has(index)) {
3505                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3506             } else {
3507                 doesNotHave(index, value, callSiteFlags);
3508             }
3509 
3510             return;
3511         }
3512 
3513         final String propName = JSType.toString(key);
3514         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3515     }
3516 
3517     @Override
3518     public void set(final int key, final Object value, final int callSiteFlags) {
3519         final int index = getArrayIndex(key);
3520 
3521         if (isValidArrayIndex(index)) {
3522             final ArrayData data = getArray();
3523             if (data.has(index)) {
3524                 setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
3525             } else {
3526                 doesNotHave(index, value, callSiteFlags);
3527             }
3528 
3529             return;
3530         }
3531 
3532         final String propName = JSType.toString(key);
3533         setObject(findProperty(propName, true), callSiteFlags, propName, value);
3534     }
3535 
3536     @Override
3537     public boolean has(final Object key) {
3538         final Object primitiveKey = JSType.toPrimitive(key);
3539         final int    index        = getArrayIndex(primitiveKey);
3540         return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), true);
3541     }
3542 
3543     @Override
3544     public boolean has(final double key) {


3666 
3667     private boolean deleteObject(final Object key, final boolean strict) {
3668         final String propName = JSType.toString(key);
3669         final FindProperty find = findProperty(propName, false);
3670 
3671         if (find == null) {
3672             return true;
3673         }
3674 
3675         if (!find.getProperty().isConfigurable()) {
3676             if (strict) {
3677                 throw typeError("cant.delete.property", propName, ScriptRuntime.safeToString(this));
3678             }
3679             return false;
3680         }
3681 
3682         final Property prop = find.getProperty();
3683         deleteOwnProperty(prop);
3684 
3685         return true;























3686     }
3687 
3688     /**
3689      * Make a new UserAccessorProperty property. getter and setter functions are stored in
3690      * this ScriptObject and slot values are used in property object.
3691      *
3692      * @param key the property name
3693      * @param propertyFlags attribute flags of the property
3694      * @param getter getter function for the property
3695      * @param setter setter function for the property
3696      * @return the newly created UserAccessorProperty
3697      */
3698     protected final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
3699         final UserAccessorProperty uc = getMap().newUserAccessors(key, propertyFlags);
3700         //property.getSetter(Object.class, getMap());
3701         uc.setAccessors(this, getMap(), new UserAccessorProperty.Accessors(getter, setter));
3702         return uc;
3703     }
3704 
3705     Object ensureSpillSize(final int slot) {




  29 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
  30 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
  31 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
  32 import static jdk.nashorn.internal.lookup.Lookup.MH;
  33 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
  34 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  35 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_DOUBLE;
  36 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_INT;
  37 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_LONG;
  38 import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
  39 import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
  40 import static jdk.nashorn.internal.runtime.PropertyDescriptor.GET;
  41 import static jdk.nashorn.internal.runtime.PropertyDescriptor.SET;
  42 import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
  43 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
  44 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
  45 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
  46 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
  47 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
  48 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
  49 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isScopeFlag;
  50 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isStrictFlag;
  51 import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
  52 
  53 import java.lang.invoke.MethodHandle;
  54 import java.lang.invoke.MethodHandles;
  55 import java.lang.invoke.MethodType;
  56 import java.lang.invoke.SwitchPoint;
  57 import java.util.AbstractMap;
  58 import java.util.ArrayList;
  59 import java.util.Arrays;
  60 import java.util.Collection;
  61 import java.util.Collections;
  62 import java.util.HashSet;
  63 import java.util.Iterator;
  64 import java.util.LinkedHashSet;
  65 import java.util.List;
  66 import java.util.Map;
  67 import java.util.Set;
  68 import jdk.internal.dynalink.CallSiteDescriptor;
  69 import jdk.internal.dynalink.linker.GuardedInvocation;
  70 import jdk.internal.dynalink.linker.LinkRequest;


  83 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
  84 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
  85 import jdk.nashorn.internal.runtime.linker.NashornGuards;
  86 
  87 /**
  88  * Base class for generic JavaScript objects.
  89  * <p>
  90  * Notes:
  91  * <ul>
  92  * <li>The map is used to identify properties in the object.</li>
  93  * <li>If the map is modified then it must be cloned and replaced.  This notifies
  94  *     any code that made assumptions about the object that things have changed.
  95  *     Ex. CallSites that have been validated must check to see if the map has
  96  *     changed (or a map from a different object type) and hence relink the method
  97  *     to call.</li>
  98  * <li>Modifications of the map include adding/deleting attributes or changing a
  99  *     function field value.</li>
 100  * </ul>
 101  */
 102 
 103 public abstract class ScriptObject implements PropertyAccess, Cloneable {
 104     /** __proto__ special property name inside object literals. ES6 draft. */
 105     public static final String PROTO_PROPERTY_NAME   = "__proto__";
 106 
 107     /** Search fall back routine name for "no such method" */
 108     public static final String NO_SUCH_METHOD_NAME   = "__noSuchMethod__";
 109 
 110     /** Search fall back routine name for "no such property" */
 111     public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
 112 
 113     /** Per ScriptObject flag - is this a scope object? */
 114     public static final int IS_SCOPE       = 1 << 0;
 115 
 116     /** Per ScriptObject flag - is this an array object? */
 117     public static final int IS_ARRAY       = 1 << 1;
 118 
 119     /** Per ScriptObject flag - is this an arguments object? */
 120     public static final int IS_ARGUMENTS   = 1 << 2;
 121 
 122     /** Is length property not-writable? */
 123     public static final int IS_LENGTH_NOT_WRITABLE = 1 << 3;


2187          * we'll end up assigning it on it's proto - which is Object.prototype.toString !!
2188          *
2189          * toString = function() { print("global toString"); } // don't affect Object.prototype.toString
2190          */
2191         FindProperty find = findProperty(name, true, this);
2192 
2193         // If it's not a scope search, then we don't want any inherited properties except those with user defined accessors.
2194         if (find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
2195             // We should still check if inherited data property is not writable
2196             if (isExtensible() && !find.getProperty().isWritable()) {
2197                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
2198             }
2199             // Otherwise, forget the found property unless this is a scope callsite and the owner is a scope object as well.
2200             if (!NashornCallSiteDescriptor.isScope(desc) || !find.getOwner().isScope()) {
2201                 find = null;
2202             }
2203         }
2204 
2205         if (find != null) {
2206             if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) {
2207                 if (NashornCallSiteDescriptor.isScope(desc) && find.getProperty().isLexicalBinding()) {
2208                     throw typeError("assign.constant", name); // Overwriting ES6 const should throw also in non-strict mode.
2209                 }
2210                 // Existing, non-writable property
2211                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
2212             }
2213         } else {
2214             if (!isExtensible()) {
2215                 return createEmptySetMethod(desc, explicitInstanceOfCheck, "object.non.extensible", false);
2216             }
2217         }
2218 
2219         final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name));
2220 
2221         final GlobalConstants globalConstants = getGlobalConstants();
2222         if (globalConstants != null) {
2223             final GuardedInvocation cinv = globalConstants.findSetMethod(find, this, inv, desc, request);
2224             if (cinv != null) {
2225                 return cinv;
2226             }
2227         }
2228 
2229         return inv;


3091         }
3092         return false;
3093     }
3094 
3095     private boolean doesNotHaveCheckArrayKeys(final long longIndex, final Object value, final int callSiteFlags) {
3096         if (getMap().containsArrayKeys()) {
3097             final String       key  = JSType.toString(longIndex);
3098             final FindProperty find = findProperty(key, true);
3099             if (find != null) {
3100                 setObject(find, callSiteFlags, key, value);
3101                 return true;
3102             }
3103         }
3104         return false;
3105     }
3106 
3107     //value agnostic
3108     private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) {
3109         if (longIndex >= oldLength) {
3110             if (!isExtensible()) {
3111                 if (isStrictFlag(callSiteFlags)) {
3112                     throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
3113                 }
3114                 return true;
3115             }
3116             setArray(getArray().ensure(longIndex));
3117         }
3118         return false;
3119     }
3120 
3121     private void doesNotHaveEnsureDelete(final long longIndex, final long oldLength, final boolean strict) {
3122         if (longIndex > oldLength) {
3123             ArrayData array = getArray();
3124             if (array.canDelete(oldLength, longIndex - 1, strict)) {
3125                 array = array.delete(oldLength, longIndex - 1);
3126             }
3127             setArray(array);
3128         }
3129     }
3130 
3131     private void doesNotHave(final int index, final int value, final int callSiteFlags) {
3132         final long oldLength = getArray().length();
3133         final long longIndex = ArrayIndex.toLongIndex(index);
3134         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3135             final boolean strict = isStrictFlag(callSiteFlags);
3136             setArray(getArray().set(index, value, strict));
3137             doesNotHaveEnsureDelete(longIndex, oldLength, strict);
3138         }
3139     }
3140 
3141     private void doesNotHave(final int index, final long value, final int callSiteFlags) {
3142         final long oldLength = getArray().length();
3143         final long longIndex = ArrayIndex.toLongIndex(index);
3144         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3145             final boolean strict = isStrictFlag(callSiteFlags);
3146             setArray(getArray().set(index, value, strict));
3147             doesNotHaveEnsureDelete(longIndex, oldLength, strict);
3148         }
3149     }
3150 
3151     private void doesNotHave(final int index, final double value, final int callSiteFlags) {
3152         final long oldLength = getArray().length();
3153         final long longIndex = ArrayIndex.toLongIndex(index);
3154         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3155             final boolean strict = isStrictFlag(callSiteFlags);
3156             setArray(getArray().set(index, value, strict));
3157             doesNotHaveEnsureDelete(longIndex, oldLength, strict);
3158         }
3159     }
3160 
3161     private void doesNotHave(final int index, final Object value, final int callSiteFlags) {
3162         final long oldLength = getArray().length();
3163         final long longIndex = ArrayIndex.toLongIndex(index);
3164         if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3165             final boolean strict = isStrictFlag(callSiteFlags);
3166             setArray(getArray().set(index, value, strict));
3167             doesNotHaveEnsureDelete(longIndex, oldLength, strict);
3168         }
3169     }
3170 
3171     /**
3172      * This is the most generic of all Object setters. Most of the others use this in some form.
3173      * TODO: should be further specialized
3174      *
3175      * @param find          found property
3176      * @param callSiteFlags callsite flags
3177      * @param key           property key
3178      * @param value         property value
3179      */
3180     public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) {
3181         FindProperty f = find;
3182 
3183         invalidateGlobalConstant(key);
3184 
3185         if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
3186             final boolean isScope = isScopeFlag(callSiteFlags);
3187             // If the start object of the find is not this object it means the property was found inside a
3188             // 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
3189             // to the 'with' object.
3190             // Note that although a 'set' operation involving a with statement follows scope rules outside
3191             // the 'with' expression (the 'set' operation is performed on the owning prototype if it exists),
3192             // it follows non-scope rules inside the 'with' expression (set is performed on the top level object).
3193             // This is why we clear the callsite flags and FindProperty in the forward call to the 'with' object.
3194             if (isScope && f.getSelf() != this) {
3195                 f.getSelf().setObject(null, 0, key, value);
3196                 return;
3197             }
3198             // Setting a property should not modify the property in prototype unless this is a scope callsite
3199             // and the owner is a scope object as well (with the exception of 'with' statement handled above).
3200             if (!isScope || !f.getOwner().isScope()) {
3201                 f = null;
3202             }
3203         }
3204 
3205         if (f != null) {
3206             if (!f.getProperty().isWritable()) {
3207                 if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) {
3208                     throw typeError("assign.constant", key); // Overwriting ES6 const should throw also in non-strict mode.
3209                 }
3210                 if (isStrictFlag(callSiteFlags)) {
3211                     throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
3212                 }
3213                 return;
3214             }
3215 
3216             f.setValue(value, isStrictFlag(callSiteFlags));
3217 
3218         } else if (!isExtensible()) {
3219             if (isStrictFlag(callSiteFlags)) {
3220                 throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
3221             }
3222         } else {
3223             ScriptObject sobj = this;
3224             // undefined scope properties are set in the global object.
3225             if (isScope()) {
3226                 while (sobj != null && !(sobj instanceof Global)) {
3227                     sobj = sobj.getProto();
3228                 }
3229                 assert sobj != null : "no parent global object in scope";
3230             }
3231             //this will unbox any Number object to its primitive type in case the
3232             //property supports primitive types, so it doesn't matter that it comes
3233             //in as an Object.
3234             sobj.addSpillProperty(key, 0, value, true);
3235         }
3236     }
3237 
3238     @Override
3239     public void set(final Object key, final int value, final int callSiteFlags) {
3240         final Object primitiveKey = JSType.toPrimitive(key, String.class);
3241         final int    index        = getArrayIndex(primitiveKey);
3242 
3243         if (isValidArrayIndex(index)) {
3244             final ArrayData data = getArray();
3245             if (data.has(index)) {
3246                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3247             } else {
3248                 doesNotHave(index, value, callSiteFlags);
3249             }
3250 
3251             return;
3252         }
3253 
3254         final String propName = JSType.toString(primitiveKey);
3255         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3256     }
3257 
3258     @Override
3259     public void set(final Object key, final long value, final int callSiteFlags) {
3260         final Object primitiveKey = JSType.toPrimitive(key, String.class);
3261         final int    index        = getArrayIndex(primitiveKey);
3262 
3263         if (isValidArrayIndex(index)) {
3264             final ArrayData data = getArray();
3265             if (data.has(index)) {
3266                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3267             } else {
3268                 doesNotHave(index, value, callSiteFlags);
3269             }
3270 
3271             return;
3272         }
3273 
3274         final String propName = JSType.toString(primitiveKey);
3275         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3276     }
3277 
3278     @Override
3279     public void set(final Object key, final double value, final int callSiteFlags) {
3280         final Object primitiveKey = JSType.toPrimitive(key, String.class);
3281         final int    index        = getArrayIndex(primitiveKey);
3282 
3283         if (isValidArrayIndex(index)) {
3284             final ArrayData data = getArray();
3285             if (data.has(index)) {
3286                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3287             } else {
3288                 doesNotHave(index, value, callSiteFlags);
3289             }
3290 
3291             return;
3292         }
3293 
3294         final String propName = JSType.toString(primitiveKey);
3295         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3296     }
3297 
3298     @Override
3299     public void set(final Object key, final Object value, final int callSiteFlags) {
3300         final Object primitiveKey = JSType.toPrimitive(key, String.class);
3301         final int    index        = getArrayIndex(primitiveKey);
3302 
3303         if (isValidArrayIndex(index)) {
3304             final ArrayData data = getArray();
3305             if (data.has(index)) {
3306                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3307             } else {
3308                 doesNotHave(index, value, callSiteFlags);
3309             }
3310 
3311             return;
3312         }
3313 
3314         final String propName = JSType.toString(primitiveKey);
3315         setObject(findProperty(propName, true), callSiteFlags, propName, value);
3316     }
3317 
3318     @Override
3319     public void set(final double key, final int value, final int callSiteFlags) {
3320         final int index = getArrayIndex(key);
3321 
3322         if (isValidArrayIndex(index)) {
3323             final ArrayData data = getArray();
3324             if (data.has(index)) {
3325                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3326             } else {
3327                 doesNotHave(index, value, callSiteFlags);
3328             }
3329 
3330             return;
3331         }
3332 
3333         final String propName = JSType.toString(key);
3334         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3335     }
3336 
3337     @Override
3338     public void set(final double key, final long value, final int callSiteFlags) {
3339         final int index = getArrayIndex(key);
3340 
3341         if (isValidArrayIndex(index)) {
3342             final ArrayData data = getArray();
3343             if (data.has(index)) {
3344                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3345             } else {
3346                 doesNotHave(index, value, callSiteFlags);
3347             }
3348 
3349             return;
3350         }
3351 
3352         final String propName = JSType.toString(key);
3353         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3354     }
3355 
3356     @Override
3357     public void set(final double key, final double value, final int callSiteFlags) {
3358         final int index = getArrayIndex(key);
3359 
3360         if (isValidArrayIndex(index)) {
3361             final ArrayData data = getArray();
3362             if (data.has(index)) {
3363                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3364             } else {
3365                 doesNotHave(index, value, callSiteFlags);
3366             }
3367 
3368             return;
3369         }
3370 
3371         final String propName = JSType.toString(key);
3372         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3373     }
3374 
3375     @Override
3376     public void set(final double key, final Object value, final int callSiteFlags) {
3377         final int index = getArrayIndex(key);
3378 
3379         if (isValidArrayIndex(index)) {
3380             final ArrayData data = getArray();
3381             if (data.has(index)) {
3382                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3383             } else {
3384                 doesNotHave(index, value, callSiteFlags);
3385             }
3386 
3387             return;
3388         }
3389 
3390         final String propName = JSType.toString(key);
3391         setObject(findProperty(propName, true), callSiteFlags, propName, value);
3392     }
3393 
3394     @Override
3395     public void set(final long key, final int value, final int callSiteFlags) {
3396         final int index = getArrayIndex(key);
3397 
3398         if (isValidArrayIndex(index)) {
3399             final ArrayData data = getArray();
3400             if (data.has(index)) {
3401                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3402             } else {
3403                 doesNotHave(index, value, callSiteFlags);
3404             }
3405 
3406             return;
3407         }
3408 
3409         final String propName = JSType.toString(key);
3410         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3411     }
3412 
3413     @Override
3414     public void set(final long key, final long value, final int callSiteFlags) {
3415         final int index = getArrayIndex(key);
3416 
3417         if (isValidArrayIndex(index)) {
3418             final ArrayData data = getArray();
3419             if (data.has(index)) {
3420                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3421             } else {
3422                 doesNotHave(index, value, callSiteFlags);
3423             }
3424 
3425             return;
3426         }
3427 
3428         final String propName = JSType.toString(key);
3429         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3430     }
3431 
3432     @Override
3433     public void set(final long key, final double value, final int callSiteFlags) {
3434         final int index = getArrayIndex(key);
3435 
3436         if (isValidArrayIndex(index)) {
3437             final ArrayData data = getArray();
3438             if (data.has(index)) {
3439                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3440             } else {
3441                 doesNotHave(index, value, callSiteFlags);
3442             }
3443 
3444             return;
3445         }
3446 
3447         final String propName = JSType.toString(key);
3448         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3449     }
3450 
3451     @Override
3452     public void set(final long key, final Object value, final int callSiteFlags) {
3453         final int index = getArrayIndex(key);
3454 
3455         if (isValidArrayIndex(index)) {
3456             final ArrayData data = getArray();
3457             if (data.has(index)) {
3458                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3459             } else {
3460                 doesNotHave(index, value, callSiteFlags);
3461             }
3462 
3463             return;
3464         }
3465 
3466         final String propName = JSType.toString(key);
3467         setObject(findProperty(propName, true), callSiteFlags, propName, value);
3468     }
3469 
3470     @Override
3471     public void set(final int key, final int value, final int callSiteFlags) {
3472         final int index = getArrayIndex(key);
3473         if (isValidArrayIndex(index)) {
3474             if (getArray().has(index)) {
3475                 final ArrayData data = getArray();
3476                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3477             } else {
3478                 doesNotHave(index, value, callSiteFlags);
3479             }
3480             return;
3481         }
3482 
3483         final String propName = JSType.toString(key);
3484         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3485     }
3486 
3487     @Override
3488     public void set(final int key, final long value, final int callSiteFlags) {
3489         final int index = getArrayIndex(key);
3490 
3491         if (isValidArrayIndex(index)) {
3492             final ArrayData data = getArray();
3493             if (data.has(index)) {
3494                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3495             } else {
3496                 doesNotHave(index, value, callSiteFlags);
3497             }
3498 
3499             return;
3500         }
3501 
3502         final String propName = JSType.toString(key);
3503         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3504     }
3505 
3506     @Override
3507     public void set(final int key, final double value, final int callSiteFlags) {
3508         final int index = getArrayIndex(key);
3509 
3510         if (isValidArrayIndex(index)) {
3511             final ArrayData data = getArray();
3512             if (data.has(index)) {
3513                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3514             } else {
3515                 doesNotHave(index, value, callSiteFlags);
3516             }
3517 
3518             return;
3519         }
3520 
3521         final String propName = JSType.toString(key);
3522         setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3523     }
3524 
3525     @Override
3526     public void set(final int key, final Object value, final int callSiteFlags) {
3527         final int index = getArrayIndex(key);
3528 
3529         if (isValidArrayIndex(index)) {
3530             final ArrayData data = getArray();
3531             if (data.has(index)) {
3532                 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3533             } else {
3534                 doesNotHave(index, value, callSiteFlags);
3535             }
3536 
3537             return;
3538         }
3539 
3540         final String propName = JSType.toString(key);
3541         setObject(findProperty(propName, true), callSiteFlags, propName, value);
3542     }
3543 
3544     @Override
3545     public boolean has(final Object key) {
3546         final Object primitiveKey = JSType.toPrimitive(key);
3547         final int    index        = getArrayIndex(primitiveKey);
3548         return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), true);
3549     }
3550 
3551     @Override
3552     public boolean has(final double key) {


3674 
3675     private boolean deleteObject(final Object key, final boolean strict) {
3676         final String propName = JSType.toString(key);
3677         final FindProperty find = findProperty(propName, false);
3678 
3679         if (find == null) {
3680             return true;
3681         }
3682 
3683         if (!find.getProperty().isConfigurable()) {
3684             if (strict) {
3685                 throw typeError("cant.delete.property", propName, ScriptRuntime.safeToString(this));
3686             }
3687             return false;
3688         }
3689 
3690         final Property prop = find.getProperty();
3691         deleteOwnProperty(prop);
3692 
3693         return true;
3694     }
3695 
3696     /**
3697      * Return a shallow copy of this ScriptObject.
3698      * @return a shallow copy.
3699      */
3700     public final ScriptObject copy() {
3701         try {
3702             return clone();
3703         } catch (final CloneNotSupportedException e) {
3704             throw new RuntimeException(e);
3705         }
3706     }
3707 
3708     @Override
3709     protected ScriptObject clone() throws CloneNotSupportedException {
3710         final ScriptObject clone = (ScriptObject) super.clone();
3711         if (objectSpill != null) {
3712             clone.objectSpill = objectSpill.clone();
3713             clone.primitiveSpill = primitiveSpill.clone();
3714         }
3715         clone.arrayData = arrayData.copy();
3716         return clone;
3717     }
3718 
3719     /**
3720      * Make a new UserAccessorProperty property. getter and setter functions are stored in
3721      * this ScriptObject and slot values are used in property object.
3722      *
3723      * @param key the property name
3724      * @param propertyFlags attribute flags of the property
3725      * @param getter getter function for the property
3726      * @param setter setter function for the property
3727      * @return the newly created UserAccessorProperty
3728      */
3729     protected final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
3730         final UserAccessorProperty uc = getMap().newUserAccessors(key, propertyFlags);
3731         //property.getSetter(Object.class, getMap());
3732         uc.setAccessors(this, getMap(), new UserAccessorProperty.Accessors(getter, setter));
3733         return uc;
3734     }
3735 
3736     Object ensureSpillSize(final int slot) {