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.util.AbstractMap;
169 public static final Call SET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class);
170
171 /** Method handle for getting the proto of a ScriptObject */
172 public static final Call GET_PROTO = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class);
173
174 /** Method handle for getting the proto of a ScriptObject */
175 public static final Call GET_PROTO_DEPTH = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class, int.class);
176
177 /** Method handle for setting the proto of a ScriptObject */
178 public static final Call SET_GLOBAL_OBJECT_PROTO = staticCallNoLookup(ScriptObject.class, "setGlobalObjectProto", void.class, ScriptObject.class);
179
180 /** Method handle for setting the proto of a ScriptObject after checking argument */
181 public static final Call SET_PROTO_FROM_LITERAL = virtualCallNoLookup(ScriptObject.class, "setProtoFromLiteral", void.class, Object.class);
182
183 /** Method handle for setting the user accessors of a ScriptObject */
184 //TODO fastpath this
185 public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class);
186
187 static final MethodHandle[] SET_SLOW = new MethodHandle[] {
188 findOwnMH_V("set", void.class, Object.class, int.class, int.class),
189 findOwnMH_V("set", void.class, Object.class, long.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
1069 } else {
1070 addOwnProperty(newUserAccessors(key, oldProperty != null ? oldProperty.getFlags() : 0, getter, setter));
1071 }
1072 }
1073
1074 private static int getIntValue(final FindProperty find, final int programPoint) {
1075 final MethodHandle getter = find.getGetter(int.class, programPoint, null);
1076 if (getter != null) {
1077 try {
1078 return (int)getter.invokeExact((Object)find.getGetterReceiver());
1079 } catch (final Error|RuntimeException e) {
1080 throw e;
1081 } catch (final Throwable e) {
1082 throw new RuntimeException(e);
1083 }
1084 }
1085
1086 return UNDEFINED_INT;
1087 }
1088
1089 private static long getLongValue(final FindProperty find, final int programPoint) {
1090 final MethodHandle getter = find.getGetter(long.class, programPoint, null);
1091 if (getter != null) {
1092 try {
1093 return (long)getter.invokeExact((Object)find.getGetterReceiver());
1094 } catch (final Error|RuntimeException e) {
1095 throw e;
1096 } catch (final Throwable e) {
1097 throw new RuntimeException(e);
1098 }
1099 }
1100
1101 return UNDEFINED_LONG;
1102 }
1103
1104 private static double getDoubleValue(final FindProperty find, final int programPoint) {
1105 final MethodHandle getter = find.getGetter(double.class, programPoint, null);
1106 if (getter != null) {
1107 try {
1108 return (double)getter.invokeExact((Object)find.getGetterReceiver());
1109 } catch (final Error|RuntimeException e) {
1110 throw e;
1111 } catch (final Throwable e) {
1112 throw new RuntimeException(e);
1113 }
1114 }
1115
1116 return UNDEFINED_DOUBLE;
1117 }
1118
1119 /**
1120 * Return methodHandle of value function for call.
1121 *
1122 * @param find data from find property.
1123 * @param type method type of function.
2751 if (array.has(index)) {
2752 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2753 }
2754
2755 return getInt(index, JSType.toString(primitiveKey), programPoint);
2756 }
2757
2758 @Override
2759 public int getInt(final double key, final int programPoint) {
2760 final int index = getArrayIndex(key);
2761 final ArrayData array = getArray();
2762
2763 if (array.has(index)) {
2764 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2765 }
2766
2767 return getInt(index, JSType.toString(key), programPoint);
2768 }
2769
2770 @Override
2771 public int getInt(final long key, final int programPoint) {
2772 final int index = getArrayIndex(key);
2773 final ArrayData array = getArray();
2774
2775 if (array.has(index)) {
2776 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2777 }
2778
2779 return getInt(index, JSType.toString(key), programPoint);
2780 }
2781
2782 @Override
2783 public int getInt(final int key, final int programPoint) {
2784 final int index = getArrayIndex(key);
2785 final ArrayData array = getArray();
2786
2787 if (array.has(index)) {
2788 return isValid(programPoint) ? array.getIntOptimistic(key, programPoint) : array.getInt(key);
2789 }
2790
2791 return getInt(index, JSType.toString(key), programPoint);
2792 }
2793
2794 private long getLong(final int index, final String key, final int programPoint) {
2795 if (isValidArrayIndex(index)) {
2796 for (ScriptObject object = this; ; ) {
2797 if (object.getMap().containsArrayKeys()) {
2798 final FindProperty find = object.findProperty(key, false, this);
2799 if (find != null) {
2800 return getLongValue(find, programPoint);
2801 }
2802 }
2803
2804 if ((object = object.getProto()) == null) {
2805 break;
2806 }
2807
2808 final ArrayData array = object.getArray();
2809
2810 if (array.has(index)) {
2811 return isValid(programPoint) ?
2812 array.getLongOptimistic(index, programPoint) :
2813 array.getLong(index);
2814 }
2815 }
2816 } else {
2817 final FindProperty find = findProperty(key, true);
2818
2819 if (find != null) {
2820 return getLongValue(find, programPoint);
2821 }
2822 }
2823
2824 return JSType.toLong(invokeNoSuchProperty(key, false, programPoint));
2825 }
2826
2827 @Override
2828 public long getLong(final Object key, final int programPoint) {
2829 final Object primitiveKey = JSType.toPrimitive(key, String.class);
2830 final int index = getArrayIndex(primitiveKey);
2831 final ArrayData array = getArray();
2832
2833 if (array.has(index)) {
2834 return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
2835 }
2836
2837 return getLong(index, JSType.toString(primitiveKey), programPoint);
2838 }
2839
2840 @Override
2841 public long getLong(final double key, final int programPoint) {
2842 final int index = getArrayIndex(key);
2843 final ArrayData array = getArray();
2844
2845 if (array.has(index)) {
2846 return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
2847 }
2848
2849 return getLong(index, JSType.toString(key), programPoint);
2850 }
2851
2852 @Override
2853 public long getLong(final long key, final int programPoint) {
2854 final int index = getArrayIndex(key);
2855 final ArrayData array = getArray();
2856
2857 if (array.has(index)) {
2858 return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index);
2859 }
2860
2861 return getLong(index, JSType.toString(key), programPoint);
2862 }
2863
2864 @Override
2865 public long getLong(final int key, final int programPoint) {
2866 final int index = getArrayIndex(key);
2867 final ArrayData array = getArray();
2868
2869 if (array.has(index)) {
2870 return isValid(programPoint) ? array.getLongOptimistic(key, programPoint) : array.getLong(key);
2871 }
2872
2873 return getLong(index, JSType.toString(key), programPoint);
2874 }
2875
2876 private double getDouble(final int index, final String key, final int programPoint) {
2877 if (isValidArrayIndex(index)) {
2878 for (ScriptObject object = this; ; ) {
2879 if (object.getMap().containsArrayKeys()) {
2880 final FindProperty find = object.findProperty(key, false, this);
2881 if (find != null) {
2882 return getDoubleValue(find, programPoint);
2883 }
2884 }
2885
2886 if ((object = object.getProto()) == null) {
2887 break;
2888 }
2889
2890 final ArrayData array = object.getArray();
2891
2892 if (array.has(index)) {
2893 return isValid(programPoint) ?
2894 array.getDoubleOptimistic(index, programPoint) :
2895 array.getDouble(index);
2915 if (array.has(index)) {
2916 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2917 }
2918
2919 return getDouble(index, JSType.toString(primitiveKey), programPoint);
2920 }
2921
2922 @Override
2923 public double getDouble(final double key, final int programPoint) {
2924 final int index = getArrayIndex(key);
2925 final ArrayData array = getArray();
2926
2927 if (array.has(index)) {
2928 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2929 }
2930
2931 return getDouble(index, JSType.toString(key), programPoint);
2932 }
2933
2934 @Override
2935 public double getDouble(final long key, final int programPoint) {
2936 final int index = getArrayIndex(key);
2937 final ArrayData array = getArray();
2938
2939 if (array.has(index)) {
2940 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2941 }
2942
2943 return getDouble(index, JSType.toString(key), programPoint);
2944 }
2945
2946 @Override
2947 public double getDouble(final int key, final int programPoint) {
2948 final int index = getArrayIndex(key);
2949 final ArrayData array = getArray();
2950
2951 if (array.has(index)) {
2952 return isValid(programPoint) ? array.getDoubleOptimistic(key, programPoint) : array.getDouble(key);
2953 }
2954
2955 return getDouble(index, JSType.toString(key), programPoint);
2956 }
2957
2958 private Object get(final int index, final String key) {
2959 if (isValidArrayIndex(index)) {
2960 for (ScriptObject object = this; ; ) {
2961 if (object.getMap().containsArrayKeys()) {
2962 final FindProperty find = object.findProperty(key, false, this);
2963
2964 if (find != null) {
2965 return find.getObjectValue();
2966 }
2996 if (array.has(index)) {
2997 return array.getObject(index);
2998 }
2999
3000 return get(index, JSType.toString(primitiveKey));
3001 }
3002
3003 @Override
3004 public Object get(final double key) {
3005 final int index = getArrayIndex(key);
3006 final ArrayData array = getArray();
3007
3008 if (array.has(index)) {
3009 return array.getObject(index);
3010 }
3011
3012 return get(index, JSType.toString(key));
3013 }
3014
3015 @Override
3016 public Object get(final long key) {
3017 final int index = getArrayIndex(key);
3018 final ArrayData array = getArray();
3019
3020 if (array.has(index)) {
3021 return array.getObject(index);
3022 }
3023
3024 return get(index, JSType.toString(key));
3025 }
3026
3027 @Override
3028 public Object get(final int key) {
3029 final int index = getArrayIndex(key);
3030 final ArrayData array = getArray();
3031
3032 if (array.has(index)) {
3033 return array.getObject(index);
3034 }
3035
3036 return get(index, JSType.toString(key));
3037 }
3038
3039 private boolean doesNotHaveCheckArrayKeys(final long longIndex, final int value, final int callSiteFlags) {
3040 if (getMap().containsArrayKeys()) {
3041 final String key = JSType.toString(longIndex);
3042 final FindProperty find = findProperty(key, true);
3043 if (find != null) {
3044 setObject(find, callSiteFlags, key, value);
3045 return true;
3046 }
3047 }
3090 if (!isExtensible()) {
3091 if (isStrictFlag(callSiteFlags)) {
3092 throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
3093 }
3094 return true;
3095 }
3096 setArray(getArray().ensure(longIndex));
3097 }
3098 return false;
3099 }
3100
3101 private void doesNotHave(final int index, final int value, final int callSiteFlags) {
3102 final long oldLength = getArray().length();
3103 final long longIndex = ArrayIndex.toLongIndex(index);
3104 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3105 final boolean strict = isStrictFlag(callSiteFlags);
3106 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3107 }
3108 }
3109
3110 private void doesNotHave(final int index, final long value, final int callSiteFlags) {
3111 final long oldLength = getArray().length();
3112 final long longIndex = ArrayIndex.toLongIndex(index);
3113 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3114 final boolean strict = isStrictFlag(callSiteFlags);
3115 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3116 }
3117 }
3118
3119 private void doesNotHave(final int index, final double value, final int callSiteFlags) {
3120 final long oldLength = getArray().length();
3121 final long longIndex = ArrayIndex.toLongIndex(index);
3122 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3123 final boolean strict = isStrictFlag(callSiteFlags);
3124 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3125 }
3126 }
3127
3128 private void doesNotHave(final int index, final Object value, final int callSiteFlags) {
3129 final long oldLength = getArray().length();
3130 final long longIndex = ArrayIndex.toLongIndex(index);
3131 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
3132 final boolean strict = isStrictFlag(callSiteFlags);
3133 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
3134 }
3135 }
3136
3137 /**
3138 * This is the most generic of all Object setters. Most of the others use this in some form.
3205 public void set(final Object key, final int value, final int callSiteFlags) {
3206 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3207 final int index = getArrayIndex(primitiveKey);
3208
3209 if (isValidArrayIndex(index)) {
3210 final ArrayData data = getArray();
3211 if (data.has(index)) {
3212 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3213 } else {
3214 doesNotHave(index, value, callSiteFlags);
3215 }
3216
3217 return;
3218 }
3219
3220 final String propName = JSType.toString(primitiveKey);
3221 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3222 }
3223
3224 @Override
3225 public void set(final Object key, final long value, final int callSiteFlags) {
3226 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3227 final int index = getArrayIndex(primitiveKey);
3228
3229 if (isValidArrayIndex(index)) {
3230 final ArrayData data = getArray();
3231 if (data.has(index)) {
3232 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3233 } else {
3234 doesNotHave(index, value, callSiteFlags);
3235 }
3236
3237 return;
3238 }
3239
3240 final String propName = JSType.toString(primitiveKey);
3241 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3242 }
3243
3244 @Override
3245 public void set(final Object key, final double value, final int callSiteFlags) {
3246 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3247 final int index = getArrayIndex(primitiveKey);
3248
3249 if (isValidArrayIndex(index)) {
3250 final ArrayData data = getArray();
3251 if (data.has(index)) {
3252 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3253 } else {
3254 doesNotHave(index, value, callSiteFlags);
3255 }
3256
3257 return;
3258 }
3259
3260 final String propName = JSType.toString(primitiveKey);
3261 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3262 }
3263
3264 @Override
3284 @Override
3285 public void set(final double key, final int value, final int callSiteFlags) {
3286 final int index = getArrayIndex(key);
3287
3288 if (isValidArrayIndex(index)) {
3289 final ArrayData data = getArray();
3290 if (data.has(index)) {
3291 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3292 } else {
3293 doesNotHave(index, value, callSiteFlags);
3294 }
3295
3296 return;
3297 }
3298
3299 final String propName = JSType.toString(key);
3300 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3301 }
3302
3303 @Override
3304 public void set(final double key, final long value, final int callSiteFlags) {
3305 final int index = getArrayIndex(key);
3306
3307 if (isValidArrayIndex(index)) {
3308 final ArrayData data = getArray();
3309 if (data.has(index)) {
3310 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3311 } else {
3312 doesNotHave(index, value, callSiteFlags);
3313 }
3314
3315 return;
3316 }
3317
3318 final String propName = JSType.toString(key);
3319 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3320 }
3321
3322 @Override
3323 public void set(final double key, final double value, final int callSiteFlags) {
3324 final int index = getArrayIndex(key);
3325
3326 if (isValidArrayIndex(index)) {
3327 final ArrayData data = getArray();
3328 if (data.has(index)) {
3329 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3330 } else {
3331 doesNotHave(index, value, callSiteFlags);
3332 }
3333
3334 return;
3335 }
3336
3337 final String propName = JSType.toString(key);
3338 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3339 }
3340
3341 @Override
3342 public void set(final double key, final Object value, final int callSiteFlags) {
3343 final int index = getArrayIndex(key);
3344
3345 if (isValidArrayIndex(index)) {
3346 final ArrayData data = getArray();
3347 if (data.has(index)) {
3348 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3349 } else {
3350 doesNotHave(index, value, callSiteFlags);
3351 }
3352
3353 return;
3354 }
3355
3356 final String propName = JSType.toString(key);
3357 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3358 }
3359
3360 @Override
3361 public void set(final long key, final int value, final int callSiteFlags) {
3362 final int index = getArrayIndex(key);
3363
3364 if (isValidArrayIndex(index)) {
3365 final ArrayData data = getArray();
3366 if (data.has(index)) {
3367 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3368 } else {
3369 doesNotHave(index, value, callSiteFlags);
3370 }
3371
3372 return;
3373 }
3374
3375 final String propName = JSType.toString(key);
3376 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3377 }
3378
3379 @Override
3380 public void set(final long key, final long value, final int callSiteFlags) {
3381 final int index = getArrayIndex(key);
3382
3383 if (isValidArrayIndex(index)) {
3384 final ArrayData data = getArray();
3385 if (data.has(index)) {
3386 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3387 } else {
3388 doesNotHave(index, value, callSiteFlags);
3389 }
3390
3391 return;
3392 }
3393
3394 final String propName = JSType.toString(key);
3395 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3396 }
3397
3398 @Override
3399 public void set(final long key, final double value, final int callSiteFlags) {
3400 final int index = getArrayIndex(key);
3401
3402 if (isValidArrayIndex(index)) {
3403 final ArrayData data = getArray();
3404 if (data.has(index)) {
3405 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3406 } else {
3407 doesNotHave(index, value, callSiteFlags);
3408 }
3409
3410 return;
3411 }
3412
3413 final String propName = JSType.toString(key);
3414 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3415 }
3416
3417 @Override
3418 public void set(final long key, final Object value, final int callSiteFlags) {
3419 final int index = getArrayIndex(key);
3420
3421 if (isValidArrayIndex(index)) {
3422 final ArrayData data = getArray();
3423 if (data.has(index)) {
3424 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3425 } else {
3426 doesNotHave(index, value, callSiteFlags);
3427 }
3428
3429 return;
3430 }
3431
3432 final String propName = JSType.toString(key);
3433 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3434 }
3435
3436 @Override
3437 public void set(final int key, final int value, final int callSiteFlags) {
3438 final int index = getArrayIndex(key);
3439 if (isValidArrayIndex(index)) {
3440 if (getArray().has(index)) {
3441 final ArrayData data = getArray();
3442 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3443 } else {
3444 doesNotHave(index, value, callSiteFlags);
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 int key, final long 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, JSType.toObject(value));
3470 }
3471
3472 @Override
3473 public void set(final int key, final double value, final int callSiteFlags) {
3474 final int index = getArrayIndex(key);
3475
3476 if (isValidArrayIndex(index)) {
3477 final ArrayData data = getArray();
3478 if (data.has(index)) {
3479 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3480 } else {
3481 doesNotHave(index, value, callSiteFlags);
3482 }
3483
3484 return;
3485 }
3486
3487 final String propName = JSType.toString(key);
3488 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3489 }
3490
3491 @Override
3492 public void set(final int key, final Object value, final int callSiteFlags) {
3504 }
3505
3506 final String propName = JSType.toString(key);
3507 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3508 }
3509
3510 @Override
3511 public boolean has(final Object key) {
3512 final Object primitiveKey = JSType.toPrimitive(key);
3513 final int index = getArrayIndex(primitiveKey);
3514 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), true);
3515 }
3516
3517 @Override
3518 public boolean has(final double key) {
3519 final int index = getArrayIndex(key);
3520 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3521 }
3522
3523 @Override
3524 public boolean has(final long key) {
3525 final int index = getArrayIndex(key);
3526 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3527 }
3528
3529 @Override
3530 public boolean has(final int key) {
3531 final int index = getArrayIndex(key);
3532 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3533 }
3534
3535 private boolean hasArrayProperty(final int index) {
3536 boolean hasArrayKeys = false;
3537
3538 for (ScriptObject self = this; self != null; self = self.getProto()) {
3539 if (self.getArray().has(index)) {
3540 return true;
3541 }
3542 hasArrayKeys = hasArrayKeys || self.getMap().containsArrayKeys();
3543 }
3544
3545 return hasArrayKeys && hasProperty(ArrayIndex.toKey(index), true);
3546 }
3547
3548 @Override
3549 public boolean hasOwnProperty(final Object key) {
3550 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3551 final int index = getArrayIndex(primitiveKey);
3552 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), false);
3553 }
3554
3555 @Override
3556 public boolean hasOwnProperty(final int key) {
3557 final int index = getArrayIndex(key);
3558 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3559 }
3560
3561 @Override
3562 public boolean hasOwnProperty(final long key) {
3563 final int index = getArrayIndex(key);
3564 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3565 }
3566
3567 @Override
3568 public boolean hasOwnProperty(final double key) {
3569 final int index = getArrayIndex(key);
3570 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3571 }
3572
3573 private boolean hasOwnArrayProperty(final int index) {
3574 return getArray().has(index) || getMap().containsArrayKeys() && hasProperty(ArrayIndex.toKey(index), false);
3575 }
3576
3577 @Override
3578 public boolean delete(final int key, final boolean strict) {
3579 final int index = getArrayIndex(key);
3580 final ArrayData array = getArray();
3581
3582 if (array.has(index)) {
3583 if (array.canDelete(index, strict)) {
3584 setArray(array.delete(index));
3585 return true;
3586 }
3587 return false;
3588 }
3589 return deleteObject(JSType.toObject(key), strict);
3590 }
3591
3592 @Override
3593 public boolean delete(final long key, final boolean strict) {
3594 final int index = getArrayIndex(key);
3595 final ArrayData array = getArray();
3596
3597 if (array.has(index)) {
3598 if (array.canDelete(index, strict)) {
3599 setArray(array.delete(index));
3600 return true;
3601 }
3602 return false;
3603 }
3604
3605 return deleteObject(JSType.toObject(key), strict);
3606 }
3607
3608 @Override
3609 public boolean delete(final double key, final boolean strict) {
3610 final int index = getArrayIndex(key);
3611 final ArrayData array = getArray();
3612
3613 if (array.has(index)) {
3614 if (array.canDelete(index, strict)) {
3615 setArray(array.delete(index));
3616 return true;
3617 }
3618 return false;
3619 }
3620
3621 return deleteObject(JSType.toObject(key), strict);
3622 }
3623
3624 @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.util.AbstractMap;
168 public static final Call SET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class);
169
170 /** Method handle for getting the proto of a ScriptObject */
171 public static final Call GET_PROTO = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class);
172
173 /** Method handle for getting the proto of a ScriptObject */
174 public static final Call GET_PROTO_DEPTH = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class, int.class);
175
176 /** Method handle for setting the proto of a ScriptObject */
177 public static final Call SET_GLOBAL_OBJECT_PROTO = staticCallNoLookup(ScriptObject.class, "setGlobalObjectProto", void.class, ScriptObject.class);
178
179 /** Method handle for setting the proto of a ScriptObject after checking argument */
180 public static final Call SET_PROTO_FROM_LITERAL = virtualCallNoLookup(ScriptObject.class, "setProtoFromLiteral", void.class, Object.class);
181
182 /** Method handle for setting the user accessors of a ScriptObject */
183 //TODO fastpath this
184 public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class);
185
186 static final MethodHandle[] SET_SLOW = new MethodHandle[] {
187 findOwnMH_V("set", void.class, Object.class, int.class, int.class),
188 findOwnMH_V("set", void.class, Object.class, double.class, int.class),
189 findOwnMH_V("set", void.class, Object.class, Object.class, int.class)
190 };
191
192 /** Method handle to reset the map of this ScriptObject */
193 public static final Call SET_MAP = virtualCallNoLookup(ScriptObject.class, "setMap", void.class, PropertyMap.class);
194
195 static final MethodHandle CAS_MAP = findOwnMH_V("compareAndSetMap", boolean.class, PropertyMap.class, PropertyMap.class);
196 static final MethodHandle EXTENSION_CHECK = findOwnMH_V("extensionCheck", boolean.class, boolean.class, String.class);
197 static final MethodHandle ENSURE_SPILL_SIZE = findOwnMH_V("ensureSpillSize", Object.class, int.class);
198
199 /**
200 * Constructor
201 */
202 public ScriptObject() {
203 this(null);
204 }
205
206 /**
207 * Constructor
1067 } else {
1068 addOwnProperty(newUserAccessors(key, oldProperty != null ? oldProperty.getFlags() : 0, getter, setter));
1069 }
1070 }
1071
1072 private static int getIntValue(final FindProperty find, final int programPoint) {
1073 final MethodHandle getter = find.getGetter(int.class, programPoint, null);
1074 if (getter != null) {
1075 try {
1076 return (int)getter.invokeExact((Object)find.getGetterReceiver());
1077 } catch (final Error|RuntimeException e) {
1078 throw e;
1079 } catch (final Throwable e) {
1080 throw new RuntimeException(e);
1081 }
1082 }
1083
1084 return UNDEFINED_INT;
1085 }
1086
1087 private static double getDoubleValue(final FindProperty find, final int programPoint) {
1088 final MethodHandle getter = find.getGetter(double.class, programPoint, null);
1089 if (getter != null) {
1090 try {
1091 return (double)getter.invokeExact((Object)find.getGetterReceiver());
1092 } catch (final Error|RuntimeException e) {
1093 throw e;
1094 } catch (final Throwable e) {
1095 throw new RuntimeException(e);
1096 }
1097 }
1098
1099 return UNDEFINED_DOUBLE;
1100 }
1101
1102 /**
1103 * Return methodHandle of value function for call.
1104 *
1105 * @param find data from find property.
1106 * @param type method type of function.
2734 if (array.has(index)) {
2735 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2736 }
2737
2738 return getInt(index, JSType.toString(primitiveKey), programPoint);
2739 }
2740
2741 @Override
2742 public int getInt(final double key, final int programPoint) {
2743 final int index = getArrayIndex(key);
2744 final ArrayData array = getArray();
2745
2746 if (array.has(index)) {
2747 return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index);
2748 }
2749
2750 return getInt(index, JSType.toString(key), programPoint);
2751 }
2752
2753 @Override
2754 public int getInt(final int key, final int programPoint) {
2755 final int index = getArrayIndex(key);
2756 final ArrayData array = getArray();
2757
2758 if (array.has(index)) {
2759 return isValid(programPoint) ? array.getIntOptimistic(key, programPoint) : array.getInt(key);
2760 }
2761
2762 return getInt(index, JSType.toString(key), programPoint);
2763 }
2764
2765 private double getDouble(final int index, final String key, final int programPoint) {
2766 if (isValidArrayIndex(index)) {
2767 for (ScriptObject object = this; ; ) {
2768 if (object.getMap().containsArrayKeys()) {
2769 final FindProperty find = object.findProperty(key, false, this);
2770 if (find != null) {
2771 return getDoubleValue(find, programPoint);
2772 }
2773 }
2774
2775 if ((object = object.getProto()) == null) {
2776 break;
2777 }
2778
2779 final ArrayData array = object.getArray();
2780
2781 if (array.has(index)) {
2782 return isValid(programPoint) ?
2783 array.getDoubleOptimistic(index, programPoint) :
2784 array.getDouble(index);
2804 if (array.has(index)) {
2805 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2806 }
2807
2808 return getDouble(index, JSType.toString(primitiveKey), programPoint);
2809 }
2810
2811 @Override
2812 public double getDouble(final double key, final int programPoint) {
2813 final int index = getArrayIndex(key);
2814 final ArrayData array = getArray();
2815
2816 if (array.has(index)) {
2817 return isValid(programPoint) ? array.getDoubleOptimistic(index, programPoint) : array.getDouble(index);
2818 }
2819
2820 return getDouble(index, JSType.toString(key), programPoint);
2821 }
2822
2823 @Override
2824 public double getDouble(final int key, final int programPoint) {
2825 final int index = getArrayIndex(key);
2826 final ArrayData array = getArray();
2827
2828 if (array.has(index)) {
2829 return isValid(programPoint) ? array.getDoubleOptimistic(key, programPoint) : array.getDouble(key);
2830 }
2831
2832 return getDouble(index, JSType.toString(key), programPoint);
2833 }
2834
2835 private Object get(final int index, final String key) {
2836 if (isValidArrayIndex(index)) {
2837 for (ScriptObject object = this; ; ) {
2838 if (object.getMap().containsArrayKeys()) {
2839 final FindProperty find = object.findProperty(key, false, this);
2840
2841 if (find != null) {
2842 return find.getObjectValue();
2843 }
2873 if (array.has(index)) {
2874 return array.getObject(index);
2875 }
2876
2877 return get(index, JSType.toString(primitiveKey));
2878 }
2879
2880 @Override
2881 public Object get(final double key) {
2882 final int index = getArrayIndex(key);
2883 final ArrayData array = getArray();
2884
2885 if (array.has(index)) {
2886 return array.getObject(index);
2887 }
2888
2889 return get(index, JSType.toString(key));
2890 }
2891
2892 @Override
2893 public Object get(final int key) {
2894 final int index = getArrayIndex(key);
2895 final ArrayData array = getArray();
2896
2897 if (array.has(index)) {
2898 return array.getObject(index);
2899 }
2900
2901 return get(index, JSType.toString(key));
2902 }
2903
2904 private boolean doesNotHaveCheckArrayKeys(final long longIndex, final int value, final int callSiteFlags) {
2905 if (getMap().containsArrayKeys()) {
2906 final String key = JSType.toString(longIndex);
2907 final FindProperty find = findProperty(key, true);
2908 if (find != null) {
2909 setObject(find, callSiteFlags, key, value);
2910 return true;
2911 }
2912 }
2955 if (!isExtensible()) {
2956 if (isStrictFlag(callSiteFlags)) {
2957 throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
2958 }
2959 return true;
2960 }
2961 setArray(getArray().ensure(longIndex));
2962 }
2963 return false;
2964 }
2965
2966 private void doesNotHave(final int index, final int value, final int callSiteFlags) {
2967 final long oldLength = getArray().length();
2968 final long longIndex = ArrayIndex.toLongIndex(index);
2969 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
2970 final boolean strict = isStrictFlag(callSiteFlags);
2971 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
2972 }
2973 }
2974
2975 private void doesNotHave(final int index, final double value, final int callSiteFlags) {
2976 final long oldLength = getArray().length();
2977 final long longIndex = ArrayIndex.toLongIndex(index);
2978 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
2979 final boolean strict = isStrictFlag(callSiteFlags);
2980 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
2981 }
2982 }
2983
2984 private void doesNotHave(final int index, final Object value, final int callSiteFlags) {
2985 final long oldLength = getArray().length();
2986 final long longIndex = ArrayIndex.toLongIndex(index);
2987 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
2988 final boolean strict = isStrictFlag(callSiteFlags);
2989 setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
2990 }
2991 }
2992
2993 /**
2994 * This is the most generic of all Object setters. Most of the others use this in some form.
3061 public void set(final Object key, final int value, final int callSiteFlags) {
3062 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3063 final int index = getArrayIndex(primitiveKey);
3064
3065 if (isValidArrayIndex(index)) {
3066 final ArrayData data = getArray();
3067 if (data.has(index)) {
3068 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3069 } else {
3070 doesNotHave(index, value, callSiteFlags);
3071 }
3072
3073 return;
3074 }
3075
3076 final String propName = JSType.toString(primitiveKey);
3077 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3078 }
3079
3080 @Override
3081 public void set(final Object key, final double value, final int callSiteFlags) {
3082 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3083 final int index = getArrayIndex(primitiveKey);
3084
3085 if (isValidArrayIndex(index)) {
3086 final ArrayData data = getArray();
3087 if (data.has(index)) {
3088 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3089 } else {
3090 doesNotHave(index, value, callSiteFlags);
3091 }
3092
3093 return;
3094 }
3095
3096 final String propName = JSType.toString(primitiveKey);
3097 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3098 }
3099
3100 @Override
3120 @Override
3121 public void set(final double key, final int value, final int callSiteFlags) {
3122 final int index = getArrayIndex(key);
3123
3124 if (isValidArrayIndex(index)) {
3125 final ArrayData data = getArray();
3126 if (data.has(index)) {
3127 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3128 } else {
3129 doesNotHave(index, value, callSiteFlags);
3130 }
3131
3132 return;
3133 }
3134
3135 final String propName = JSType.toString(key);
3136 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3137 }
3138
3139 @Override
3140 public void set(final double key, final double value, final int callSiteFlags) {
3141 final int index = getArrayIndex(key);
3142
3143 if (isValidArrayIndex(index)) {
3144 final ArrayData data = getArray();
3145 if (data.has(index)) {
3146 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3147 } else {
3148 doesNotHave(index, value, callSiteFlags);
3149 }
3150
3151 return;
3152 }
3153
3154 final String propName = JSType.toString(key);
3155 setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value));
3156 }
3157
3158 @Override
3159 public void set(final double key, final Object value, final int callSiteFlags) {
3160 final int index = getArrayIndex(key);
3161
3162 if (isValidArrayIndex(index)) {
3163 final ArrayData data = getArray();
3164 if (data.has(index)) {
3165 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3166 } else {
3167 doesNotHave(index, value, callSiteFlags);
3168 }
3169
3170 return;
3171 }
3172
3173 final String propName = JSType.toString(key);
3174 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3175 }
3176
3177 @Override
3178 public void set(final int key, final int value, final int callSiteFlags) {
3179 final int index = getArrayIndex(key);
3180 if (isValidArrayIndex(index)) {
3181 if (getArray().has(index)) {
3182 final ArrayData data = getArray();
3183 setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
3184 } else {
3185 doesNotHave(index, value, callSiteFlags);
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 int key, final double 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, JSType.toObject(value));
3211 }
3212
3213 @Override
3214 public void set(final int key, final Object value, final int callSiteFlags) {
3226 }
3227
3228 final String propName = JSType.toString(key);
3229 setObject(findProperty(propName, true), callSiteFlags, propName, value);
3230 }
3231
3232 @Override
3233 public boolean has(final Object key) {
3234 final Object primitiveKey = JSType.toPrimitive(key);
3235 final int index = getArrayIndex(primitiveKey);
3236 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), true);
3237 }
3238
3239 @Override
3240 public boolean has(final double key) {
3241 final int index = getArrayIndex(key);
3242 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3243 }
3244
3245 @Override
3246 public boolean has(final int key) {
3247 final int index = getArrayIndex(key);
3248 return isValidArrayIndex(index) ? hasArrayProperty(index) : hasProperty(JSType.toString(key), true);
3249 }
3250
3251 private boolean hasArrayProperty(final int index) {
3252 boolean hasArrayKeys = false;
3253
3254 for (ScriptObject self = this; self != null; self = self.getProto()) {
3255 if (self.getArray().has(index)) {
3256 return true;
3257 }
3258 hasArrayKeys = hasArrayKeys || self.getMap().containsArrayKeys();
3259 }
3260
3261 return hasArrayKeys && hasProperty(ArrayIndex.toKey(index), true);
3262 }
3263
3264 @Override
3265 public boolean hasOwnProperty(final Object key) {
3266 final Object primitiveKey = JSType.toPrimitive(key, String.class);
3267 final int index = getArrayIndex(primitiveKey);
3268 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(primitiveKey), false);
3269 }
3270
3271 @Override
3272 public boolean hasOwnProperty(final int key) {
3273 final int index = getArrayIndex(key);
3274 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3275 }
3276
3277 @Override
3278 public boolean hasOwnProperty(final double key) {
3279 final int index = getArrayIndex(key);
3280 return isValidArrayIndex(index) ? hasOwnArrayProperty(index) : hasProperty(JSType.toString(key), false);
3281 }
3282
3283 private boolean hasOwnArrayProperty(final int index) {
3284 return getArray().has(index) || getMap().containsArrayKeys() && hasProperty(ArrayIndex.toKey(index), false);
3285 }
3286
3287 @Override
3288 public boolean delete(final int key, final boolean strict) {
3289 final int index = getArrayIndex(key);
3290 final ArrayData array = getArray();
3291
3292 if (array.has(index)) {
3293 if (array.canDelete(index, strict)) {
3294 setArray(array.delete(index));
3295 return true;
3296 }
3297 return false;
3298 }
3299 return deleteObject(JSType.toObject(key), strict);
3300 }
3301
3302 @Override
3303 public boolean delete(final double key, final boolean strict) {
3304 final int index = getArrayIndex(key);
3305 final ArrayData array = getArray();
3306
3307 if (array.has(index)) {
3308 if (array.canDelete(index, strict)) {
3309 setArray(array.delete(index));
3310 return true;
3311 }
3312 return false;
3313 }
3314
3315 return deleteObject(JSType.toObject(key), strict);
3316 }
3317
3318 @Override
|