blob: cbde8f372e872dcdb5053e24b6f87258d44a68ed [file] [log] [blame]
Emily Bernier958fae72015-03-24 16:35:39 -04001// 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
Ben Murdoch014dc512016-03-22 12:00:34 +00005#include "src/runtime/runtime-utils.h"
Emily Bernier958fae72015-03-24 16:35:39 -04006
7#include "src/arguments.h"
Ben Murdoch3b9bc312016-06-02 14:46:10 +01008#include "src/code-stubs.h"
Ben Murdoch014dc512016-03-22 12:00:34 +00009#include "src/conversions-inl.h"
10#include "src/elements.h"
11#include "src/factory.h"
12#include "src/isolate-inl.h"
Ben Murdoch3b9bc312016-06-02 14:46:10 +010013#include "src/keys.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000014#include "src/messages.h"
15#include "src/prototype.h"
Emily Bernier958fae72015-03-24 16:35:39 -040016
17namespace v8 {
18namespace internal {
19
20RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
21 HandleScope scope(isolate);
22 DCHECK(args.length() == 1);
23 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
24 Object* length = prototype->length();
Ben Murdoch13e2dad2016-09-16 13:49:30 +010025 CHECK(length->IsSmi());
26 CHECK(Smi::cast(length)->value() == 0);
27 CHECK(prototype->HasFastSmiOrObjectElements());
Emily Bernier958fae72015-03-24 16:35:39 -040028 // This is necessary to enable fast checks for absence of elements
29 // on Array.prototype and below.
30 prototype->set_elements(isolate->heap()->empty_fixed_array());
31 return Smi::FromInt(0);
32}
33
Ben Murdoch3b9bc312016-06-02 14:46:10 +010034static void InstallCode(Isolate* isolate, Handle<JSObject> holder,
Ben Murdochf91f0612016-11-29 16:50:11 +000035 const char* name, Handle<Code> code, int argc = -1) {
Emily Bernier958fae72015-03-24 16:35:39 -040036 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
Emily Bernier958fae72015-03-24 16:35:39 -040037 Handle<JSFunction> optimized =
38 isolate->factory()->NewFunctionWithoutPrototype(key, code);
Ben Murdochf91f0612016-11-29 16:50:11 +000039 if (argc < 0) {
40 optimized->shared()->DontAdaptArguments();
41 } else {
42 optimized->shared()->set_internal_formal_parameter_count(argc);
43 }
Emily Bernier958fae72015-03-24 16:35:39 -040044 JSObject::AddProperty(holder, key, optimized, NONE);
45}
46
Ben Murdoch3b9bc312016-06-02 14:46:10 +010047static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
Ben Murdochf91f0612016-11-29 16:50:11 +000048 const char* name, Builtins::Name builtin_name,
49 int argc = -1) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +010050 InstallCode(isolate, holder, name,
Ben Murdochf91f0612016-11-29 16:50:11 +000051 handle(isolate->builtins()->builtin(builtin_name), isolate),
52 argc);
Ben Murdoch3b9bc312016-06-02 14:46:10 +010053}
Emily Bernier958fae72015-03-24 16:35:39 -040054
55RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
56 HandleScope scope(isolate);
57 DCHECK(args.length() == 0);
58 Handle<JSObject> holder =
59 isolate->factory()->NewJSObject(isolate->object_function());
60
61 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
Ben Murdochf91f0612016-11-29 16:50:11 +000062 if (FLAG_minimal) {
63 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
64 } else {
65 FastArrayPushStub stub(isolate);
66 InstallCode(isolate, holder, "push", stub.GetCode());
67 }
Emily Bernier958fae72015-03-24 16:35:39 -040068 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
69 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
70 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
71 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
Ben Murdochf91f0612016-11-29 16:50:11 +000072 InstallBuiltin(isolate, holder, "includes", Builtins::kArrayIncludes, 2);
73 InstallBuiltin(isolate, holder, "indexOf", Builtins::kArrayIndexOf, 2);
Emily Bernier958fae72015-03-24 16:35:39 -040074
75 return *holder;
76}
77
78
Ben Murdoch014dc512016-03-22 12:00:34 +000079RUNTIME_FUNCTION(Runtime_FixedArrayGet) {
80 SealHandleScope shs(isolate);
81 DCHECK(args.length() == 2);
82 CONVERT_ARG_CHECKED(FixedArray, object, 0);
83 CONVERT_SMI_ARG_CHECKED(index, 1);
84 return object->get(index);
85}
86
87
88RUNTIME_FUNCTION(Runtime_FixedArraySet) {
89 SealHandleScope shs(isolate);
90 DCHECK(args.length() == 3);
91 CONVERT_ARG_CHECKED(FixedArray, object, 0);
92 CONVERT_SMI_ARG_CHECKED(index, 1);
93 CONVERT_ARG_CHECKED(Object, value, 2);
94 object->set(index, value);
95 return isolate->heap()->undefined_value();
96}
97
98
Emily Bernier958fae72015-03-24 16:35:39 -040099RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
100 HandleScope scope(isolate);
Ben Murdochf91f0612016-11-29 16:50:11 +0000101 DCHECK_EQ(2, args.length());
102 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
103 CONVERT_ARG_HANDLE_CHECKED(Map, to_map, 1);
104 ElementsKind to_kind = to_map->elements_kind();
105 ElementsAccessor::ForKind(to_kind)->TransitionElementsKind(object, to_map);
106 return *object;
Emily Bernier958fae72015-03-24 16:35:39 -0400107}
108
109
Emily Bernier958fae72015-03-24 16:35:39 -0400110// Moves all own elements of an object, that are below a limit, to positions
111// starting at zero. All undefined values are placed after non-undefined values,
112// and are followed by non-existing element. Does not change the length
113// property.
114// Returns the number of non-undefined elements collected.
115// Returns -1 if hole removal is not supported by this method.
116RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
117 HandleScope scope(isolate);
118 DCHECK(args.length() == 2);
Ben Murdoch109988c2016-05-18 11:27:45 +0100119 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
Emily Bernier958fae72015-03-24 16:35:39 -0400120 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
Ben Murdoch109988c2016-05-18 11:27:45 +0100121 if (object->IsJSProxy()) return Smi::FromInt(-1);
122 return *JSObject::PrepareElementsForSort(Handle<JSObject>::cast(object),
123 limit);
Emily Bernier958fae72015-03-24 16:35:39 -0400124}
125
126
127// Move contents of argument 0 (an array) to argument 1 (an array)
128RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
129 HandleScope scope(isolate);
130 DCHECK(args.length() == 2);
131 CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
132 CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
133 JSObject::ValidateElements(from);
134 JSObject::ValidateElements(to);
135
136 Handle<FixedArrayBase> new_elements(from->elements());
137 ElementsKind from_kind = from->GetElementsKind();
138 Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
139 JSObject::SetMapAndElements(to, new_map, new_elements);
140 to->set_length(from->length());
141
142 JSObject::ResetElements(from);
143 from->set_length(Smi::FromInt(0));
144
145 JSObject::ValidateElements(to);
146 return *to;
147}
148
149
150// How many elements does this object/array have?
151RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
152 HandleScope scope(isolate);
153 DCHECK(args.length() == 1);
154 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
155 Handle<FixedArrayBase> elements(array->elements(), isolate);
156 SealHandleScope shs(isolate);
157 if (elements->IsDictionary()) {
158 int result =
159 Handle<SeededNumberDictionary>::cast(elements)->NumberOfElements();
160 return Smi::FromInt(result);
161 } else {
162 DCHECK(array->length()->IsSmi());
163 // For packed elements, we know the exact number of elements
164 int length = elements->length();
165 ElementsKind kind = array->GetElementsKind();
166 if (IsFastPackedElementsKind(kind)) {
167 return Smi::FromInt(length);
168 }
169 // For holey elements, take samples from the buffer checking for holes
170 // to generate the estimate.
171 const int kNumberOfHoleCheckSamples = 97;
172 int increment = (length < kNumberOfHoleCheckSamples)
173 ? 1
174 : static_cast<int>(length / kNumberOfHoleCheckSamples);
175 ElementsAccessor* accessor = array->GetElementsAccessor();
176 int holes = 0;
177 for (int i = 0; i < length; i += increment) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000178 if (!accessor->HasElement(array, i, elements)) {
Emily Bernier958fae72015-03-24 16:35:39 -0400179 ++holes;
180 }
181 }
182 int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
183 kNumberOfHoleCheckSamples * length);
184 return Smi::FromInt(estimate);
185 }
186}
187
188
189// Returns an array that tells you where in the [0, length) interval an array
190// might have elements. Can either return an array of keys (positive integers
191// or undefined) or a number representing the positive length of an interval
192// starting at index 0.
193// Intervals can span over some keys that are not in the object.
194RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
195 HandleScope scope(isolate);
196 DCHECK(args.length() == 2);
197 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
198 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100199 ElementsKind kind = array->GetElementsKind();
Ben Murdoch014dc512016-03-22 12:00:34 +0000200
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100201 if (IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind)) {
202 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
203 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
204 }
205
206 if (kind == FAST_STRING_WRAPPER_ELEMENTS) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100207 int string_length =
208 String::cast(Handle<JSValue>::cast(array)->value())->length();
209 int backing_store_length = array->elements()->length();
210 return *isolate->factory()->NewNumberFromUint(
211 Min(length,
212 static_cast<uint32_t>(Max(string_length, backing_store_length))));
213 }
214
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100215 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
216 ALL_PROPERTIES);
217 for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
Ben Murdoch014dc512016-03-22 12:00:34 +0000218 !iter.IsAtEnd(); iter.Advance()) {
219 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy() ||
220 PrototypeIterator::GetCurrent<JSObject>(iter)
221 ->HasIndexedInterceptor()) {
222 // Bail out if we find a proxy or interceptor, likely not worth
223 // collecting keys in that case.
224 return *isolate->factory()->NewNumberFromUint(length);
225 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000226 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100227 accumulator.CollectOwnElementIndices(array, current);
Ben Murdoch014dc512016-03-22 12:00:34 +0000228 }
229 // Erase any keys >= length.
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100230 Handle<FixedArray> keys =
231 accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100232 int j = 0;
Ben Murdoch014dc512016-03-22 12:00:34 +0000233 for (int i = 0; i < keys->length(); i++) {
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100234 if (NumberToUint32(keys->get(i)) >= length) continue;
235 if (i != j) keys->set(j, keys->get(i));
236 j++;
Ben Murdoch014dc512016-03-22 12:00:34 +0000237 }
Ben Murdoch3b9bc312016-06-02 14:46:10 +0100238
239 if (j != keys->length()) {
240 isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
241 *keys, keys->length() - j);
242 }
243
Ben Murdoch014dc512016-03-22 12:00:34 +0000244 return *isolate->factory()->NewJSArrayWithElements(keys);
Emily Bernier958fae72015-03-24 16:35:39 -0400245}
246
247
Ben Murdoch014dc512016-03-22 12:00:34 +0000248namespace {
249
250Object* ArrayConstructorCommon(Isolate* isolate, Handle<JSFunction> constructor,
251 Handle<JSReceiver> new_target,
252 Handle<AllocationSite> site,
253 Arguments* caller_args) {
Emily Bernier958fae72015-03-24 16:35:39 -0400254 Factory* factory = isolate->factory();
255
Ben Murdoch014dc512016-03-22 12:00:34 +0000256 // If called through new, new.target can be:
257 // - a subclass of constructor,
258 // - a proxy wrapper around constructor, or
259 // - the constructor itself.
260 // If called through Reflect.construct, it's guaranteed to be a constructor by
261 // REFLECT_CONSTRUCT_PREPARE.
262 DCHECK(new_target->IsConstructor());
263
Emily Bernier958fae72015-03-24 16:35:39 -0400264 bool holey = false;
Ben Murdoch014dc512016-03-22 12:00:34 +0000265 bool can_use_type_feedback = !site.is_null();
266 bool can_inline_array_constructor = true;
Emily Bernier958fae72015-03-24 16:35:39 -0400267 if (caller_args->length() == 1) {
268 Handle<Object> argument_one = caller_args->at<Object>(0);
269 if (argument_one->IsSmi()) {
270 int value = Handle<Smi>::cast(argument_one)->value();
Ben Murdoch014dc512016-03-22 12:00:34 +0000271 if (value < 0 ||
272 JSArray::SetLengthWouldNormalize(isolate->heap(), value)) {
Emily Bernier958fae72015-03-24 16:35:39 -0400273 // the array is a dictionary in this case.
274 can_use_type_feedback = false;
275 } else if (value != 0) {
276 holey = true;
Ben Murdoch014dc512016-03-22 12:00:34 +0000277 if (value >= JSArray::kInitialMaxFastElementArray) {
278 can_inline_array_constructor = false;
279 }
Emily Bernier958fae72015-03-24 16:35:39 -0400280 }
281 } else {
282 // Non-smi length argument produces a dictionary
283 can_use_type_feedback = false;
284 }
285 }
286
Ben Murdoch014dc512016-03-22 12:00:34 +0000287 Handle<Map> initial_map;
288 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
289 isolate, initial_map,
290 JSFunction::GetDerivedMap(isolate, constructor, new_target));
Emily Bernier958fae72015-03-24 16:35:39 -0400291
Ben Murdoch014dc512016-03-22 12:00:34 +0000292 ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
293 : initial_map->elements_kind();
294 if (holey && !IsFastHoleyElementsKind(to_kind)) {
295 to_kind = GetHoleyElementsKind(to_kind);
296 // Update the allocation site info to reflect the advice alteration.
297 if (!site.is_null()) site->SetElementsKind(to_kind);
Emily Bernier958fae72015-03-24 16:35:39 -0400298 }
299
Ben Murdoch014dc512016-03-22 12:00:34 +0000300 // We should allocate with an initial map that reflects the allocation site
301 // advice. Therefore we use AllocateJSObjectFromMap instead of passing
302 // the constructor.
303 if (to_kind != initial_map->elements_kind()) {
304 initial_map = Map::AsElementsKind(initial_map, to_kind);
305 }
306
307 // If we don't care to track arrays of to_kind ElementsKind, then
308 // don't emit a memento for them.
309 Handle<AllocationSite> allocation_site;
310 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
311 allocation_site = site;
312 }
313
314 Handle<JSArray> array = Handle<JSArray>::cast(
315 factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
316
Emily Bernier958fae72015-03-24 16:35:39 -0400317 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
318
319 ElementsKind old_kind = array->GetElementsKind();
320 RETURN_FAILURE_ON_EXCEPTION(
321 isolate, ArrayConstructInitializeElements(array, caller_args));
322 if (!site.is_null() &&
Ben Murdoch014dc512016-03-22 12:00:34 +0000323 (old_kind != array->GetElementsKind() || !can_use_type_feedback ||
324 !can_inline_array_constructor)) {
Emily Bernier958fae72015-03-24 16:35:39 -0400325 // The arguments passed in caused a transition. This kind of complexity
326 // can't be dealt with in the inlined hydrogen array constructor case.
327 // We must mark the allocationsite as un-inlinable.
328 site->SetDoNotInlineCall();
329 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000330
Emily Bernier958fae72015-03-24 16:35:39 -0400331 return *array;
332}
333
Ben Murdoch014dc512016-03-22 12:00:34 +0000334} // namespace
335
Ben Murdoch014dc512016-03-22 12:00:34 +0000336RUNTIME_FUNCTION(Runtime_NewArray) {
337 HandleScope scope(isolate);
338 DCHECK_LE(3, args.length());
339 int const argc = args.length() - 3;
340 // TODO(bmeurer): Remove this Arguments nonsense.
341 Arguments argv(argc, args.arguments() - 1);
342 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
343 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, argc + 1);
344 CONVERT_ARG_HANDLE_CHECKED(HeapObject, type_info, argc + 2);
345 // TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite.
346 Handle<AllocationSite> site = type_info->IsAllocationSite()
347 ? Handle<AllocationSite>::cast(type_info)
348 : Handle<AllocationSite>::null();
349 return ArrayConstructorCommon(isolate, constructor, new_target, site, &argv);
350}
351
Emily Bernier958fae72015-03-24 16:35:39 -0400352RUNTIME_FUNCTION(Runtime_NormalizeElements) {
353 HandleScope scope(isolate);
354 DCHECK(args.length() == 1);
355 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100356 CHECK(!array->HasFixedTypedArrayElements());
357 CHECK(!array->IsJSGlobalProxy());
Emily Bernier958fae72015-03-24 16:35:39 -0400358 JSObject::NormalizeElements(array);
359 return *array;
360}
361
362
Ben Murdoch014dc512016-03-22 12:00:34 +0000363// GrowArrayElements returns a sentinel Smi if the object was normalized.
364RUNTIME_FUNCTION(Runtime_GrowArrayElements) {
365 HandleScope scope(isolate);
366 DCHECK(args.length() == 2);
367 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
368 CONVERT_NUMBER_CHECKED(int, key, Int32, args[1]);
369
370 if (key < 0) {
371 return object->elements();
372 }
373
374 uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
375 uint32_t index = static_cast<uint32_t>(key);
376
377 if (index >= capacity) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000378 if (!object->GetElementsAccessor()->GrowCapacity(object, index)) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000379 return Smi::FromInt(0);
380 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000381 }
382
383 // On success, return the fixed array elements.
384 return object->elements();
385}
386
387
Emily Bernier958fae72015-03-24 16:35:39 -0400388RUNTIME_FUNCTION(Runtime_HasComplexElements) {
389 HandleScope scope(isolate);
390 DCHECK(args.length() == 1);
391 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100392 for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
Emily Bernier958fae72015-03-24 16:35:39 -0400393 !iter.IsAtEnd(); iter.Advance()) {
394 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
395 return isolate->heap()->true_value();
396 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000397 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
Emily Bernier958fae72015-03-24 16:35:39 -0400398 if (current->HasIndexedInterceptor()) {
399 return isolate->heap()->true_value();
400 }
401 if (!current->HasDictionaryElements()) continue;
402 if (current->element_dictionary()->HasComplexElements()) {
403 return isolate->heap()->true_value();
404 }
405 }
406 return isolate->heap()->false_value();
407}
408
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100409// ES6 22.1.2.2 Array.isArray
410RUNTIME_FUNCTION(Runtime_ArrayIsArray) {
411 HandleScope shs(isolate);
412 DCHECK(args.length() == 1);
413 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
414 Maybe<bool> result = Object::IsArray(object);
415 MAYBE_RETURN(result, isolate->heap()->exception());
416 return isolate->heap()->ToBoolean(result.FromJust());
417}
Emily Bernier958fae72015-03-24 16:35:39 -0400418
Ben Murdoch014dc512016-03-22 12:00:34 +0000419RUNTIME_FUNCTION(Runtime_IsArray) {
Emily Bernier958fae72015-03-24 16:35:39 -0400420 SealHandleScope shs(isolate);
421 DCHECK(args.length() == 1);
422 CONVERT_ARG_CHECKED(Object, obj, 0);
423 return isolate->heap()->ToBoolean(obj->IsJSArray());
424}
425
Ben Murdoch014dc512016-03-22 12:00:34 +0000426RUNTIME_FUNCTION(Runtime_HasCachedArrayIndex) {
Emily Bernier958fae72015-03-24 16:35:39 -0400427 SealHandleScope shs(isolate);
428 DCHECK(args.length() == 1);
429 return isolate->heap()->false_value();
430}
431
432
Ben Murdoch014dc512016-03-22 12:00:34 +0000433RUNTIME_FUNCTION(Runtime_GetCachedArrayIndex) {
434 // This can never be reached, because Runtime_HasCachedArrayIndex always
435 // returns false.
436 UNIMPLEMENTED();
437 return nullptr;
Emily Bernier958fae72015-03-24 16:35:39 -0400438}
439
440
Ben Murdoch014dc512016-03-22 12:00:34 +0000441RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
442 HandleScope scope(isolate);
443 DCHECK(args.length() == 1);
444 CONVERT_ARG_HANDLE_CHECKED(Object, original_array, 0);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100445 RETURN_RESULT_OR_FAILURE(
446 isolate, Object::ArraySpeciesConstructor(isolate, original_array));
Emily Bernier958fae72015-03-24 16:35:39 -0400447}
Ben Murdoch014dc512016-03-22 12:00:34 +0000448
Ben Murdochf91f0612016-11-29 16:50:11 +0000449// ES7 22.1.3.11 Array.prototype.includes
450RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
451 HandleScope shs(isolate);
452 DCHECK(args.length() == 3);
453 CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
454 CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
455
456 // Let O be ? ToObject(this value).
457 Handle<JSReceiver> object;
458 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
459 isolate, object, Object::ToObject(isolate, handle(args[0], isolate)));
460
461 // Let len be ? ToLength(? Get(O, "length")).
462 int64_t len;
463 {
464 if (object->map()->instance_type() == JS_ARRAY_TYPE) {
465 uint32_t len32 = 0;
466 bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
467 DCHECK(success);
468 USE(success);
469 len = len32;
470 } else {
471 Handle<Object> len_;
472 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
473 isolate, len_,
474 Object::GetProperty(object, isolate->factory()->length_string()));
475
476 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
477 Object::ToLength(isolate, len_));
478 len = static_cast<int64_t>(len_->Number());
479 DCHECK_EQ(len, len_->Number());
480 }
481 }
482
483 if (len == 0) return isolate->heap()->false_value();
484
485 // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
486 // produces the value 0.)
487 int64_t start_from;
488 {
489 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
490 Object::ToInteger(isolate, from_index));
491 double fp = from_index->Number();
492 if (fp > len) return isolate->heap()->false_value();
493 start_from = static_cast<int64_t>(fp);
494 }
495
496 int64_t index;
497 if (start_from >= 0) {
498 index = start_from;
499 } else {
500 index = len + start_from;
501 if (index < 0) {
502 index = 0;
503 }
504 }
505
506 // If the receiver is not a special receiver type, and the length is a valid
507 // element index, perform fast operation tailored to specific ElementsKinds.
508 if (object->map()->instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
509 len < kMaxUInt32 &&
510 JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
511 Handle<JSObject> obj = Handle<JSObject>::cast(object);
512 ElementsAccessor* elements = obj->GetElementsAccessor();
513 Maybe<bool> result = elements->IncludesValue(isolate, obj, search_element,
514 static_cast<uint32_t>(index),
515 static_cast<uint32_t>(len));
516 MAYBE_RETURN(result, isolate->heap()->exception());
517 return *isolate->factory()->ToBoolean(result.FromJust());
518 }
519
520 // Otherwise, perform slow lookups for special receiver types
521 for (; index < len; ++index) {
522 // Let elementK be the result of ? Get(O, ! ToString(k)).
523 Handle<Object> element_k;
524 {
525 Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
526 bool success;
527 LookupIterator it = LookupIterator::PropertyOrElement(
528 isolate, object, index_obj, &success);
529 DCHECK(success);
530 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
531 Object::GetProperty(&it));
532 }
533
534 // If SameValueZero(searchElement, elementK) is true, return true.
535 if (search_element->SameValueZero(*element_k)) {
536 return isolate->heap()->true_value();
537 }
538 }
539 return isolate->heap()->false_value();
540}
541
542RUNTIME_FUNCTION(Runtime_ArrayIndexOf) {
543 HandleScope shs(isolate);
544 DCHECK(args.length() == 3);
545 CONVERT_ARG_HANDLE_CHECKED(Object, search_element, 1);
546 CONVERT_ARG_HANDLE_CHECKED(Object, from_index, 2);
547
548 // Let O be ? ToObject(this value).
549 Handle<Object> receiver_obj = args.at<Object>(0);
550 if (receiver_obj->IsNull(isolate) || receiver_obj->IsUndefined(isolate)) {
551 THROW_NEW_ERROR_RETURN_FAILURE(
552 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
553 isolate->factory()->NewStringFromAsciiChecked(
554 "Array.prototype.indexOf")));
555 }
556 Handle<JSReceiver> object;
557 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
558 isolate, object, Object::ToObject(isolate, args.at<Object>(0)));
559
560 // Let len be ? ToLength(? Get(O, "length")).
561 int64_t len;
562 {
563 if (object->IsJSArray()) {
564 uint32_t len32 = 0;
565 bool success = JSArray::cast(*object)->length()->ToArrayLength(&len32);
566 DCHECK(success);
567 USE(success);
568 len = len32;
569 } else {
570 Handle<Object> len_;
571 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
572 isolate, len_,
573 Object::GetProperty(object, isolate->factory()->length_string()));
574
575 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len_,
576 Object::ToLength(isolate, len_));
577 len = static_cast<int64_t>(len_->Number());
578 DCHECK_EQ(len, len_->Number());
579 }
580 }
581
582 if (len == 0) return Smi::FromInt(-1);
583
584 // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
585 // produces the value 0.)
586 int64_t start_from;
587 {
588 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, from_index,
589 Object::ToInteger(isolate, from_index));
590 double fp = from_index->Number();
591 if (fp > len) return Smi::FromInt(-1);
592 start_from = static_cast<int64_t>(fp);
593 }
594
595 int64_t index;
596 if (start_from >= 0) {
597 index = start_from;
598 } else {
599 index = len + start_from;
600 if (index < 0) {
601 index = 0;
602 }
603 }
604
605 // If the receiver is not a special receiver type, and the length is a valid
606 // element index, perform fast operation tailored to specific ElementsKinds.
607 if (object->map()->instance_type() > LAST_SPECIAL_RECEIVER_TYPE &&
608 len < kMaxUInt32 &&
609 JSObject::PrototypeHasNoElements(isolate, JSObject::cast(*object))) {
610 Handle<JSObject> obj = Handle<JSObject>::cast(object);
611 ElementsAccessor* elements = obj->GetElementsAccessor();
612 Maybe<int64_t> result = elements->IndexOfValue(isolate, obj, search_element,
613 static_cast<uint32_t>(index),
614 static_cast<uint32_t>(len));
615 MAYBE_RETURN(result, isolate->heap()->exception());
616 return *isolate->factory()->NewNumberFromInt64(result.FromJust());
617 }
618
619 // Otherwise, perform slow lookups for special receiver types
620 for (; index < len; ++index) {
621 // Let elementK be the result of ? Get(O, ! ToString(k)).
622 Handle<Object> element_k;
623 {
624 Handle<Object> index_obj = isolate->factory()->NewNumberFromInt64(index);
625 bool success;
626 LookupIterator it = LookupIterator::PropertyOrElement(
627 isolate, object, index_obj, &success);
628 DCHECK(success);
629 if (!JSReceiver::HasProperty(&it).FromJust()) {
630 continue;
631 }
632 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
633 Object::GetProperty(&it));
634 if (search_element->StrictEquals(*element_k)) {
635 return *index_obj;
636 }
637 }
638 }
639 return Smi::FromInt(-1);
640}
641
Ben Murdoch014dc512016-03-22 12:00:34 +0000642} // namespace internal
643} // namespace v8