Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/objects.cc

Issue 8372064: Fix setting array length to be ES5 conform. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments by Daniel Clifford. Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | test/test262/test262.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 8345 matching lines...) Expand 10 before | Expand all | Expand 10 after
8356 set_elements(elems); 8356 set_elements(elems);
8357 8357
8358 if (IsJSArray()) { 8358 if (IsJSArray()) {
8359 JSArray::cast(this)->set_length(Smi::FromInt(length)); 8359 JSArray::cast(this)->set_length(Smi::FromInt(length));
8360 } 8360 }
8361 8361
8362 return this; 8362 return this;
8363 } 8363 }
8364 8364
8365 8365
8366 MaybeObject* JSObject::SetSlowElements(Object* len) {
8367 // We should never end in here with a pixel or external array.
8368 ASSERT(!HasExternalArrayElements());
8369
8370 uint32_t new_length = static_cast<uint32_t>(len->Number());
8371
8372 FixedArrayBase* old_elements = elements();
8373 ElementsKind elements_kind = GetElementsKind();
8374 switch (elements_kind) {
8375 case FAST_SMI_ONLY_ELEMENTS:
8376 case FAST_ELEMENTS:
8377 case FAST_DOUBLE_ELEMENTS: {
8378 // Make sure we never try to shrink dense arrays into sparse arrays.
8379 ASSERT(static_cast<uint32_t>(old_elements->length()) <= new_length);
8380 MaybeObject* result = NormalizeElements();
8381 if (result->IsFailure()) return result;
8382
8383 // Update length for JSArrays.
8384 if (IsJSArray()) JSArray::cast(this)->set_length(len);
8385 break;
8386 }
8387 case DICTIONARY_ELEMENTS: {
8388 if (IsJSArray()) {
8389 uint32_t old_length =
8390 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
8391 element_dictionary()->RemoveNumberEntries(new_length, old_length),
8392 JSArray::cast(this)->set_length(len);
8393 }
8394 break;
8395 }
8396 case NON_STRICT_ARGUMENTS_ELEMENTS:
8397 UNIMPLEMENTED();
8398 break;
8399 case EXTERNAL_BYTE_ELEMENTS:
8400 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8401 case EXTERNAL_SHORT_ELEMENTS:
8402 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8403 case EXTERNAL_INT_ELEMENTS:
8404 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8405 case EXTERNAL_FLOAT_ELEMENTS:
8406 case EXTERNAL_DOUBLE_ELEMENTS:
8407 case EXTERNAL_PIXEL_ELEMENTS:
8408 UNREACHABLE();
8409 break;
8410 }
8411
8412 if (FLAG_trace_elements_transitions) {
8413 PrintElementsTransition(stdout, elements_kind, old_elements,
8414 DICTIONARY_ELEMENTS, elements());
8415 }
8416
8417 return this;
8418 }
8419
8420
8421 MaybeObject* JSArray::Initialize(int capacity) { 8366 MaybeObject* JSArray::Initialize(int capacity) {
8422 Heap* heap = GetHeap(); 8367 Heap* heap = GetHeap();
8423 ASSERT(capacity >= 0); 8368 ASSERT(capacity >= 0);
8424 set_length(Smi::FromInt(0)); 8369 set_length(Smi::FromInt(0));
8425 FixedArray* new_elements; 8370 FixedArray* new_elements;
8426 if (capacity == 0) { 8371 if (capacity == 0) {
8427 new_elements = heap->empty_fixed_array(); 8372 new_elements = heap->empty_fixed_array();
8428 } else { 8373 } else {
8429 Object* obj; 8374 Object* obj;
8430 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); 8375 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
(...skipping 11 matching lines...) Expand all
8442 Handle<FixedArray> old_backing(FixedArray::cast(elements())); 8387 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
8443 int old_size = old_backing->length(); 8388 int old_size = old_backing->length();
8444 int new_size = required_size > old_size ? required_size : old_size; 8389 int new_size = required_size > old_size ? required_size : old_size;
8445 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size); 8390 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
8446 // Can't use this any more now because we may have had a GC! 8391 // Can't use this any more now because we may have had a GC!
8447 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); 8392 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
8448 GetIsolate()->factory()->SetContent(self, new_backing); 8393 GetIsolate()->factory()->SetContent(self, new_backing);
8449 } 8394 }
8450 8395
8451 8396
8452 static Failure* ArrayLengthRangeError(Heap* heap) {
8453 HandleScope scope(heap->isolate());
8454 return heap->isolate()->Throw(
8455 *FACTORY->NewRangeError("invalid_array_length",
8456 HandleVector<Object>(NULL, 0)));
8457 }
8458
8459
8460 MaybeObject* JSObject::SetElementsLength(Object* len) { 8397 MaybeObject* JSObject::SetElementsLength(Object* len) {
8461 // We should never end in here with a pixel or external array. 8398 // We should never end in here with a pixel or external array.
8462 ASSERT(AllowsSetElementsLength()); 8399 ASSERT(AllowsSetElementsLength());
8463 8400 return GetElementsAccessor()->SetLength(this, len);
8464 MaybeObject* maybe_smi_length = len->ToSmi();
8465 Object* smi_length = Smi::FromInt(0);
8466 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
8467 const int value = Smi::cast(smi_length)->value();
8468 if (value < 0) return ArrayLengthRangeError(GetHeap());
8469 ElementsKind elements_kind = GetElementsKind();
8470 switch (elements_kind) {
8471 case FAST_SMI_ONLY_ELEMENTS:
8472 case FAST_ELEMENTS:
8473 case FAST_DOUBLE_ELEMENTS: {
8474 int old_capacity = FixedArrayBase::cast(elements())->length();
8475 if (value <= old_capacity) {
8476 if (IsJSArray()) {
8477 Object* obj;
8478 if (elements_kind == FAST_ELEMENTS ||
8479 elements_kind == FAST_SMI_ONLY_ELEMENTS) {
8480 MaybeObject* maybe_obj = EnsureWritableFastElements();
8481 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8482 }
8483 if (2 * value <= old_capacity) {
8484 // If more than half the elements won't be used, trim the array.
8485 if (value == 0) {
8486 initialize_elements();
8487 } else {
8488 Address filler_start;
8489 int filler_size;
8490 if (elements_kind == FAST_ELEMENTS ||
8491 elements_kind == FAST_SMI_ONLY_ELEMENTS) {
8492 FixedArray* fast_elements = FixedArray::cast(elements());
8493 fast_elements->set_length(value);
8494 filler_start = fast_elements->address() +
8495 FixedArray::OffsetOfElementAt(value);
8496 filler_size = (old_capacity - value) * kPointerSize;
8497 } else {
8498 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
8499 FixedDoubleArray* fast_double_elements =
8500 FixedDoubleArray::cast(elements());
8501 fast_double_elements->set_length(value);
8502 filler_start = fast_double_elements->address() +
8503 FixedDoubleArray::OffsetOfElementAt(value);
8504 filler_size = (old_capacity - value) * kDoubleSize;
8505 }
8506 GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
8507 }
8508 } else {
8509 // Otherwise, fill the unused tail with holes.
8510 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
8511 if (elements_kind == FAST_ELEMENTS ||
8512 elements_kind == FAST_SMI_ONLY_ELEMENTS) {
8513 FixedArray* fast_elements = FixedArray::cast(elements());
8514 for (int i = value; i < old_length; i++) {
8515 fast_elements->set_the_hole(i);
8516 }
8517 } else {
8518 ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS);
8519 FixedDoubleArray* fast_double_elements =
8520 FixedDoubleArray::cast(elements());
8521 for (int i = value; i < old_length; i++) {
8522 fast_double_elements->set_the_hole(i);
8523 }
8524 }
8525 }
8526 JSArray::cast(this)->set_length(Smi::cast(smi_length));
8527 }
8528 return this;
8529 }
8530 int min = NewElementsCapacity(old_capacity);
8531 int new_capacity = value > min ? value : min;
8532 if (!ShouldConvertToSlowElements(new_capacity)) {
8533 MaybeObject* result;
8534 if (elements_kind == FAST_ELEMENTS ||
8535 elements_kind == FAST_SMI_ONLY_ELEMENTS) {
8536 SetFastElementsCapacityMode set_capacity_mode =
8537 elements_kind == FAST_SMI_ONLY_ELEMENTS
8538 ? kAllowSmiOnlyElements
8539 : kDontAllowSmiOnlyElements;
8540 result = SetFastElementsCapacityAndLength(new_capacity,
8541 value,
8542 set_capacity_mode);
8543 } else {
8544 ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS);
8545 result = SetFastDoubleElementsCapacityAndLength(new_capacity,
8546 value);
8547 }
8548 if (result->IsFailure()) return result;
8549 return this;
8550 }
8551 break;
8552 }
8553 case DICTIONARY_ELEMENTS: {
8554 if (IsJSArray()) {
8555 if (value == 0) {
8556 // If the length of a slow array is reset to zero, we clear
8557 // the array and flush backing storage. This has the added
8558 // benefit that the array returns to fast mode.
8559 Object* obj;
8560 { MaybeObject* maybe_obj = ResetElements();
8561 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8562 }
8563 } else {
8564 // Remove deleted elements.
8565 uint32_t old_length =
8566 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
8567 element_dictionary()->RemoveNumberEntries(value, old_length);
8568 }
8569 JSArray::cast(this)->set_length(Smi::cast(smi_length));
8570 }
8571 return this;
8572 }
8573 case NON_STRICT_ARGUMENTS_ELEMENTS:
8574 case EXTERNAL_BYTE_ELEMENTS:
8575 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8576 case EXTERNAL_SHORT_ELEMENTS:
8577 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8578 case EXTERNAL_INT_ELEMENTS:
8579 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8580 case EXTERNAL_FLOAT_ELEMENTS:
8581 case EXTERNAL_DOUBLE_ELEMENTS:
8582 case EXTERNAL_PIXEL_ELEMENTS:
8583 UNREACHABLE();
8584 break;
8585 }
8586 }
8587
8588 // General slow case.
8589 if (len->IsNumber()) {
8590 uint32_t length;
8591 if (len->ToArrayIndex(&length)) {
8592 return SetSlowElements(len);
8593 } else {
8594 return ArrayLengthRangeError(GetHeap());
8595 }
8596 }
8597
8598 // len is not a number so make the array size one and
8599 // set only element to len.
8600 Object* obj;
8601 MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
8602 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8603 FixedArray::cast(obj)->set(0, len);
8604
8605 maybe_obj = EnsureCanContainElements(&len, 1);
8606 if (maybe_obj->IsFailure()) return maybe_obj;
8607
8608 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
8609 set_elements(FixedArray::cast(obj));
8610 return this;
8611 } 8401 }
8612 8402
8613 8403
8614 Object* Map::GetPrototypeTransition(Object* prototype) { 8404 Object* Map::GetPrototypeTransition(Object* prototype) {
8615 FixedArray* cache = prototype_transitions(); 8405 FixedArray* cache = prototype_transitions();
8616 int number_of_transitions = NumberOfProtoTransitions(); 8406 int number_of_transitions = NumberOfProtoTransitions();
8617 const int proto_offset = 8407 const int proto_offset =
8618 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset; 8408 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8619 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; 8409 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8620 const int step = kProtoTransitionElementsPerEntry; 8410 const int step = kProtoTransitionElementsPerEntry;
(...skipping 3350 matching lines...) Expand 10 before | Expand all | Expand 10 after
11971 // If not, we generate new indices for the properties. 11761 // If not, we generate new indices for the properties.
11972 Object* result; 11762 Object* result;
11973 { MaybeObject* maybe_result = GenerateNewEnumerationIndices(); 11763 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11974 if (!maybe_result->ToObject(&result)) return maybe_result; 11764 if (!maybe_result->ToObject(&result)) return maybe_result;
11975 } 11765 }
11976 } 11766 }
11977 return HashTable<Shape, Key>::EnsureCapacity(n, key); 11767 return HashTable<Shape, Key>::EnsureCapacity(n, key);
11978 } 11768 }
11979 11769
11980 11770
11981 void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
11982 // Do nothing if the interval [from, to) is empty.
11983 if (from >= to) return;
11984
11985 Heap* heap = GetHeap();
11986 int removed_entries = 0;
11987 Object* sentinel = heap->null_value();
11988 int capacity = Capacity();
11989 for (int i = 0; i < capacity; i++) {
11990 Object* key = KeyAt(i);
11991 if (key->IsNumber()) {
11992 uint32_t number = static_cast<uint32_t>(key->Number());
11993 if (from <= number && number < to) {
11994 SetEntry(i, sentinel, sentinel);
11995 removed_entries++;
11996 }
11997 }
11998 }
11999
12000 // Update the number of elements.
12001 ElementsRemoved(removed_entries);
12002 }
12003
12004
12005 template<typename Shape, typename Key> 11771 template<typename Shape, typename Key>
12006 Object* Dictionary<Shape, Key>::DeleteProperty(int entry, 11772 Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
12007 JSReceiver::DeleteMode mode) { 11773 JSReceiver::DeleteMode mode) {
12008 Heap* heap = Dictionary<Shape, Key>::GetHeap(); 11774 Heap* heap = Dictionary<Shape, Key>::GetHeap();
12009 PropertyDetails details = DetailsAt(entry); 11775 PropertyDetails details = DetailsAt(entry);
12010 // Ignore attributes if forcing a deletion. 11776 // Ignore attributes if forcing a deletion.
12011 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) { 11777 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
12012 return heap->false_value(); 11778 return heap->false_value();
12013 } 11779 }
12014 SetEntry(entry, heap->null_value(), heap->null_value()); 11780 SetEntry(entry, heap->null_value(), heap->null_value());
(...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after
12752 if (break_point_objects()->IsUndefined()) return 0; 12518 if (break_point_objects()->IsUndefined()) return 0;
12753 // Single break point. 12519 // Single break point.
12754 if (!break_point_objects()->IsFixedArray()) return 1; 12520 if (!break_point_objects()->IsFixedArray()) return 1;
12755 // Multiple break points. 12521 // Multiple break points.
12756 return FixedArray::cast(break_point_objects())->length(); 12522 return FixedArray::cast(break_point_objects())->length();
12757 } 12523 }
12758 #endif // ENABLE_DEBUGGER_SUPPORT 12524 #endif // ENABLE_DEBUGGER_SUPPORT
12759 12525
12760 12526
12761 } } // namespace v8::internal 12527 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | test/test262/test262.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698