LCOV - code coverage report
Current view: top level - src/runtime - runtime-array.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 275 287 95.8 %
Date: 2017-04-26 Functions: 21 41 51.2 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/runtime/runtime-utils.h"
       6             : 
       7             : #include "src/arguments.h"
       8             : #include "src/code-stubs.h"
       9             : #include "src/conversions-inl.h"
      10             : #include "src/elements.h"
      11             : #include "src/factory.h"
      12             : #include "src/isolate-inl.h"
      13             : #include "src/keys.h"
      14             : #include "src/messages.h"
      15             : #include "src/prototype.h"
      16             : 
      17             : namespace v8 {
      18             : namespace internal {
      19             : 
      20         869 : static void InstallCode(
      21             :     Isolate* isolate, Handle<JSObject> holder, const char* name,
      22             :     Handle<Code> code, int argc = -1,
      23             :     BuiltinFunctionId id = static_cast<BuiltinFunctionId>(-1)) {
      24         869 :   Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
      25             :   Handle<JSFunction> optimized =
      26         869 :       isolate->factory()->NewFunctionWithoutPrototype(key, code, true);
      27         869 :   if (argc < 0) {
      28             :     optimized->shared()->DontAdaptArguments();
      29             :   } else {
      30             :     optimized->shared()->set_internal_formal_parameter_count(argc);
      31             :   }
      32         869 :   if (id >= 0) {
      33             :     optimized->shared()->set_builtin_function_id(id);
      34             :   }
      35             :   optimized->shared()->set_language_mode(STRICT);
      36             :   optimized->shared()->set_native(true);
      37         869 :   JSObject::AddProperty(holder, key, optimized, NONE);
      38         869 : }
      39             : 
      40         869 : static void InstallBuiltin(
      41             :     Isolate* isolate, Handle<JSObject> holder, const char* name,
      42             :     Builtins::Name builtin_name, int argc = -1,
      43             :     BuiltinFunctionId id = static_cast<BuiltinFunctionId>(-1)) {
      44             :   InstallCode(isolate, holder, name,
      45             :               handle(isolate->builtins()->builtin(builtin_name), isolate), argc,
      46         869 :               id);
      47         869 : }
      48             : 
      49         158 : RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
      50          79 :   HandleScope scope(isolate);
      51             :   DCHECK_EQ(0, args.length());
      52             :   Handle<JSObject> holder =
      53          79 :       isolate->factory()->NewJSObject(isolate->object_function());
      54             : 
      55          79 :   InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
      56          79 :   InstallBuiltin(isolate, holder, "push", Builtins::kFastArrayPush);
      57          79 :   InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
      58          79 :   InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
      59          79 :   InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
      60          79 :   InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
      61          79 :   InstallBuiltin(isolate, holder, "includes", Builtins::kArrayIncludes, 2);
      62          79 :   InstallBuiltin(isolate, holder, "indexOf", Builtins::kArrayIndexOf, 2);
      63             :   InstallBuiltin(isolate, holder, "keys", Builtins::kArrayPrototypeKeys, 0,
      64          79 :                  kArrayKeys);
      65             :   InstallBuiltin(isolate, holder, "values", Builtins::kArrayPrototypeValues, 0,
      66          79 :                  kArrayValues);
      67             :   InstallBuiltin(isolate, holder, "entries", Builtins::kArrayPrototypeEntries,
      68          79 :                  0, kArrayEntries);
      69          79 :   return *holder;
      70             : }
      71             : 
      72    11632692 : RUNTIME_FUNCTION(Runtime_FixedArrayGet) {
      73             :   SealHandleScope shs(isolate);
      74             :   DCHECK_EQ(2, args.length());
      75    11632692 :   CONVERT_ARG_CHECKED(FixedArray, object, 0);
      76    11632688 :   CONVERT_SMI_ARG_CHECKED(index, 1);
      77     5816342 :   return object->get(index);
      78             : }
      79             : 
      80             : 
      81     4275104 : RUNTIME_FUNCTION(Runtime_FixedArraySet) {
      82             :   SealHandleScope shs(isolate);
      83             :   DCHECK_EQ(3, args.length());
      84     4275104 :   CONVERT_ARG_CHECKED(FixedArray, object, 0);
      85     4275104 :   CONVERT_SMI_ARG_CHECKED(index, 1);
      86     2137552 :   CONVERT_ARG_CHECKED(Object, value, 2);
      87     2137552 :   object->set(index, value);
      88     2137552 :   return isolate->heap()->undefined_value();
      89             : }
      90             : 
      91             : 
      92         642 : RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
      93         321 :   HandleScope scope(isolate);
      94             :   DCHECK_EQ(2, args.length());
      95         642 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
      96         642 :   CONVERT_ARG_HANDLE_CHECKED(Map, to_map, 1);
      97         321 :   ElementsKind to_kind = to_map->elements_kind();
      98         321 :   ElementsAccessor::ForKind(to_kind)->TransitionElementsKind(object, to_map);
      99         321 :   return *object;
     100             : }
     101             : 
     102             : 
     103             : // Moves all own elements of an object, that are below a limit, to positions
     104             : // starting at zero. All undefined values are placed after non-undefined values,
     105             : // and are followed by non-existing element. Does not change the length
     106             : // property.
     107             : // Returns the number of non-undefined elements collected.
     108             : // Returns -1 if hole removal is not supported by this method.
     109      253294 : RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
     110      126647 :   HandleScope scope(isolate);
     111             :   DCHECK_EQ(2, args.length());
     112      253294 :   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
     113      253294 :   CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
     114      126647 :   if (object->IsJSProxy()) return Smi::FromInt(-1);
     115             :   return *JSObject::PrepareElementsForSort(Handle<JSObject>::cast(object),
     116      253264 :                                            limit);
     117             : }
     118             : 
     119             : 
     120             : // Move contents of argument 0 (an array) to argument 1 (an array)
     121        4876 : RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
     122        2438 :   HandleScope scope(isolate);
     123             :   DCHECK_EQ(2, args.length());
     124        4876 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
     125        4876 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
     126        2438 :   JSObject::ValidateElements(from);
     127        2438 :   JSObject::ValidateElements(to);
     128             : 
     129        2438 :   Handle<FixedArrayBase> new_elements(from->elements());
     130        2438 :   ElementsKind from_kind = from->GetElementsKind();
     131        2438 :   Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
     132        2438 :   JSObject::SetMapAndElements(to, new_map, new_elements);
     133        4876 :   to->set_length(from->length());
     134             : 
     135        2438 :   JSObject::ResetElements(from);
     136        2438 :   from->set_length(Smi::kZero);
     137             : 
     138        2438 :   JSObject::ValidateElements(to);
     139        2438 :   return *to;
     140             : }
     141             : 
     142             : 
     143             : // How many elements does this object/array have?
     144        6654 : RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
     145        3327 :   DisallowHeapAllocation no_gc;
     146        3327 :   HandleScope scope(isolate);
     147             :   DCHECK_EQ(1, args.length());
     148        6654 :   CONVERT_ARG_CHECKED(JSArray, array, 0);
     149        3327 :   FixedArrayBase* elements = array->elements();
     150             :   SealHandleScope shs(isolate);
     151        3327 :   if (elements->IsDictionary()) {
     152        1444 :     int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
     153        1444 :     return Smi::FromInt(result);
     154             :   } else {
     155             :     DCHECK(array->length()->IsSmi());
     156             :     // For packed elements, we know the exact number of elements
     157        1883 :     int length = elements->length();
     158        1883 :     ElementsKind kind = array->GetElementsKind();
     159        1883 :     if (IsFastPackedElementsKind(kind)) {
     160         387 :       return Smi::FromInt(length);
     161             :     }
     162             :     // For holey elements, take samples from the buffer checking for holes
     163             :     // to generate the estimate.
     164             :     const int kNumberOfHoleCheckSamples = 97;
     165             :     int increment = (length < kNumberOfHoleCheckSamples)
     166             :                         ? 1
     167        1496 :                         : static_cast<int>(length / kNumberOfHoleCheckSamples);
     168        1496 :     ElementsAccessor* accessor = array->GetElementsAccessor();
     169             :     int holes = 0;
     170      147627 :     for (int i = 0; i < length; i += increment) {
     171      147627 :       if (!accessor->HasElement(array, i, elements)) {
     172       63043 :         ++holes;
     173             :       }
     174             :     }
     175        1496 :     int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
     176        1496 :                                     kNumberOfHoleCheckSamples * length);
     177        1496 :     return Smi::FromInt(estimate);
     178        3327 :   }
     179             : }
     180             : 
     181             : 
     182             : // Returns an array that tells you where in the [0, length) interval an array
     183             : // might have elements.  Can either return an array of keys (positive integers
     184             : // or undefined) or a number representing the positive length of an interval
     185             : // starting at index 0.
     186             : // Intervals can span over some keys that are not in the object.
     187       11510 : RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
     188        5755 :   HandleScope scope(isolate);
     189             :   DCHECK_EQ(2, args.length());
     190       11510 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
     191       11510 :   CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
     192        5755 :   ElementsKind kind = array->GetElementsKind();
     193             : 
     194        5755 :   if (IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind)) {
     195        2038 :     uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
     196        4076 :     return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
     197             :   }
     198             : 
     199        3717 :   if (kind == FAST_STRING_WRAPPER_ELEMENTS) {
     200             :     int string_length =
     201          30 :         String::cast(Handle<JSValue>::cast(array)->value())->length();
     202          15 :     int backing_store_length = array->elements()->length();
     203             :     return *isolate->factory()->NewNumberFromUint(
     204             :         Min(length,
     205          30 :             static_cast<uint32_t>(Max(string_length, backing_store_length))));
     206             :   }
     207             : 
     208             :   KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
     209        7404 :                              ALL_PROPERTIES);
     210       18330 :   for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
     211       10926 :        !iter.IsAtEnd(); iter.Advance()) {
     212       43704 :     if (PrototypeIterator::GetCurrent(iter)->IsJSProxy() ||
     213             :         PrototypeIterator::GetCurrent<JSObject>(iter)
     214       32778 :             ->HasIndexedInterceptor()) {
     215             :       // Bail out if we find a proxy or interceptor, likely not worth
     216             :       // collecting keys in that case.
     217           0 :       return *isolate->factory()->NewNumberFromUint(length);
     218             :     }
     219       10926 :     Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
     220       10926 :     accumulator.CollectOwnElementIndices(array, current);
     221             :   }
     222             :   // Erase any keys >= length.
     223             :   Handle<FixedArray> keys =
     224        3702 :       accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
     225             :   int j = 0;
     226       37660 :   for (int i = 0; i < keys->length(); i++) {
     227       16979 :     if (NumberToUint32(keys->get(i)) >= length) continue;
     228       16154 :     if (i != j) keys->set(j, keys->get(i));
     229       15794 :     j++;
     230             :   }
     231             : 
     232        3702 :   if (j != keys->length()) {
     233         540 :     isolate->heap()->RightTrimFixedArray(*keys, keys->length() - j);
     234             :   }
     235             : 
     236       13159 :   return *isolate->factory()->NewJSArrayWithElements(keys);
     237             : }
     238             : 
     239             : 
     240             : namespace {
     241             : 
     242     1516326 : Object* ArrayConstructorCommon(Isolate* isolate, Handle<JSFunction> constructor,
     243             :                                Handle<JSReceiver> new_target,
     244             :                                Handle<AllocationSite> site,
     245     1516326 :                                Arguments* caller_args) {
     246             :   Factory* factory = isolate->factory();
     247             : 
     248             :   // If called through new, new.target can be:
     249             :   // - a subclass of constructor,
     250             :   // - a proxy wrapper around constructor, or
     251             :   // - the constructor itself.
     252             :   // If called through Reflect.construct, it's guaranteed to be a constructor by
     253             :   // REFLECT_CONSTRUCT_PREPARE.
     254             :   DCHECK(new_target->IsConstructor());
     255             : 
     256             :   bool holey = false;
     257     1516326 :   bool can_use_type_feedback = !site.is_null();
     258             :   bool can_inline_array_constructor = true;
     259     1516326 :   if (caller_args->length() == 1) {
     260             :     Handle<Object> argument_one = caller_args->at<Object>(0);
     261      183289 :     if (argument_one->IsSmi()) {
     262             :       int value = Handle<Smi>::cast(argument_one)->value();
     263      362423 :       if (value < 0 ||
     264      181189 :           JSArray::SetLengthWouldNormalize(isolate->heap(), value)) {
     265             :         // the array is a dictionary in this case.
     266             :         can_use_type_feedback = false;
     267      180846 :       } else if (value != 0) {
     268             :         holey = true;
     269      175054 :         if (value >= JSArray::kInitialMaxFastElementArray) {
     270             :           can_inline_array_constructor = false;
     271             :         }
     272             :       }
     273             :     } else {
     274             :       // Non-smi length argument produces a dictionary
     275             :       can_use_type_feedback = false;
     276             :     }
     277             :   }
     278             : 
     279             :   Handle<Map> initial_map;
     280     3032652 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     281             :       isolate, initial_map,
     282             :       JSFunction::GetDerivedMap(isolate, constructor, new_target));
     283             : 
     284             :   ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
     285     1516326 :                                                : initial_map->elements_kind();
     286     1691380 :   if (holey && !IsFastHoleyElementsKind(to_kind)) {
     287             :     to_kind = GetHoleyElementsKind(to_kind);
     288             :     // Update the allocation site info to reflect the advice alteration.
     289      172708 :     if (!site.is_null()) site->SetElementsKind(to_kind);
     290             :   }
     291             : 
     292             :   // We should allocate with an initial map that reflects the allocation site
     293             :   // advice. Therefore we use AllocateJSObjectFromMap instead of passing
     294             :   // the constructor.
     295     1516326 :   if (to_kind != initial_map->elements_kind()) {
     296      874851 :     initial_map = Map::AsElementsKind(initial_map, to_kind);
     297             :   }
     298             : 
     299             :   // If we don't care to track arrays of to_kind ElementsKind, then
     300             :   // don't emit a memento for them.
     301             :   Handle<AllocationSite> allocation_site;
     302     1516326 :   if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
     303      815254 :     allocation_site = site;
     304             :   }
     305             : 
     306             :   Handle<JSArray> array = Handle<JSArray>::cast(
     307     1516326 :       factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
     308             : 
     309     1516326 :   factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
     310             : 
     311             :   ElementsKind old_kind = array->GetElementsKind();
     312     3032652 :   RETURN_FAILURE_ON_EXCEPTION(
     313             :       isolate, ArrayConstructInitializeElements(array, caller_args));
     314     4095221 :   if (!site.is_null() &&
     315     2122454 :       (old_kind != array->GetElementsKind() || !can_use_type_feedback ||
     316     1061227 :        !can_inline_array_constructor)) {
     317             :     // The arguments passed in caused a transition. This kind of complexity
     318             :     // can't be dealt with in the inlined hydrogen array constructor case.
     319             :     // We must mark the allocationsite as un-inlinable.
     320        3674 :     site->SetDoNotInlineCall();
     321             :   }
     322             : 
     323     1516162 :   return *array;
     324             : }
     325             : 
     326             : }  // namespace
     327             : 
     328     3032652 : RUNTIME_FUNCTION(Runtime_NewArray) {
     329     1516326 :   HandleScope scope(isolate);
     330             :   DCHECK_LE(3, args.length());
     331     1516326 :   int const argc = args.length() - 3;
     332             :   // TODO(bmeurer): Remove this Arguments nonsense.
     333     1516326 :   Arguments argv(argc, args.arguments() - 1);
     334     3032652 :   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
     335     3032652 :   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, argc + 1);
     336     3032652 :   CONVERT_ARG_HANDLE_CHECKED(HeapObject, type_info, argc + 2);
     337             :   // TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite.
     338             :   Handle<AllocationSite> site = type_info->IsAllocationSite()
     339             :                                     ? Handle<AllocationSite>::cast(type_info)
     340     1516326 :                                     : Handle<AllocationSite>::null();
     341     1516326 :   return ArrayConstructorCommon(isolate, constructor, new_target, site, &argv);
     342             : }
     343             : 
     344        8946 : RUNTIME_FUNCTION(Runtime_NormalizeElements) {
     345        4473 :   HandleScope scope(isolate);
     346             :   DCHECK_EQ(1, args.length());
     347        8946 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
     348        4473 :   CHECK(!array->HasFixedTypedArrayElements());
     349        4473 :   CHECK(!array->IsJSGlobalProxy());
     350        4473 :   JSObject::NormalizeElements(array);
     351        4473 :   return *array;
     352             : }
     353             : 
     354             : 
     355             : // GrowArrayElements returns a sentinel Smi if the object was normalized.
     356         984 : RUNTIME_FUNCTION(Runtime_GrowArrayElements) {
     357         492 :   HandleScope scope(isolate);
     358             :   DCHECK_EQ(2, args.length());
     359         984 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
     360         984 :   CONVERT_NUMBER_CHECKED(int, key, Int32, args[1]);
     361             : 
     362         492 :   if (key < 0) {
     363           0 :     return object->elements();
     364             :   }
     365             : 
     366         492 :   uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
     367         492 :   uint32_t index = static_cast<uint32_t>(key);
     368             : 
     369         492 :   if (index >= capacity) {
     370         492 :     if (!object->GetElementsAccessor()->GrowCapacity(object, index)) {
     371             :       return Smi::kZero;
     372             :     }
     373             :   }
     374             : 
     375             :   // On success, return the fixed array elements.
     376         434 :   return object->elements();
     377             : }
     378             : 
     379             : 
     380        9260 : RUNTIME_FUNCTION(Runtime_HasComplexElements) {
     381        4630 :   HandleScope scope(isolate);
     382             :   DCHECK_EQ(1, args.length());
     383        9260 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
     384       22865 :   for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
     385       13605 :        !iter.IsAtEnd(); iter.Advance()) {
     386       27360 :     if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
     387           0 :       return isolate->heap()->true_value();
     388             :     }
     389       13680 :     Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
     390       13680 :     if (current->HasIndexedInterceptor()) {
     391           0 :       return isolate->heap()->true_value();
     392             :     }
     393       13680 :     if (!current->HasDictionaryElements()) continue;
     394        4562 :     if (current->element_dictionary()->HasComplexElements()) {
     395          75 :       return isolate->heap()->true_value();
     396             :     }
     397             :   }
     398        4555 :   return isolate->heap()->false_value();
     399             : }
     400             : 
     401             : // ES6 22.1.2.2 Array.isArray
     402        1326 : RUNTIME_FUNCTION(Runtime_ArrayIsArray) {
     403         663 :   HandleScope shs(isolate);
     404             :   DCHECK_EQ(1, args.length());
     405         663 :   CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
     406         663 :   Maybe<bool> result = Object::IsArray(object);
     407         663 :   MAYBE_RETURN(result, isolate->heap()->exception());
     408         607 :   return isolate->heap()->ToBoolean(result.FromJust());
     409             : }
     410             : 
     411          42 : RUNTIME_FUNCTION(Runtime_IsArray) {
     412             :   SealHandleScope shs(isolate);
     413             :   DCHECK_EQ(1, args.length());
     414          21 :   CONVERT_ARG_CHECKED(Object, obj, 0);
     415          21 :   return isolate->heap()->ToBoolean(obj->IsJSArray());
     416             : }
     417             : 
     418      124788 : RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
     419       62394 :   HandleScope scope(isolate);
     420             :   DCHECK_EQ(1, args.length());
     421       62394 :   CONVERT_ARG_HANDLE_CHECKED(Object, original_array, 0);
     422      124788 :   RETURN_RESULT_OR_FAILURE(
     423       62394 :       isolate, Object::ArraySpeciesConstructor(isolate, original_array));
     424             : }
     425             : 
     426             : // ES7 22.1.3.11 Array.prototype.includes
     427       14350 : RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
     428        7175 :   HandleScope shs(isolate);
     429             :   DCHECK_EQ(3, args.length());
     430        7175 :   CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
     431        7175 :   CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
     432             : 
     433             :   // Let O be ? ToObject(this value).
     434             :   Handle<JSReceiver> object;
     435       21525 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     436             :       isolate, object, Object::ToObject(isolate, handle(args[0], isolate)));
     437             : 
     438             :   // Let len be ? ToLength(? Get(O, "length")).
     439             :   int64_t len;
     440             :   {
     441        7147 :     if (object->map()->instance_type() == JS_ARRAY_TYPE) {
     442         322 :       uint32_t len32 = 0;
     443         322 :       bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
     444             :       DCHECK(success);
     445             :       USE(success);
     446         322 :       len = len32;
     447             :     } else {
     448             :       Handle<Object> len_;
     449       20475 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     450             :           isolate, len_,
     451             :           Object::GetProperty(object, isolate->factory()->length_string()));
     452             : 
     453       13622 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
     454             :                                          Object::ToLength(isolate, len_));
     455        6783 :       len = static_cast<int64_t>(len_->Number());
     456             :       DCHECK_EQ(len, len_->Number());
     457             :     }
     458             :   }
     459             : 
     460        7105 :   if (len == 0) return isolate->heap()->false_value();
     461             : 
     462             :   // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
     463             :   // produces the value 0.)
     464             :   int64_t index = 0;
     465        6573 :   if (!from_index->IsUndefined(isolate)) {
     466        4288 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
     467             :                                        Object::ToInteger(isolate, from_index));
     468             : 
     469        2116 :     if (V8_LIKELY(from_index->IsSmi())) {
     470        2032 :       int start_from = Smi::cast(*from_index)->value();
     471        2032 :       if (start_from < 0) {
     472         322 :         index = std::max<int64_t>(len + start_from, 0);
     473             :       } else {
     474        1710 :         index = start_from;
     475             :       }
     476             :     } else {
     477             :       DCHECK(from_index->IsHeapNumber());
     478          84 :       double start_from = from_index->Number();
     479          84 :       if (start_from >= len) return isolate->heap()->false_value();
     480          56 :       if (V8_LIKELY(std::isfinite(start_from))) {
     481          42 :         if (start_from < 0) {
     482           0 :           index = static_cast<int64_t>(std::max<double>(start_from + len, 0));
     483             :         } else {
     484          42 :           index = start_from;
     485             :         }
     486             :       }
     487             :     }
     488             : 
     489             :     DCHECK_GE(index, 0);
     490             :   }
     491             : 
     492             :   // If the receiver is not a special receiver type, and the length is a valid
     493             :   // element index, perform fast operation tailored to specific ElementsKinds.
     494       12978 :   if (!object->map()->IsSpecialReceiverMap() && len < kMaxUInt32 &&
     495        6461 :       JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
     496        2957 :     Handle<JSObject> obj = Handle<JSObject>::cast(object);
     497        2957 :     ElementsAccessor* elements = obj->GetElementsAccessor();
     498             :     Maybe<bool> result = elements->IncludesValue(isolate, obj, search_element,
     499             :                                                  static_cast<uint32_t>(index),
     500        2957 :                                                  static_cast<uint32_t>(len));
     501        2957 :     MAYBE_RETURN(result, isolate->heap()->exception());
     502        5886 :     return *isolate->factory()->ToBoolean(result.FromJust());
     503             :   }
     504             : 
     505             :   // Otherwise, perform slow lookups for special receiver types
     506       16179 :   for (; index < len; ++index) {
     507             :     // Let elementK be the result of ? Get(O, ! ToString(k)).
     508             :     Handle<Object> element_k;
     509             :     {
     510       16511 :       Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
     511             :       bool success;
     512             :       LookupIterator it = LookupIterator::PropertyOrElement(
     513       16511 :           isolate, object, index_obj, &success);
     514             :       DCHECK(success);
     515       33022 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
     516             :                                          Object::GetProperty(&it));
     517             :     }
     518             : 
     519             :     // If SameValueZero(searchElement, elementK) is true, return true.
     520       16511 :     if (search_element->SameValueZero(*element_k)) {
     521         332 :       return isolate->heap()->true_value();
     522             :     }
     523             :   }
     524        3228 :   return isolate->heap()->false_value();
     525             : }
     526             : 
     527       20152 : RUNTIME_FUNCTION(Runtime_ArrayIndexOf) {
     528       10076 :   HandleScope shs(isolate);
     529             :   DCHECK_EQ(3, args.length());
     530       10076 :   CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
     531       10076 :   CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
     532             : 
     533             :   // Let O be ? ToObject(this value).
     534             :   Handle<JSReceiver> object;
     535       20152 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     536             :       isolate, object,
     537             :       Object::ToObject(isolate, args.at(0), "Array.prototype.indexOf"));
     538             : 
     539             :   // Let len be ? ToLength(? Get(O, "length")).
     540             :   int64_t len;
     541             :   {
     542        9792 :     if (object->IsJSArray()) {
     543        6677 :       uint32_t len32 = 0;
     544        6677 :       bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
     545             :       DCHECK(success);
     546             :       USE(success);
     547        6677 :       len = len32;
     548             :     } else {
     549             :       Handle<Object> len_;
     550        9345 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     551             :           isolate, len_,
     552             :           Object::GetProperty(object, isolate->factory()->length_string()));
     553             : 
     554        6202 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
     555             :                                          Object::ToLength(isolate, len_));
     556        3101 :       len = static_cast<int64_t>(len_->Number());
     557             :       DCHECK_EQ(len, len_->Number());
     558             :     }
     559             :   }
     560             : 
     561        9778 :   if (len == 0) return Smi::FromInt(-1);
     562             : 
     563             :   // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
     564             :   // produces the value 0.)
     565             :   int64_t start_from;
     566             :   {
     567       17266 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
     568             :                                        Object::ToInteger(isolate, from_index));
     569        8633 :     double fp = from_index->Number();
     570        8633 :     if (fp > len) return Smi::FromInt(-1);
     571        8633 :     start_from = static_cast<int64_t>(fp);
     572             :   }
     573             : 
     574             :   int64_t index;
     575        8633 :   if (start_from >= 0) {
     576             :     index = start_from;
     577             :   } else {
     578         419 :     index = len + start_from;
     579         419 :     if (index < 0) {
     580             :       index = 0;
     581             :     }
     582             :   }
     583             : 
     584             :   // If the receiver is not a special receiver type, and the length is a valid
     585             :   // element index, perform fast operation tailored to specific ElementsKinds.
     586       17223 :   if (!object->map()->IsSpecialReceiverMap() && len < kMaxUInt32 &&
     587        8590 :       JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
     588        8338 :     Handle<JSObject> obj = Handle<JSObject>::cast(object);
     589        8338 :     ElementsAccessor* elements = obj->GetElementsAccessor();
     590             :     Maybe<int64_t> result = elements->IndexOfValue(isolate, obj, search_element,
     591             :                                                    static_cast<uint32_t>(index),
     592        8338 :                                                    static_cast<uint32_t>(len));
     593        8338 :     MAYBE_RETURN(result, isolate->heap()->exception());
     594       16648 :     return *isolate->factory()->NewNumberFromInt64(result.FromJust());
     595             :   }
     596             : 
     597             :   // Otherwise, perform slow lookups for special receiver types
     598         830 :   for (; index < len; ++index) {
     599             :     // Let elementK be the result of ? Get(O, ! ToString(k)).
     600             :     Handle<Object> element_k;
     601             :     {
     602         992 :       Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
     603             :       bool success;
     604             :       LookupIterator it = LookupIterator::PropertyOrElement(
     605         992 :           isolate, object, index_obj, &success);
     606             :       DCHECK(success);
     607        1984 :       if (!JSReceiver::HasProperty(&it).FromJust()) {
     608         178 :         continue;
     609             :       }
     610        1790 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
     611             :                                          Object::GetProperty(&it));
     612         814 :       if (search_element->StrictEquals(*element_k)) {
     613             :         return *index_obj;
     614             :       }
     615             :     }
     616             :   }
     617         133 :   return Smi::FromInt(-1);
     618             : }
     619             : 
     620             : 
     621           0 : RUNTIME_FUNCTION(Runtime_SpreadIterablePrepare) {
     622           0 :   HandleScope scope(isolate);
     623             :   DCHECK_EQ(1, args.length());
     624           0 :   CONVERT_ARG_HANDLE_CHECKED(Object, spread, 0);
     625             : 
     626             :   // Iterate over the spread if we need to.
     627           0 :   if (spread->IterationHasObservableEffects()) {
     628           0 :     Handle<JSFunction> spread_iterable_function = isolate->spread_iterable();
     629           0 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     630             :         isolate, spread,
     631             :         Execution::Call(isolate, spread_iterable_function,
     632             :                         isolate->factory()->undefined_value(), 1, &spread));
     633             :   }
     634             : 
     635           0 :   return *spread;
     636             : }
     637             : 
     638      156896 : RUNTIME_FUNCTION(Runtime_SpreadIterableFixed) {
     639       78448 :   HandleScope scope(isolate);
     640             :   DCHECK_EQ(1, args.length());
     641       78448 :   CONVERT_ARG_HANDLE_CHECKED(Object, spread, 0);
     642             : 
     643             :   // The caller should check if proper iteration is necessary.
     644       78448 :   Handle<JSFunction> spread_iterable_function = isolate->spread_iterable();
     645      235344 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     646             :       isolate, spread,
     647             :       Execution::Call(isolate, spread_iterable_function,
     648             :                       isolate->factory()->undefined_value(), 1, &spread));
     649             : 
     650             :   // Create a new FixedArray and put the result of the spread into it.
     651       78405 :   Handle<JSArray> spread_array = Handle<JSArray>::cast(spread);
     652             :   uint32_t spread_length;
     653       78405 :   CHECK(spread_array->length()->ToArrayIndex(&spread_length));
     654             : 
     655       78405 :   Handle<FixedArray> result = isolate->factory()->NewFixedArray(spread_length);
     656       78405 :   ElementsAccessor* accessor = spread_array->GetElementsAccessor();
     657     1618983 :   for (uint32_t i = 0; i < spread_length; i++) {
     658             :     DCHECK(accessor->HasElement(*spread_array, i));
     659     3237966 :     Handle<Object> element = accessor->Get(spread_array, i);
     660     3237966 :     result->set(i, *element);
     661             :   }
     662             : 
     663       78448 :   return *result;
     664             : }
     665             : 
     666             : }  // namespace internal
     667             : }  // namespace v8

Generated by: LCOV version 1.10