| Index: src/runtime/runtime-array.cc
|
| diff --git a/src/runtime/runtime-array.cc b/src/runtime/runtime-array.cc
|
| index 6664c814006798046ef7a6ffa279788e04146a49..f6c6e9d6f27486eceabfb89ce0ddb30a775b0166 100644
|
| --- a/src/runtime/runtime-array.cc
|
| +++ b/src/runtime/runtime-array.cc
|
| @@ -32,18 +32,24 @@ RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
|
| }
|
|
|
| static void InstallCode(Isolate* isolate, Handle<JSObject> holder,
|
| - const char* name, Handle<Code> code) {
|
| + const char* name, Handle<Code> code, int argc = -1) {
|
| Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
|
| Handle<JSFunction> optimized =
|
| isolate->factory()->NewFunctionWithoutPrototype(key, code);
|
| - optimized->shared()->DontAdaptArguments();
|
| + if (argc < 0) {
|
| + optimized->shared()->DontAdaptArguments();
|
| + } else {
|
| + optimized->shared()->set_internal_formal_parameter_count(argc);
|
| + }
|
| JSObject::AddProperty(holder, key, optimized, NONE);
|
| }
|
|
|
| static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
|
| - const char* name, Builtins::Name builtin_name) {
|
| + const char* name, Builtins::Name builtin_name,
|
| + int argc = -1) {
|
| InstallCode(isolate, holder, name,
|
| - handle(isolate->builtins()->builtin(builtin_name), isolate));
|
| + handle(isolate->builtins()->builtin(builtin_name), isolate),
|
| + argc);
|
| }
|
|
|
| RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
|
| @@ -59,6 +65,7 @@ RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
|
| InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
|
| InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
|
| InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
|
| + InstallBuiltin(isolate, holder, "includes", Builtins::kArrayIncludes, 2);
|
|
|
| return *holder;
|
| }
|
| @@ -439,5 +446,100 @@ RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
|
| isolate, Object::ArraySpeciesConstructor(isolate, original_array));
|
| }
|
|
|
| +static inline Object* FastArrayIncludes(Isolate* isolate,
|
| + Handle<JSObject> object,
|
| + Handle<Object> value, uint32_t k,
|
| + uint32_t len) {
|
| + ElementsAccessor* elements = object->GetElementsAccessor();
|
| + Maybe<bool> result = elements->IncludesValue(isolate, object, value, k, len);
|
| + MAYBE_RETURN(result, isolate->heap()->exception());
|
| + return *isolate->factory()->ToBoolean(result.FromJust());
|
| +}
|
| +
|
| +// ES7 22.1.3.11 Array.prototype.includes
|
| +RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
|
| + HandleScope shs(isolate);
|
| + DCHECK(args.length() == 3);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, start_from_, 2);
|
| +
|
| + // 1. Let O be ? ToObject(this value).
|
| + Handle<JSReceiver> object;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, object, Object::ToObject(isolate, handle(args[0], isolate)));
|
| +
|
| + // 2. Let len be ? ToLength(? Get(O, "length")).
|
| + Handle<Object> len_;
|
| + int64_t len;
|
| + if (object->map()->instance_type() == JS_ARRAY_TYPE) {
|
| + len_ = handle(JSArray::cast(*object)->length(), isolate);
|
| + } else {
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, len_,
|
| + Object::GetProperty(object, isolate->factory()->length_string()));
|
| + }
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
|
| + Object::ToLength(isolate, len_));
|
| + len = static_cast<int64_t>(len_->Number());
|
| + DCHECK_EQ(len, len_->Number());
|
| +
|
| + // 3. If len is 0, return false.
|
| + if (len == 0) return isolate->heap()->false_value();
|
| +
|
| + // 4. Let n be ? ToInteger(fromIndex). (If fromIndex is undefined,
|
| + // this step produces the value 0.)
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, start_from_,
|
| + Object::ToInteger(isolate, start_from_));
|
| + if (std::isinf(start_from_->Number()) && start_from_->Number() > 0.0) {
|
| + return isolate->heap()->false_value();
|
| + }
|
| + int64_t start_from = static_cast<int64_t>(start_from_->Number());
|
| +
|
| + int64_t index;
|
| + if (start_from >= 0) {
|
| + index = start_from;
|
| + } else {
|
| + index = len + start_from;
|
| + if (index < 0) {
|
| + index = 0;
|
| + }
|
| + }
|
| +
|
| + // In the slow path, we can still take a fast path similar to the TurboFan
|
| + // implementation if there are no elements in the prototype, and if the length
|
| + // is within elements boundaries.
|
| + //
|
| + // This would apply to Array-like Objects with no elements in the prototype,
|
| + // for example.
|
| + if (object->map()->instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
|
| + len < std::numeric_limits<uint32_t>::max() &&
|
| + JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
|
| + return FastArrayIncludes(isolate, Handle<JSObject>::cast(object),
|
| + search_element, static_cast<uint32_t>(index),
|
| + static_cast<uint32_t>(len));
|
| + }
|
| +
|
| + // Otherwise, perform slow lookups for JSProxies and API objects, or for
|
| + // objects with long `length` values.
|
| + for (; index < len; ++index) {
|
| + Handle<Object> element_k;
|
| +
|
| + Handle<Object> index_object = isolate->factory()->NewNumberFromInt64(index);
|
| +
|
| + bool success;
|
| + LookupIterator it = LookupIterator::PropertyOrElement(
|
| + isolate, object, index_object, &success);
|
| + DCHECK(success);
|
| +
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
|
| + Object::GetProperty(&it));
|
| +
|
| + if (search_element->SameValueZero(*element_k)) {
|
| + return isolate->heap()->true_value();
|
| + }
|
| + }
|
| + return isolate->heap()->false_value();
|
| +}
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|