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

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