LCOV - code coverage report
Current view: top level - src/runtime - runtime-array.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 302 318 95.0 %
Date: 2017-10-20 Functions: 16 32 50.0 %

          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     1485402 : RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
      21      742701 :   HandleScope scope(isolate);
      22             :   DCHECK_EQ(2, args.length());
      23     1485402 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
      24     1485402 :   CONVERT_ARG_HANDLE_CHECKED(Map, to_map, 1);
      25      742701 :   ElementsKind to_kind = to_map->elements_kind();
      26      742701 :   ElementsAccessor::ForKind(to_kind)->TransitionElementsKind(object, to_map);
      27      742701 :   return *object;
      28             : }
      29             : 
      30             : namespace {
      31             : // As PrepareElementsForSort, but only on objects where elements is
      32             : // a dictionary, and it will stay a dictionary.  Collates undefined and
      33             : // unexisting elements below limit from position zero of the elements.
      34        2078 : Object* PrepareSlowElementsForSort(Handle<JSObject> object, uint32_t limit) {
      35             :   DCHECK(object->HasDictionaryElements());
      36             :   Isolate* isolate = object->GetIsolate();
      37             :   // Must stay in dictionary mode, either because of requires_slow_elements,
      38             :   // or because we are not going to sort (and therefore compact) all of the
      39             :   // elements.
      40             :   Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
      41             :   Handle<SeededNumberDictionary> new_dict =
      42        2078 :       SeededNumberDictionary::New(isolate, dict->NumberOfElements());
      43             : 
      44             :   uint32_t pos = 0;
      45             :   uint32_t undefs = 0;
      46             :   uint32_t max_key = 0;
      47             :   int capacity = dict->Capacity();
      48             :   Smi* bailout = Smi::FromInt(-1);
      49             :   // Entry to the new dictionary does not cause it to grow, as we have
      50             :   // allocated one that is large enough for all entries.
      51       10364 :   for (int i = 0; i < capacity; i++) {
      52             :     Object* k;
      53       12462 :     if (!dict->ToKey(isolate, i, &k)) continue;
      54             : 
      55             :     DCHECK_LE(0, k->Number());
      56             :     DCHECK_LE(k->Number(), kMaxUInt32);
      57             : 
      58             :     HandleScope scope(isolate);
      59        4168 :     Handle<Object> value(dict->ValueAt(i), isolate);
      60             :     PropertyDetails details = dict->DetailsAt(i);
      61        8307 :     if (details.kind() == kAccessor || details.IsReadOnly()) {
      62             :       // Bail out and do the sorting of undefineds and array holes in JS.
      63             :       // Also bail out if the element is not supposed to be moved.
      64             :       return bailout;
      65             :     }
      66             : 
      67        4139 :     uint32_t key = NumberToUint32(k);
      68        4139 :     if (key < limit) {
      69        2109 :       if (value->IsUndefined(isolate)) {
      70          10 :         undefs++;
      71             :       } else {
      72             :         Handle<Object> result =
      73        2099 :             SeededNumberDictionary::Add(new_dict, pos, value, details);
      74             :         // Add should not grow the dictionary since we allocated the right size.
      75             :         DCHECK(result.is_identical_to(new_dict));
      76             :         USE(result);
      77        2099 :         pos++;
      78             :       }
      79             :     } else {
      80             :       Handle<Object> result =
      81        2030 :           SeededNumberDictionary::Add(new_dict, key, value, details);
      82             :       // Add should not grow the dictionary since we allocated the right size.
      83             :       DCHECK(result.is_identical_to(new_dict));
      84             :       USE(result);
      85             :       max_key = Max(max_key, key);
      86             :     }
      87             :   }
      88             : 
      89             :   uint32_t result = pos;
      90        2049 :   PropertyDetails no_details = PropertyDetails::Empty();
      91        4108 :   while (undefs > 0) {
      92          10 :     if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
      93             :       // Adding an entry with the key beyond smi-range requires
      94             :       // allocation. Bailout.
      95             :       return bailout;
      96             :     }
      97             :     HandleScope scope(isolate);
      98             :     Handle<Object> result = SeededNumberDictionary::Add(
      99          10 :         new_dict, pos, isolate->factory()->undefined_value(), no_details);
     100             :     // Add should not grow the dictionary since we allocated the right size.
     101             :     DCHECK(result.is_identical_to(new_dict));
     102             :     USE(result);
     103          10 :     pos++;
     104          10 :     undefs--;
     105             :   }
     106        2049 :   max_key = Max(max_key, pos - 1);
     107             : 
     108        2049 :   object->set_elements(*new_dict);
     109        2049 :   new_dict->UpdateMaxNumberKey(max_key, object);
     110        2049 :   JSObject::ValidateElements(*object);
     111             : 
     112        4098 :   return *isolate->factory()->NewNumberFromUint(result);
     113             : }
     114             : 
     115             : // Collects all defined (non-hole) and non-undefined (array) elements at the
     116             : // start of the elements array.  If the object is in dictionary mode, it is
     117             : // converted to fast elements mode.  Undefined values are placed after
     118             : // non-undefined values.  Returns the number of non-undefined values.
     119       92778 : Object* PrepareElementsForSort(Handle<JSObject> object, uint32_t limit) {
     120             :   Isolate* isolate = object->GetIsolate();
     121      185536 :   if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) {
     122             :     return Smi::FromInt(-1);
     123             :   }
     124       92708 :   if (object->HasStringWrapperElements()) {
     125             :     int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
     126          10 :     return Smi::FromInt(len);
     127             :   }
     128             : 
     129       92698 :   JSObject::ValidateElements(*object);
     130       92698 :   if (object->HasDictionaryElements()) {
     131             :     // Convert to fast elements containing only the existing properties.
     132             :     // Ordering is irrelevant, since we are going to sort anyway.
     133             :     Handle<SeededNumberDictionary> dict(object->element_dictionary());
     134        4247 :     if (object->IsJSArray() || dict->requires_slow_elements() ||
     135          40 :         dict->max_number_key() >= limit) {
     136        2078 :       return PrepareSlowElementsForSort(object, limit);
     137             :     }
     138             :     // Convert to fast elements.
     139             :     Handle<Map> new_map =
     140          40 :         JSObject::GetElementsTransitionMap(object, HOLEY_ELEMENTS);
     141             : 
     142             :     PretenureFlag tenure =
     143          40 :         isolate->heap()->InNewSpace(*object) ? NOT_TENURED : TENURED;
     144             :     Handle<FixedArray> fast_elements =
     145          40 :         isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
     146          40 :     dict->CopyValuesTo(*fast_elements);
     147             : 
     148          40 :     JSObject::SetMapAndElements(object, new_map, fast_elements);
     149          40 :     JSObject::ValidateElements(*object);
     150       90580 :   } else if (object->HasFixedTypedArrayElements()) {
     151             :     // Typed arrays cannot have holes or undefined elements.
     152          91 :     return Smi::FromInt(FixedArrayBase::cast(object->elements())->length());
     153       90489 :   } else if (!object->HasDoubleElements()) {
     154       90452 :     JSObject::EnsureWritableFastElements(object);
     155             :   }
     156             :   DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements());
     157             : 
     158             :   // Collect holes at the end, undefined before that and the rest at the
     159             :   // start, and return the number of non-hole, non-undefined values.
     160             : 
     161             :   Handle<FixedArrayBase> elements_base(object->elements());
     162       90529 :   uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
     163       90529 :   if (limit > elements_length) {
     164             :     limit = elements_length;
     165             :   }
     166       90529 :   if (limit == 0) {
     167             :     return Smi::kZero;
     168             :   }
     169             : 
     170             :   uint32_t result = 0;
     171       90519 :   if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
     172             :     FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
     173             :     // Split elements into defined and the_hole, in that order.
     174             :     unsigned int holes = limit;
     175             :     // Assume most arrays contain no holes and undefined values, so minimize the
     176             :     // number of stores of non-undefined, non-the-hole values.
     177        3805 :     for (unsigned int i = 0; i < holes; i++) {
     178        7536 :       if (elements->is_the_hole(i)) {
     179           0 :         holes--;
     180             :       } else {
     181             :         continue;
     182             :       }
     183             :       // Position i needs to be filled.
     184           0 :       while (holes > i) {
     185           0 :         if (elements->is_the_hole(holes)) {
     186           0 :           holes--;
     187             :         } else {
     188             :           elements->set(i, elements->get_scalar(holes));
     189             :           break;
     190             :         }
     191             :       }
     192             :     }
     193             :     result = holes;
     194          37 :     while (holes < limit) {
     195           0 :       elements->set_the_hole(holes);
     196           0 :       holes++;
     197             :     }
     198             :   } else {
     199             :     FixedArray* elements = FixedArray::cast(*elements_base);
     200             :     DisallowHeapAllocation no_gc;
     201             : 
     202             :     // Split elements into defined, undefined and the_hole, in that order.  Only
     203             :     // count locations for undefined and the hole, and fill them afterwards.
     204       90482 :     WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
     205             :     unsigned int undefs = limit;
     206             :     unsigned int holes = limit;
     207             :     // Assume most arrays contain no holes and undefined values, so minimize the
     208             :     // number of stores of non-undefined, non-the-hole values.
     209     4464967 :     for (unsigned int i = 0; i < undefs; i++) {
     210     4374485 :       Object* current = elements->get(i);
     211     4374485 :       if (current->IsTheHole(isolate)) {
     212       30941 :         holes--;
     213       30941 :         undefs--;
     214     4343544 :       } else if (current->IsUndefined(isolate)) {
     215         731 :         undefs--;
     216             :       } else {
     217             :         continue;
     218             :       }
     219             :       // Position i needs to be filled.
     220     5144609 :       while (undefs > i) {
     221     5144172 :         current = elements->get(undefs);
     222     5144172 :         if (current->IsTheHole(isolate)) {
     223     5112161 :           holes--;
     224     5112161 :           undefs--;
     225       32011 :         } else if (current->IsUndefined(isolate)) {
     226         776 :           undefs--;
     227             :         } else {
     228       31235 :           elements->set(i, current, write_barrier);
     229       31235 :           break;
     230             :         }
     231             :       }
     232             :     }
     233             :     result = undefs;
     234       91989 :     while (undefs < holes) {
     235        1507 :       elements->set_undefined(isolate, undefs);
     236        1507 :       undefs++;
     237             :     }
     238     5233584 :     while (holes < limit) {
     239     5143102 :       elements->set_the_hole(isolate, holes);
     240     5143102 :       holes++;
     241             :     }
     242             :   }
     243             : 
     244      181038 :   return *isolate->factory()->NewNumberFromUint(result);
     245             : }
     246             : 
     247             : }  // namespace
     248             : 
     249             : // Moves all own elements of an object, that are below a limit, to positions
     250             : // starting at zero. All undefined values are placed after non-undefined values,
     251             : // and are followed by non-existing element. Does not change the length
     252             : // property.
     253             : // Returns the number of non-undefined elements collected.
     254             : // Returns -1 if hole removal is not supported by this method.
     255      185576 : RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
     256       92788 :   HandleScope scope(isolate);
     257             :   DCHECK_EQ(2, args.length());
     258      185576 :   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
     259      185576 :   CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
     260       92788 :   if (object->IsJSProxy()) return Smi::FromInt(-1);
     261       92778 :   return PrepareElementsForSort(Handle<JSObject>::cast(object), limit);
     262             : }
     263             : 
     264             : 
     265             : // Move contents of argument 0 (an array) to argument 1 (an array)
     266        2962 : RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
     267        1481 :   HandleScope scope(isolate);
     268             :   DCHECK_EQ(2, args.length());
     269        2962 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
     270        2962 :   CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
     271        1481 :   JSObject::ValidateElements(*from);
     272        1481 :   JSObject::ValidateElements(*to);
     273             : 
     274        1481 :   Handle<FixedArrayBase> new_elements(from->elements());
     275        1481 :   ElementsKind from_kind = from->GetElementsKind();
     276        1481 :   Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
     277        1481 :   JSObject::SetMapAndElements(to, new_map, new_elements);
     278        2962 :   to->set_length(from->length());
     279             : 
     280        1481 :   from->initialize_elements();
     281        1481 :   from->set_length(Smi::kZero);
     282             : 
     283        1481 :   JSObject::ValidateElements(*to);
     284        1481 :   return *to;
     285             : }
     286             : 
     287             : 
     288             : // How many elements does this object/array have?
     289        4516 : RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
     290        2258 :   DisallowHeapAllocation no_gc;
     291        2258 :   HandleScope scope(isolate);
     292             :   DCHECK_EQ(1, args.length());
     293        4516 :   CONVERT_ARG_CHECKED(JSArray, array, 0);
     294        2258 :   FixedArrayBase* elements = array->elements();
     295             :   SealHandleScope shs(isolate);
     296        2258 :   if (elements->IsDictionary()) {
     297         969 :     int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
     298         969 :     return Smi::FromInt(result);
     299             :   } else {
     300             :     DCHECK(array->length()->IsSmi());
     301             :     // For packed elements, we know the exact number of elements
     302        1289 :     int length = elements->length();
     303        1289 :     ElementsKind kind = array->GetElementsKind();
     304        1289 :     if (IsFastPackedElementsKind(kind)) {
     305         280 :       return Smi::FromInt(length);
     306             :     }
     307             :     // For holey elements, take samples from the buffer checking for holes
     308             :     // to generate the estimate.
     309             :     const int kNumberOfHoleCheckSamples = 97;
     310             :     int increment = (length < kNumberOfHoleCheckSamples)
     311             :                         ? 1
     312        1009 :                         : static_cast<int>(length / kNumberOfHoleCheckSamples);
     313        1009 :     ElementsAccessor* accessor = array->GetElementsAccessor();
     314             :     int holes = 0;
     315       99561 :     for (int i = 0; i < length; i += increment) {
     316       99561 :       if (!accessor->HasElement(array, i, elements)) {
     317       43172 :         ++holes;
     318             :       }
     319             :     }
     320        1009 :     int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
     321        1009 :                                     kNumberOfHoleCheckSamples * length);
     322        1009 :     return Smi::FromInt(estimate);
     323        2258 :   }
     324             : }
     325             : 
     326             : 
     327             : // Returns an array that tells you where in the [0, length) interval an array
     328             : // might have elements.  Can either return an array of keys (positive integers
     329             : // or undefined) or a number representing the positive length of an interval
     330             : // starting at index 0.
     331             : // Intervals can span over some keys that are not in the object.
     332       11706 : RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
     333        5853 :   HandleScope scope(isolate);
     334             :   DCHECK_EQ(2, args.length());
     335       11706 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
     336       11706 :   CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
     337        5853 :   ElementsKind kind = array->GetElementsKind();
     338             : 
     339        5853 :   if (IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind)) {
     340        3358 :     uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
     341        6716 :     return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
     342             :   }
     343             : 
     344        2495 :   if (kind == FAST_STRING_WRAPPER_ELEMENTS) {
     345             :     int string_length =
     346          20 :         String::cast(Handle<JSValue>::cast(array)->value())->length();
     347          10 :     int backing_store_length = array->elements()->length();
     348             :     return *isolate->factory()->NewNumberFromUint(
     349             :         Min(length,
     350          20 :             static_cast<uint32_t>(Max(string_length, backing_store_length))));
     351             :   }
     352             : 
     353             :   KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
     354        4970 :                              ALL_PROPERTIES);
     355       12305 :   for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
     356        7335 :        !iter.IsAtEnd(); iter.Advance()) {
     357        7335 :     Handle<JSReceiver> current(PrototypeIterator::GetCurrent<JSReceiver>(iter));
     358        7335 :     if (current->HasComplexElements()) {
     359           0 :       return *isolate->factory()->NewNumberFromUint(length);
     360             :     }
     361             :     accumulator.CollectOwnElementIndices(array,
     362       14670 :                                          Handle<JSObject>::cast(current));
     363             :   }
     364             :   // Erase any keys >= length.
     365             :   Handle<FixedArray> keys =
     366        2485 :       accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
     367             :   int j = 0;
     368       25103 :   for (int i = 0; i < keys->length(); i++) {
     369       11309 :     if (NumberToUint32(keys->get(i)) >= length) continue;
     370       10759 :     if (i != j) keys->set(j, keys->get(i));
     371       10519 :     j++;
     372             :   }
     373             : 
     374        2485 :   if (j != keys->length()) {
     375         360 :     isolate->heap()->RightTrimFixedArray(*keys, keys->length() - j);
     376             :   }
     377             : 
     378       10823 :   return *isolate->factory()->NewJSArrayWithElements(keys);
     379             : }
     380             : 
     381     1004022 : RUNTIME_FUNCTION(Runtime_NewArray) {
     382      502011 :   HandleScope scope(isolate);
     383             :   DCHECK_LE(3, args.length());
     384      502011 :   int const argc = args.length() - 3;
     385             :   // TODO(bmeurer): Remove this Arguments nonsense.
     386      502011 :   Arguments argv(argc, args.arguments() - 1);
     387     1004022 :   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
     388     1004022 :   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, argc + 1);
     389     1004022 :   CONVERT_ARG_HANDLE_CHECKED(HeapObject, type_info, argc + 2);
     390             :   // TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite.
     391             :   Handle<AllocationSite> site = type_info->IsAllocationSite()
     392             :                                     ? Handle<AllocationSite>::cast(type_info)
     393      502011 :                                     : Handle<AllocationSite>::null();
     394             : 
     395      502011 :   Factory* factory = isolate->factory();
     396             : 
     397             :   // If called through new, new.target can be:
     398             :   // - a subclass of constructor,
     399             :   // - a proxy wrapper around constructor, or
     400             :   // - the constructor itself.
     401             :   // If called through Reflect.construct, it's guaranteed to be a constructor by
     402             :   // REFLECT_CONSTRUCT_PREPARE.
     403             :   DCHECK(new_target->IsConstructor());
     404             : 
     405             :   bool holey = false;
     406      502011 :   bool can_use_type_feedback = !site.is_null();
     407             :   bool can_inline_array_constructor = true;
     408      502011 :   if (argv.length() == 1) {
     409        5003 :     Handle<Object> argument_one = argv.at<Object>(0);
     410        5003 :     if (argument_one->IsSmi()) {
     411        6722 :       int value = Handle<Smi>::cast(argument_one)->value();
     412        6683 :       if (value < 0 ||
     413        3322 :           JSArray::SetLengthWouldNormalize(isolate->heap(), value)) {
     414             :         // the array is a dictionary in this case.
     415             :         can_use_type_feedback = false;
     416        3036 :       } else if (value != 0) {
     417             :         holey = true;
     418        2419 :         if (value >= JSArray::kInitialMaxFastElementArray) {
     419             :           can_inline_array_constructor = false;
     420             :         }
     421             :       }
     422             :     } else {
     423             :       // Non-smi length argument produces a dictionary
     424             :       can_use_type_feedback = false;
     425             :     }
     426             :   }
     427             : 
     428             :   Handle<Map> initial_map;
     429     1004022 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     430             :       isolate, initial_map,
     431             :       JSFunction::GetDerivedMap(isolate, constructor, new_target));
     432             : 
     433             :   ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
     434     1004022 :                                                : initial_map->elements_kind();
     435      502011 :   if (holey && !IsHoleyElementsKind(to_kind)) {
     436         761 :     to_kind = GetHoleyElementsKind(to_kind);
     437             :     // Update the allocation site info to reflect the advice alteration.
     438         761 :     if (!site.is_null()) site->SetElementsKind(to_kind);
     439             :   }
     440             : 
     441             :   // We should allocate with an initial map that reflects the allocation site
     442             :   // advice. Therefore we use AllocateJSObjectFromMap instead of passing
     443             :   // the constructor.
     444      502011 :   if (to_kind != initial_map->elements_kind()) {
     445      329713 :     initial_map = Map::AsElementsKind(initial_map, to_kind);
     446             :   }
     447             : 
     448             :   // If we don't care to track arrays of to_kind ElementsKind, then
     449             :   // don't emit a memento for them.
     450             :   Handle<AllocationSite> allocation_site;
     451      502011 :   if (AllocationSite::ShouldTrack(to_kind)) {
     452      173861 :     allocation_site = site;
     453             :   }
     454             : 
     455             :   Handle<JSArray> array = Handle<JSArray>::cast(
     456      502011 :       factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
     457             : 
     458      502011 :   factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
     459             : 
     460      502011 :   ElementsKind old_kind = array->GetElementsKind();
     461      502011 :   RETURN_FAILURE_ON_EXCEPTION(isolate,
     462             :                               ArrayConstructInitializeElements(array, &argv));
     463      501893 :   if (!site.is_null()) {
     464      677306 :     if ((old_kind != array->GetElementsKind() || !can_use_type_feedback ||
     465      338174 :          !can_inline_array_constructor)) {
     466             :       // The arguments passed in caused a transition. This kind of complexity
     467             :       // can't be dealt with in the inlined hydrogen array constructor case.
     468             :       // We must mark the allocationsite as un-inlinable.
     469        2356 :       site->SetDoNotInlineCall();
     470             :     }
     471             :   } else {
     472      162761 :     if (old_kind != array->GetElementsKind() || !can_inline_array_constructor) {
     473             :       // We don't have an AllocationSite for this Array constructor invocation,
     474             :       // i.e. it might a call from Array#map or from an Array subclass, so we
     475             :       // just flip the bit on the global protector cell instead.
     476             :       // TODO(bmeurer): Find a better way to mark this. Global protectors
     477             :       // tend to back-fire over time...
     478        2301 :       if (isolate->IsArrayConstructorIntact()) {
     479         216 :         isolate->InvalidateArrayConstructorProtector();
     480             :       }
     481             :     }
     482             :   }
     483             : 
     484      502011 :   return *array;
     485             : }
     486             : 
     487        5982 : RUNTIME_FUNCTION(Runtime_NormalizeElements) {
     488        2991 :   HandleScope scope(isolate);
     489             :   DCHECK_EQ(1, args.length());
     490        5982 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
     491        2991 :   CHECK(!array->HasFixedTypedArrayElements());
     492        2991 :   CHECK(!array->IsJSGlobalProxy());
     493        2991 :   JSObject::NormalizeElements(array);
     494        2991 :   return *array;
     495             : }
     496             : 
     497             : 
     498             : // GrowArrayElements returns a sentinel Smi if the object was normalized.
     499         712 : RUNTIME_FUNCTION(Runtime_GrowArrayElements) {
     500         356 :   HandleScope scope(isolate);
     501             :   DCHECK_EQ(2, args.length());
     502         712 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
     503         712 :   CONVERT_NUMBER_CHECKED(int, key, Int32, args[1]);
     504             : 
     505         356 :   if (key < 0) {
     506           0 :     return object->elements();
     507             :   }
     508             : 
     509         356 :   uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
     510         356 :   uint32_t index = static_cast<uint32_t>(key);
     511             : 
     512         356 :   if (index >= capacity) {
     513         356 :     if (!object->GetElementsAccessor()->GrowCapacity(object, index)) {
     514             :       return Smi::kZero;
     515             :     }
     516             :   }
     517             : 
     518             :   // On success, return the fixed array elements.
     519         356 :   return object->elements();
     520             : }
     521             : 
     522             : 
     523        6262 : RUNTIME_FUNCTION(Runtime_HasComplexElements) {
     524        3131 :   HandleScope scope(isolate);
     525             :   DCHECK_EQ(1, args.length());
     526        6262 :   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
     527       15455 :   for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
     528        9193 :        !iter.IsAtEnd(); iter.Advance()) {
     529       18496 :     if (PrototypeIterator::GetCurrent<JSReceiver>(iter)->HasComplexElements()) {
     530          55 :       return isolate->heap()->true_value();
     531             :     }
     532             :   }
     533        3076 :   return isolate->heap()->false_value();
     534             : }
     535             : 
     536             : // ES6 22.1.2.2 Array.isArray
     537         876 : RUNTIME_FUNCTION(Runtime_ArrayIsArray) {
     538         438 :   HandleScope shs(isolate);
     539             :   DCHECK_EQ(1, args.length());
     540         438 :   CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
     541             :   Maybe<bool> result = Object::IsArray(object);
     542         438 :   MAYBE_RETURN(result, isolate->heap()->exception());
     543         392 :   return isolate->heap()->ToBoolean(result.FromJust());
     544             : }
     545             : 
     546          36 : RUNTIME_FUNCTION(Runtime_IsArray) {
     547             :   SealHandleScope shs(isolate);
     548             :   DCHECK_EQ(1, args.length());
     549          18 :   CONVERT_ARG_CHECKED(Object, obj, 0);
     550          18 :   return isolate->heap()->ToBoolean(obj->IsJSArray());
     551             : }
     552             : 
     553       10252 : RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
     554        5126 :   HandleScope scope(isolate);
     555             :   DCHECK_EQ(1, args.length());
     556        5126 :   CONVERT_ARG_HANDLE_CHECKED(Object, original_array, 0);
     557       10252 :   RETURN_RESULT_OR_FAILURE(
     558        5126 :       isolate, Object::ArraySpeciesConstructor(isolate, original_array));
     559             : }
     560             : 
     561             : // ES7 22.1.3.11 Array.prototype.includes
     562        9740 : RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
     563        4870 :   HandleScope shs(isolate);
     564             :   DCHECK_EQ(3, args.length());
     565        4870 :   CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
     566        4870 :   CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
     567             : 
     568             :   // Let O be ? ToObject(this value).
     569             :   Handle<JSReceiver> object;
     570       14610 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     571             :       isolate, object, Object::ToObject(isolate, handle(args[0], isolate)));
     572             : 
     573             :   // Let len be ? ToLength(? Get(O, "length")).
     574             :   int64_t len;
     575             :   {
     576        4852 :     if (object->map()->instance_type() == JS_ARRAY_TYPE) {
     577         207 :       uint32_t len32 = 0;
     578         207 :       bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
     579             :       DCHECK(success);
     580             :       USE(success);
     581         207 :       len = len32;
     582             :     } else {
     583             :       Handle<Object> len_;
     584       13935 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     585             :           isolate, len_,
     586             :           Object::GetProperty(object, isolate->factory()->length_string()));
     587             : 
     588        9272 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
     589             :                                          Object::ToLength(isolate, len_));
     590        4618 :       len = static_cast<int64_t>(len_->Number());
     591             :       DCHECK_EQ(len, len_->Number());
     592             :     }
     593             :   }
     594             : 
     595        4825 :   if (len == 0) return isolate->heap()->false_value();
     596             : 
     597             :   // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
     598             :   // produces the value 0.)
     599             :   int64_t index = 0;
     600        4483 :   if (!from_index->IsUndefined(isolate)) {
     601        2758 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
     602             :                                        Object::ToInteger(isolate, from_index));
     603             : 
     604        1361 :     if (V8_LIKELY(from_index->IsSmi())) {
     605        1307 :       int start_from = Smi::ToInt(*from_index);
     606        1307 :       if (start_from < 0) {
     607         207 :         index = std::max<int64_t>(len + start_from, 0);
     608             :       } else {
     609        1100 :         index = start_from;
     610             :       }
     611             :     } else {
     612             :       DCHECK(from_index->IsHeapNumber());
     613          54 :       double start_from = from_index->Number();
     614          54 :       if (start_from >= len) return isolate->heap()->false_value();
     615          36 :       if (V8_LIKELY(std::isfinite(start_from))) {
     616          27 :         if (start_from < 0) {
     617           0 :           index = static_cast<int64_t>(std::max<double>(start_from + len, 0));
     618             :         } else {
     619          27 :           index = start_from;
     620             :         }
     621             :       }
     622             :     }
     623             : 
     624             :     DCHECK_GE(index, 0);
     625             :   }
     626             : 
     627             :   // If the receiver is not a special receiver type, and the length is a valid
     628             :   // element index, perform fast operation tailored to specific ElementsKinds.
     629        8858 :   if (!object->map()->IsSpecialReceiverMap() && len < kMaxUInt32 &&
     630        4411 :       JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
     631        1902 :     Handle<JSObject> obj = Handle<JSObject>::cast(object);
     632        1902 :     ElementsAccessor* elements = obj->GetElementsAccessor();
     633             :     Maybe<bool> result = elements->IncludesValue(isolate, obj, search_element,
     634             :                                                  static_cast<uint32_t>(index),
     635        1902 :                                                  static_cast<uint32_t>(len));
     636        1902 :     MAYBE_RETURN(result, isolate->heap()->exception());
     637        3786 :     return *isolate->factory()->ToBoolean(result.FromJust());
     638             :   }
     639             : 
     640             :   // Otherwise, perform slow lookups for special receiver types
     641       11669 :   for (; index < len; ++index) {
     642             :     // Let elementK be the result of ? Get(O, ! ToString(k)).
     643             :     Handle<Object> element_k;
     644             :     {
     645       11886 :       Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
     646             :       bool success;
     647             :       LookupIterator it = LookupIterator::PropertyOrElement(
     648       11886 :           isolate, object, index_obj, &success);
     649             :       DCHECK(success);
     650       23772 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
     651             :                                          Object::GetProperty(&it));
     652             :     }
     653             : 
     654             :     // If SameValueZero(searchElement, elementK) is true, return true.
     655       11886 :     if (search_element->SameValueZero(*element_k)) {
     656         217 :       return isolate->heap()->true_value();
     657             :     }
     658             :   }
     659        2328 :   return isolate->heap()->false_value();
     660             : }
     661             : 
     662       14658 : RUNTIME_FUNCTION(Runtime_ArrayIndexOf) {
     663        7329 :   HandleScope shs(isolate);
     664             :   DCHECK_EQ(3, args.length());
     665        7329 :   CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
     666        7329 :   CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
     667             : 
     668             :   // Let O be ? ToObject(this value).
     669             :   Handle<JSReceiver> object;
     670       14658 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     671             :       isolate, object,
     672             :       Object::ToObject(isolate, args.at(0), "Array.prototype.indexOf"));
     673             : 
     674             :   // Let len be ? ToLength(? Get(O, "length")).
     675             :   int64_t len;
     676             :   {
     677        7140 :     if (object->IsJSArray()) {
     678        5055 :       uint32_t len32 = 0;
     679        5055 :       bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
     680             :       DCHECK(success);
     681             :       USE(success);
     682        5055 :       len = len32;
     683             :     } else {
     684             :       Handle<Object> len_;
     685        6255 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     686             :           isolate, len_,
     687             :           Object::GetProperty(object, isolate->factory()->length_string()));
     688             : 
     689        4152 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
     690             :                                          Object::ToLength(isolate, len_));
     691        2076 :       len = static_cast<int64_t>(len_->Number());
     692             :       DCHECK_EQ(len, len_->Number());
     693             :     }
     694             :   }
     695             : 
     696        7131 :   if (len == 0) return Smi::FromInt(-1);
     697             : 
     698             :   // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
     699             :   // produces the value 0.)
     700             :   int64_t start_from;
     701             :   {
     702       12648 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
     703             :                                        Object::ToInteger(isolate, from_index));
     704        6324 :     double fp = from_index->Number();
     705        6324 :     if (fp > len) return Smi::FromInt(-1);
     706        6324 :     if (V8_LIKELY(fp >=
     707             :                   static_cast<double>(std::numeric_limits<int64_t>::min()))) {
     708             :       DCHECK(fp < std::numeric_limits<int64_t>::max());
     709        6324 :       start_from = static_cast<int64_t>(fp);
     710             :     } else {
     711             :       start_from = std::numeric_limits<int64_t>::min();
     712             :     }
     713             :   }
     714             : 
     715             :   int64_t index;
     716        6324 :   if (start_from >= 0) {
     717             :     index = start_from;
     718             :   } else {
     719         279 :     index = len + start_from;
     720         279 :     if (index < 0) {
     721             :       index = 0;
     722             :     }
     723             :   }
     724             : 
     725             :   // If the receiver is not a special receiver type, and the length is a valid
     726             :   // element index, perform fast operation tailored to specific ElementsKinds.
     727       12610 :   if (!object->map()->IsSpecialReceiverMap() && len < kMaxUInt32 &&
     728        6286 :       JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
     729        6101 :     Handle<JSObject> obj = Handle<JSObject>::cast(object);
     730        6101 :     ElementsAccessor* elements = obj->GetElementsAccessor();
     731             :     Maybe<int64_t> result = elements->IndexOfValue(isolate, obj, search_element,
     732             :                                                    static_cast<uint32_t>(index),
     733        6101 :                                                    static_cast<uint32_t>(len));
     734        6101 :     MAYBE_RETURN(result, isolate->heap()->exception());
     735       12184 :     return *isolate->factory()->NewNumberFromInt64(result.FromJust());
     736             :   }
     737             : 
     738             :   // Otherwise, perform slow lookups for special receiver types
     739         568 :   for (; index < len; ++index) {
     740             :     // Let elementK be the result of ? Get(O, ! ToString(k)).
     741             :     Handle<Object> element_k;
     742             :     {
     743         703 :       Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
     744             :       bool success;
     745             :       LookupIterator it = LookupIterator::PropertyOrElement(
     746         703 :           isolate, object, index_obj, &success);
     747             :       DCHECK(success);
     748         703 :       Maybe<bool> present = JSReceiver::HasProperty(&it);
     749         838 :       MAYBE_RETURN(present, isolate->heap()->exception());
     750         811 :       if (!present.FromJust()) continue;
     751        1150 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
     752             :                                          Object::GetProperty(&it));
     753         575 :       if (search_element->StrictEquals(*element_k)) {
     754             :         return *index_obj;
     755             :       }
     756             :     }
     757             :   }
     758          88 :   return Smi::FromInt(-1);
     759             : }
     760             : 
     761             : 
     762           0 : RUNTIME_FUNCTION(Runtime_SpreadIterablePrepare) {
     763           0 :   HandleScope scope(isolate);
     764             :   DCHECK_EQ(1, args.length());
     765           0 :   CONVERT_ARG_HANDLE_CHECKED(Object, spread, 0);
     766             : 
     767             :   // Iterate over the spread if we need to.
     768           0 :   if (spread->IterationHasObservableEffects()) {
     769           0 :     Handle<JSFunction> spread_iterable_function = isolate->spread_iterable();
     770           0 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     771             :         isolate, spread,
     772             :         Execution::Call(isolate, spread_iterable_function,
     773             :                         isolate->factory()->undefined_value(), 1, &spread));
     774             :   }
     775             : 
     776           0 :   return *spread;
     777             : }
     778             : 
     779             : }  // namespace internal
     780             : }  // namespace v8

Generated by: LCOV version 1.10