OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3133 return *v8::Utils::OpenHandle(*result); | 3133 return *v8::Utils::OpenHandle(*result); |
3134 } | 3134 } |
3135 } | 3135 } |
3136 MaybeObject* raw_result = | 3136 MaybeObject* raw_result = |
3137 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); | 3137 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); |
3138 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 3138 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
3139 return raw_result; | 3139 return raw_result; |
3140 } | 3140 } |
3141 | 3141 |
3142 | 3142 |
3143 MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index, | |
3144 DeleteMode mode) { | |
3145 ASSERT(!HasExternalArrayElements()); | |
3146 switch (GetElementsKind()) { | |
3147 case FAST_ELEMENTS: { | |
3148 Object* obj; | |
3149 { MaybeObject* maybe_obj = EnsureWritableFastElements(); | |
3150 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
3151 } | |
3152 uint32_t length = IsJSArray() ? | |
3153 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | |
3154 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | |
3155 if (index < length) { | |
3156 FixedArray::cast(elements())->set_the_hole(index); | |
3157 } | |
3158 break; | |
3159 } | |
3160 case DICTIONARY_ELEMENTS: { | |
3161 NumberDictionary* dictionary = element_dictionary(); | |
3162 int entry = dictionary->FindEntry(index); | |
3163 if (entry != NumberDictionary::kNotFound) { | |
3164 Object* deleted = dictionary->DeleteProperty(entry, mode); | |
3165 if (deleted == GetHeap()->true_value()) { | |
3166 MaybeObject* maybe_elements = dictionary->Shrink(index); | |
3167 FixedArray* new_elements = NULL; | |
3168 if (!maybe_elements->To(&new_elements)) { | |
3169 return maybe_elements; | |
3170 } | |
3171 set_elements(new_elements); | |
3172 } | |
3173 return deleted; | |
3174 } | |
3175 break; | |
3176 } | |
3177 default: | |
3178 UNREACHABLE(); | |
3179 break; | |
3180 } | |
3181 return GetHeap()->true_value(); | |
3182 } | |
3183 | |
3184 | |
3185 MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) { | 3143 MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) { |
3186 Isolate* isolate = GetIsolate(); | 3144 Isolate* isolate = GetIsolate(); |
3187 Heap* heap = isolate->heap(); | 3145 Heap* heap = isolate->heap(); |
3188 // Make sure that the top context does not change when doing | 3146 // Make sure that the top context does not change when doing |
3189 // callbacks or interceptor calls. | 3147 // callbacks or interceptor calls. |
3190 AssertNoContextChange ncc; | 3148 AssertNoContextChange ncc; |
3191 HandleScope scope(isolate); | 3149 HandleScope scope(isolate); |
3192 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); | 3150 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); |
3193 if (interceptor->deleter()->IsUndefined()) return heap->false_value(); | 3151 if (interceptor->deleter()->IsUndefined()) return heap->false_value(); |
3194 v8::IndexedPropertyDeleter deleter = | 3152 v8::IndexedPropertyDeleter deleter = |
3195 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter()); | 3153 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter()); |
3196 Handle<JSObject> this_handle(this); | 3154 Handle<JSObject> this_handle(this); |
3197 LOG(isolate, | 3155 LOG(isolate, |
3198 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); | 3156 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); |
3199 CustomArguments args(isolate, interceptor->data(), this, this); | 3157 CustomArguments args(isolate, interceptor->data(), this, this); |
3200 v8::AccessorInfo info(args.end()); | 3158 v8::AccessorInfo info(args.end()); |
3201 v8::Handle<v8::Boolean> result; | 3159 v8::Handle<v8::Boolean> result; |
3202 { | 3160 { |
3203 // Leaving JavaScript. | 3161 // Leaving JavaScript. |
3204 VMState state(isolate, EXTERNAL); | 3162 VMState state(isolate, EXTERNAL); |
3205 result = deleter(index, info); | 3163 result = deleter(index, info); |
3206 } | 3164 } |
3207 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 3165 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
3208 if (!result.IsEmpty()) { | 3166 if (!result.IsEmpty()) { |
3209 ASSERT(result->IsBoolean()); | 3167 ASSERT(result->IsBoolean()); |
3210 return *v8::Utils::OpenHandle(*result); | 3168 return *v8::Utils::OpenHandle(*result); |
3211 } | 3169 } |
3212 MaybeObject* raw_result = | 3170 MaybeObject* raw_result = GetElementsAccessor()->Delete(*this_handle, |
3213 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); | 3171 index, |
| 3172 NORMAL_DELETION); |
3214 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 3173 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
3215 return raw_result; | 3174 return raw_result; |
3216 } | 3175 } |
3217 | 3176 |
3218 | 3177 |
3219 MaybeObject* JSObject::DeleteFastElement(uint32_t index) { | |
3220 ASSERT(HasFastElements() || HasFastArgumentsElements()); | |
3221 Heap* heap = GetHeap(); | |
3222 FixedArray* backing_store = FixedArray::cast(elements()); | |
3223 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { | |
3224 backing_store = FixedArray::cast(backing_store->get(1)); | |
3225 } else { | |
3226 Object* writable; | |
3227 MaybeObject* maybe = EnsureWritableFastElements(); | |
3228 if (!maybe->ToObject(&writable)) return maybe; | |
3229 backing_store = FixedArray::cast(writable); | |
3230 } | |
3231 uint32_t length = static_cast<uint32_t>( | |
3232 IsJSArray() | |
3233 ? Smi::cast(JSArray::cast(this)->length())->value() | |
3234 : backing_store->length()); | |
3235 if (index < length) { | |
3236 backing_store->set_the_hole(index); | |
3237 // If an old space backing store is larger than a certain size and | |
3238 // has too few used values, normalize it. | |
3239 // To avoid doing the check on every delete we require at least | |
3240 // one adjacent hole to the value being deleted. | |
3241 Object* hole = heap->the_hole_value(); | |
3242 const int kMinLengthForSparsenessCheck = 64; | |
3243 if (backing_store->length() >= kMinLengthForSparsenessCheck && | |
3244 !heap->InNewSpace(backing_store) && | |
3245 ((index > 0 && backing_store->get(index - 1) == hole) || | |
3246 (index + 1 < length && backing_store->get(index + 1) == hole))) { | |
3247 int num_used = 0; | |
3248 for (int i = 0; i < backing_store->length(); ++i) { | |
3249 if (backing_store->get(i) != hole) ++num_used; | |
3250 // Bail out early if more than 1/4 is used. | |
3251 if (4 * num_used > backing_store->length()) break; | |
3252 } | |
3253 if (4 * num_used <= backing_store->length()) { | |
3254 MaybeObject* result = NormalizeElements(); | |
3255 if (result->IsFailure()) return result; | |
3256 } | |
3257 } | |
3258 } | |
3259 return heap->true_value(); | |
3260 } | |
3261 | |
3262 | |
3263 MaybeObject* JSObject::DeleteDictionaryElement(uint32_t index, | |
3264 DeleteMode mode) { | |
3265 Isolate* isolate = GetIsolate(); | |
3266 Heap* heap = isolate->heap(); | |
3267 FixedArray* backing_store = FixedArray::cast(elements()); | |
3268 bool is_arguments = | |
3269 (GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS); | |
3270 if (is_arguments) { | |
3271 backing_store = FixedArray::cast(backing_store->get(1)); | |
3272 } | |
3273 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | |
3274 int entry = dictionary->FindEntry(index); | |
3275 if (entry != NumberDictionary::kNotFound) { | |
3276 Object* result = dictionary->DeleteProperty(entry, mode); | |
3277 if (result == heap->true_value()) { | |
3278 MaybeObject* maybe_elements = dictionary->Shrink(index); | |
3279 FixedArray* new_elements = NULL; | |
3280 if (!maybe_elements->To(&new_elements)) { | |
3281 return maybe_elements; | |
3282 } | |
3283 if (is_arguments) { | |
3284 FixedArray::cast(elements())->set(1, new_elements); | |
3285 } else { | |
3286 set_elements(new_elements); | |
3287 } | |
3288 } | |
3289 if (mode == STRICT_DELETION && result == heap->false_value()) { | |
3290 // In strict mode, attempting to delete a non-configurable property | |
3291 // throws an exception. | |
3292 HandleScope scope(isolate); | |
3293 Handle<Object> holder(this); | |
3294 Handle<Object> name = isolate->factory()->NewNumberFromUint(index); | |
3295 Handle<Object> args[2] = { name, holder }; | |
3296 Handle<Object> error = | |
3297 isolate->factory()->NewTypeError("strict_delete_property", | |
3298 HandleVector(args, 2)); | |
3299 return isolate->Throw(*error); | |
3300 } | |
3301 } | |
3302 return heap->true_value(); | |
3303 } | |
3304 | |
3305 | |
3306 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { | 3178 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { |
3307 Isolate* isolate = GetIsolate(); | 3179 Isolate* isolate = GetIsolate(); |
3308 // Check access rights if needed. | 3180 // Check access rights if needed. |
3309 if (IsAccessCheckNeeded() && | 3181 if (IsAccessCheckNeeded() && |
3310 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { | 3182 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { |
3311 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); | 3183 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); |
3312 return isolate->heap()->false_value(); | 3184 return isolate->heap()->false_value(); |
3313 } | 3185 } |
3314 | 3186 |
3315 if (IsJSGlobalProxy()) { | 3187 if (IsJSGlobalProxy()) { |
3316 Object* proto = GetPrototype(); | 3188 Object* proto = GetPrototype(); |
3317 if (proto->IsNull()) return isolate->heap()->false_value(); | 3189 if (proto->IsNull()) return isolate->heap()->false_value(); |
3318 ASSERT(proto->IsJSGlobalObject()); | 3190 ASSERT(proto->IsJSGlobalObject()); |
3319 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); | 3191 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); |
3320 } | 3192 } |
3321 | 3193 |
3322 if (HasIndexedInterceptor()) { | 3194 if (HasIndexedInterceptor()) { |
3323 // Skip interceptor if forcing deletion. | 3195 // Skip interceptor if forcing deletion. |
3324 return (mode == FORCE_DELETION) | 3196 if (mode != FORCE_DELETION) { |
3325 ? DeleteElementPostInterceptor(index, FORCE_DELETION) | 3197 return DeleteElementWithInterceptor(index); |
3326 : DeleteElementWithInterceptor(index); | 3198 } |
| 3199 mode = JSReceiver::FORCE_DELETION; |
3327 } | 3200 } |
3328 | 3201 |
3329 switch (GetElementsKind()) { | 3202 return GetElementsAccessor()->Delete(this, index, mode); |
3330 case FAST_ELEMENTS: | |
3331 return DeleteFastElement(index); | |
3332 | |
3333 case DICTIONARY_ELEMENTS: | |
3334 return DeleteDictionaryElement(index, mode); | |
3335 | |
3336 case FAST_DOUBLE_ELEMENTS: { | |
3337 int length = IsJSArray() | |
3338 ? Smi::cast(JSArray::cast(this)->length())->value() | |
3339 : FixedDoubleArray::cast(elements())->length(); | |
3340 if (index < static_cast<uint32_t>(length)) { | |
3341 FixedDoubleArray::cast(elements())->set_the_hole(index); | |
3342 } | |
3343 break; | |
3344 } | |
3345 case EXTERNAL_PIXEL_ELEMENTS: | |
3346 case EXTERNAL_BYTE_ELEMENTS: | |
3347 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
3348 case EXTERNAL_SHORT_ELEMENTS: | |
3349 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
3350 case EXTERNAL_INT_ELEMENTS: | |
3351 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
3352 case EXTERNAL_FLOAT_ELEMENTS: | |
3353 case EXTERNAL_DOUBLE_ELEMENTS: | |
3354 // Pixel and external array elements cannot be deleted. Just | |
3355 // silently ignore here. | |
3356 break; | |
3357 | |
3358 case NON_STRICT_ARGUMENTS_ELEMENTS: { | |
3359 FixedArray* parameter_map = FixedArray::cast(elements()); | |
3360 uint32_t length = parameter_map->length(); | |
3361 Object* probe = | |
3362 index < (length - 2) ? parameter_map->get(index + 2) : NULL; | |
3363 if (probe != NULL && !probe->IsTheHole()) { | |
3364 // TODO(kmillikin): We could check if this was the last aliased | |
3365 // parameter, and revert to normal elements in that case. That | |
3366 // would enable GC of the context. | |
3367 parameter_map->set_the_hole(index + 2); | |
3368 } else { | |
3369 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
3370 if (arguments->IsDictionary()) { | |
3371 return DeleteDictionaryElement(index, mode); | |
3372 } else { | |
3373 return DeleteFastElement(index); | |
3374 } | |
3375 } | |
3376 break; | |
3377 } | |
3378 } | |
3379 return isolate->heap()->true_value(); | |
3380 } | 3203 } |
3381 | 3204 |
3382 | 3205 |
3383 MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) { | 3206 MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) { |
3384 if (IsJSProxy()) { | 3207 if (IsJSProxy()) { |
3385 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode); | 3208 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode); |
3386 } else { | 3209 } else { |
3387 return JSObject::cast(this)->DeleteProperty(name, mode); | 3210 return JSObject::cast(this)->DeleteProperty(name, mode); |
3388 } | 3211 } |
3389 } | 3212 } |
(...skipping 8505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11895 if (break_point_objects()->IsUndefined()) return 0; | 11718 if (break_point_objects()->IsUndefined()) return 0; |
11896 // Single break point. | 11719 // Single break point. |
11897 if (!break_point_objects()->IsFixedArray()) return 1; | 11720 if (!break_point_objects()->IsFixedArray()) return 1; |
11898 // Multiple break points. | 11721 // Multiple break points. |
11899 return FixedArray::cast(break_point_objects())->length(); | 11722 return FixedArray::cast(break_point_objects())->length(); |
11900 } | 11723 } |
11901 #endif | 11724 #endif |
11902 | 11725 |
11903 | 11726 |
11904 } } // namespace v8::internal | 11727 } } // namespace v8::internal |
OLD | NEW |