Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/builtins-array.cc')
-rw-r--r--deps/v8/src/builtins/builtins-array.cc198
1 files changed, 183 insertions, 15 deletions
diff --git a/deps/v8/src/builtins/builtins-array.cc b/deps/v8/src/builtins/builtins-array.cc
index 5154b904f5f..ceeee5f37db 100644
--- a/deps/v8/src/builtins/builtins-array.cc
+++ b/deps/v8/src/builtins/builtins-array.cc
@@ -2,19 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h"
-#include "src/builtins/builtins-utils.h"
-
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/contexts.h"
#include "src/counters.h"
-#include "src/elements.h"
+#include "src/debug/debug.h"
+#include "src/elements-inl.h"
#include "src/global-handles.h"
#include "src/isolate.h"
#include "src/lookup.h"
#include "src/objects-inl.h"
#include "src/objects/hash-table-inl.h"
+#include "src/objects/js-array-inl.h"
#include "src/prototype.h"
namespace v8 {
@@ -79,11 +80,14 @@ inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) {
}
// Returns |false| if not applicable.
+// TODO(szuend): Refactor this function because it is getting hard to
+// understand what each call-site actually checks.
V8_WARN_UNUSED_RESULT
inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate,
Handle<Object> receiver,
BuiltinArguments* args,
- int first_added_arg) {
+ int first_arg_index,
+ int num_arguments) {
if (!receiver->IsJSArray()) return false;
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
ElementsKind origin_kind = array->GetElementsKind();
@@ -102,13 +106,14 @@ inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate,
// Need to ensure that the arguments passed in args can be contained in
// the array.
int args_length = args->length();
- if (first_added_arg >= args_length) return true;
+ if (first_arg_index >= args_length) return true;
if (IsObjectElementsKind(origin_kind)) return true;
ElementsKind target_kind = origin_kind;
{
DisallowHeapAllocation no_gc;
- for (int i = first_added_arg; i < args_length; i++) {
+ int last_arg_index = std::min(first_arg_index + num_arguments, args_length);
+ for (int i = first_arg_index; i < last_arg_index; i++) {
Object* arg = (*args)[i];
if (arg->IsHeapObject()) {
if (arg->IsHeapNumber()) {
@@ -142,6 +147,164 @@ V8_WARN_UNUSED_RESULT static Object* CallJsIntrinsic(
Execution::Call(isolate, function, args.receiver(), argc, argv.start()));
}
+// If |index| is Undefined, returns init_if_undefined.
+// If |index| is negative, returns length + index.
+// If |index| is positive, returns index.
+// Returned value is guaranteed to be in the interval of [0, length].
+V8_WARN_UNUSED_RESULT Maybe<double> GetRelativeIndex(Isolate* isolate,
+ double length,
+ Handle<Object> index,
+ double init_if_undefined) {
+ double relative_index = init_if_undefined;
+ if (!index->IsUndefined()) {
+ Handle<Object> relative_index_obj;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, relative_index_obj,
+ Object::ToInteger(isolate, index),
+ Nothing<double>());
+ relative_index = relative_index_obj->Number();
+ }
+
+ if (relative_index < 0) {
+ return Just(std::max(length + relative_index, 0.0));
+ }
+
+ return Just(std::min(relative_index, length));
+}
+
+// Returns "length", has "fast-path" for JSArrays.
+V8_WARN_UNUSED_RESULT Maybe<double> GetLengthProperty(
+ Isolate* isolate, Handle<JSReceiver> receiver) {
+ if (receiver->IsJSArray()) {
+ Handle<JSArray> array = Handle<JSArray>::cast(receiver);
+ double length = array->length()->Number();
+ DCHECK(0 <= length && length <= kMaxSafeInteger);
+
+ return Just(length);
+ }
+
+ Handle<Object> raw_length_number;
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+ isolate, raw_length_number,
+ Object::GetLengthFromArrayLike(isolate, receiver), Nothing<double>());
+ return Just(raw_length_number->Number());
+}
+
+V8_WARN_UNUSED_RESULT Object* GenericArrayFill(Isolate* isolate,
+ Handle<JSReceiver> receiver,
+ Handle<Object> value,
+ double start, double end) {
+ // 7. Repeat, while k < final.
+ while (start < end) {
+ // a. Let Pk be ! ToString(k).
+ Handle<String> index = isolate->factory()->NumberToString(
+ isolate->factory()->NewNumber(start));
+
+ // b. Perform ? Set(O, Pk, value, true).
+ RETURN_FAILURE_ON_EXCEPTION(
+ isolate, Object::SetPropertyOrElement(isolate, receiver, index, value,
+ LanguageMode::kStrict));
+
+ // c. Increase k by 1.
+ ++start;
+ }
+
+ // 8. Return O.
+ return *receiver;
+}
+
+V8_WARN_UNUSED_RESULT bool TryFastArrayFill(
+ Isolate* isolate, BuiltinArguments* args, Handle<JSReceiver> receiver,
+ Handle<Object> value, double start_index, double end_index) {
+ // If indices are too large, use generic path since they are stored as
+ // properties, not in the element backing store.
+ if (end_index > kMaxUInt32) return false;
+ if (!receiver->IsJSObject()) return false;
+
+ if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, args, 1, 1)) {
+ return false;
+ }
+
+ Handle<JSArray> array = Handle<JSArray>::cast(receiver);
+
+ // If no argument was provided, we fill the array with 'undefined'.
+ // EnsureJSArrayWith... does not handle that case so we do it here.
+ // TODO(szuend): Pass target elements kind to EnsureJSArrayWith... when
+ // it gets refactored.
+ if (args->length() == 1 && array->GetElementsKind() != PACKED_ELEMENTS) {
+ // Use a short-lived HandleScope to avoid creating several copies of the
+ // elements handle which would cause issues when left-trimming later-on.
+ HandleScope scope(isolate);
+ JSObject::TransitionElementsKind(array, PACKED_ELEMENTS);
+ }
+
+ DCHECK_LE(start_index, kMaxUInt32);
+ DCHECK_LE(end_index, kMaxUInt32);
+
+ uint32_t start, end;
+ CHECK(DoubleToUint32IfEqualToSelf(start_index, &start));
+ CHECK(DoubleToUint32IfEqualToSelf(end_index, &end));
+
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ accessor->Fill(array, value, start, end);
+ return true;
+}
+} // namespace
+
+BUILTIN(ArrayPrototypeFill) {
+ HandleScope scope(isolate);
+
+ if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) {
+ if (!isolate->debug()->PerformSideEffectCheckForObject(args.receiver())) {
+ return ReadOnlyRoots(isolate).exception();
+ }
+ }
+
+ // 1. Let O be ? ToObject(this value).
+ Handle<JSReceiver> receiver;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, receiver, Object::ToObject(isolate, args.receiver()));
+
+ // 2. Let len be ? ToLength(? Get(O, "length")).
+ double length;
+ MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, length, GetLengthProperty(isolate, receiver));
+
+ // 3. Let relativeStart be ? ToInteger(start).
+ // 4. If relativeStart < 0, let k be max((len + relativeStart), 0);
+ // else let k be min(relativeStart, len).
+ Handle<Object> start = args.atOrUndefined(isolate, 2);
+
+ double start_index;
+ MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, start_index, GetRelativeIndex(isolate, length, start, 0));
+
+ // 5. If end is undefined, let relativeEnd be len;
+ // else let relativeEnd be ? ToInteger(end).
+ // 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0);
+ // else let final be min(relativeEnd, len).
+ Handle<Object> end = args.atOrUndefined(isolate, 3);
+
+ double end_index;
+ MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, end_index, GetRelativeIndex(isolate, length, end, length));
+
+ if (start_index >= end_index) return *receiver;
+
+ // Ensure indexes are within array bounds
+ DCHECK_LE(0, start_index);
+ DCHECK_LE(start_index, end_index);
+ DCHECK_LE(end_index, length);
+
+ Handle<Object> value = args.atOrUndefined(isolate, 1);
+
+ if (TryFastArrayFill(isolate, &args, receiver, value, start_index,
+ end_index)) {
+ return *receiver;
+ }
+ return GenericArrayFill(isolate, receiver, value, start_index, end_index);
+}
+
+namespace {
V8_WARN_UNUSED_RESULT Object* GenericArrayPush(Isolate* isolate,
BuiltinArguments* args) {
// 1. Let O be ? ToObject(this value).
@@ -153,7 +316,7 @@ V8_WARN_UNUSED_RESULT Object* GenericArrayPush(Isolate* isolate,
Handle<Object> raw_length_number;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, raw_length_number,
- Object::GetLengthFromArrayLike(isolate, Handle<Object>::cast(receiver)));
+ Object::GetLengthFromArrayLike(isolate, receiver));
// 3. Let args be a List whose elements are, in left to right order,
// the arguments that were passed to this function invocation.
@@ -210,7 +373,8 @@ V8_WARN_UNUSED_RESULT Object* GenericArrayPush(Isolate* isolate,
BUILTIN(ArrayPush) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
- if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) {
+ if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1,
+ args.length() - 1)) {
return GenericArrayPush(isolate, &args);
}
@@ -293,7 +457,8 @@ V8_WARN_UNUSED_RESULT Object* GenericArrayPop(Isolate* isolate,
BUILTIN(ArrayPop) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
- if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) {
+ if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0,
+ 0)) {
return GenericArrayPop(isolate, &args);
}
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
@@ -324,7 +489,8 @@ BUILTIN(ArrayShift) {
HandleScope scope(isolate);
Heap* heap = isolate->heap();
Handle<Object> receiver = args.receiver();
- if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0) ||
+ if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0,
+ 0) ||
!IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
return CallJsIntrinsic(isolate, isolate->array_shift(), args);
}
@@ -344,7 +510,8 @@ BUILTIN(ArrayShift) {
BUILTIN(ArrayUnshift) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
- if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) {
+ if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1,
+ args.length() - 1)) {
return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
}
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
@@ -367,7 +534,8 @@ BUILTIN(ArraySplice) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
if (V8_UNLIKELY(
- !EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3) ||
+ !EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3,
+ args.length() - 3) ||
// If this is a subclass of Array, then call out to JS.
!Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) ||
// If anything with @@species has been messed with, call out to JS.
@@ -662,7 +830,7 @@ uint32_t EstimateElementCount(Isolate* isolate, Handle<JSArray> array) {
}
break;
}
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
@@ -733,7 +901,7 @@ void CollectElementIndices(Isolate* isolate, Handle<JSObject> object,
});
break;
}
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
@@ -958,7 +1126,7 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
}
case NO_ELEMENTS:
break;
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
return IterateElementsSlow(isolate, receiver, length, visitor);