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
|