Home | History | Annotate | Download | only in runtime
      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/arguments-inl.h"
      6 #include "src/code-stubs.h"
      7 #include "src/conversions-inl.h"
      8 #include "src/debug/debug.h"
      9 #include "src/elements.h"
     10 #include "src/heap/factory.h"
     11 #include "src/isolate-inl.h"
     12 #include "src/keys.h"
     13 #include "src/messages.h"
     14 #include "src/objects/arguments-inl.h"
     15 #include "src/objects/hash-table-inl.h"
     16 #include "src/objects/js-array-inl.h"
     17 #include "src/prototype.h"
     18 #include "src/runtime/runtime-utils.h"
     19 
     20 namespace v8 {
     21 namespace internal {
     22 
     23 RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
     24   HandleScope scope(isolate);
     25   DCHECK_EQ(2, args.length());
     26   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
     27   CONVERT_ARG_HANDLE_CHECKED(Map, to_map, 1);
     28   ElementsKind to_kind = to_map->elements_kind();
     29   ElementsAccessor::ForKind(to_kind)->TransitionElementsKind(object, to_map);
     30   return *object;
     31 }
     32 
     33 namespace {
     34 // Find the next free position. undefined and holes are both considered
     35 // free spots. Returns "Nothing" if an exception occurred.
     36 V8_WARN_UNUSED_RESULT
     37 Maybe<uint32_t> FindNextFreePosition(Isolate* isolate,
     38                                      Handle<JSReceiver> receiver,
     39                                      uint32_t current_pos) {
     40   for (uint32_t position = current_pos;; ++position) {
     41     Maybe<bool> has_element = JSReceiver::HasElement(receiver, position);
     42     MAYBE_RETURN(has_element, Nothing<uint32_t>());
     43     if (!has_element.FromJust()) return Just(position);
     44 
     45     Handle<Object> element;
     46     ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     47         isolate, element, JSReceiver::GetElement(isolate, receiver, position),
     48         Nothing<uint32_t>());
     49     if (element->IsUndefined(isolate)) return Just(position);
     50   }
     51 }
     52 
     53 // As RemoveArrayHoles, but also handles Dictionary elements that stay
     54 // Dictionary (requires_slow_elements() is true), proxies and objects that
     55 // might have accessors.
     56 V8_WARN_UNUSED_RESULT
     57 Object* RemoveArrayHolesGeneric(Isolate* isolate, Handle<JSReceiver> receiver,
     58                                 uint32_t limit) {
     59   HandleScope scope(isolate);
     60 
     61   // For proxies, we do not collect the keys, instead we use all indices in
     62   // the full range of [0, limit).
     63   Handle<FixedArray> keys;
     64   if (!receiver->IsJSProxy()) {
     65     keys = JSReceiver::GetOwnElementIndices(isolate, receiver,
     66                                             Handle<JSObject>::cast(receiver));
     67   }
     68 
     69   uint32_t num_undefined = 0;
     70   uint32_t current_pos = 0;
     71   int num_indices = keys.is_null() ? limit : keys->length();
     72 
     73   // Compact keys with undefined values and moves non-undefined
     74   // values to the front.
     75   // The loop does two things simultaneously:
     76   //   (1) Count the number of 'undefined', i.e.
     77   //       i.e.: HasProperty(receiver, key) && Get(receiver, key) == undefined
     78   //   (2) Move all non-undefined values to the front. The variable current_pos
     79   //       is used to track free spots in the array starting at the beginning.
     80   //       Holes and 'undefined' are considered free spots.
     81   //       A hole is when HasElement(receiver, key) is false.
     82   for (int i = 0; i < num_indices; ++i) {
     83     uint32_t key = keys.is_null() ? i : NumberToUint32(keys->get(i));
     84 
     85     // We only care about array indices that are smaller than the limit.
     86     // The keys are sorted, so we can break as soon as we encounter the first.
     87     if (key >= limit) break;
     88 
     89     Maybe<bool> has_element = JSReceiver::HasElement(receiver, key);
     90     MAYBE_RETURN(has_element, ReadOnlyRoots(isolate).exception());
     91     if (!has_element.FromJust()) {
     92       continue;
     93     }
     94 
     95     Handle<Object> element;
     96     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     97         isolate, element, JSReceiver::GetElement(isolate, receiver, key));
     98 
     99     if (element->IsUndefined(isolate)) {
    100       ++num_undefined;
    101     } else {
    102       // Find next free position to move elements to.
    103       Maybe<uint32_t> free_position =
    104           FindNextFreePosition(isolate, receiver, current_pos);
    105       MAYBE_RETURN(free_position, ReadOnlyRoots(isolate).exception());
    106       current_pos = free_position.FromJust();
    107 
    108       // Do not move elements that are already in the "packed" area.
    109       if (key <= current_pos) continue;
    110 
    111       // array[current_pos] = array[key].
    112       // Deleting array[key] is done later. This is to preserve the same
    113       // semantics as the old JS implementation when working with non-extensible
    114       // objects:
    115       // If the array contains undefineds, the position at 'key' might later
    116       // bet set to 'undefined'. If we delete the element now and later set it
    117       // to undefined, the set operation would throw an exception.
    118       RETURN_FAILURE_ON_EXCEPTION(
    119           isolate, JSReceiver::SetElement(isolate, receiver, current_pos,
    120                                           element, LanguageMode::kStrict));
    121       ++current_pos;
    122     }
    123   }
    124 
    125   // Set [current_pos, current_pos + num_undefined) to undefined.
    126   uint32_t result = current_pos;
    127   for (uint32_t i = 0; i < num_undefined; ++i) {
    128     RETURN_FAILURE_ON_EXCEPTION(
    129         isolate, JSReceiver::SetElement(isolate, receiver, current_pos++,
    130                                         isolate->factory()->undefined_value(),
    131                                         LanguageMode::kStrict));
    132   }
    133   // TODO(szuend): Re-enable when we also copy from the prototype chain for
    134   //               JSArrays. Then we can use HasOwnProperty instead of
    135   //               HasElement and this condition will hold.
    136   // DCHECK_LE(current_pos, num_indices);
    137 
    138   // Deleting everything after the undefineds up unto the limit.
    139   for (int i = num_indices - 1; i >= 0; --i) {
    140     uint32_t key = keys.is_null() ? i : NumberToUint32(keys->get(i));
    141     if (key < current_pos) break;
    142     if (key >= limit) continue;
    143 
    144     Maybe<bool> delete_result = JSReceiver::DeleteElement(receiver, key);
    145     MAYBE_RETURN(delete_result, ReadOnlyRoots(isolate).exception());
    146   }
    147 
    148   // TODO(jgruber, szuend, chromium:897512): This is a workaround to prevent
    149   // returning a number greater than array.length to Array.p.sort, which could
    150   // trigger OOB accesses. There is still a correctness bug here though in
    151   // how we shift around undefineds and delete elements in the two blocks above.
    152   // This needs to be fixed soon.
    153   const uint32_t number_of_non_undefined_elements = std::min(limit, result);
    154 
    155   return *isolate->factory()->NewNumberFromUint(
    156       number_of_non_undefined_elements);
    157 }
    158 
    159 // Collects all defined (non-hole) and non-undefined (array) elements at the
    160 // start of the elements array.  If the object is in dictionary mode, it is
    161 // converted to fast elements mode.  Undefined values are placed after
    162 // non-undefined values.  Returns the number of non-undefined values.
    163 V8_WARN_UNUSED_RESULT
    164 Object* RemoveArrayHoles(Isolate* isolate, Handle<JSReceiver> receiver,
    165                          uint32_t limit) {
    166   if (receiver->IsJSProxy()) {
    167     return RemoveArrayHolesGeneric(isolate, receiver, limit);
    168   }
    169 
    170   Handle<JSObject> object = Handle<JSObject>::cast(receiver);
    171   if (object->HasStringWrapperElements()) {
    172     int len = String::cast(Handle<JSValue>::cast(object)->value())->length();
    173     DCHECK_LE(len, limit);
    174     return Smi::FromInt(len);
    175   }
    176 
    177   if (object->HasSloppyArgumentsElements() || !object->map()->is_extensible()) {
    178     return RemoveArrayHolesGeneric(isolate, receiver, limit);
    179   }
    180 
    181   JSObject::ValidateElements(*object);
    182   if (object->HasDictionaryElements()) {
    183     // Convert to fast elements containing only the existing properties.
    184     // Ordering is irrelevant, since we are going to sort anyway.
    185     Handle<NumberDictionary> dict(object->element_dictionary(), isolate);
    186     if (object->IsJSArray() || dict->requires_slow_elements() ||
    187         dict->max_number_key() >= limit) {
    188       return RemoveArrayHolesGeneric(isolate, receiver, limit);
    189     }
    190     // Convert to fast elements.
    191     Handle<Map> new_map =
    192         JSObject::GetElementsTransitionMap(object, HOLEY_ELEMENTS);
    193 
    194     PretenureFlag tenure = Heap::InNewSpace(*object) ? NOT_TENURED : TENURED;
    195     Handle<FixedArray> fast_elements =
    196         isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
    197     dict->CopyValuesTo(*fast_elements);
    198 
    199     JSObject::SetMapAndElements(object, new_map, fast_elements);
    200     JSObject::ValidateElements(*object);
    201   } else if (object->HasFixedTypedArrayElements()) {
    202     // Typed arrays cannot have holes or undefined elements.
    203     int array_length = FixedArrayBase::cast(object->elements())->length();
    204     return Smi::FromInt(Min(limit, static_cast<uint32_t>(array_length)));
    205   } else if (!object->HasDoubleElements()) {
    206     JSObject::EnsureWritableFastElements(object);
    207   }
    208   DCHECK(object->HasSmiOrObjectElements() || object->HasDoubleElements());
    209 
    210   // Collect holes at the end, undefined before that and the rest at the
    211   // start, and return the number of non-hole, non-undefined values.
    212 
    213   Handle<FixedArrayBase> elements_base(object->elements(), isolate);
    214   uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
    215   if (limit > elements_length) {
    216     limit = elements_length;
    217   }
    218   if (limit == 0) {
    219     return Smi::kZero;
    220   }
    221 
    222   uint32_t result = 0;
    223   if (elements_base->map() == ReadOnlyRoots(isolate).fixed_double_array_map()) {
    224     FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
    225     // Split elements into defined and the_hole, in that order.
    226     unsigned int holes = limit;
    227     // Assume most arrays contain no holes and undefined values, so minimize the
    228     // number of stores of non-undefined, non-the-hole values.
    229     for (unsigned int i = 0; i < holes; i++) {
    230       if (elements->is_the_hole(i)) {
    231         holes--;
    232       } else {
    233         continue;
    234       }
    235       // Position i needs to be filled.
    236       while (holes > i) {
    237         if (elements->is_the_hole(holes)) {
    238           holes--;
    239         } else {
    240           elements->set(i, elements->get_scalar(holes));
    241           break;
    242         }
    243       }
    244     }
    245     result = holes;
    246     while (holes < limit) {
    247       elements->set_the_hole(holes);
    248       holes++;
    249     }
    250   } else {
    251     FixedArray* elements = FixedArray::cast(*elements_base);
    252     DisallowHeapAllocation no_gc;
    253 
    254     // Split elements into defined, undefined and the_hole, in that order.  Only
    255     // count locations for undefined and the hole, and fill them afterwards.
    256     WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
    257     unsigned int undefs = limit;
    258     unsigned int holes = limit;
    259     // Assume most arrays contain no holes and undefined values, so minimize the
    260     // number of stores of non-undefined, non-the-hole values.
    261     for (unsigned int i = 0; i < undefs; i++) {
    262       Object* current = elements->get(i);
    263       if (current->IsTheHole(isolate)) {
    264         holes--;
    265         undefs--;
    266       } else if (current->IsUndefined(isolate)) {
    267         undefs--;
    268       } else {
    269         continue;
    270       }
    271       // Position i needs to be filled.
    272       while (undefs > i) {
    273         current = elements->get(undefs);
    274         if (current->IsTheHole(isolate)) {
    275           holes--;
    276           undefs--;
    277         } else if (current->IsUndefined(isolate)) {
    278           undefs--;
    279         } else {
    280           elements->set(i, current, write_barrier);
    281           break;
    282         }
    283       }
    284     }
    285     result = undefs;
    286     while (undefs < holes) {
    287       elements->set_undefined(isolate, undefs);
    288       undefs++;
    289     }
    290     while (holes < limit) {
    291       elements->set_the_hole(isolate, holes);
    292       holes++;
    293     }
    294   }
    295 
    296   DCHECK_LE(result, limit);
    297   return *isolate->factory()->NewNumberFromUint(result);
    298 }
    299 
    300 // Copy element at index from source to target only if target does not have the
    301 // element on its own. Returns true if a copy occurred, false if not
    302 // and Nothing if an exception occurred.
    303 V8_WARN_UNUSED_RESULT
    304 Maybe<bool> ConditionalCopy(Isolate* isolate, Handle<JSReceiver> source,
    305                             Handle<JSReceiver> target, uint32_t index) {
    306   Maybe<bool> source_has_prop = JSReceiver::HasOwnProperty(source, index);
    307   MAYBE_RETURN(source_has_prop, Nothing<bool>());
    308   if (!source_has_prop.FromJust()) return Just(false);
    309 
    310   Maybe<bool> target_has_prop = JSReceiver::HasOwnProperty(target, index);
    311   MAYBE_RETURN(target_has_prop, Nothing<bool>());
    312   if (target_has_prop.FromJust()) return Just(false);
    313 
    314   Handle<Object> source_element;
    315   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
    316       isolate, source_element, JSReceiver::GetElement(isolate, source, index),
    317       Nothing<bool>());
    318 
    319   Handle<Object> set_result;
    320   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
    321       isolate, set_result,
    322       JSReceiver::SetElement(isolate, target, index, source_element,
    323                              LanguageMode::kStrict),
    324       Nothing<bool>());
    325 
    326   return Just(true);
    327 }
    328 
    329 // Copy elements in the range 0..length from objects prototype chain
    330 // to object itself, if object has holes. Returns null on error and undefined on
    331 // success.
    332 V8_WARN_UNUSED_RESULT
    333 MaybeHandle<Object> CopyFromPrototype(Isolate* isolate,
    334                                       Handle<JSReceiver> object,
    335                                       uint32_t length) {
    336   for (PrototypeIterator iter(isolate, object, kStartAtPrototype);
    337        !iter.IsAtEnd(); iter.Advance()) {
    338     Handle<JSReceiver> current(PrototypeIterator::GetCurrent<JSReceiver>(iter));
    339 
    340     if (current->IsJSProxy()) {
    341       for (uint32_t i = 0; i < length; ++i) {
    342         MAYBE_RETURN_NULL(ConditionalCopy(isolate, current, object, i));
    343       }
    344     } else {
    345       Handle<FixedArray> keys = JSReceiver::GetOwnElementIndices(
    346           isolate, object, Handle<JSObject>::cast(current));
    347 
    348       uint32_t num_indices = keys->length();
    349       for (uint32_t i = 0; i < num_indices; ++i) {
    350         uint32_t idx = NumberToUint32(keys->get(i));
    351 
    352         // Prototype might have indices that go past length, but we are only
    353         // interested in the range [0, length).
    354         if (idx >= length) break;
    355 
    356         MAYBE_RETURN_NULL(ConditionalCopy(isolate, current, object, idx));
    357       }
    358     }
    359   }
    360   return isolate->factory()->undefined_value();
    361 }
    362 
    363 }  // namespace
    364 
    365 RUNTIME_FUNCTION(Runtime_PrepareElementsForSort) {
    366   HandleScope scope(isolate);
    367   DCHECK_EQ(2, args.length());
    368   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
    369   CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
    370 
    371   if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) {
    372     if (!isolate->debug()->PerformSideEffectCheckForObject(object)) {
    373       return ReadOnlyRoots(isolate).exception();
    374     }
    375   }
    376 
    377   // Counter for sorting arrays that have non-packed elements and where either
    378   // the ElementsProtector is invalid or the prototype does not match
    379   // Array.prototype.
    380   if (object->IsJSArray() &&
    381       !Handle<JSArray>::cast(object)->HasFastPackedElements()) {
    382     JSObject* initial_array_proto = JSObject::cast(
    383         isolate->native_context()->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX));
    384     if (!isolate->IsNoElementsProtectorIntact() ||
    385         object->map()->prototype() != initial_array_proto) {
    386       isolate->CountUsage(
    387           v8::Isolate::kArrayPrototypeSortJSArrayModifiedPrototype);
    388     }
    389   }
    390 
    391   if (!object->IsJSArray()) {
    392     RETURN_FAILURE_ON_EXCEPTION(isolate,
    393                                 CopyFromPrototype(isolate, object, length));
    394   }
    395   return RemoveArrayHoles(isolate, object, length);
    396 }
    397 
    398 // Move contents of argument 0 (an array) to argument 1 (an array)
    399 RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
    400   HandleScope scope(isolate);
    401   DCHECK_EQ(2, args.length());
    402   CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
    403   CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
    404   JSObject::ValidateElements(*from);
    405   JSObject::ValidateElements(*to);
    406 
    407   Handle<FixedArrayBase> new_elements(from->elements(), isolate);
    408   ElementsKind from_kind = from->GetElementsKind();
    409   Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
    410   JSObject::SetMapAndElements(to, new_map, new_elements);
    411   to->set_length(from->length());
    412 
    413   from->initialize_elements();
    414   from->set_length(Smi::kZero);
    415 
    416   JSObject::ValidateElements(*to);
    417   return *to;
    418 }
    419 
    420 
    421 // How many elements does this object/array have?
    422 RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
    423   DisallowHeapAllocation no_gc;
    424   HandleScope scope(isolate);
    425   DCHECK_EQ(1, args.length());
    426   CONVERT_ARG_CHECKED(JSArray, array, 0);
    427   FixedArrayBase* elements = array->elements();
    428   SealHandleScope shs(isolate);
    429   if (elements->IsNumberDictionary()) {
    430     int result = NumberDictionary::cast(elements)->NumberOfElements();
    431     return Smi::FromInt(result);
    432   } else {
    433     DCHECK(array->length()->IsSmi());
    434     // For packed elements, we know the exact number of elements
    435     int length = elements->length();
    436     ElementsKind kind = array->GetElementsKind();
    437     if (IsFastPackedElementsKind(kind)) {
    438       return Smi::FromInt(length);
    439     }
    440     // For holey elements, take samples from the buffer checking for holes
    441     // to generate the estimate.
    442     const int kNumberOfHoleCheckSamples = 97;
    443     int increment = (length < kNumberOfHoleCheckSamples)
    444                         ? 1
    445                         : static_cast<int>(length / kNumberOfHoleCheckSamples);
    446     ElementsAccessor* accessor = array->GetElementsAccessor();
    447     int holes = 0;
    448     for (int i = 0; i < length; i += increment) {
    449       if (!accessor->HasElement(array, i, elements)) {
    450         ++holes;
    451       }
    452     }
    453     int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
    454                                     kNumberOfHoleCheckSamples * length);
    455     return Smi::FromInt(estimate);
    456   }
    457 }
    458 
    459 
    460 // Returns an array that tells you where in the [0, length) interval an array
    461 // might have elements.  Can either return an array of keys (positive integers
    462 // or undefined) or a number representing the positive length of an interval
    463 // starting at index 0.
    464 // Intervals can span over some keys that are not in the object.
    465 RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
    466   HandleScope scope(isolate);
    467   DCHECK_EQ(2, args.length());
    468   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
    469   CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
    470   ElementsKind kind = array->GetElementsKind();
    471 
    472   if (IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind)) {
    473     uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
    474     return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
    475   }
    476 
    477   if (kind == FAST_STRING_WRAPPER_ELEMENTS) {
    478     int string_length =
    479         String::cast(Handle<JSValue>::cast(array)->value())->length();
    480     int backing_store_length = array->elements()->length();
    481     return *isolate->factory()->NewNumberFromUint(
    482         Min(length,
    483             static_cast<uint32_t>(Max(string_length, backing_store_length))));
    484   }
    485 
    486   KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
    487                              ALL_PROPERTIES);
    488   for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
    489        !iter.IsAtEnd(); iter.Advance()) {
    490     Handle<JSReceiver> current(PrototypeIterator::GetCurrent<JSReceiver>(iter));
    491     if (current->HasComplexElements()) {
    492       return *isolate->factory()->NewNumberFromUint(length);
    493     }
    494     accumulator.CollectOwnElementIndices(array,
    495                                          Handle<JSObject>::cast(current));
    496   }
    497   // Erase any keys >= length.
    498   Handle<FixedArray> keys =
    499       accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
    500   int j = 0;
    501   for (int i = 0; i < keys->length(); i++) {
    502     if (NumberToUint32(keys->get(i)) >= length) continue;
    503     if (i != j) keys->set(j, keys->get(i));
    504     j++;
    505   }
    506 
    507   keys = FixedArray::ShrinkOrEmpty(isolate, keys, j);
    508   return *isolate->factory()->NewJSArrayWithElements(keys);
    509 }
    510 
    511 RUNTIME_FUNCTION(Runtime_TrySliceSimpleNonFastElements) {
    512   HandleScope scope(isolate);
    513   DCHECK_EQ(3, args.length());
    514   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
    515   CONVERT_SMI_ARG_CHECKED(first, 1);
    516   CONVERT_SMI_ARG_CHECKED(count, 2);
    517   uint32_t length = first + count;
    518 
    519   // Only handle elements kinds that have a ElementsAccessor Slice
    520   // implementation.
    521   if (receiver->IsJSArray()) {
    522     // This "fastish" path must make sure the destination array is a JSArray.
    523     if (!isolate->IsArraySpeciesLookupChainIntact() ||
    524         !JSArray::cast(*receiver)->HasArrayPrototype(isolate)) {
    525       return Smi::FromInt(0);
    526     }
    527   } else {
    528     int len;
    529     if (!receiver->IsJSObject() ||
    530         !JSSloppyArgumentsObject::GetSloppyArgumentsLength(
    531             isolate, Handle<JSObject>::cast(receiver), &len) ||
    532         (length > static_cast<uint32_t>(len))) {
    533       return Smi::FromInt(0);
    534     }
    535   }
    536 
    537   // This "fastish" path must also ensure that elements are simple (no
    538   // geters/setters), no elements on prototype chain.
    539   Handle<JSObject> object(Handle<JSObject>::cast(receiver));
    540   if (!JSObject::PrototypeHasNoElements(isolate, *object) ||
    541       object->HasComplexElements()) {
    542     return Smi::FromInt(0);
    543   }
    544 
    545   ElementsAccessor* accessor = object->GetElementsAccessor();
    546   return *accessor->Slice(object, first, length);
    547 }
    548 
    549 RUNTIME_FUNCTION(Runtime_NewArray) {
    550   HandleScope scope(isolate);
    551   DCHECK_LE(3, args.length());
    552   int const argc = args.length() - 3;
    553   // TODO(bmeurer): Remove this Arguments nonsense.
    554   Arguments argv(argc, args.arguments() - 1);
    555   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
    556   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, argc + 1);
    557   CONVERT_ARG_HANDLE_CHECKED(HeapObject, type_info, argc + 2);
    558   // TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite.
    559   Handle<AllocationSite> site = type_info->IsAllocationSite()
    560                                     ? Handle<AllocationSite>::cast(type_info)
    561                                     : Handle<AllocationSite>::null();
    562 
    563   Factory* factory = isolate->factory();
    564 
    565   // If called through new, new.target can be:
    566   // - a subclass of constructor,
    567   // - a proxy wrapper around constructor, or
    568   // - the constructor itself.
    569   // If called through Reflect.construct, it's guaranteed to be a constructor by
    570   // REFLECT_CONSTRUCT_PREPARE.
    571   DCHECK(new_target->IsConstructor());
    572 
    573   bool holey = false;
    574   bool can_use_type_feedback = !site.is_null();
    575   bool can_inline_array_constructor = true;
    576   if (argv.length() == 1) {
    577     Handle<Object> argument_one = argv.at<Object>(0);
    578     if (argument_one->IsSmi()) {
    579       int value = Handle<Smi>::cast(argument_one)->value();
    580       if (value < 0 ||
    581           JSArray::SetLengthWouldNormalize(isolate->heap(), value)) {
    582         // the array is a dictionary in this case.
    583         can_use_type_feedback = false;
    584       } else if (value != 0) {
    585         holey = true;
    586         if (value >= JSArray::kInitialMaxFastElementArray) {
    587           can_inline_array_constructor = false;
    588         }
    589       }
    590     } else {
    591       // Non-smi length argument produces a dictionary
    592       can_use_type_feedback = false;
    593     }
    594   }
    595 
    596   Handle<Map> initial_map;
    597   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    598       isolate, initial_map,
    599       JSFunction::GetDerivedMap(isolate, constructor, new_target));
    600 
    601   ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
    602                                                : initial_map->elements_kind();
    603   if (holey && !IsHoleyElementsKind(to_kind)) {
    604     to_kind = GetHoleyElementsKind(to_kind);
    605     // Update the allocation site info to reflect the advice alteration.
    606     if (!site.is_null()) site->SetElementsKind(to_kind);
    607   }
    608 
    609   // We should allocate with an initial map that reflects the allocation site
    610   // advice. Therefore we use AllocateJSObjectFromMap instead of passing
    611   // the constructor.
    612   initial_map = Map::AsElementsKind(isolate, initial_map, to_kind);
    613 
    614   // If we don't care to track arrays of to_kind ElementsKind, then
    615   // don't emit a memento for them.
    616   Handle<AllocationSite> allocation_site;
    617   if (AllocationSite::ShouldTrack(to_kind)) {
    618     allocation_site = site;
    619   }
    620 
    621   Handle<JSArray> array = Handle<JSArray>::cast(
    622       factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
    623 
    624   factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
    625 
    626   ElementsKind old_kind = array->GetElementsKind();
    627   RETURN_FAILURE_ON_EXCEPTION(isolate,
    628                               ArrayConstructInitializeElements(array, &argv));
    629   if (!site.is_null()) {
    630     if ((old_kind != array->GetElementsKind() || !can_use_type_feedback ||
    631          !can_inline_array_constructor)) {
    632       // The arguments passed in caused a transition. This kind of complexity
    633       // can't be dealt with in the inlined optimized array constructor case.
    634       // We must mark the allocationsite as un-inlinable.
    635       site->SetDoNotInlineCall();
    636     }
    637   } else {
    638     if (old_kind != array->GetElementsKind() || !can_inline_array_constructor) {
    639       // We don't have an AllocationSite for this Array constructor invocation,
    640       // i.e. it might a call from Array#map or from an Array subclass, so we
    641       // just flip the bit on the global protector cell instead.
    642       // TODO(bmeurer): Find a better way to mark this. Global protectors
    643       // tend to back-fire over time...
    644       if (isolate->IsArrayConstructorIntact()) {
    645         isolate->InvalidateArrayConstructorProtector();
    646       }
    647     }
    648   }
    649 
    650   return *array;
    651 }
    652 
    653 RUNTIME_FUNCTION(Runtime_NormalizeElements) {
    654   HandleScope scope(isolate);
    655   DCHECK_EQ(1, args.length());
    656   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
    657   CHECK(!array->HasFixedTypedArrayElements());
    658   CHECK(!array->IsJSGlobalProxy());
    659   JSObject::NormalizeElements(array);
    660   return *array;
    661 }
    662 
    663 // GrowArrayElements returns a sentinel Smi if the object was normalized or if
    664 // the key is negative.
    665 RUNTIME_FUNCTION(Runtime_GrowArrayElements) {
    666   HandleScope scope(isolate);
    667   DCHECK_EQ(2, args.length());
    668   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
    669   CONVERT_NUMBER_CHECKED(int, key, Int32, args[1]);
    670 
    671   if (key < 0) return Smi::kZero;
    672 
    673   uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
    674   uint32_t index = static_cast<uint32_t>(key);
    675 
    676   if (index >= capacity) {
    677     if (!object->GetElementsAccessor()->GrowCapacity(object, index)) {
    678       return Smi::kZero;
    679     }
    680   }
    681 
    682   return object->elements();
    683 }
    684 
    685 
    686 RUNTIME_FUNCTION(Runtime_HasComplexElements) {
    687   HandleScope scope(isolate);
    688   DCHECK_EQ(1, args.length());
    689   CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
    690   for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
    691        !iter.IsAtEnd(); iter.Advance()) {
    692     if (PrototypeIterator::GetCurrent<JSReceiver>(iter)->HasComplexElements()) {
    693       return ReadOnlyRoots(isolate).true_value();
    694     }
    695   }
    696   return ReadOnlyRoots(isolate).false_value();
    697 }
    698 
    699 // ES6 22.1.2.2 Array.isArray
    700 RUNTIME_FUNCTION(Runtime_ArrayIsArray) {
    701   HandleScope shs(isolate);
    702   DCHECK_EQ(1, args.length());
    703   CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
    704   Maybe<bool> result = Object::IsArray(object);
    705   MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
    706   return isolate->heap()->ToBoolean(result.FromJust());
    707 }
    708 
    709 RUNTIME_FUNCTION(Runtime_IsArray) {
    710   SealHandleScope shs(isolate);
    711   DCHECK_EQ(1, args.length());
    712   CONVERT_ARG_CHECKED(Object, obj, 0);
    713   return isolate->heap()->ToBoolean(obj->IsJSArray());
    714 }
    715 
    716 RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
    717   HandleScope scope(isolate);
    718   DCHECK_EQ(1, args.length());
    719   CONVERT_ARG_HANDLE_CHECKED(Object, original_array, 0);
    720   RETURN_RESULT_OR_FAILURE(
    721       isolate, Object::ArraySpeciesConstructor(isolate, original_array));
    722 }
    723 
    724 // ES7 22.1.3.11 Array.prototype.includes
    725 RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
    726   HandleScope shs(isolate);
    727   DCHECK_EQ(3, args.length());
    728   CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
    729   CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
    730 
    731   // Let O be ? ToObject(this value).
    732   Handle<JSReceiver> object;
    733   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    734       isolate, object, Object::ToObject(isolate, handle(args[0], isolate)));
    735 
    736   // Let len be ? ToLength(? Get(O, "length")).
    737   int64_t len;
    738   {
    739     if (object->map()->instance_type() == JS_ARRAY_TYPE) {
    740       uint32_t len32 = 0;
    741       bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
    742       DCHECK(success);
    743       USE(success);
    744       len = len32;
    745     } else {
    746       Handle<Object> len_;
    747       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    748           isolate, len_,
    749           Object::GetProperty(isolate, object,
    750                               isolate->factory()->length_string()));
    751 
    752       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
    753                                          Object::ToLength(isolate, len_));
    754       len = static_cast<int64_t>(len_->Number());
    755       DCHECK_EQ(len, len_->Number());
    756     }
    757   }
    758 
    759   if (len == 0) return ReadOnlyRoots(isolate).false_value();
    760 
    761   // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
    762   // produces the value 0.)
    763   int64_t index = 0;
    764   if (!from_index->IsUndefined(isolate)) {
    765     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
    766                                        Object::ToInteger(isolate, from_index));
    767 
    768     if (V8_LIKELY(from_index->IsSmi())) {
    769       int start_from = Smi::ToInt(*from_index);
    770       if (start_from < 0) {
    771         index = std::max<int64_t>(len + start_from, 0);
    772       } else {
    773         index = start_from;
    774       }
    775     } else {
    776       DCHECK(from_index->IsHeapNumber());
    777       double start_from = from_index->Number();
    778       if (start_from >= len) return ReadOnlyRoots(isolate).false_value();
    779       if (V8_LIKELY(std::isfinite(start_from))) {
    780         if (start_from < 0) {
    781           index = static_cast<int64_t>(std::max<double>(start_from + len, 0));
    782         } else {
    783           index = start_from;
    784         }
    785       }
    786     }
    787 
    788     DCHECK_GE(index, 0);
    789   }
    790 
    791   // If the receiver is not a special receiver type, and the length is a valid
    792   // element index, perform fast operation tailored to specific ElementsKinds.
    793   if (!object->map()->IsSpecialReceiverMap() && len < kMaxUInt32 &&
    794       JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
    795     Handle<JSObject> obj = Handle<JSObject>::cast(object);
    796     ElementsAccessor* elements = obj->GetElementsAccessor();
    797     Maybe<bool> result = elements->IncludesValue(isolate, obj, search_element,
    798                                                  static_cast<uint32_t>(index),
    799                                                  static_cast<uint32_t>(len));
    800     MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
    801     return *isolate->factory()->ToBoolean(result.FromJust());
    802   }
    803 
    804   // Otherwise, perform slow lookups for special receiver types
    805   for (; index < len; ++index) {
    806     // Let elementK be the result of ? Get(O, ! ToString(k)).
    807     Handle<Object> element_k;
    808     {
    809       Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
    810       bool success;
    811       LookupIterator it = LookupIterator::PropertyOrElement(
    812           isolate, object, index_obj, &success);
    813       DCHECK(success);
    814       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
    815                                          Object::GetProperty(&it));
    816     }
    817 
    818     // If SameValueZero(searchElement, elementK) is true, return true.
    819     if (search_element->SameValueZero(*element_k)) {
    820       return ReadOnlyRoots(isolate).true_value();
    821     }
    822   }
    823   return ReadOnlyRoots(isolate).false_value();
    824 }
    825 
    826 RUNTIME_FUNCTION(Runtime_ArrayIndexOf) {
    827   HandleScope shs(isolate);
    828   DCHECK_EQ(3, args.length());
    829   CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
    830   CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
    831 
    832   // Let O be ? ToObject(this value).
    833   Handle<JSReceiver> object;
    834   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    835       isolate, object,
    836       Object::ToObject(isolate, args.at(0), "Array.prototype.indexOf"));
    837 
    838   // Let len be ? ToLength(? Get(O, "length")).
    839   int64_t len;
    840   {
    841     if (object->IsJSArray()) {
    842       uint32_t len32 = 0;
    843       bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
    844       DCHECK(success);
    845       USE(success);
    846       len = len32;
    847     } else {
    848       Handle<Object> len_;
    849       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    850           isolate, len_,
    851           Object::GetProperty(isolate, object,
    852                               isolate->factory()->length_string()));
    853 
    854       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
    855                                          Object::ToLength(isolate, len_));
    856       len = static_cast<int64_t>(len_->Number());
    857       DCHECK_EQ(len, len_->Number());
    858     }
    859   }
    860 
    861   if (len == 0) return Smi::FromInt(-1);
    862 
    863   // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
    864   // produces the value 0.)
    865   int64_t start_from;
    866   {
    867     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
    868                                        Object::ToInteger(isolate, from_index));
    869     double fp = from_index->Number();
    870     if (fp > len) return Smi::FromInt(-1);
    871     if (V8_LIKELY(fp >=
    872                   static_cast<double>(std::numeric_limits<int64_t>::min()))) {
    873       DCHECK(fp < std::numeric_limits<int64_t>::max());
    874       start_from = static_cast<int64_t>(fp);
    875     } else {
    876       start_from = std::numeric_limits<int64_t>::min();
    877     }
    878   }
    879 
    880   int64_t index;
    881   if (start_from >= 0) {
    882     index = start_from;
    883   } else {
    884     index = len + start_from;
    885     if (index < 0) {
    886       index = 0;
    887     }
    888   }
    889 
    890   // If the receiver is not a special receiver type, and the length is a valid
    891   // element index, perform fast operation tailored to specific ElementsKinds.
    892   if (!object->map()->IsSpecialReceiverMap() && len < kMaxUInt32 &&
    893       JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
    894     Handle<JSObject> obj = Handle<JSObject>::cast(object);
    895     ElementsAccessor* elements = obj->GetElementsAccessor();
    896     Maybe<int64_t> result = elements->IndexOfValue(isolate, obj, search_element,
    897                                                    static_cast<uint32_t>(index),
    898                                                    static_cast<uint32_t>(len));
    899     MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
    900     return *isolate->factory()->NewNumberFromInt64(result.FromJust());
    901   }
    902 
    903   // Otherwise, perform slow lookups for special receiver types
    904   for (; index < len; ++index) {
    905     // Let elementK be the result of ? Get(O, ! ToString(k)).
    906     Handle<Object> element_k;
    907     {
    908       Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
    909       bool success;
    910       LookupIterator it = LookupIterator::PropertyOrElement(
    911           isolate, object, index_obj, &success);
    912       DCHECK(success);
    913       Maybe<bool> present = JSReceiver::HasProperty(&it);
    914       MAYBE_RETURN(present, ReadOnlyRoots(isolate).exception());
    915       if (!present.FromJust()) continue;
    916       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
    917                                          Object::GetProperty(&it));
    918       if (search_element->StrictEquals(*element_k)) {
    919         return *index_obj;
    920       }
    921     }
    922   }
    923   return Smi::FromInt(-1);
    924 }
    925 
    926 }  // namespace internal
    927 }  // namespace v8
    928