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

Side by Side Diff: src/runtime.cc

Issue 11377132: Support all fast elements kinds in the major array operations. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments (and rebased) Created 8 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/parser.cc ('k') | src/x64/macro-assembler-x64.h » ('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 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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/parser.cc ('k') | src/x64/macro-assembler-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698