16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.runtime;
27
28 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
29 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
30 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
31 import static jdk.nashorn.internal.lookup.Lookup.MH;
32 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
33 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
34 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_DOUBLE;
35 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_INT;
36 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_LONG;
37 import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
38 import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
39 import static jdk.nashorn.internal.runtime.PropertyDescriptor.GET;
40 import static jdk.nashorn.internal.runtime.PropertyDescriptor.SET;
41 import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
42 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
43 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
44 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
45 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
46 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
47 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
48 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isScopeFlag;
49 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isStrictFlag;
50 import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
51
52 import java.lang.invoke.MethodHandle;
53 import java.lang.invoke.MethodHandles;
54 import java.lang.invoke.MethodType;
55 import java.lang.invoke.SwitchPoint;
56 import java.lang.reflect.Array;
171 public static final Call SET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class);
172
173 /** Method handle for getting the proto of a ScriptObject */
174 public static final Call GET_PROTO = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class);
175
176 /** Method handle for getting the proto of a ScriptObject */
177 public static final Call GET_PROTO_DEPTH = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class, int.class);
178
179 /** Method handle for setting the proto of a ScriptObject */
180 public static final Call SET_GLOBAL_OBJECT_PROTO = staticCallNoLookup(ScriptObject.class, "setGlobalObjectProto", void.class, ScriptObject.class);
181
182 /** Method handle for setting the proto of a ScriptObject after checking argument */
183 public static final Call SET_PROTO_FROM_LITERAL = virtualCallNoLookup(ScriptObject.class, "setProtoFromLiteral", void.class, Object.class);
184
185 /** Method handle for setting the user accessors of a ScriptObject */
186 //TODO fastpath this
187 public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class);
188
189 static final MethodHandle[] SET_SLOW = new MethodHandle[] {
190 findOwnMH_V("set", void.class, Object.class, int.class, int.class),
191 findOwnMH_V("set", void.class, Object.class, long.class, int.class),
192 findOwnMH_V("set", void.class, Object.class, double.class, int.class),
193 findOwnMH_V("set", void.class, Object.class, Object.class, int.class)
194 };
195
196 /** Method handle to reset the map of this ScriptObject */
197 public static final Call SET_MAP = virtualCallNoLookup(ScriptObject.class, "setMap", void.class, PropertyMap.class);
198
199 static final MethodHandle CAS_MAP = findOwnMH_V("compareAndSetMap", boolean.class, PropertyMap.class, PropertyMap.class);
200 static final MethodHandle EXTENSION_CHECK = findOwnMH_V("extensionCheck", boolean.class, boolean.class, String.class);
201 static final MethodHandle ENSURE_SPILL_SIZE = findOwnMH_V("ensureSpillSize", Object.class, int.class);
202
203 /**
204 * Constructor
205 */
206 public ScriptObject() {
207 this(null);
208 }
209
210 /**
211 * Constructor
1070 } else {
1071 addOwnProperty(newUserAccessors(key, oldProperty != null ? oldProperty.getFlags() : 0, getter, setter));
1072 }
1073 }
1074
1075 private static int getIntValue(final FindProperty find, final int programPoint) {
1076 final MethodHandle getter = find.getGetter(int.class, programPoint, null);
1077 if (getter != null) {
1078 try {
1079 return (int)getter.invokeExact((Object)find.getGetterReceiver());
1080 } catch (final Error|RuntimeException e) {
1081 throw e;
1082 } catch (final Throwable e) {
1083 throw new RuntimeException(e);
1084 }
1085 }
1086
1087 return UNDEFINED_INT;
1088 }
1089
1090 private static long getLongValue(final FindProperty find, final int programPoint) {
1091 final MethodHandle getter = find.getGetter(long.class, programPoint, null);
1092 if (getter != null) {
1093 try {
1094 return (long)getter.invokeExact((Object)find.getGetterReceiver());
1095 } catch (final Error|RuntimeException e) {
1096 throw e;
1097 } catch (final Throwable e) {
1098 throw new RuntimeException(e);
1099 }
1100 }
1101
1102 return UNDEFINED_LONG;
1103 }
1104
1105 private static double getDoubleValue(final FindProperty find, final int programPoint) {
1106 final MethodHandle getter = find.getGetter(double.class, programPoint, null);
1107 if (getter != null) {
1108 try {
1109 return (double)getter.invokeExact((Object)find.getGetterReceiver());
1110 } catch (final Error|RuntimeException e) {
1111 throw e;
1112 } catch (final Throwable e) {
1113 throw new RuntimeException(e);
1114 }
1115 }
1116
1117 return UNDEFINED_DOUBLE;
1118 }
1119
1120 /**
1121 * Return methodHandle of value function for call.
1122 *
1123 * @param find data from find property.
1124 * @param type method type of function.
2787 if (array.has(index)) {
2788 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2789 }
2790
2791 return getInt(index, JSType.toPropertyKey(primitiveKey), programPoint);
2792 }
2793
2794 @Override
2795 public int getInt(final double key, final int programPoint) {
2796 final int index = getArrayIndex(key);
2797 final ArrayData array = getArray();
2798
2799 if (array.has(index)) {
2800 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2801 }
2802
2803 return getInt(index, JSType.toString(key), programPoint);
2804 }
2805
2806 @Override
2807 public int getInt(final long key, final int programPoint) {
2808 final int index = getArrayIndex(key);
2809 final ArrayData array = getArray();
2810
2811 if (array.has(index)) {
2812 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2813 }
2814
2815 return getInt(index, JSType.toString(key), programPoint);
2816 }
2817
2818 @Override
2819 public int getInt(final int key, final int programPoint) {
2820 final int index = getArrayIndex(key);
2821 final ArrayData array = getArray();
2822
2823 if (array.has(index)) {
2824 return isValid(programPoint) ? array.getIntOptimistic(key, programPoint) : array.getInt(key);
2825 }
2826
2827 return getInt(index, JSType.toString(key), programPoint);
2828 }
2829
2830 private long getLong(final int index, final Object key, final int programPoint) {
2831 if (isValidArrayIndex(index)) {
2832 for (ScriptObject object = this; ; ) {
2833 if (object.getMap().containsArrayKeys()) {
2834 final FindProperty find = object.findProperty(key, false, this);
2835 if (find != null) {
2836 return getLongValue(find, programPoint);
2837 }
2838 }
2839
2840 if ((object = object.getProto()) == null) {
2841 break;
2842 }
2843
2844 final ArrayData array = object.getArray();
2845
2846 if (array.has(index)) {
2847 return isValid(programPoint) ?
2848 array.getLongOptimistic(index, programPoint) :
2849 array.getLong(index);
2850 }
2851 }
2852 } else {
2853 final FindProperty find = findProperty(key, true);
2854
2855 if (find != null) {
2856 return getLongValue(find, programPoint);
2857 }
2858 }
2859
2860 return JSType.toLong(invokeNoSuchProperty(key, false, programPoint));
2861 }
2862
2863 @Override
2864 public long getLong(final Object key, final int programPoint) {
2865 final Object primitiveKey = JSType.toPrimitive(key, String.class);
2866 final int index = getArrayIndex(primitiveKey);
2867 final ArrayData array = getArray();
2868
2869 if (array.has(index)) {
2870 return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
2871 }
2872
2873 return getLong(index, JSType.toPropertyKey(primitiveKey), programPoint);
2874 }
2875
2876 @Override
2877 public long getLong(final double key, final int programPoint) {
2878 final int index = getArrayIndex(key);
2879 final ArrayData array = getArray();
2880
2881 if (array.has(index)) {
2882 return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
2883 }
2884
2885 return getLong(index, JSType.toString(key), programPoint);
2886 }
2887
2888 @Override
2889 public long getLong(final long key, final int programPoint) {
2890 final int index = getArrayIndex(key);
2891 final ArrayData array = getArray();
2892
2893 if (array.has(index)) {
2894 return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
2895 }
2896
2897 return getLong(index, JSType.toString(key), programPoint);
2898 }
2899
2900 @Override
2901 public long getLong(final int key, final int programPoint) {
2902 final int index = getArrayIndex(key);
2903 final ArrayData array = getArray();
2904
2905 if (array.has(index)) {
2906 return isValid(programPoint) ? array.getLongOptimistic(key, programPoint) : array.getLong(key);
2907 }
2908
2909 return getLong(index, JSType.toString(key), programPoint);
2910 }
2911
2912 private double getDouble(final int index, final Object key, final int programPoint) {
2913 if (isValidArrayIndex(index)) {
2914 for (ScriptObject object = this; ; ) {
2915 if (object.getMap().containsArrayKeys()) {
2916 final FindProperty find = object.findProperty(key, false, this);
2917 if (find != null) {
2918 return getDoubleValue(find, programPoint);
2919 }
2920 }
2921
2922 if ((object = object.getProto()) == null) {
2923 break;
2924 }
2925
2926 final ArrayData array = object.getArray();
2927
2928 if (array.has(index)) {
2929 return isValid(programPoint) ?
2930 array.getDoubleOptimistic(index, programPoint) :
2931 array.getDouble(index);
2951 if (array.has(index)) {
2952 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2953 }
2954
2955 return getDouble(index, JSType.toPropertyKey(primitiveKey), programPoint);
2956 }
2957
2958 @Override
2959 public double getDouble(final double key, final int programPoint) {
2960 final int index = getArrayIndex(key);
2961 final ArrayData array = getArray();
2962
2963 if (array.has(index)) {
2964 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2965 }
2966
2967 return getDouble(index, JSType.toString(key), programPoint);
2968 }
2969
2970 @Override
2971 public double getDouble(final long key, final int programPoint) {
2972 final int index = getArrayIndex(key);
2973 final ArrayData array = getArray();
2974
2975 if (array.has(index)) {
2976 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2977 }
2978
2979 return getDouble(index, JSType.toString(key), programPoint);
2980 }
2981
2982 @Override
2983 public double getDouble(final int key, final int programPoint) {
2984 final int index = getArrayIndex(key);
2985 final ArrayData array = getArray();
2986
2987 if (array.has(index)) {
2988 return isValid(programPoint) ? array.getDoubleOptimistic(key, programPoint) : array.getDouble(key);
2989 }
2990
2991 return getDouble(index, JSType.toString(key), programPoint);
2992 }
2993
2994 private Object get(final int index, final Object key) {
2995 if (isValidArrayIndex(index)) {
2996 for (ScriptObject object = this; ; ) {
2997 if (object.getMap().containsArrayKeys()) {
2998 final FindProperty find = object.findProperty(key, false, this);
2999
3000 if (find != null) {
3001 return find.getObjectValue();
3002 }
3032 if (array.has(index)) {
3033 return array.getObject(index);
3034 }
3035
3036 return get(index, JSType.toPropertyKey(primitiveKey));
3037 }
3038
3039 @Override
3040 public Object get(final double key) {
3041 final int index = getArrayIndex(key);
3042 final ArrayData array = getArray();
3043
3044 if (array.has(index)) {
3045 return array.getObject(index);
3046 }
3047
3048 return get(index, JSType.toString(key));
3049 }
3050
3051 @Override
3052 public Object get(final long key) {
3053 final int index = getArrayIndex(key);
3054 final ArrayData array = getArray();
3055
3056 if (array.has(index)) {
3057 return array.getObject(index);
3058 }
3059
3060 return get(index, JSType.toString(key));
3061 }
3062
3063 @Override
3064 public Object get(final int key) {
3065 final int index = getArrayIndex(key);
3066 final ArrayData array = getArray();
3067
3068 if (array.has(index)) {
3069 return array.getObject(index);
3070 }
3071
3072 return get(index, JSType.toString(key));
3073 }
3074
3075 private boolean doesNotHaveCheckArrayKeys(final long longIndex, final int value, final int callSiteFlags) {
3076 if (getMap().containsArrayKeys()) {
3077 final String key = JSType.toString(longIndex);
3078 final FindProperty find = findProperty(key, true);
3079 if (find != null) {
3080 setObject(find, callSiteFlags, key, value);
3081 return true;
3082 }
3083 }
3126 if (!isExtensible()) {
3127 if (isStrictFlag(callSiteFlags)) {
3128 throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
3129 }
3130 return true;
3131 }
3132 setArray(getArray().ensure(longIndex));
3133 }
3134 return false;
3135 }
3136
3137 private void doesNotHave(final int index, final int value, final int callSiteFlags) {
3138 final long oldLength = getArray().length();
3139 final long longIndex = ArrayIndex.toLongIndex(index);
3140 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3141 final boolean strict = isStrictFlag(callSiteFlags);
3142 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3143 }
3144 }
3145
3146 private void doesNotHave(final int index, final long 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 = isStrictFlag(callSiteFlags);
3151 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3152 }
3153 }
3154
3155 private void doesNotHave(final int index, final double value, final int callSiteFlags) {
3156 final long oldLength = getArray().length();
3157 final long longIndex = ArrayIndex.toLongIndex(index);
3158 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3159 final boolean strict = isStrictFlag(callSiteFlags);
3160 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3161 }
3162 }
3163
3164 private void doesNotHave(final int index, final Object value, final int callSiteFlags) {
3165 final long oldLength = getArray().length();
3166 final long longIndex = ArrayIndex.toLongIndex(index);
3167 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3168 final boolean strict = isStrictFlag(callSiteFlags);
3169 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3170 }
3171 }
3172
3173 /**
3174 * This is the most generic of all Object setters. Most of the others use this in some form.
3241 public void set(final Object key, final int value, final int callSiteFlags) {
3242 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3243 final int index = getArrayIndex(primitiveKey);
3244
3245 if (isValidArrayIndex(index)) {
3246 final ArrayData data = getArray();
3247 if (data.has(index)) {
3248 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3249 } else {
3250 doesNotHave(index, value, callSiteFlags);
3251 }
3252
3253 return;
3254 }
3255
3256 final Object propName = JSType.toPropertyKey(primitiveKey);
3257 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3258 }
3259
3260 @Override
3261 public void set(final Object key, final long value, final int callSiteFlags) {
3262 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3263 final int index = getArrayIndex(primitiveKey);
3264
3265 if (isValidArrayIndex(index)) {
3266 final ArrayData data = getArray();
3267 if (data.has(index)) {
3268 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3269 } else {
3270 doesNotHave(index, value, callSiteFlags);
3271 }
3272
3273 return;
3274 }
3275
3276 final Object propName = JSType.toPropertyKey(primitiveKey);
3277 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3278 }
3279
3280 @Override
3281 public void set(final Object key, final double value, final int callSiteFlags) {
3282 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3283 final int index = getArrayIndex(primitiveKey);
3284
3285 if (isValidArrayIndex(index)) {
3286 final ArrayData data = getArray();
3287 if (data.has(index)) {
3288 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3289 } else {
3290 doesNotHave(index, value, callSiteFlags);
3291 }
3292
3293 return;
3294 }
3295
3296 final Object propName = JSType.toPropertyKey(primitiveKey);
3297 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3298 }
3299
3300 @Override
3320 @Override
3321 public void set(final double key, final int value, final int callSiteFlags) {
3322 final int index = getArrayIndex(key);
3323
3324 if (isValidArrayIndex(index)) {
3325 final ArrayData data = getArray();
3326 if (data.has(index)) {
3327 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3328 } else {
3329 doesNotHave(index, value, callSiteFlags);
3330 }
3331
3332 return;
3333 }
3334
3335 final String propName = JSType.toString(key);
3336 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3337 }
3338
3339 @Override
3340 public void set(final double key, final long value, final int callSiteFlags) {
3341 final int index = getArrayIndex(key);
3342
3343 if (isValidArrayIndex(index)) {
3344 final ArrayData data = getArray();
3345 if (data.has(index)) {
3346 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3347 } else {
3348 doesNotHave(index, value, callSiteFlags);
3349 }
3350
3351 return;
3352 }
3353
3354 final String propName = JSType.toString(key);
3355 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3356 }
3357
3358 @Override
3359 public void set(final double key, final double value, final int callSiteFlags) {
3360 final int index = getArrayIndex(key);
3361
3362 if (isValidArrayIndex(index)) {
3363 final ArrayData data = getArray();
3364 if (data.has(index)) {
3365 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3366 } else {
3367 doesNotHave(index, value, callSiteFlags);
3368 }
3369
3370 return;
3371 }
3372
3373 final String propName = JSType.toString(key);
3374 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3375 }
3376
3377 @Override
3378 public void set(final double key, final Object value, final int callSiteFlags) {
3379 final int index = getArrayIndex(key);
3380
3381 if (isValidArrayIndex(index)) {
3382 final ArrayData data = getArray();
3383 if (data.has(index)) {
3384 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3385 } else {
3386 doesNotHave(index, value, callSiteFlags);
3387 }
3388
3389 return;
3390 }
3391
3392 final String propName = JSType.toString(key);
3393 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3394 }
3395
3396 @Override
3397 public void set(final long key, final int value, final int callSiteFlags) {
3398 final int index = getArrayIndex(key);
3399
3400 if (isValidArrayIndex(index)) {
3401 final ArrayData data = getArray();
3402 if (data.has(index)) {
3403 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3404 } else {
3405 doesNotHave(index, value, callSiteFlags);
3406 }
3407
3408 return;
3409 }
3410
3411 final String propName = JSType.toString(key);
3412 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3413 }
3414
3415 @Override
3416 public void set(final long key, final long value, final int callSiteFlags) {
3417 final int index = getArrayIndex(key);
3418
3419 if (isValidArrayIndex(index)) {
3420 final ArrayData data = getArray();
3421 if (data.has(index)) {
3422 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3423 } else {
3424 doesNotHave(index, value, callSiteFlags);
3425 }
3426
3427 return;
3428 }
3429
3430 final String propName = JSType.toString(key);
3431 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3432 }
3433
3434 @Override
3435 public void set(final long key, final double value, final int callSiteFlags) {
3436 final int index = getArrayIndex(key);
3437
3438 if (isValidArrayIndex(index)) {
3439 final ArrayData data = getArray();
3440 if (data.has(index)) {
3441 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3442 } else {
3443 doesNotHave(index, value, callSiteFlags);
3444 }
3445
3446 return;
3447 }
3448
3449 final String propName = JSType.toString(key);
3450 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3451 }
3452
3453 @Override
3454 public void set(final long key, final Object value, final int callSiteFlags) {
3455 final int index = getArrayIndex(key);
3456
3457 if (isValidArrayIndex(index)) {
3458 final ArrayData data = getArray();
3459 if (data.has(index)) {
3460 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3461 } else {
3462 doesNotHave(index, value, callSiteFlags);
3463 }
3464
3465 return;
3466 }
3467
3468 final String propName = JSType.toString(key);
3469 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3470 }
3471
3472 @Override
3473 public void set(final int key, final int value, final int callSiteFlags) {
3474 final int index = getArrayIndex(key);
3475 if (isValidArrayIndex(index)) {
3476 if (getArray().has(index)) {
3477 final ArrayData data = getArray();
3478 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3479 } else {
3480 doesNotHave(index, value, callSiteFlags);
3481 }
3482 return;
3483 }
3484
3485 final String propName = JSType.toString(key);
3486 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3487 }
3488
3489 @Override
3490 public void set(final int key, final long value, final int callSiteFlags) {
3491 final int index = getArrayIndex(key);
3492
3493 if (isValidArrayIndex(index)) {
3494 final ArrayData data = getArray();
3495 if (data.has(index)) {
3496 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3497 } else {
3498 doesNotHave(index, value, callSiteFlags);
3499 }
3500
3501 return;
3502 }
3503
3504 final String propName = JSType.toString(key);
3505 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3506 }
3507
3508 @Override
3509 public void set(final int key, final double value, final int callSiteFlags) {
3510 final int index = getArrayIndex(key);
3511
3512 if (isValidArrayIndex(index)) {
3513 final ArrayData data = getArray();
3514 if (data.has(index)) {
3515 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3516 } else {
3517 doesNotHave(index, value, callSiteFlags);
3518 }
3519
3520 return;
3521 }
3522
3523 final String propName = JSType.toString(key);
3524 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3525 }
3526
3527 @Override
3528 public void set(final int key, final Object value, final int callSiteFlags) {
3540 }
3541
3542 final String propName = JSType.toString(key);
3543 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3544 }
3545
3546 @Override
3547 public boolean has(final Object key) {
3548 final Object primitiveKey = JSType.toPrimitive(key);
3549 final int index = getArrayIndex(primitiveKey);
3550 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toPropertyKey(primitiveKey), true);
3551 }
3552
3553 @Override
3554 public boolean has(final double key) {
3555 final int index = getArrayIndex(key);
3556 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3557 }
3558
3559 @Override
3560 public boolean has(final long key) {
3561 final int index = getArrayIndex(key);
3562 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3563 }
3564
3565 @Override
3566 public boolean has(final int key) {
3567 final int index = getArrayIndex(key);
3568 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3569 }
3570
3571 private boolean hasArrayProperty(final int index) {
3572 boolean hasArrayKeys = false;
3573
3574 for (ScriptObject self = this; self != null; self = self.getProto()) {
3575 if (self.getArray().has(index)) {
3576 return true;
3577 }
3578 hasArrayKeys = hasArrayKeys || self.getMap().containsArrayKeys();
3579 }
3580
3581 return hasArrayKeys && hasProperty(ArrayIndex.toKey(index), true);
3582 }
3583
3584 @Override
3585 public boolean hasOwnProperty(final Object key) {
3586 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3587 final int index = getArrayIndex(primitiveKey);
3588 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toPropertyKey(primitiveKey), false);
3589 }
3590
3591 @Override
3592 public boolean hasOwnProperty(final int key) {
3593 final int index = getArrayIndex(key);
3594 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3595 }
3596
3597 @Override
3598 public boolean hasOwnProperty(final long key) {
3599 final int index = getArrayIndex(key);
3600 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3601 }
3602
3603 @Override
3604 public boolean hasOwnProperty(final double key) {
3605 final int index = getArrayIndex(key);
3606 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3607 }
3608
3609 private boolean hasOwnArrayProperty(final int index) {
3610 return getArray().has(index) || getMap().containsArrayKeys() && hasProperty(ArrayIndex.toKey(index), false);
3611 }
3612
3613 @Override
3614 public boolean delete(final int key, final boolean strict) {
3615 final int index = getArrayIndex(key);
3616 final ArrayData array = getArray();
3617
3618 if (array.has(index)) {
3619 if (array.canDelete(index, strict)) {
3620 setArray(array.delete(index));
3621 return true;
3622 }
3623 return false;
3624 }
3625 return deleteObject(JSType.toObject(key), strict);
3626 }
3627
3628 @Override
3629 public boolean delete(final long key, final boolean strict) {
3630 final int index = getArrayIndex(key);
3631 final ArrayData array = getArray();
3632
3633 if (array.has(index)) {
3634 if (array.canDelete(index, strict)) {
3635 setArray(array.delete(index));
3636 return true;
3637 }
3638 return false;
3639 }
3640
3641 return deleteObject(JSType.toObject(key), strict);
3642 }
3643
3644 @Override
3645 public boolean delete(final double key, final boolean strict) {
3646 final int index = getArrayIndex(key);
3647 final ArrayData array = getArray();
3648
3649 if (array.has(index)) {
3650 if (array.canDelete(index, strict)) {
3651 setArray(array.delete(index));
3652 return true;
3653 }
3654 return false;
3655 }
3656
3657 return deleteObject(JSType.toObject(key), strict);
3658 }
3659
3660 @Override
|
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.runtime;
27
28 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
29 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
30 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
31 import static jdk.nashorn.internal.lookup.Lookup.MH;
32 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
33 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
34 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_DOUBLE;
35 import static jdk.nashorn.internal.runtime.JSType.UNDEFINED_INT;
36 import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
37 import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
38 import static jdk.nashorn.internal.runtime.PropertyDescriptor.GET;
39 import static jdk.nashorn.internal.runtime.PropertyDescriptor.SET;
40 import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
41 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
42 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
43 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
44 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
45 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
46 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
47 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isScopeFlag;
48 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isStrictFlag;
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.lang.reflect.Array;
170 public static final Call SET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class);
171
172 /** Method handle for getting the proto of a ScriptObject */
173 public static final Call GET_PROTO = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class);
174
175 /** Method handle for getting the proto of a ScriptObject */
176 public static final Call GET_PROTO_DEPTH = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class, int.class);
177
178 /** Method handle for setting the proto of a ScriptObject */
179 public static final Call SET_GLOBAL_OBJECT_PROTO = staticCallNoLookup(ScriptObject.class, "setGlobalObjectProto", void.class, ScriptObject.class);
180
181 /** Method handle for setting the proto of a ScriptObject after checking argument */
182 public static final Call SET_PROTO_FROM_LITERAL = virtualCallNoLookup(ScriptObject.class, "setProtoFromLiteral", void.class, Object.class);
183
184 /** Method handle for setting the user accessors of a ScriptObject */
185 //TODO fastpath this
186 public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class);
187
188 static final MethodHandle[] SET_SLOW = new MethodHandle[] {
189 findOwnMH_V("set", void.class, Object.class, int.class, int.class),
190 findOwnMH_V("set", void.class, Object.class, double.class, int.class),
191 findOwnMH_V("set", void.class, Object.class, Object.class, int.class)
192 };
193
194 /** Method handle to reset the map of this ScriptObject */
195 public static final Call SET_MAP = virtualCallNoLookup(ScriptObject.class, "setMap", void.class, PropertyMap.class);
196
197 static final MethodHandle CAS_MAP = findOwnMH_V("compareAndSetMap", boolean.class, PropertyMap.class, PropertyMap.class);
198 static final MethodHandle EXTENSION_CHECK = findOwnMH_V("extensionCheck", boolean.class, boolean.class, String.class);
199 static final MethodHandle ENSURE_SPILL_SIZE = findOwnMH_V("ensureSpillSize", Object.class, int.class);
200
201 /**
202 * Constructor
203 */
204 public ScriptObject() {
205 this(null);
206 }
207
208 /**
209 * Constructor
1068 } else {
1069 addOwnProperty(newUserAccessors(key, oldProperty != null ? oldProperty.getFlags() : 0, getter, setter));
1070 }
1071 }
1072
1073 private static int getIntValue(final FindProperty find, final int programPoint) {
1074 final MethodHandle getter = find.getGetter(int.class, programPoint, null);
1075 if (getter != null) {
1076 try {
1077 return (int)getter.invokeExact((Object)find.getGetterReceiver());
1078 } catch (final Error|RuntimeException e) {
1079 throw e;
1080 } catch (final Throwable e) {
1081 throw new RuntimeException(e);
1082 }
1083 }
1084
1085 return UNDEFINED_INT;
1086 }
1087
1088 private static double getDoubleValue(final FindProperty find, final int programPoint) {
1089 final MethodHandle getter = find.getGetter(double.class, programPoint, null);
1090 if (getter != null) {
1091 try {
1092 return (double)getter.invokeExact((Object)find.getGetterReceiver());
1093 } catch (final Error|RuntimeException e) {
1094 throw e;
1095 } catch (final Throwable e) {
1096 throw new RuntimeException(e);
1097 }
1098 }
1099
1100 return UNDEFINED_DOUBLE;
1101 }
1102
1103 /**
1104 * Return methodHandle of value function for call.
1105 *
1106 * @param find data from find property.
1107 * @param type method type of function.
2770 if (array.has(index)) {
2771 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2772 }
2773
2774 return getInt(index, JSType.toPropertyKey(primitiveKey), programPoint);
2775 }
2776
2777 @Override
2778 public int getInt(final double key, final int programPoint) {
2779 final int index = getArrayIndex(key);
2780 final ArrayData array = getArray();
2781
2782 if (array.has(index)) {
2783 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2784 }
2785
2786 return getInt(index, JSType.toString(key), programPoint);
2787 }
2788
2789 @Override
2790 public int getInt(final int key, final int programPoint) {
2791 final int index = getArrayIndex(key);
2792 final ArrayData array = getArray();
2793
2794 if (array.has(index)) {
2795 return isValid(programPoint) ? array.getIntOptimistic(key, programPoint) : array.getInt(key);
2796 }
2797
2798 return getInt(index, JSType.toString(key), programPoint);
2799 }
2800
2801 private double getDouble(final int index, final Object key, final int programPoint) {
2802 if (isValidArrayIndex(index)) {
2803 for (ScriptObject object = this; ; ) {
2804 if (object.getMap().containsArrayKeys()) {
2805 final FindProperty find = object.findProperty(key, false, this);
2806 if (find != null) {
2807 return getDoubleValue(find, programPoint);
2808 }
2809 }
2810
2811 if ((object = object.getProto()) == null) {
2812 break;
2813 }
2814
2815 final ArrayData array = object.getArray();
2816
2817 if (array.has(index)) {
2818 return isValid(programPoint) ?
2819 array.getDoubleOptimistic(index, programPoint) :
2820 array.getDouble(index);
2840 if (array.has(index)) {
2841 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2842 }
2843
2844 return getDouble(index, JSType.toPropertyKey(primitiveKey), programPoint);
2845 }
2846
2847 @Override
2848 public double getDouble(final double key, final int programPoint) {
2849 final int index = getArrayIndex(key);
2850 final ArrayData array = getArray();
2851
2852 if (array.has(index)) {
2853 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2854 }
2855
2856 return getDouble(index, JSType.toString(key), programPoint);
2857 }
2858
2859 @Override
2860 public double getDouble(final int key, final int programPoint) {
2861 final int index = getArrayIndex(key);
2862 final ArrayData array = getArray();
2863
2864 if (array.has(index)) {
2865 return isValid(programPoint) ? array.getDoubleOptimistic(key, programPoint) : array.getDouble(key);
2866 }
2867
2868 return getDouble(index, JSType.toString(key), programPoint);
2869 }
2870
2871 private Object get(final int index, final Object key) {
2872 if (isValidArrayIndex(index)) {
2873 for (ScriptObject object = this; ; ) {
2874 if (object.getMap().containsArrayKeys()) {
2875 final FindProperty find = object.findProperty(key, false, this);
2876
2877 if (find != null) {
2878 return find.getObjectValue();
2879 }
2909 if (array.has(index)) {
2910 return array.getObject(index);
2911 }
2912
2913 return get(index, JSType.toPropertyKey(primitiveKey));
2914 }
2915
2916 @Override
2917 public Object get(final double key) {
2918 final int index = getArrayIndex(key);
2919 final ArrayData array = getArray();
2920
2921 if (array.has(index)) {
2922 return array.getObject(index);
2923 }
2924
2925 return get(index, JSType.toString(key));
2926 }
2927
2928 @Override
2929 public Object get(final int key) {
2930 final int index = getArrayIndex(key);
2931 final ArrayData array = getArray();
2932
2933 if (array.has(index)) {
2934 return array.getObject(index);
2935 }
2936
2937 return get(index, JSType.toString(key));
2938 }
2939
2940 private boolean doesNotHaveCheckArrayKeys(final long longIndex, final int value, final int callSiteFlags) {
2941 if (getMap().containsArrayKeys()) {
2942 final String key = JSType.toString(longIndex);
2943 final FindProperty find = findProperty(key, true);
2944 if (find != null) {
2945 setObject(find, callSiteFlags, key, value);
2946 return true;
2947 }
2948 }
2991 if (!isExtensible()) {
2992 if (isStrictFlag(callSiteFlags)) {
2993 throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
2994 }
2995 return true;
2996 }
2997 setArray(getArray().ensure(longIndex));
2998 }
2999 return false;
3000 }
3001
3002 private void doesNotHave(final int index, final int value, final int callSiteFlags) {
3003 final long oldLength = getArray().length();
3004 final long longIndex = ArrayIndex.toLongIndex(index);
3005 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3006 final boolean strict = isStrictFlag(callSiteFlags);
3007 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3008 }
3009 }
3010
3011 private void doesNotHave(final int index, final double value, final int callSiteFlags) {
3012 final long oldLength = getArray().length();
3013 final long longIndex = ArrayIndex.toLongIndex(index);
3014 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3015 final boolean strict = isStrictFlag(callSiteFlags);
3016 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3017 }
3018 }
3019
3020 private void doesNotHave(final int index, final Object value, final int callSiteFlags) {
3021 final long oldLength = getArray().length();
3022 final long longIndex = ArrayIndex.toLongIndex(index);
3023 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3024 final boolean strict = isStrictFlag(callSiteFlags);
3025 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3026 }
3027 }
3028
3029 /**
3030 * This is the most generic of all Object setters. Most of the others use this in some form.
3097 public void set(final Object key, final int value, final int callSiteFlags) {
3098 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3099 final int index = getArrayIndex(primitiveKey);
3100
3101 if (isValidArrayIndex(index)) {
3102 final ArrayData data = getArray();
3103 if (data.has(index)) {
3104 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3105 } else {
3106 doesNotHave(index, value, callSiteFlags);
3107 }
3108
3109 return;
3110 }
3111
3112 final Object propName = JSType.toPropertyKey(primitiveKey);
3113 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3114 }
3115
3116 @Override
3117 public void set(final Object key, final double value, final int callSiteFlags) {
3118 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3119 final int index = getArrayIndex(primitiveKey);
3120
3121 if (isValidArrayIndex(index)) {
3122 final ArrayData data = getArray();
3123 if (data.has(index)) {
3124 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3125 } else {
3126 doesNotHave(index, value, callSiteFlags);
3127 }
3128
3129 return;
3130 }
3131
3132 final Object propName = JSType.toPropertyKey(primitiveKey);
3133 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3134 }
3135
3136 @Override
3156 @Override
3157 public void set(final double key, final int value, final int callSiteFlags) {
3158 final int index = getArrayIndex(key);
3159
3160 if (isValidArrayIndex(index)) {
3161 final ArrayData data = getArray();
3162 if (data.has(index)) {
3163 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3164 } else {
3165 doesNotHave(index, value, callSiteFlags);
3166 }
3167
3168 return;
3169 }
3170
3171 final String propName = JSType.toString(key);
3172 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3173 }
3174
3175 @Override
3176 public void set(final double key, final double value, final int callSiteFlags) {
3177 final int index = getArrayIndex(key);
3178
3179 if (isValidArrayIndex(index)) {
3180 final ArrayData data = getArray();
3181 if (data.has(index)) {
3182 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3183 } else {
3184 doesNotHave(index, value, callSiteFlags);
3185 }
3186
3187 return;
3188 }
3189
3190 final String propName = JSType.toString(key);
3191 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3192 }
3193
3194 @Override
3195 public void set(final double key, final Object value, final int callSiteFlags) {
3196 final int index = getArrayIndex(key);
3197
3198 if (isValidArrayIndex(index)) {
3199 final ArrayData data = getArray();
3200 if (data.has(index)) {
3201 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3202 } else {
3203 doesNotHave(index, value, callSiteFlags);
3204 }
3205
3206 return;
3207 }
3208
3209 final String propName = JSType.toString(key);
3210 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3211 }
3212
3213 @Override
3214 public void set(final int key, final int value, final int callSiteFlags) {
3215 final int index = getArrayIndex(key);
3216 if (isValidArrayIndex(index)) {
3217 if (getArray().has(index)) {
3218 final ArrayData data = getArray();
3219 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3220 } else {
3221 doesNotHave(index, value, callSiteFlags);
3222 }
3223 return;
3224 }
3225
3226 final String propName = JSType.toString(key);
3227 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3228 }
3229
3230 @Override
3231 public void set(final int key, final double value, final int callSiteFlags) {
3232 final int index = getArrayIndex(key);
3233
3234 if (isValidArrayIndex(index)) {
3235 final ArrayData data = getArray();
3236 if (data.has(index)) {
3237 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3238 } else {
3239 doesNotHave(index, value, callSiteFlags);
3240 }
3241
3242 return;
3243 }
3244
3245 final String propName = JSType.toString(key);
3246 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3247 }
3248
3249 @Override
3250 public void set(final int key, final Object value, final int callSiteFlags) {
3262 }
3263
3264 final String propName = JSType.toString(key);
3265 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3266 }
3267
3268 @Override
3269 public boolean has(final Object key) {
3270 final Object primitiveKey = JSType.toPrimitive(key);
3271 final int index = getArrayIndex(primitiveKey);
3272 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toPropertyKey(primitiveKey), true);
3273 }
3274
3275 @Override
3276 public boolean has(final double key) {
3277 final int index = getArrayIndex(key);
3278 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3279 }
3280
3281 @Override
3282 public boolean has(final int key) {
3283 final int index = getArrayIndex(key);
3284 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3285 }
3286
3287 private boolean hasArrayProperty(final int index) {
3288 boolean hasArrayKeys = false;
3289
3290 for (ScriptObject self = this; self != null; self = self.getProto()) {
3291 if (self.getArray().has(index)) {
3292 return true;
3293 }
3294 hasArrayKeys = hasArrayKeys || self.getMap().containsArrayKeys();
3295 }
3296
3297 return hasArrayKeys && hasProperty(ArrayIndex.toKey(index), true);
3298 }
3299
3300 @Override
3301 public boolean hasOwnProperty(final Object key) {
3302 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3303 final int index = getArrayIndex(primitiveKey);
3304 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toPropertyKey(primitiveKey), false);
3305 }
3306
3307 @Override
3308 public boolean hasOwnProperty(final int key) {
3309 final int index = getArrayIndex(key);
3310 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3311 }
3312
3313 @Override
3314 public boolean hasOwnProperty(final double key) {
3315 final int index = getArrayIndex(key);
3316 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3317 }
3318
3319 private boolean hasOwnArrayProperty(final int index) {
3320 return getArray().has(index) || getMap().containsArrayKeys() && hasProperty(ArrayIndex.toKey(index), false);
3321 }
3322
3323 @Override
3324 public boolean delete(final int key, final boolean strict) {
3325 final int index = getArrayIndex(key);
3326 final ArrayData array = getArray();
3327
3328 if (array.has(index)) {
3329 if (array.canDelete(index, strict)) {
3330 setArray(array.delete(index));
3331 return true;
3332 }
3333 return false;
3334 }
3335 return deleteObject(JSType.toObject(key), strict);
3336 }
3337
3338 @Override
3339 public boolean delete(final double key, final boolean strict) {
3340 final int index = getArrayIndex(key);
3341 final ArrayData array = getArray();
3342
3343 if (array.has(index)) {
3344 if (array.canDelete(index, strict)) {
3345 setArray(array.delete(index));
3346 return true;
3347 }
3348 return false;
3349 }
3350
3351 return deleteObject(JSType.toObject(key), strict);
3352 }
3353
3354 @Override
|