OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <iomanip> | 5 #include <iomanip> |
6 #include <sstream> | 6 #include <sstream> |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
(...skipping 12267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12278 void JSObject::ValidateElements(Handle<JSObject> object) { | 12278 void JSObject::ValidateElements(Handle<JSObject> object) { |
12279 #ifdef ENABLE_SLOW_DCHECKS | 12279 #ifdef ENABLE_SLOW_DCHECKS |
12280 if (FLAG_enable_slow_asserts) { | 12280 if (FLAG_enable_slow_asserts) { |
12281 ElementsAccessor* accessor = object->GetElementsAccessor(); | 12281 ElementsAccessor* accessor = object->GetElementsAccessor(); |
12282 accessor->Validate(object); | 12282 accessor->Validate(object); |
12283 } | 12283 } |
12284 #endif | 12284 #endif |
12285 } | 12285 } |
12286 | 12286 |
12287 | 12287 |
| 12288 static void AddDictionaryElement(Handle<JSObject> object, |
| 12289 Handle<SeededNumberDictionary> dictionary, |
| 12290 uint32_t index, Handle<Object> value, |
| 12291 PropertyAttributes attributes) { |
| 12292 // TODO(verwaest): Handle with the elements accessor. |
| 12293 // Insert element in the dictionary. |
| 12294 #ifdef DEBUG |
| 12295 int entry = dictionary->FindEntry(index); |
| 12296 DCHECK_EQ(SeededNumberDictionary::kNotFound, entry); |
| 12297 #endif |
| 12298 |
| 12299 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); |
| 12300 Handle<SeededNumberDictionary> new_dictionary = |
| 12301 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, details); |
| 12302 |
| 12303 if (*dictionary == *new_dictionary) return; |
| 12304 |
| 12305 if (object->HasSloppyArgumentsElements()) { |
| 12306 FixedArray::cast(object->elements())->set(1, *new_dictionary); |
| 12307 } else { |
| 12308 object->set_elements(*new_dictionary); |
| 12309 } |
| 12310 } |
| 12311 |
| 12312 |
12288 void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object, | 12313 void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object, |
12289 uint32_t index, | 12314 uint32_t index, |
12290 Handle<Object> value, | 12315 Handle<Object> value, |
12291 PropertyAttributes attributes) { | 12316 PropertyAttributes attributes) { |
12292 // TODO(verwaest): Handle with the elements accessor. | 12317 // TODO(verwaest): Handle with the elements accessor. |
12293 Isolate* isolate = object->GetIsolate(); | 12318 Isolate* isolate = object->GetIsolate(); |
12294 | 12319 |
12295 DCHECK(object->HasDictionaryArgumentsElements()); | 12320 DCHECK(object->HasDictionaryArgumentsElements()); |
12296 | 12321 |
12297 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); | 12322 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); |
12298 uint32_t length = parameter_map->length(); | 12323 uint32_t length = parameter_map->length(); |
12299 Handle<Object> probe = | 12324 Handle<Object> probe = |
12300 index < length - 2 | 12325 index < length - 2 |
12301 ? handle(parameter_map->get(index + 2), isolate) | 12326 ? handle(parameter_map->get(index + 2), isolate) |
12302 : Handle<Object>::cast(isolate->factory()->the_hole_value()); | 12327 : Handle<Object>::cast(isolate->factory()->the_hole_value()); |
12303 if (!probe->IsTheHole()) { | 12328 if (!probe->IsTheHole()) { |
12304 Handle<Context> context(Context::cast(parameter_map->get(0))); | 12329 Handle<Context> context(Context::cast(parameter_map->get(0))); |
12305 int context_index = Handle<Smi>::cast(probe)->value(); | 12330 int context_index = Handle<Smi>::cast(probe)->value(); |
12306 DCHECK(!context->get(context_index)->IsTheHole()); | 12331 DCHECK(!context->get(context_index)->IsTheHole()); |
12307 context->set(context_index, *value); | 12332 context->set(context_index, *value); |
12308 | 12333 |
12309 DCHECK_NE(NONE, attributes); | 12334 DCHECK_NE(NONE, attributes); |
12310 | 12335 |
12311 // Redefining attributes of an aliased element destroys fast aliasing. | 12336 // Redefining attributes of an aliased element destroys fast aliasing. |
12312 parameter_map->set_the_hole(index + 2); | 12337 parameter_map->set_the_hole(index + 2); |
12313 // For elements that are still writable we re-establish slow aliasing. | 12338 // For elements that are still writable we re-establish slow aliasing. |
12314 if ((attributes & READ_ONLY) == 0) { | 12339 if ((attributes & READ_ONLY) == 0) { |
12315 value = isolate->factory()->NewAliasedArgumentsEntry(context_index); | 12340 value = isolate->factory()->NewAliasedArgumentsEntry(context_index); |
12316 } | 12341 } |
12317 AddDictionaryElement(object, index, value, attributes); | 12342 Handle<SeededNumberDictionary> dictionary( |
| 12343 SeededNumberDictionary::cast(parameter_map->get(1))); |
| 12344 AddDictionaryElement(object, dictionary, index, value, attributes); |
12318 } else { | 12345 } else { |
12319 SetDictionaryElement(object, index, value, attributes); | 12346 SetDictionaryElement(object, index, value, attributes); |
12320 } | 12347 } |
12321 } | 12348 } |
12322 | 12349 |
12323 | 12350 |
12324 void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index, | 12351 void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index, |
12325 Handle<Object> value, | 12352 Handle<Object> value, |
12326 PropertyAttributes attributes) { | 12353 PropertyAttributes attributes) { |
12327 // TODO(verwaest): Handle with the elements accessor. | 12354 // TODO(verwaest): Handle with the elements accessor. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12359 context->set(context_index, *value); | 12386 context->set(context_index, *value); |
12360 // For elements that are still writable we keep slow aliasing. | 12387 // For elements that are still writable we keep slow aliasing. |
12361 if (!details.IsReadOnly()) value = element; | 12388 if (!details.IsReadOnly()) value = element; |
12362 } | 12389 } |
12363 } | 12390 } |
12364 | 12391 |
12365 dictionary->ValueAtPut(entry, *value); | 12392 dictionary->ValueAtPut(entry, *value); |
12366 } | 12393 } |
12367 | 12394 |
12368 | 12395 |
12369 static bool ShouldConvertToFastElements(SeededNumberDictionary* dictionary, | |
12370 uint32_t array_size) { | |
12371 // If properties with non-standard attributes or accessors were added, we | |
12372 // cannot go back to fast elements. | |
12373 if (dictionary->requires_slow_elements()) return false; | |
12374 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * | |
12375 SeededNumberDictionary::kEntrySize; | |
12376 return 2 * dictionary_size >= array_size; | |
12377 } | |
12378 | |
12379 | |
12380 void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index, | |
12381 Handle<Object> value, | |
12382 PropertyAttributes attributes) { | |
12383 // TODO(verwaest): Handle with the elements accessor. | |
12384 // Insert element in the dictionary. | |
12385 DCHECK(object->HasDictionaryElements() || | |
12386 object->HasDictionaryArgumentsElements()); | |
12387 DCHECK(object->map()->is_extensible()); | |
12388 | |
12389 Handle<FixedArray> elements(FixedArray::cast(object->elements())); | |
12390 bool is_arguments = object->HasSloppyArgumentsElements(); | |
12391 Handle<SeededNumberDictionary> dictionary( | |
12392 is_arguments ? SeededNumberDictionary::cast(elements->get(1)) | |
12393 : SeededNumberDictionary::cast(*elements)); | |
12394 | |
12395 #ifdef DEBUG | |
12396 int entry = dictionary->FindEntry(index); | |
12397 DCHECK_EQ(SeededNumberDictionary::kNotFound, entry); | |
12398 #endif | |
12399 | |
12400 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | |
12401 Handle<SeededNumberDictionary> new_dictionary = | |
12402 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, details); | |
12403 | |
12404 if (*dictionary != *new_dictionary) { | |
12405 if (is_arguments) { | |
12406 elements->set(1, *new_dictionary); | |
12407 } else { | |
12408 object->set_elements(*new_dictionary); | |
12409 } | |
12410 } | |
12411 | |
12412 uint32_t length = 0; | |
12413 if (object->IsJSArray()) { | |
12414 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&length)); | |
12415 if (index >= length) { | |
12416 length = index + 1; | |
12417 Isolate* isolate = object->GetIsolate(); | |
12418 Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length); | |
12419 JSArray::cast(*object)->set_length(*length_obj); | |
12420 } | |
12421 } else if (!new_dictionary->requires_slow_elements()) { | |
12422 length = new_dictionary->max_number_key() + 1; | |
12423 } | |
12424 | |
12425 // Attempt to put this object back in fast case. | |
12426 if (object->HasDenseElements() && | |
12427 ShouldConvertToFastElements(*new_dictionary, length)) { | |
12428 ElementsKind to_kind = object->BestFittingFastElementsKind(); | |
12429 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); | |
12430 accessor->GrowCapacityAndConvert(object, length); | |
12431 #ifdef DEBUG | |
12432 if (FLAG_trace_normalization) { | |
12433 OFStream os(stdout); | |
12434 os << "Object elements are fast case again:\n"; | |
12435 object->Print(os); | |
12436 } | |
12437 #endif | |
12438 } | |
12439 } | |
12440 | |
12441 | |
12442 // static | 12396 // static |
12443 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, | 12397 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, |
12444 uint32_t index, Handle<Object> value, | 12398 uint32_t index, Handle<Object> value, |
12445 LanguageMode language_mode) { | 12399 LanguageMode language_mode) { |
12446 Isolate* isolate = object->GetIsolate(); | 12400 Isolate* isolate = object->GetIsolate(); |
12447 LookupIterator it(isolate, object, index); | 12401 LookupIterator it(isolate, object, index); |
12448 return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED); | 12402 return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED); |
12449 } | 12403 } |
12450 | 12404 |
12451 | 12405 |
12452 static void AddFastElement(Handle<JSObject> object, uint32_t index, | 12406 static void AddFastElement(Handle<JSObject> object, uint32_t index, |
12453 Handle<Object> value, ElementsKind from_kind, | 12407 Handle<Object> value, ElementsKind from_kind, |
12454 uint32_t capacity, uint32_t new_capacity) { | 12408 uint32_t array_length, uint32_t capacity, |
12455 // Check if the length property of this object needs to be updated. | 12409 uint32_t new_capacity) { |
12456 uint32_t array_length = 0; | 12410 bool introduces_holes = !object->IsJSArray() || index > array_length; |
12457 bool introduces_holes = true; | |
12458 if (object->IsJSArray()) { | |
12459 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length)); | |
12460 introduces_holes = index > array_length; | |
12461 } else { | |
12462 introduces_holes = index >= capacity; | |
12463 } | |
12464 | 12411 |
12465 ElementsKind to_kind = value->OptimalElementsKind(); | 12412 ElementsKind to_kind = value->OptimalElementsKind(); |
12466 if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind); | 12413 if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind); |
12467 to_kind = IsMoreGeneralElementsKindTransition(from_kind, to_kind) ? to_kind | 12414 to_kind = IsMoreGeneralElementsKindTransition(from_kind, to_kind) ? to_kind |
12468 : from_kind; | 12415 : from_kind; |
12469 if (introduces_holes) to_kind = GetHoleyElementsKind(to_kind); | 12416 if (introduces_holes) to_kind = GetHoleyElementsKind(to_kind); |
12470 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); | 12417 ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); |
12471 | 12418 |
12472 // Increase backing store capacity if that's been decided previously. | 12419 // Increase backing store capacity if that's been decided previously. |
12473 if (capacity != new_capacity || IsDictionaryElementsKind(from_kind) || | 12420 // The capacity is indicated as 0 if the incoming object was dictionary or |
| 12421 // slow-mode sloppy arguments. |
| 12422 if (capacity != new_capacity || |
12474 IsFastDoubleElementsKind(from_kind) != | 12423 IsFastDoubleElementsKind(from_kind) != |
12475 IsFastDoubleElementsKind(to_kind)) { | 12424 IsFastDoubleElementsKind(to_kind)) { |
12476 accessor->GrowCapacityAndConvert(object, new_capacity); | 12425 accessor->GrowCapacityAndConvert(object, new_capacity); |
12477 } else if (from_kind != to_kind) { | 12426 } else if (from_kind != to_kind) { |
12478 JSObject::TransitionElementsKind(object, to_kind); | 12427 JSObject::TransitionElementsKind(object, to_kind); |
12479 } | 12428 } |
12480 | 12429 |
12481 if (object->IsJSArray() && index >= array_length) { | |
12482 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); | |
12483 } | |
12484 | |
12485 accessor->Set(object->elements(), index, *value); | 12430 accessor->Set(object->elements(), index, *value); |
12486 } | 12431 } |
12487 | 12432 |
12488 | 12433 |
| 12434 // Do we want to keep fast elements when adding an element at |index|? Returns |
| 12435 // |new_capacity| indicating to which capacity the object should be increased. |
| 12436 static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity, |
| 12437 uint32_t index, |
| 12438 uint32_t* new_capacity) { |
| 12439 STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <= |
| 12440 JSObject::kMaxUncheckedFastElementsLength); |
| 12441 if (index < capacity) { |
| 12442 *new_capacity = capacity; |
| 12443 return false; |
| 12444 } |
| 12445 if (index - capacity >= JSObject::kMaxGap) return true; |
| 12446 *new_capacity = JSObject::NewElementsCapacity(index + 1); |
| 12447 DCHECK_LT(index, *new_capacity); |
| 12448 if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength || |
| 12449 (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength && |
| 12450 object->GetHeap()->InNewSpace(object))) { |
| 12451 return false; |
| 12452 } |
| 12453 // If the fast-case backing storage takes up roughly three times as |
| 12454 // much space (in machine words) as a dictionary backing storage |
| 12455 // would, the object should have slow elements. |
| 12456 int old_capacity = 0; |
| 12457 int used_elements = 0; |
| 12458 object->GetElementsCapacityAndUsage(&old_capacity, &used_elements); |
| 12459 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * |
| 12460 SeededNumberDictionary::kEntrySize; |
| 12461 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; |
| 12462 } |
| 12463 |
| 12464 |
| 12465 bool JSObject::WouldConvertToSlowElements(uint32_t index) { |
| 12466 if (HasFastElements()) { |
| 12467 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); |
| 12468 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); |
| 12469 uint32_t new_capacity; |
| 12470 return ShouldConvertToSlowElements(this, capacity, index, &new_capacity); |
| 12471 } |
| 12472 return false; |
| 12473 } |
| 12474 |
| 12475 |
| 12476 static ElementsKind BestFittingFastElementsKind(JSObject* object) { |
| 12477 if (object->HasSloppyArgumentsElements()) return SLOPPY_ARGUMENTS_ELEMENTS; |
| 12478 DCHECK(object->HasDictionaryElements()); |
| 12479 SeededNumberDictionary* dictionary = object->element_dictionary(); |
| 12480 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; |
| 12481 for (int i = 0; i < dictionary->Capacity(); i++) { |
| 12482 Object* key = dictionary->KeyAt(i); |
| 12483 if (key->IsNumber()) { |
| 12484 Object* value = dictionary->ValueAt(i); |
| 12485 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; |
| 12486 if (!value->IsSmi()) { |
| 12487 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; |
| 12488 kind = FAST_HOLEY_DOUBLE_ELEMENTS; |
| 12489 } |
| 12490 } |
| 12491 } |
| 12492 return kind; |
| 12493 } |
| 12494 |
| 12495 |
| 12496 static bool ShouldConvertToFastElements(JSObject* object, |
| 12497 SeededNumberDictionary* dictionary, |
| 12498 uint32_t index, |
| 12499 uint32_t* new_capacity) { |
| 12500 // If properties with non-standard attributes or accessors were added, we |
| 12501 // cannot go back to fast elements. |
| 12502 if (dictionary->requires_slow_elements()) return false; |
| 12503 |
| 12504 // Adding a property with this index will require slow elements. |
| 12505 if (index >= static_cast<uint32_t>(Smi::kMaxValue)) return false; |
| 12506 |
| 12507 if (object->IsJSArray()) { |
| 12508 Object* length = JSArray::cast(object)->length(); |
| 12509 if (!length->IsSmi()) return false; |
| 12510 *new_capacity = static_cast<uint32_t>(Smi::cast(length)->value()); |
| 12511 } else { |
| 12512 *new_capacity = dictionary->max_number_key() + 1; |
| 12513 } |
| 12514 *new_capacity = Max(index + 1, *new_capacity); |
| 12515 |
| 12516 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * |
| 12517 SeededNumberDictionary::kEntrySize; |
| 12518 return 2 * dictionary_size >= *new_capacity; |
| 12519 } |
| 12520 |
| 12521 |
12489 // static | 12522 // static |
12490 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object, | 12523 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object, |
12491 uint32_t index, | 12524 uint32_t index, |
12492 Handle<Object> value, | 12525 Handle<Object> value, |
12493 PropertyAttributes attributes) { | 12526 PropertyAttributes attributes) { |
12494 DCHECK(object->map()->is_extensible()); | 12527 DCHECK(object->map()->is_extensible()); |
12495 | 12528 |
12496 Isolate* isolate = object->GetIsolate(); | 12529 Isolate* isolate = object->GetIsolate(); |
12497 | 12530 |
12498 // TODO(verwaest): Use ElementAccessor. | 12531 ElementsKind kind = object->GetElementsKind(); |
| 12532 bool handle_slow; |
| 12533 uint32_t old_length = 0; |
| 12534 uint32_t old_capacity = 0; |
| 12535 uint32_t new_capacity = 0; |
| 12536 |
12499 Handle<Object> old_length_handle; | 12537 Handle<Object> old_length_handle; |
12500 if (object->IsJSArray() && object->map()->is_observed()) { | 12538 if (object->IsJSArray()) { |
12501 old_length_handle = handle(JSArray::cast(*object)->length(), isolate); | 12539 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); |
| 12540 if (object->map()->is_observed()) { |
| 12541 old_length_handle = handle(JSArray::cast(*object)->length(), isolate); |
| 12542 } |
12502 } | 12543 } |
12503 | 12544 |
12504 ElementsKind kind = object->GetElementsKind(); | 12545 Handle<SeededNumberDictionary> dictionary; |
12505 bool handle_slow = IsDictionaryElementsKind(kind); | 12546 FixedArrayBase* elements = object->elements(); |
12506 uint32_t capacity = 0; | 12547 if (IsSloppyArgumentsElements(kind)) { |
12507 uint32_t new_capacity = 0; | 12548 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); |
12508 if (attributes != NONE) { | 12549 } |
12509 // TODO(verwaest): Move set_requires_slow_elements into NormalizeElements. | 12550 |
12510 NormalizeElements(object)->set_requires_slow_elements(); | 12551 if (elements->IsSeededNumberDictionary()) { |
12511 handle_slow = true; | 12552 dictionary = handle(SeededNumberDictionary::cast(elements)); |
12512 } else if (IsSloppyArgumentsElements(kind)) { | 12553 handle_slow = attributes != NONE || |
12513 FixedArray* parameter_map = FixedArray::cast(object->elements()); | 12554 !ShouldConvertToFastElements(*object, *dictionary, index, |
12514 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 12555 &new_capacity); |
12515 if (arguments->IsDictionary()) { | 12556 if (!handle_slow) kind = BestFittingFastElementsKind(*object); |
12516 handle_slow = true; | 12557 } else { |
12517 } else { | 12558 old_capacity = static_cast<uint32_t>(elements->length()); |
12518 capacity = static_cast<uint32_t>(arguments->length()); | |
12519 handle_slow = | |
12520 object->ShouldConvertToSlowElements(capacity, index, &new_capacity); | |
12521 if (handle_slow) NormalizeElements(object); | |
12522 } | |
12523 } else if (!handle_slow) { | |
12524 capacity = static_cast<uint32_t>(object->elements()->length()); | |
12525 handle_slow = | 12559 handle_slow = |
12526 object->ShouldConvertToSlowElements(capacity, index, &new_capacity); | 12560 attributes != NONE || ShouldConvertToSlowElements(*object, old_capacity, |
| 12561 index, &new_capacity); |
12527 if (handle_slow) { | 12562 if (handle_slow) { |
12528 NormalizeElements(object); | 12563 dictionary = NormalizeElements(object); |
12529 } else if (IsFastSmiOrObjectElementsKind(kind)) { | 12564 } else if (IsFastSmiOrObjectElementsKind(kind)) { |
12530 EnsureWritableFastElements(object); | 12565 EnsureWritableFastElements(object); |
12531 } | 12566 } |
12532 } | 12567 } |
12533 | 12568 |
12534 if (handle_slow) { | 12569 if (handle_slow) { |
| 12570 if (attributes != NONE) dictionary->set_requires_slow_elements(); |
12535 DCHECK(object->HasDictionaryElements() || | 12571 DCHECK(object->HasDictionaryElements() || |
12536 object->HasDictionaryArgumentsElements()); | 12572 object->HasDictionaryArgumentsElements()); |
12537 AddDictionaryElement(object, index, value, attributes); | 12573 AddDictionaryElement(object, dictionary, index, value, attributes); |
12538 } else { | 12574 } else { |
12539 AddFastElement(object, index, value, kind, capacity, new_capacity); | 12575 AddFastElement(object, index, value, kind, old_length, old_capacity, |
| 12576 new_capacity); |
12540 } | 12577 } |
12541 | 12578 |
12542 if (!old_length_handle.is_null() && | 12579 uint32_t new_length = old_length; |
12543 !old_length_handle->SameValue(Handle<JSArray>::cast(object)->length())) { | 12580 Handle<Object> new_length_handle; |
| 12581 if (object->IsJSArray() && index >= old_length) { |
| 12582 new_length = index + 1; |
| 12583 new_length_handle = isolate->factory()->NewNumberFromUint(new_length); |
| 12584 JSArray::cast(*object)->set_length(*new_length_handle); |
| 12585 } |
| 12586 |
| 12587 if (!old_length_handle.is_null() && new_length != old_length) { |
12544 // |old_length_handle| is kept null above unless the object is observed. | 12588 // |old_length_handle| is kept null above unless the object is observed. |
12545 DCHECK(object->map()->is_observed()); | 12589 DCHECK(object->map()->is_observed()); |
12546 Handle<JSArray> array = Handle<JSArray>::cast(object); | 12590 Handle<JSArray> array = Handle<JSArray>::cast(object); |
12547 Handle<String> name = isolate->factory()->Uint32ToString(index); | 12591 Handle<String> name = isolate->factory()->Uint32ToString(index); |
12548 Handle<Object> new_length_handle(array->length(), isolate); | |
12549 uint32_t old_length = 0; | |
12550 uint32_t new_length = 0; | |
12551 CHECK(old_length_handle->ToArrayLength(&old_length)); | |
12552 CHECK(new_length_handle->ToArrayLength(&new_length)); | |
12553 | 12592 |
12554 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); | 12593 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); |
12555 RETURN_ON_EXCEPTION( | 12594 RETURN_ON_EXCEPTION( |
12556 isolate, EnqueueChangeRecord(array, "add", name, | 12595 isolate, EnqueueChangeRecord(array, "add", name, |
12557 isolate->factory()->the_hole_value()), | 12596 isolate->factory()->the_hole_value()), |
12558 Object); | 12597 Object); |
12559 RETURN_ON_EXCEPTION(isolate, | 12598 RETURN_ON_EXCEPTION(isolate, |
12560 EnqueueChangeRecord(array, "update", | 12599 EnqueueChangeRecord(array, "update", |
12561 isolate->factory()->length_string(), | 12600 isolate->factory()->length_string(), |
12562 old_length_handle), | 12601 old_length_handle), |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12770 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { | 12809 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { |
12771 Isolate* isolate = array->GetIsolate(); | 12810 Isolate* isolate = array->GetIsolate(); |
12772 Handle<Name> length = isolate->factory()->length_string(); | 12811 Handle<Name> length = isolate->factory()->length_string(); |
12773 THROW_NEW_ERROR( | 12812 THROW_NEW_ERROR( |
12774 isolate, | 12813 isolate, |
12775 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, length, array), | 12814 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, length, array), |
12776 Object); | 12815 Object); |
12777 } | 12816 } |
12778 | 12817 |
12779 | 12818 |
12780 bool JSObject::HasDenseElements() { | |
12781 int capacity = 0; | |
12782 int used = 0; | |
12783 GetElementsCapacityAndUsage(&capacity, &used); | |
12784 return (capacity == 0) || (used > (capacity / 2)); | |
12785 } | |
12786 | |
12787 | |
12788 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { | 12819 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
12789 *capacity = 0; | 12820 *capacity = 0; |
12790 *used = 0; | 12821 *used = 0; |
12791 | 12822 |
12792 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); | 12823 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); |
12793 FixedArray* backing_store = NULL; | 12824 FixedArray* backing_store = NULL; |
12794 switch (GetElementsKind()) { | 12825 switch (GetElementsKind()) { |
12795 case SLOPPY_ARGUMENTS_ELEMENTS: | 12826 case SLOPPY_ARGUMENTS_ELEMENTS: |
12796 backing_store_base = | 12827 backing_store_base = |
12797 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); | 12828 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12853 // External arrays are considered 100% used. | 12884 // External arrays are considered 100% used. |
12854 FixedArrayBase* external_array = FixedArrayBase::cast(elements()); | 12885 FixedArrayBase* external_array = FixedArrayBase::cast(elements()); |
12855 *capacity = external_array->length(); | 12886 *capacity = external_array->length(); |
12856 *used = external_array->length(); | 12887 *used = external_array->length(); |
12857 break; | 12888 break; |
12858 } | 12889 } |
12859 } | 12890 } |
12860 } | 12891 } |
12861 | 12892 |
12862 | 12893 |
12863 bool JSObject::WouldConvertToSlowElements(uint32_t index) { | |
12864 if (HasFastElements()) { | |
12865 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements())); | |
12866 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | |
12867 uint32_t new_capacity; | |
12868 return ShouldConvertToSlowElements(capacity, index, &new_capacity); | |
12869 } | |
12870 return false; | |
12871 } | |
12872 | |
12873 | |
12874 bool JSObject::ShouldConvertToSlowElements(uint32_t capacity, uint32_t index, | |
12875 uint32_t* new_capacity) { | |
12876 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <= | |
12877 kMaxUncheckedFastElementsLength); | |
12878 if (index < capacity) { | |
12879 *new_capacity = capacity; | |
12880 return false; | |
12881 } | |
12882 if (index - capacity >= kMaxGap) return true; | |
12883 *new_capacity = NewElementsCapacity(index + 1); | |
12884 DCHECK_LT(index, *new_capacity); | |
12885 if (*new_capacity <= kMaxUncheckedOldFastElementsLength || | |
12886 (*new_capacity <= kMaxUncheckedFastElementsLength && | |
12887 GetHeap()->InNewSpace(this))) { | |
12888 return false; | |
12889 } | |
12890 // If the fast-case backing storage takes up roughly three times as | |
12891 // much space (in machine words) as a dictionary backing storage | |
12892 // would, the object should have slow elements. | |
12893 int old_capacity = 0; | |
12894 int used_elements = 0; | |
12895 GetElementsCapacityAndUsage(&old_capacity, &used_elements); | |
12896 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * | |
12897 SeededNumberDictionary::kEntrySize; | |
12898 return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; | |
12899 } | |
12900 | |
12901 | |
12902 ElementsKind JSObject::BestFittingFastElementsKind() { | |
12903 if (HasSloppyArgumentsElements()) return FAST_HOLEY_ELEMENTS; | |
12904 DCHECK(HasDictionaryElements()); | |
12905 SeededNumberDictionary* dictionary = element_dictionary(); | |
12906 ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; | |
12907 for (int i = 0; i < dictionary->Capacity(); i++) { | |
12908 Object* key = dictionary->KeyAt(i); | |
12909 if (key->IsNumber()) { | |
12910 Object* value = dictionary->ValueAt(i); | |
12911 if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; | |
12912 if (!value->IsSmi()) { | |
12913 if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; | |
12914 kind = FAST_HOLEY_DOUBLE_ELEMENTS; | |
12915 } | |
12916 } | |
12917 } | |
12918 return kind; | |
12919 } | |
12920 | |
12921 | |
12922 // Certain compilers request function template instantiation when they | 12894 // Certain compilers request function template instantiation when they |
12923 // see the definition of the other template functions in the | 12895 // see the definition of the other template functions in the |
12924 // class. This requires us to have the template functions put | 12896 // class. This requires us to have the template functions put |
12925 // together, so even though this function belongs in objects-debug.cc, | 12897 // together, so even though this function belongs in objects-debug.cc, |
12926 // we keep it here instead to satisfy certain compilers. | 12898 // we keep it here instead to satisfy certain compilers. |
12927 #ifdef OBJECT_PRINT | 12899 #ifdef OBJECT_PRINT |
12928 template <typename Derived, typename Shape, typename Key> | 12900 template <typename Derived, typename Shape, typename Key> |
12929 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT | 12901 void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT |
12930 int capacity = this->Capacity(); | 12902 int capacity = this->Capacity(); |
12931 for (int i = 0; i < capacity; i++) { | 12903 for (int i = 0; i < capacity; i++) { |
(...skipping 3303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16235 Handle<Object> new_value) { | 16207 Handle<Object> new_value) { |
16236 if (cell->value() != *new_value) { | 16208 if (cell->value() != *new_value) { |
16237 cell->set_value(*new_value); | 16209 cell->set_value(*new_value); |
16238 Isolate* isolate = cell->GetIsolate(); | 16210 Isolate* isolate = cell->GetIsolate(); |
16239 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16211 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
16240 isolate, DependentCode::kPropertyCellChangedGroup); | 16212 isolate, DependentCode::kPropertyCellChangedGroup); |
16241 } | 16213 } |
16242 } | 16214 } |
16243 } // namespace internal | 16215 } // namespace internal |
16244 } // namespace v8 | 16216 } // namespace v8 |
OLD | NEW |