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) {
|