OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 4084 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4095 } | 4095 } |
4096 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) { | 4096 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) { |
4097 // JSObject without a string key. If the key is a Smi, check for a | 4097 // JSObject without a string key. If the key is a Smi, check for a |
4098 // definite out-of-bounds access to elements, which is a strong indicator | 4098 // definite out-of-bounds access to elements, which is a strong indicator |
4099 // that subsequent accesses will also call the runtime. Proactively | 4099 // that subsequent accesses will also call the runtime. Proactively |
4100 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of | 4100 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of |
4101 // doubles for those future calls in the case that the elements would | 4101 // doubles for those future calls in the case that the elements would |
4102 // become FAST_DOUBLE_ELEMENTS. | 4102 // become FAST_DOUBLE_ELEMENTS. |
4103 Handle<JSObject> js_object(args.at<JSObject>(0)); | 4103 Handle<JSObject> js_object(args.at<JSObject>(0)); |
4104 ElementsKind elements_kind = js_object->GetElementsKind(); | 4104 ElementsKind elements_kind = js_object->GetElementsKind(); |
4105 if (IsFastElementsKind(elements_kind) && | 4105 if (IsFastDoubleElementsKind(elements_kind)) { |
4106 !IsFastObjectElementsKind(elements_kind)) { | |
4107 FixedArrayBase* elements = js_object->elements(); | 4106 FixedArrayBase* elements = js_object->elements(); |
4108 if (args.at<Smi>(1)->value() >= elements->length()) { | 4107 if (args.at<Smi>(1)->value() >= elements->length()) { |
4109 if (IsFastHoleyElementsKind(elements_kind)) { | 4108 if (IsFastHoleyElementsKind(elements_kind)) { |
4110 elements_kind = FAST_HOLEY_ELEMENTS; | 4109 elements_kind = FAST_HOLEY_ELEMENTS; |
4111 } else { | 4110 } else { |
4112 elements_kind = FAST_ELEMENTS; | 4111 elements_kind = FAST_ELEMENTS; |
4113 } | 4112 } |
4114 MaybeObject* maybe_object = TransitionElements(js_object, | 4113 MaybeObject* maybe_object = TransitionElements(js_object, |
4115 elements_kind, | 4114 elements_kind, |
4116 isolate); | 4115 isolate); |
4117 if (maybe_object->IsFailure()) return maybe_object; | 4116 if (maybe_object->IsFailure()) return maybe_object; |
4118 } | 4117 } |
| 4118 } else { |
| 4119 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || |
| 4120 !IsFastElementsKind(elements_kind)); |
4119 } | 4121 } |
4120 } | 4122 } |
4121 } else if (args[0]->IsString() && args[1]->IsSmi()) { | 4123 } else if (args[0]->IsString() && args[1]->IsSmi()) { |
4122 // Fast case for string indexing using [] with a smi index. | 4124 // Fast case for string indexing using [] with a smi index. |
4123 HandleScope scope(isolate); | 4125 HandleScope scope(isolate); |
4124 Handle<String> str = args.at<String>(0); | 4126 Handle<String> str = args.at<String>(0); |
4125 int index = args.smi_at(1); | 4127 int index = args.smi_at(1); |
4126 if (index >= 0 && index < str->length()) { | 4128 if (index >= 0 && index < str->length()) { |
4127 Handle<Object> result = GetCharAt(str, index); | 4129 Handle<Object> result = GetCharAt(str, index); |
4128 return *result; | 4130 return *result; |
(...skipping 5167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9296 ASSERT(!fast_elements_); | 9298 ASSERT(!fast_elements_); |
9297 Handle<SeededNumberDictionary> dict( | 9299 Handle<SeededNumberDictionary> dict( |
9298 SeededNumberDictionary::cast(*storage_)); | 9300 SeededNumberDictionary::cast(*storage_)); |
9299 Handle<SeededNumberDictionary> result = | 9301 Handle<SeededNumberDictionary> result = |
9300 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); | 9302 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); |
9301 if (!result.is_identical_to(dict)) { | 9303 if (!result.is_identical_to(dict)) { |
9302 // Dictionary needed to grow. | 9304 // Dictionary needed to grow. |
9303 clear_storage(); | 9305 clear_storage(); |
9304 set_storage(*result); | 9306 set_storage(*result); |
9305 } | 9307 } |
9306 } | 9308 } |
9307 | 9309 |
9308 void increase_index_offset(uint32_t delta) { | 9310 void increase_index_offset(uint32_t delta) { |
9309 if (JSObject::kMaxElementCount - index_offset_ < delta) { | 9311 if (JSObject::kMaxElementCount - index_offset_ < delta) { |
9310 index_offset_ = JSObject::kMaxElementCount; | 9312 index_offset_ = JSObject::kMaxElementCount; |
9311 } else { | 9313 } else { |
9312 index_offset_ += delta; | 9314 index_offset_ += delta; |
9313 } | 9315 } |
9314 } | 9316 } |
9315 | 9317 |
9316 Handle<JSArray> ToArray() { | 9318 Handle<JSArray> ToArray() { |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9387 // a 32-bit signed integer. | 9389 // a 32-bit signed integer. |
9388 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); | 9390 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); |
9389 int fast_length = static_cast<int>(length); | 9391 int fast_length = static_cast<int>(length); |
9390 Handle<FixedArray> elements(FixedArray::cast(array->elements())); | 9392 Handle<FixedArray> elements(FixedArray::cast(array->elements())); |
9391 for (int i = 0; i < fast_length; i++) { | 9393 for (int i = 0; i < fast_length; i++) { |
9392 if (!elements->get(i)->IsTheHole()) element_count++; | 9394 if (!elements->get(i)->IsTheHole()) element_count++; |
9393 } | 9395 } |
9394 break; | 9396 break; |
9395 } | 9397 } |
9396 case FAST_DOUBLE_ELEMENTS: | 9398 case FAST_DOUBLE_ELEMENTS: |
9397 case FAST_HOLEY_DOUBLE_ELEMENTS: | 9399 case FAST_HOLEY_DOUBLE_ELEMENTS: { |
9398 // TODO(1810): Decide if it's worthwhile to implement this. | 9400 // Fast elements can't have lengths that are not representable by |
9399 UNREACHABLE(); | 9401 // a 32-bit signed integer. |
| 9402 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0); |
| 9403 int fast_length = static_cast<int>(length); |
| 9404 if (array->elements()->IsFixedArray()) { |
| 9405 ASSERT(FixedArray::cast(array->elements())->length() == 0); |
| 9406 break; |
| 9407 } |
| 9408 Handle<FixedDoubleArray> elements( |
| 9409 FixedDoubleArray::cast(array->elements())); |
| 9410 for (int i = 0; i < fast_length; i++) { |
| 9411 if (!elements->is_the_hole(i)) element_count++; |
| 9412 } |
9400 break; | 9413 break; |
| 9414 } |
9401 case DICTIONARY_ELEMENTS: { | 9415 case DICTIONARY_ELEMENTS: { |
9402 Handle<SeededNumberDictionary> dictionary( | 9416 Handle<SeededNumberDictionary> dictionary( |
9403 SeededNumberDictionary::cast(array->elements())); | 9417 SeededNumberDictionary::cast(array->elements())); |
9404 int capacity = dictionary->Capacity(); | 9418 int capacity = dictionary->Capacity(); |
9405 for (int i = 0; i < capacity; i++) { | 9419 for (int i = 0; i < capacity; i++) { |
9406 Handle<Object> key(dictionary->KeyAt(i)); | 9420 Handle<Object> key(dictionary->KeyAt(i)); |
9407 if (dictionary->IsKey(*key)) { | 9421 if (dictionary->IsKey(*key)) { |
9408 element_count++; | 9422 element_count++; |
9409 } | 9423 } |
9410 } | 9424 } |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9633 // have the correct receiver. | 9647 // have the correct receiver. |
9634 element_value = Object::GetElement(receiver, j); | 9648 element_value = Object::GetElement(receiver, j); |
9635 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); | 9649 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); |
9636 visitor->visit(j, element_value); | 9650 visitor->visit(j, element_value); |
9637 } | 9651 } |
9638 } | 9652 } |
9639 break; | 9653 break; |
9640 } | 9654 } |
9641 case FAST_HOLEY_DOUBLE_ELEMENTS: | 9655 case FAST_HOLEY_DOUBLE_ELEMENTS: |
9642 case FAST_DOUBLE_ELEMENTS: { | 9656 case FAST_DOUBLE_ELEMENTS: { |
9643 // TODO(1810): Decide if it's worthwhile to implement this. | 9657 // Run through the elements FixedArray and use HasElement and GetElement |
9644 UNREACHABLE(); | 9658 // to check the prototype for missing elements. |
| 9659 Handle<FixedDoubleArray> elements( |
| 9660 FixedDoubleArray::cast(receiver->elements())); |
| 9661 int fast_length = static_cast<int>(length); |
| 9662 ASSERT(fast_length <= elements->length()); |
| 9663 for (int j = 0; j < fast_length; j++) { |
| 9664 HandleScope loop_scope(isolate); |
| 9665 if (!elements->is_the_hole(j)) { |
| 9666 double double_value = elements->get_scalar(j); |
| 9667 Handle<Object> element_value = |
| 9668 isolate->factory()->NewNumber(double_value); |
| 9669 visitor->visit(j, element_value); |
| 9670 } else if (receiver->HasElement(j)) { |
| 9671 // Call GetElement on receiver, not its prototype, or getters won't |
| 9672 // have the correct receiver. |
| 9673 Handle<Object> element_value = Object::GetElement(receiver, j); |
| 9674 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); |
| 9675 visitor->visit(j, element_value); |
| 9676 } |
| 9677 } |
9645 break; | 9678 break; |
9646 } | 9679 } |
9647 case DICTIONARY_ELEMENTS: { | 9680 case DICTIONARY_ELEMENTS: { |
9648 Handle<SeededNumberDictionary> dict(receiver->element_dictionary()); | 9681 Handle<SeededNumberDictionary> dict(receiver->element_dictionary()); |
9649 List<uint32_t> indices(dict->Capacity() / 2); | 9682 List<uint32_t> indices(dict->Capacity() / 2); |
9650 // Collect all indices in the object and the prototypes less | 9683 // Collect all indices in the object and the prototypes less |
9651 // than length. This might introduce duplicates in the indices list. | 9684 // than length. This might introduce duplicates in the indices list. |
9652 CollectElementIndices(receiver, length, &indices); | 9685 CollectElementIndices(receiver, length, &indices); |
9653 indices.Sort(&compareUInt32); | 9686 indices.Sort(&compareUInt32); |
9654 int j = 0; | 9687 int j = 0; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9737 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0); | 9770 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0); |
9738 int argument_count = static_cast<int>(arguments->length()->Number()); | 9771 int argument_count = static_cast<int>(arguments->length()->Number()); |
9739 RUNTIME_ASSERT(arguments->HasFastObjectElements()); | 9772 RUNTIME_ASSERT(arguments->HasFastObjectElements()); |
9740 Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); | 9773 Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); |
9741 | 9774 |
9742 // Pass 1: estimate the length and number of elements of the result. | 9775 // Pass 1: estimate the length and number of elements of the result. |
9743 // The actual length can be larger if any of the arguments have getters | 9776 // The actual length can be larger if any of the arguments have getters |
9744 // that mutate other arguments (but will otherwise be precise). | 9777 // that mutate other arguments (but will otherwise be precise). |
9745 // The number of elements is precise if there are no inherited elements. | 9778 // The number of elements is precise if there are no inherited elements. |
9746 | 9779 |
| 9780 ElementsKind kind = FAST_SMI_ELEMENTS; |
| 9781 |
9747 uint32_t estimate_result_length = 0; | 9782 uint32_t estimate_result_length = 0; |
9748 uint32_t estimate_nof_elements = 0; | 9783 uint32_t estimate_nof_elements = 0; |
9749 { | 9784 for (int i = 0; i < argument_count; i++) { |
9750 for (int i = 0; i < argument_count; i++) { | 9785 HandleScope loop_scope; |
9751 HandleScope loop_scope; | 9786 Handle<Object> obj(elements->get(i)); |
9752 Handle<Object> obj(elements->get(i)); | 9787 uint32_t length_estimate; |
9753 uint32_t length_estimate; | 9788 uint32_t element_estimate; |
9754 uint32_t element_estimate; | 9789 if (obj->IsJSArray()) { |
9755 if (obj->IsJSArray()) { | 9790 Handle<JSArray> array(Handle<JSArray>::cast(obj)); |
9756 Handle<JSArray> array(Handle<JSArray>::cast(obj)); | 9791 length_estimate = static_cast<uint32_t>(array->length()->Number()); |
9757 // TODO(1810): Find out if it's worthwhile to properly support | 9792 if (length_estimate != 0) { |
9758 // arbitrary ElementsKinds. For now, pessimistically transition to | 9793 ElementsKind array_kind = |
9759 // FAST_*_ELEMENTS. | 9794 GetPackedElementsKind(array->map()->elements_kind()); |
9760 if (array->HasFastDoubleElements()) { | 9795 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) { |
9761 ElementsKind to_kind = FAST_ELEMENTS; | 9796 kind = array_kind; |
9762 if (array->HasFastHoleyElements()) { | 9797 } |
9763 to_kind = FAST_HOLEY_ELEMENTS; | 9798 } |
| 9799 element_estimate = EstimateElementCount(array); |
| 9800 } else { |
| 9801 if (obj->IsHeapObject()) { |
| 9802 if (obj->IsNumber()) { |
| 9803 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) { |
| 9804 kind = FAST_DOUBLE_ELEMENTS; |
9764 } | 9805 } |
9765 array = Handle<JSArray>::cast( | 9806 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) { |
9766 JSObject::TransitionElementsKind(array, to_kind)); | 9807 kind = FAST_ELEMENTS; |
9767 } | 9808 } |
9768 length_estimate = | |
9769 static_cast<uint32_t>(array->length()->Number()); | |
9770 element_estimate = | |
9771 EstimateElementCount(array); | |
9772 } else { | |
9773 length_estimate = 1; | |
9774 element_estimate = 1; | |
9775 } | 9809 } |
9776 // Avoid overflows by capping at kMaxElementCount. | 9810 length_estimate = 1; |
9777 if (JSObject::kMaxElementCount - estimate_result_length < | 9811 element_estimate = 1; |
9778 length_estimate) { | 9812 } |
9779 estimate_result_length = JSObject::kMaxElementCount; | 9813 // Avoid overflows by capping at kMaxElementCount. |
9780 } else { | 9814 if (JSObject::kMaxElementCount - estimate_result_length < |
9781 estimate_result_length += length_estimate; | 9815 length_estimate) { |
9782 } | 9816 estimate_result_length = JSObject::kMaxElementCount; |
9783 if (JSObject::kMaxElementCount - estimate_nof_elements < | 9817 } else { |
9784 element_estimate) { | 9818 estimate_result_length += length_estimate; |
9785 estimate_nof_elements = JSObject::kMaxElementCount; | 9819 } |
9786 } else { | 9820 if (JSObject::kMaxElementCount - estimate_nof_elements < |
9787 estimate_nof_elements += element_estimate; | 9821 element_estimate) { |
9788 } | 9822 estimate_nof_elements = JSObject::kMaxElementCount; |
| 9823 } else { |
| 9824 estimate_nof_elements += element_estimate; |
9789 } | 9825 } |
9790 } | 9826 } |
9791 | 9827 |
9792 // If estimated number of elements is more than half of length, a | 9828 // If estimated number of elements is more than half of length, a |
9793 // fixed array (fast case) is more time and space-efficient than a | 9829 // fixed array (fast case) is more time and space-efficient than a |
9794 // dictionary. | 9830 // dictionary. |
9795 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; | 9831 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; |
9796 | 9832 |
9797 Handle<FixedArray> storage; | 9833 Handle<FixedArray> storage; |
9798 if (fast_case) { | 9834 if (fast_case) { |
9799 // The backing storage array must have non-existing elements to | 9835 if (kind == FAST_DOUBLE_ELEMENTS) { |
9800 // preserve holes across concat operations. | 9836 Handle<FixedDoubleArray> double_storage = |
| 9837 isolate->factory()->NewFixedDoubleArray(estimate_result_length); |
| 9838 int j = 0; |
| 9839 bool failure = false; |
| 9840 for (int i = 0; i < argument_count; i++) { |
| 9841 Handle<Object> obj(elements->get(i)); |
| 9842 if (obj->IsSmi()) { |
| 9843 double_storage->set(j, Smi::cast(*obj)->value()); |
| 9844 j++; |
| 9845 } else if (obj->IsNumber()) { |
| 9846 double_storage->set(j, obj->Number()); |
| 9847 j++; |
| 9848 } else { |
| 9849 JSArray* array = JSArray::cast(*obj); |
| 9850 uint32_t length = static_cast<uint32_t>(array->length()->Number()); |
| 9851 switch (array->map()->elements_kind()) { |
| 9852 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 9853 case FAST_DOUBLE_ELEMENTS: { |
| 9854 // Empty fixed array indicates that there are no elements. |
| 9855 if (array->elements()->IsFixedArray()) break; |
| 9856 FixedDoubleArray* elements = |
| 9857 FixedDoubleArray::cast(array->elements()); |
| 9858 for (uint32_t i = 0; i < length; i++) { |
| 9859 if (elements->is_the_hole(i)) { |
| 9860 failure = true; |
| 9861 break; |
| 9862 } |
| 9863 double double_value = elements->get_scalar(i); |
| 9864 double_storage->set(j, double_value); |
| 9865 j++; |
| 9866 } |
| 9867 break; |
| 9868 } |
| 9869 case FAST_HOLEY_SMI_ELEMENTS: |
| 9870 case FAST_SMI_ELEMENTS: { |
| 9871 FixedArray* elements( |
| 9872 FixedArray::cast(array->elements())); |
| 9873 for (uint32_t i = 0; i < length; i++) { |
| 9874 Object* element = elements->get(i); |
| 9875 if (element->IsTheHole()) { |
| 9876 failure = true; |
| 9877 break; |
| 9878 } |
| 9879 int32_t int_value = Smi::cast(element)->value(); |
| 9880 double_storage->set(j, int_value); |
| 9881 j++; |
| 9882 } |
| 9883 break; |
| 9884 } |
| 9885 case FAST_HOLEY_ELEMENTS: |
| 9886 ASSERT_EQ(0, length); |
| 9887 break; |
| 9888 default: |
| 9889 UNREACHABLE(); |
| 9890 } |
| 9891 } |
| 9892 if (failure) break; |
| 9893 } |
| 9894 Handle<JSArray> array = isolate->factory()->NewJSArray(0); |
| 9895 Smi* length = Smi::FromInt(j); |
| 9896 Handle<Map> map; |
| 9897 map = isolate->factory()->GetElementsTransitionMap(array, kind); |
| 9898 array->set_map(*map); |
| 9899 array->set_length(length); |
| 9900 array->set_elements(*double_storage); |
| 9901 return *array; |
| 9902 } |
| 9903 // The backing storage array must have non-existing elements to preserve |
| 9904 // holes across concat operations. |
9801 storage = isolate->factory()->NewFixedArrayWithHoles( | 9905 storage = isolate->factory()->NewFixedArrayWithHoles( |
9802 estimate_result_length); | 9906 estimate_result_length); |
9803 } else { | 9907 } else { |
9804 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate | 9908 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate |
9805 uint32_t at_least_space_for = estimate_nof_elements + | 9909 uint32_t at_least_space_for = estimate_nof_elements + |
9806 (estimate_nof_elements >> 2); | 9910 (estimate_nof_elements >> 2); |
9807 storage = Handle<FixedArray>::cast( | 9911 storage = Handle<FixedArray>::cast( |
9808 isolate->factory()->NewSeededNumberDictionary(at_least_space_for)); | 9912 isolate->factory()->NewSeededNumberDictionary(at_least_space_for)); |
9809 } | 9913 } |
9810 | 9914 |
(...skipping 3506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13317 // Handle last resort GC and make sure to allow future allocations | 13421 // Handle last resort GC and make sure to allow future allocations |
13318 // to grow the heap without causing GCs (if possible). | 13422 // to grow the heap without causing GCs (if possible). |
13319 isolate->counters()->gc_last_resort_from_js()->Increment(); | 13423 isolate->counters()->gc_last_resort_from_js()->Increment(); |
13320 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 13424 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
13321 "Runtime::PerformGC"); | 13425 "Runtime::PerformGC"); |
13322 } | 13426 } |
13323 } | 13427 } |
13324 | 13428 |
13325 | 13429 |
13326 } } // namespace v8::internal | 13430 } } // namespace v8::internal |
OLD | NEW |