Index: src/builtins.cc |
diff --git a/src/builtins.cc b/src/builtins.cc |
index 021615217c42a3935c9b1ed5a6d2bf6b3e34e311..c4ed125a01573a2110febcd279bbbd060e056b8c 100644 |
--- a/src/builtins.cc |
+++ b/src/builtins.cc |
@@ -134,7 +134,7 @@ BUILTIN_LIST_C(DEF_ARG_TYPE) |
#ifdef DEBUG |
-static inline bool CalledAsConstructor(Isolate* isolate) { |
+inline bool CalledAsConstructor(Isolate* isolate) { |
// Calculate the result using a full stack frame iterator and check |
// that the state of the stack is as we assume it to be in the |
// code below. |
@@ -165,16 +165,25 @@ static inline bool CalledAsConstructor(Isolate* isolate) { |
// ---------------------------------------------------------------------------- |
-bool ClampedToInteger(Object* object, int* out) { |
+inline bool ClampedToInteger(Object* object, int* out) { |
// This is an extended version of ECMA-262 7.1.11 handling signed values |
// Try to convert object to a number and clamp values to [kMinInt, kMaxInt] |
if (object->IsSmi()) { |
*out = Smi::cast(object)->value(); |
return true; |
} else if (object->IsHeapNumber()) { |
- *out = FastD2IChecked(HeapNumber::cast(object)->value()); |
+ double value = HeapNumber::cast(object)->value(); |
+ if (std::isnan(value)) { |
+ *out = 0; |
+ } else if (value > kMaxInt) { |
+ *out = kMaxInt; |
+ } else if (value < kMinInt) { |
+ *out = kMinInt; |
+ } else { |
+ *out = static_cast<int>(value); |
+ } |
return true; |
- } else if (object->IsUndefined()) { |
+ } else if (object->IsUndefined() || object->IsNull()) { |
*out = 0; |
return true; |
} else if (object->IsBoolean()) { |
@@ -185,15 +194,31 @@ bool ClampedToInteger(Object* object, int* out) { |
} |
-static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index, |
- FixedDoubleArray* src, int src_index, int len) { |
+void MoveDoubleElements(FixedDoubleArray* dst, int dst_index, |
+ FixedDoubleArray* src, int src_index, int len) { |
if (len == 0) return; |
MemMove(dst->data_start() + dst_index, src->data_start() + src_index, |
len * kDoubleSize); |
} |
-static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) { |
+inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object, |
+ int* out) { |
+ Map* arguments_map = |
+ isolate->context()->native_context()->sloppy_arguments_map(); |
+ if (object->map() != arguments_map || !object->HasFastElements()) { |
+ return false; |
+ } |
+ Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); |
+ if (!len_obj->IsSmi()) { |
+ return false; |
+ } |
+ *out = Smi::cast(len_obj)->value(); |
+ return *out <= object->elements()->length(); |
+} |
+ |
+ |
+bool PrototypeHasNoElements(PrototypeIterator* iter) { |
DisallowHeapAllocation no_gc; |
for (; !iter->IsAtEnd(); iter->Advance()) { |
if (iter->GetCurrent()->IsJSProxy()) return false; |
@@ -206,8 +231,8 @@ static bool ArrayPrototypeHasNoElements(PrototypeIterator* iter) { |
} |
-static inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
- JSArray* receiver) { |
+inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
+ JSArray* receiver) { |
DisallowHeapAllocation no_gc; |
// If the array prototype chain is intact (and free of elements), and if the |
// receiver's prototype is the array prototype, then we are done. |
@@ -220,16 +245,14 @@ static inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
// Slow case. |
PrototypeIterator iter(isolate, receiver); |
- return ArrayPrototypeHasNoElements(&iter); |
+ return PrototypeHasNoElements(&iter); |
} |
// Returns empty handle if not applicable. |
MUST_USE_RESULT |
-static inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements( |
- Isolate* isolate, |
- Handle<Object> receiver, |
- Arguments* args, |
+inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements( |
+ Isolate* isolate, Handle<Object> receiver, Arguments* args, |
int first_added_arg) { |
if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>(); |
Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
@@ -495,140 +518,79 @@ BUILTIN(ArrayUnshift) { |
BUILTIN(ArraySlice) { |
HandleScope scope(isolate); |
Handle<Object> receiver = args.receiver(); |
+ Handle<JSObject> object; |
+ Handle<FixedArrayBase> elms_obj; |
int len = -1; |
int relative_start = 0; |
int relative_end = 0; |
- { |
- DisallowHeapAllocation no_gc; |
- if (receiver->IsJSArray()) { |
- JSArray* array = JSArray::cast(*receiver); |
- if (!IsJSArrayFastElementMovingAllowed(isolate, array)) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
- |
- if (!array->HasFastElements()) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
+ bool is_sloppy_arguments = false; |
- len = Smi::cast(array->length())->value(); |
- } else { |
- // Array.slice(arguments, ...) is quite a common idiom (notably more |
- // than 50% of invocations in Web apps). Treat it in C++ as well. |
- Map* arguments_map = |
- isolate->context()->native_context()->sloppy_arguments_map(); |
- |
- bool is_arguments_object_with_fast_elements = |
- receiver->IsJSObject() && |
- JSObject::cast(*receiver)->map() == arguments_map; |
- if (!is_arguments_object_with_fast_elements) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
- JSObject* object = JSObject::cast(*receiver); |
- |
- if (!object->HasFastElements()) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
- |
- Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); |
- if (!len_obj->IsSmi()) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
- len = Smi::cast(len_obj)->value(); |
- if (len > object->elements()->length()) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
+ if (receiver->IsJSArray()) { |
+ DisallowHeapAllocation no_gc; |
+ JSArray* array = JSArray::cast(*receiver); |
+ if (!array->HasFastElements() || |
+ !IsJSArrayFastElementMovingAllowed(isolate, array)) { |
+ AllowHeapAllocation allow_allocation; |
+ return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
} |
- |
- DCHECK(len >= 0); |
- int n_arguments = args.length() - 1; |
- |
- // Note carefully choosen defaults---if argument is missing, |
- // it's undefined which gets converted to 0 for relative_start |
- // and to len for relative_end. |
- relative_start = 0; |
- relative_end = len; |
- if (n_arguments > 0) { |
- 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 CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
- relative_start = std::isnan(start) ? 0 : static_cast<int>(start); |
- } else if (!arg1->IsUndefined()) { |
+ len = Smi::cast(array->length())->value(); |
+ object = Handle<JSObject>::cast(receiver); |
+ elms_obj = handle(array->elements(), isolate); |
+ } else if (receiver->IsJSObject() && |
+ GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver), |
+ &len)) { |
+ // Array.prototype.slice(arguments, ...) is quite a common idiom |
+ // (notably more than 50% of invocations in Web apps). |
+ // Treat it in C++ as well. |
+ is_sloppy_arguments = true; |
+ object = Handle<JSObject>::cast(receiver); |
+ elms_obj = handle(object->elements(), isolate); |
+ } else { |
+ AllowHeapAllocation allow_allocation; |
+ return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
+ } |
+ DCHECK(len >= 0); |
+ int argument_count = args.length() - 1; |
+ // Note carefully chosen defaults---if argument is missing, |
+ // it's undefined which gets converted to 0 for relative_start |
+ // and to len for relative_end. |
+ relative_start = 0; |
+ relative_end = len; |
+ if (argument_count > 0) { |
+ DisallowHeapAllocation no_gc; |
+ if (!ClampedToInteger(args[1], &relative_start)) { |
+ AllowHeapAllocation allow_allocation; |
+ return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
+ } |
+ if (argument_count > 1) { |
+ Object* end_arg = args[2]; |
+ // slice handles the end_arg specially |
+ if (end_arg->IsUndefined()) { |
+ relative_end = len; |
+ } else if (!ClampedToInteger(end_arg, &relative_end)) { |
AllowHeapAllocation allow_allocation; |
return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
} |
- if (n_arguments > 1) { |
- Object* arg2 = args[2]; |
- if (arg2->IsSmi()) { |
- relative_end = Smi::cast(arg2)->value(); |
- } else if (arg2->IsHeapNumber()) { |
- double end = HeapNumber::cast(arg2)->value(); |
- if (end < kMinInt || end > kMaxInt) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
- relative_end = std::isnan(end) ? 0 : static_cast<int>(end); |
- } else if (!arg2->IsUndefined()) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
- } |
} |
} |
// ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. |
- int k = (relative_start < 0) ? Max(len + relative_start, 0) |
- : Min(relative_start, len); |
+ uint32_t actual_start = (relative_start < 0) ? Max(len + relative_start, 0) |
+ : Min(relative_start, len); |
// ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. |
- int final = (relative_end < 0) ? Max(len + relative_end, 0) |
- : Min(relative_end, len); |
- |
- // Calculate the length of result array. |
- int result_len = Max(final - k, 0); |
+ uint32_t actual_end = |
+ (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len); |
- Handle<JSObject> object = Handle<JSObject>::cast(receiver); |
- Handle<FixedArrayBase> elms(object->elements(), isolate); |
- |
- ElementsKind kind = object->GetElementsKind(); |
- if (IsHoleyElementsKind(kind)) { |
- DisallowHeapAllocation no_gc; |
- bool packed = true; |
- ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); |
- for (int i = k; i < final; i++) { |
- if (!accessor->HasElement(object, i, elms)) { |
- packed = false; |
- break; |
- } |
- } |
- if (packed) { |
- kind = GetPackedElementsKind(kind); |
- } else if (!receiver->IsJSArray()) { |
- AllowHeapAllocation allow_allocation; |
- return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
- } |
+ ElementsAccessor* accessor = object->GetElementsAccessor(); |
+ if (is_sloppy_arguments && |
+ !accessor->IsPacked(object, elms_obj, actual_start, actual_end)) { |
+ // Don't deal with arguments with holes in C++ |
+ AllowHeapAllocation allow_allocation; |
+ return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
} |
- |
Handle<JSArray> result_array = |
- isolate->factory()->NewJSArray(kind, result_len, result_len); |
- |
- DisallowHeapAllocation no_gc; |
- if (result_len == 0) return *result_array; |
- |
- ElementsAccessor* accessor = object->GetElementsAccessor(); |
- accessor->CopyElements( |
- elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); |
+ accessor->Slice(object, elms_obj, actual_start, actual_end); |
return *result_array; |
} |
@@ -687,9 +649,9 @@ BUILTIN(ArraySplice) { |
return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
} |
ElementsAccessor* accessor = array->GetElementsAccessor(); |
- Handle<JSArray> result = accessor->Splice( |
+ Handle<JSArray> result_array = accessor->Splice( |
array, elms_obj, actual_start, actual_delete_count, args, add_count); |
- return *result; |
+ return *result_array; |
} |
@@ -706,7 +668,7 @@ BUILTIN(ArrayConcat) { |
Object* array_proto = native_context->array_function()->prototype(); |
PrototypeIterator iter(isolate, array_proto, |
PrototypeIterator::START_AT_RECEIVER); |
- if (!ArrayPrototypeHasNoElements(&iter)) { |
+ if (!PrototypeHasNoElements(&iter)) { |
AllowHeapAllocation allow_allocation; |
return CallJsIntrinsic(isolate, isolate->array_concat(), args); |
} |