Chromium Code Reviews| Index: src/builtins.cc |
| diff --git a/src/builtins.cc b/src/builtins.cc |
| index 6b0b2229cdfc8d500feb69ef3622ae97325bccdf..8373f73d1e84da61d800af67cef7bcb7cd320ddd 100644 |
| --- a/src/builtins.cc |
| +++ b/src/builtins.cc |
| @@ -176,6 +176,27 @@ BUILTIN(EmptyFunction) { |
| } |
| +// TODO(cbruni): check if this is a suitable method on Object |
| +bool ClampedToInteger(Object* object, int* out) { |
|
mvstanton
2015/08/20 10:45:33
I like this method much better, thanks for address
|
| + // This is an extended version of ECMA-262 9.4, but additionally |
| + // clamps values to [kMinInt, kMaxInt] |
| + if (object->IsSmi()) { |
| + *out = Smi::cast(object)->value(); |
| + return true; |
| + } else if (object->IsHeapNumber()) { |
| + *out = FastD2IChecked(HeapNumber::cast(object)->value()); |
| + return true; |
| + } else if (object->IsUndefined()) { |
| + *out = 0; |
| + return true; |
| + } else if (object->IsBoolean()) { |
| + *out = (Oddball::cast(object)->kind() == Oddball::kTrue) ? 1 : 0; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| + |
| static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index, |
| FixedDoubleArray* src, int src_index, int len) { |
| if (len == 0) return; |
| @@ -621,7 +642,6 @@ BUILTIN(ArraySlice) { |
| BUILTIN(ArraySplice) { |
| HandleScope scope(isolate); |
| - Heap* heap = isolate->heap(); |
| Handle<Object> receiver = args.receiver(); |
| MaybeHandle<FixedArrayBase> maybe_elms_obj = |
| EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); |
| @@ -632,209 +652,51 @@ BUILTIN(ArraySplice) { |
| Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
| DCHECK(!array->map()->is_observed()); |
| - int len = Smi::cast(array->length())->value(); |
| - |
| - int n_arguments = args.length() - 1; |
| - |
| + int argument_count = args.length() - 1; |
| int relative_start = 0; |
| - if (n_arguments > 0) { |
| + if (argument_count > 0) { |
| DisallowHeapAllocation no_gc; |
| - Object* arg1 = args[1]; |
| - if (arg1->IsSmi()) { |
| - relative_start = Smi::cast(arg1)->value(); |
| - } else if (arg1->IsHeapNumber()) { |
| - double start = HeapNumber::cast(arg1)->value(); |
| - if (start < kMinInt || start > kMaxInt) { |
| - AllowHeapAllocation allow_allocation; |
| - return CallJsBuiltin(isolate, "$arraySplice", args); |
| - } |
| - relative_start = std::isnan(start) ? 0 : static_cast<int>(start); |
| - } else if (!arg1->IsUndefined()) { |
| + if (!ClampedToInteger(args[1], &relative_start)) { |
| AllowHeapAllocation allow_allocation; |
| return CallJsBuiltin(isolate, "$arraySplice", args); |
| } |
| } |
| + int len = Smi::cast(array->length())->value(); |
| + // clip relative start to [0, len] |
| int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) |
| : Min(relative_start, len); |
| - // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is |
| - // given as a request to delete all the elements from the start. |
| - // And it differs from the case of undefined delete count. |
| - // This does not follow ECMA-262, but we do the same for |
| - // compatibility. |
| int actual_delete_count; |
| - if (n_arguments == 1) { |
| + if (argument_count == 1) { |
| + // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is |
| + // given as a request to delete all the elements from the start. |
| + // And it differs from the case of undefined delete count. |
| + // This does not follow ECMA-262, but we do the same for compatibility. |
| DCHECK(len - actual_start >= 0); |
| actual_delete_count = len - actual_start; |
| } else { |
| - int value = 0; // ToInteger(undefined) == 0 |
| - if (n_arguments > 1) { |
| - DisallowHeapAllocation no_gc; |
| - Object* arg2 = args[2]; |
| - if (arg2->IsSmi()) { |
| - value = Smi::cast(arg2)->value(); |
| - } else { |
| + int delete_count = 0; |
| + DisallowHeapAllocation no_gc; |
| + if (argument_count > 1) { |
| + if (!ClampedToInteger(args[2], &delete_count)) { |
| AllowHeapAllocation allow_allocation; |
| return CallJsBuiltin(isolate, "$arraySplice", args); |
| } |
| } |
| - actual_delete_count = Min(Max(value, 0), len - actual_start); |
| + actual_delete_count = Min(Max(delete_count, 0), len - actual_start); |
| } |
| - ElementsKind elements_kind = array->GetElementsKind(); |
| - |
| - int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; |
| - int new_length = len - actual_delete_count + item_count; |
| - |
| - // For double mode we do not support changing the length. |
| - if (new_length > len && IsFastDoubleElementsKind(elements_kind)) { |
| - return CallJsBuiltin(isolate, "$arraySplice", args); |
| - } |
| + int add_count = (argument_count > 1) ? (argument_count - 2) : 0; |
| + int new_length = len - actual_delete_count + add_count; |
| if (new_length != len && JSArray::HasReadOnlyLength(array)) { |
| AllowHeapAllocation allow_allocation; |
| return CallJsBuiltin(isolate, "$arraySplice", args); |
| } |
| - |
| - if (new_length == 0) { |
| - Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements( |
| - elms_obj, elements_kind, actual_delete_count); |
| - array->set_elements(heap->empty_fixed_array()); |
| - array->set_length(Smi::FromInt(0)); |
| - return *result; |
| - } |
| - |
| - Handle<JSArray> result_array = |
| - isolate->factory()->NewJSArray(elements_kind, |
| - actual_delete_count, |
| - actual_delete_count); |
| - |
| - if (actual_delete_count > 0) { |
| - DisallowHeapAllocation no_gc; |
| - ElementsAccessor* accessor = array->GetElementsAccessor(); |
| - accessor->CopyElements( |
| - elms_obj, actual_start, elements_kind, |
| - handle(result_array->elements(), isolate), 0, actual_delete_count); |
| - } |
| - |
| - bool elms_changed = false; |
| - if (item_count < actual_delete_count) { |
| - // Shrink the array. |
| - const bool trim_array = !heap->lo_space()->Contains(*elms_obj) && |
| - ((actual_start + item_count) < |
| - (len - actual_delete_count - actual_start)); |
| - if (trim_array) { |
| - const int delta = actual_delete_count - item_count; |
| - |
| - if (elms_obj->IsFixedDoubleArray()) { |
| - Handle<FixedDoubleArray> elms = |
| - Handle<FixedDoubleArray>::cast(elms_obj); |
| - MoveDoubleElements(*elms, delta, *elms, 0, actual_start); |
| - } else { |
| - Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); |
| - DisallowHeapAllocation no_gc; |
| - heap->MoveElements(*elms, delta, 0, actual_start); |
| - } |
| - |
| - if (heap->CanMoveObjectStart(*elms_obj)) { |
| - // On the fast path we move the start of the object in memory. |
| - elms_obj = handle(heap->LeftTrimFixedArray(*elms_obj, delta)); |
| - } else { |
| - // This is the slow path. We are going to move the elements to the left |
| - // by copying them. For trimmed values we store the hole. |
| - if (elms_obj->IsFixedDoubleArray()) { |
| - Handle<FixedDoubleArray> elms = |
| - Handle<FixedDoubleArray>::cast(elms_obj); |
| - MoveDoubleElements(*elms, 0, *elms, delta, len - delta); |
| - elms->FillWithHoles(len - delta, len); |
| - } else { |
| - Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); |
| - DisallowHeapAllocation no_gc; |
| - heap->MoveElements(*elms, 0, delta, len - delta); |
| - elms->FillWithHoles(len - delta, len); |
| - } |
| - } |
| - elms_changed = true; |
| - } else { |
| - if (elms_obj->IsFixedDoubleArray()) { |
| - Handle<FixedDoubleArray> elms = |
| - Handle<FixedDoubleArray>::cast(elms_obj); |
| - MoveDoubleElements(*elms, actual_start + item_count, |
| - *elms, actual_start + actual_delete_count, |
| - (len - actual_delete_count - actual_start)); |
| - elms->FillWithHoles(new_length, len); |
| - } else { |
| - Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); |
| - DisallowHeapAllocation no_gc; |
| - heap->MoveElements(*elms, actual_start + item_count, |
| - actual_start + actual_delete_count, |
| - (len - actual_delete_count - actual_start)); |
| - elms->FillWithHoles(new_length, len); |
| - } |
| - } |
| - } else if (item_count > actual_delete_count) { |
| - Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); |
| - // Currently fixed arrays cannot grow too big, so |
| - // we should never hit this case. |
| - DCHECK((item_count - actual_delete_count) <= (Smi::kMaxValue - len)); |
| - |
| - // Check if array need to grow. |
| - if (new_length > elms->length()) { |
| - // New backing storage is needed. |
| - int capacity = new_length + (new_length >> 1) + 16; |
| - Handle<FixedArray> new_elms = |
| - isolate->factory()->NewUninitializedFixedArray(capacity); |
| - |
| - DisallowHeapAllocation no_gc; |
| - |
| - ElementsKind kind = array->GetElementsKind(); |
| - ElementsAccessor* accessor = array->GetElementsAccessor(); |
| - if (actual_start > 0) { |
| - // Copy the part before actual_start as is. |
| - accessor->CopyElements( |
| - elms, 0, kind, new_elms, 0, actual_start); |
| - } |
| - accessor->CopyElements( |
| - elms, actual_start + actual_delete_count, kind, |
| - new_elms, actual_start + item_count, |
| - ElementsAccessor::kCopyToEndAndInitializeToHole); |
| - |
| - elms_obj = new_elms; |
| - elms_changed = true; |
| - } else { |
| - DisallowHeapAllocation no_gc; |
| - heap->MoveElements(*elms, actual_start + item_count, |
| - actual_start + actual_delete_count, |
| - (len - actual_delete_count - actual_start)); |
| - } |
| - } |
| - |
| - if (IsFastDoubleElementsKind(elements_kind)) { |
| - Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj); |
| - for (int k = actual_start; k < actual_start + item_count; k++) { |
| - Object* arg = args[3 + k - actual_start]; |
| - if (arg->IsSmi()) { |
| - elms->set(k, Smi::cast(arg)->value()); |
| - } else { |
| - elms->set(k, HeapNumber::cast(arg)->value()); |
| - } |
| - } |
| - } else { |
| - Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); |
| - DisallowHeapAllocation no_gc; |
| - WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); |
| - for (int k = actual_start; k < actual_start + item_count; k++) { |
| - elms->set(k, args[3 + k - actual_start], mode); |
| - } |
| - } |
| - |
| - if (elms_changed) { |
| - array->set_elements(*elms_obj); |
| - } |
| - // Set the length. |
| - array->set_length(Smi::FromInt(new_length)); |
| - |
| - return *result_array; |
| + ElementsAccessor* accessor = array->GetElementsAccessor(); |
| + Handle<JSArray> result = accessor->Splice( |
| + array, elms_obj, actual_start, actual_delete_count, args, add_count); |
| + return *result; |
| } |