| Index: src/runtime.cc
|
| diff --git a/src/runtime.cc b/src/runtime.cc
|
| index a63b66d49254e4787b5ee8d00afab78bb219a36a..7bd771be8640ba83e043ad2ec7d93c3e79c84905 100644
|
| --- a/src/runtime.cc
|
| +++ b/src/runtime.cc
|
| @@ -4102,8 +4102,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
|
| // become FAST_DOUBLE_ELEMENTS.
|
| Handle<JSObject> js_object(args.at<JSObject>(0));
|
| ElementsKind elements_kind = js_object->GetElementsKind();
|
| - if (IsFastElementsKind(elements_kind) &&
|
| - !IsFastObjectElementsKind(elements_kind)) {
|
| + if (IsFastDoubleElementsKind(elements_kind)) {
|
| FixedArrayBase* elements = js_object->elements();
|
| if (args.at<Smi>(1)->value() >= elements->length()) {
|
| if (IsFastHoleyElementsKind(elements_kind)) {
|
| @@ -4116,6 +4115,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
|
| isolate);
|
| if (maybe_object->IsFailure()) return maybe_object;
|
| }
|
| + } else {
|
| + ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
|
| + !IsFastElementsKind(elements_kind));
|
| }
|
| }
|
| } else if (args[0]->IsString() && args[1]->IsSmi()) {
|
| @@ -9303,7 +9305,7 @@ class ArrayConcatVisitor {
|
| clear_storage();
|
| set_storage(*result);
|
| }
|
| -}
|
| + }
|
|
|
| void increase_index_offset(uint32_t delta) {
|
| if (JSObject::kMaxElementCount - index_offset_ < delta) {
|
| @@ -9394,10 +9396,22 @@ static uint32_t EstimateElementCount(Handle<JSArray> array) {
|
| break;
|
| }
|
| case FAST_DOUBLE_ELEMENTS:
|
| - case FAST_HOLEY_DOUBLE_ELEMENTS:
|
| - // TODO(1810): Decide if it's worthwhile to implement this.
|
| - UNREACHABLE();
|
| + case FAST_HOLEY_DOUBLE_ELEMENTS: {
|
| + // Fast elements can't have lengths that are not representable by
|
| + // a 32-bit signed integer.
|
| + ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
|
| + int fast_length = static_cast<int>(length);
|
| + if (array->elements()->IsFixedArray()) {
|
| + ASSERT(FixedArray::cast(array->elements())->length() == 0);
|
| + break;
|
| + }
|
| + Handle<FixedDoubleArray> elements(
|
| + FixedDoubleArray::cast(array->elements()));
|
| + for (int i = 0; i < fast_length; i++) {
|
| + if (!elements->is_the_hole(i)) element_count++;
|
| + }
|
| break;
|
| + }
|
| case DICTIONARY_ELEMENTS: {
|
| Handle<SeededNumberDictionary> dictionary(
|
| SeededNumberDictionary::cast(array->elements()));
|
| @@ -9640,8 +9654,27 @@ static bool IterateElements(Isolate* isolate,
|
| }
|
| case FAST_HOLEY_DOUBLE_ELEMENTS:
|
| case FAST_DOUBLE_ELEMENTS: {
|
| - // TODO(1810): Decide if it's worthwhile to implement this.
|
| - UNREACHABLE();
|
| + // Run through the elements FixedArray and use HasElement and GetElement
|
| + // to check the prototype for missing elements.
|
| + Handle<FixedDoubleArray> elements(
|
| + FixedDoubleArray::cast(receiver->elements()));
|
| + int fast_length = static_cast<int>(length);
|
| + ASSERT(fast_length <= elements->length());
|
| + for (int j = 0; j < fast_length; j++) {
|
| + HandleScope loop_scope(isolate);
|
| + if (!elements->is_the_hole(j)) {
|
| + double double_value = elements->get_scalar(j);
|
| + Handle<Object> element_value =
|
| + isolate->factory()->NewNumber(double_value);
|
| + visitor->visit(j, element_value);
|
| + } else if (receiver->HasElement(j)) {
|
| + // Call GetElement on receiver, not its prototype, or getters won't
|
| + // have the correct receiver.
|
| + Handle<Object> element_value = Object::GetElement(receiver, j);
|
| + RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
|
| + visitor->visit(j, element_value);
|
| + }
|
| + }
|
| break;
|
| }
|
| case DICTIONARY_ELEMENTS: {
|
| @@ -9744,48 +9777,51 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
|
| // that mutate other arguments (but will otherwise be precise).
|
| // The number of elements is precise if there are no inherited elements.
|
|
|
| + ElementsKind kind = FAST_SMI_ELEMENTS;
|
| +
|
| uint32_t estimate_result_length = 0;
|
| uint32_t estimate_nof_elements = 0;
|
| - {
|
| - for (int i = 0; i < argument_count; i++) {
|
| - HandleScope loop_scope;
|
| - Handle<Object> obj(elements->get(i));
|
| - uint32_t length_estimate;
|
| - uint32_t element_estimate;
|
| - if (obj->IsJSArray()) {
|
| - Handle<JSArray> array(Handle<JSArray>::cast(obj));
|
| - // TODO(1810): Find out if it's worthwhile to properly support
|
| - // arbitrary ElementsKinds. For now, pessimistically transition to
|
| - // FAST_*_ELEMENTS.
|
| - if (array->HasFastDoubleElements()) {
|
| - ElementsKind to_kind = FAST_ELEMENTS;
|
| - if (array->HasFastHoleyElements()) {
|
| - to_kind = FAST_HOLEY_ELEMENTS;
|
| - }
|
| - array = Handle<JSArray>::cast(
|
| - JSObject::TransitionElementsKind(array, to_kind));
|
| + for (int i = 0; i < argument_count; i++) {
|
| + HandleScope loop_scope;
|
| + Handle<Object> obj(elements->get(i));
|
| + uint32_t length_estimate;
|
| + uint32_t element_estimate;
|
| + if (obj->IsJSArray()) {
|
| + Handle<JSArray> array(Handle<JSArray>::cast(obj));
|
| + length_estimate = static_cast<uint32_t>(array->length()->Number());
|
| + if (length_estimate != 0) {
|
| + ElementsKind array_kind =
|
| + GetPackedElementsKind(array->map()->elements_kind());
|
| + if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
|
| + kind = array_kind;
|
| }
|
| - length_estimate =
|
| - static_cast<uint32_t>(array->length()->Number());
|
| - element_estimate =
|
| - EstimateElementCount(array);
|
| - } else {
|
| - length_estimate = 1;
|
| - element_estimate = 1;
|
| - }
|
| - // Avoid overflows by capping at kMaxElementCount.
|
| - if (JSObject::kMaxElementCount - estimate_result_length <
|
| - length_estimate) {
|
| - estimate_result_length = JSObject::kMaxElementCount;
|
| - } else {
|
| - estimate_result_length += length_estimate;
|
| }
|
| - if (JSObject::kMaxElementCount - estimate_nof_elements <
|
| - element_estimate) {
|
| - estimate_nof_elements = JSObject::kMaxElementCount;
|
| - } else {
|
| - estimate_nof_elements += element_estimate;
|
| + element_estimate = EstimateElementCount(array);
|
| + } else {
|
| + if (obj->IsHeapObject()) {
|
| + if (obj->IsNumber()) {
|
| + if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
|
| + kind = FAST_DOUBLE_ELEMENTS;
|
| + }
|
| + } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
|
| + kind = FAST_ELEMENTS;
|
| + }
|
| }
|
| + length_estimate = 1;
|
| + element_estimate = 1;
|
| + }
|
| + // Avoid overflows by capping at kMaxElementCount.
|
| + if (JSObject::kMaxElementCount - estimate_result_length <
|
| + length_estimate) {
|
| + estimate_result_length = JSObject::kMaxElementCount;
|
| + } else {
|
| + estimate_result_length += length_estimate;
|
| + }
|
| + if (JSObject::kMaxElementCount - estimate_nof_elements <
|
| + element_estimate) {
|
| + estimate_nof_elements = JSObject::kMaxElementCount;
|
| + } else {
|
| + estimate_nof_elements += element_estimate;
|
| }
|
| }
|
|
|
| @@ -9796,8 +9832,76 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
|
|
|
| Handle<FixedArray> storage;
|
| if (fast_case) {
|
| - // The backing storage array must have non-existing elements to
|
| - // preserve holes across concat operations.
|
| + if (kind == FAST_DOUBLE_ELEMENTS) {
|
| + Handle<FixedDoubleArray> double_storage =
|
| + isolate->factory()->NewFixedDoubleArray(estimate_result_length);
|
| + int j = 0;
|
| + bool failure = false;
|
| + for (int i = 0; i < argument_count; i++) {
|
| + Handle<Object> obj(elements->get(i));
|
| + if (obj->IsSmi()) {
|
| + double_storage->set(j, Smi::cast(*obj)->value());
|
| + j++;
|
| + } else if (obj->IsNumber()) {
|
| + double_storage->set(j, obj->Number());
|
| + j++;
|
| + } else {
|
| + JSArray* array = JSArray::cast(*obj);
|
| + uint32_t length = static_cast<uint32_t>(array->length()->Number());
|
| + switch (array->map()->elements_kind()) {
|
| + case FAST_HOLEY_DOUBLE_ELEMENTS:
|
| + case FAST_DOUBLE_ELEMENTS: {
|
| + // Empty fixed array indicates that there are no elements.
|
| + if (array->elements()->IsFixedArray()) break;
|
| + FixedDoubleArray* elements =
|
| + FixedDoubleArray::cast(array->elements());
|
| + for (uint32_t i = 0; i < length; i++) {
|
| + if (elements->is_the_hole(i)) {
|
| + failure = true;
|
| + break;
|
| + }
|
| + double double_value = elements->get_scalar(i);
|
| + double_storage->set(j, double_value);
|
| + j++;
|
| + }
|
| + break;
|
| + }
|
| + case FAST_HOLEY_SMI_ELEMENTS:
|
| + case FAST_SMI_ELEMENTS: {
|
| + FixedArray* elements(
|
| + FixedArray::cast(array->elements()));
|
| + for (uint32_t i = 0; i < length; i++) {
|
| + Object* element = elements->get(i);
|
| + if (element->IsTheHole()) {
|
| + failure = true;
|
| + break;
|
| + }
|
| + int32_t int_value = Smi::cast(element)->value();
|
| + double_storage->set(j, int_value);
|
| + j++;
|
| + }
|
| + break;
|
| + }
|
| + case FAST_HOLEY_ELEMENTS:
|
| + ASSERT_EQ(0, length);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + }
|
| + if (failure) break;
|
| + }
|
| + Handle<JSArray> array = isolate->factory()->NewJSArray(0);
|
| + Smi* length = Smi::FromInt(j);
|
| + Handle<Map> map;
|
| + map = isolate->factory()->GetElementsTransitionMap(array, kind);
|
| + array->set_map(*map);
|
| + array->set_length(length);
|
| + array->set_elements(*double_storage);
|
| + return *array;
|
| + }
|
| + // The backing storage array must have non-existing elements to preserve
|
| + // holes across concat operations.
|
| storage = isolate->factory()->NewFixedArrayWithHoles(
|
| estimate_result_length);
|
| } else {
|
|
|