blob: 519df7784bca7a1506229f1f2da7491830beb5c9 [file] [log] [blame]
Emily Bernierd0a1eb72015-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 Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/runtime/runtime-utils.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006
7#include "src/arguments.h"
Ben Murdochda12d292016-06-02 14:46:10 +01008#include "src/code-stubs.h"
Ben Murdoch4a90d5f2016-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 Murdochda12d292016-06-02 14:46:10 +010013#include "src/keys.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/messages.h"
15#include "src/prototype.h"
Emily Bernierd0a1eb72015-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();
25 RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0);
26 RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements());
27 // This is necessary to enable fast checks for absence of elements
28 // on Array.prototype and below.
29 prototype->set_elements(isolate->heap()->empty_fixed_array());
30 return Smi::FromInt(0);
31}
32
Ben Murdochda12d292016-06-02 14:46:10 +010033static void InstallCode(Isolate* isolate, Handle<JSObject> holder,
34 const char* name, Handle<Code> code) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040035 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036 Handle<JSFunction> optimized =
37 isolate->factory()->NewFunctionWithoutPrototype(key, code);
38 optimized->shared()->DontAdaptArguments();
39 JSObject::AddProperty(holder, key, optimized, NONE);
40}
41
Ben Murdochda12d292016-06-02 14:46:10 +010042static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
43 const char* name, Builtins::Name builtin_name) {
44 InstallCode(isolate, holder, name,
45 handle(isolate->builtins()->builtin(builtin_name), isolate));
46}
Emily Bernierd0a1eb72015-03-24 16:35:39 -040047
48RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
49 HandleScope scope(isolate);
50 DCHECK(args.length() == 0);
51 Handle<JSObject> holder =
52 isolate->factory()->NewJSObject(isolate->object_function());
53
54 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
Ben Murdochda12d292016-06-02 14:46:10 +010055 FastArrayPushStub stub(isolate);
56 InstallCode(isolate, holder, "push", stub.GetCode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040057 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
58 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
59 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
60 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040061
62 return *holder;
63}
64
65
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066RUNTIME_FUNCTION(Runtime_FixedArrayGet) {
67 SealHandleScope shs(isolate);
68 DCHECK(args.length() == 2);
69 CONVERT_ARG_CHECKED(FixedArray, object, 0);
70 CONVERT_SMI_ARG_CHECKED(index, 1);
71 return object->get(index);
72}
73
74
75RUNTIME_FUNCTION(Runtime_FixedArraySet) {
76 SealHandleScope shs(isolate);
77 DCHECK(args.length() == 3);
78 CONVERT_ARG_CHECKED(FixedArray, object, 0);
79 CONVERT_SMI_ARG_CHECKED(index, 1);
80 CONVERT_ARG_CHECKED(Object, value, 2);
81 object->set(index, value);
82 return isolate->heap()->undefined_value();
83}
84
85
Emily Bernierd0a1eb72015-03-24 16:35:39 -040086RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
87 HandleScope scope(isolate);
88 RUNTIME_ASSERT(args.length() == 2);
89 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
90 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
91 JSObject::TransitionElementsKind(array, map->elements_kind());
92 return *array;
93}
94
95
Emily Bernierd0a1eb72015-03-24 16:35:39 -040096// Moves all own elements of an object, that are below a limit, to positions
97// starting at zero. All undefined values are placed after non-undefined values,
98// and are followed by non-existing element. Does not change the length
99// property.
100// Returns the number of non-undefined elements collected.
101// Returns -1 if hole removal is not supported by this method.
102RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
103 HandleScope scope(isolate);
104 DCHECK(args.length() == 2);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100105 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400106 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100107 if (object->IsJSProxy()) return Smi::FromInt(-1);
108 return *JSObject::PrepareElementsForSort(Handle<JSObject>::cast(object),
109 limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400110}
111
112
113// Move contents of argument 0 (an array) to argument 1 (an array)
114RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
115 HandleScope scope(isolate);
116 DCHECK(args.length() == 2);
117 CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
118 CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
119 JSObject::ValidateElements(from);
120 JSObject::ValidateElements(to);
121
122 Handle<FixedArrayBase> new_elements(from->elements());
123 ElementsKind from_kind = from->GetElementsKind();
124 Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
125 JSObject::SetMapAndElements(to, new_map, new_elements);
126 to->set_length(from->length());
127
128 JSObject::ResetElements(from);
129 from->set_length(Smi::FromInt(0));
130
131 JSObject::ValidateElements(to);
132 return *to;
133}
134
135
136// How many elements does this object/array have?
137RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
138 HandleScope scope(isolate);
139 DCHECK(args.length() == 1);
140 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
141 Handle<FixedArrayBase> elements(array->elements(), isolate);
142 SealHandleScope shs(isolate);
143 if (elements->IsDictionary()) {
144 int result =
145 Handle<SeededNumberDictionary>::cast(elements)->NumberOfElements();
146 return Smi::FromInt(result);
147 } else {
148 DCHECK(array->length()->IsSmi());
149 // For packed elements, we know the exact number of elements
150 int length = elements->length();
151 ElementsKind kind = array->GetElementsKind();
152 if (IsFastPackedElementsKind(kind)) {
153 return Smi::FromInt(length);
154 }
155 // For holey elements, take samples from the buffer checking for holes
156 // to generate the estimate.
157 const int kNumberOfHoleCheckSamples = 97;
158 int increment = (length < kNumberOfHoleCheckSamples)
159 ? 1
160 : static_cast<int>(length / kNumberOfHoleCheckSamples);
161 ElementsAccessor* accessor = array->GetElementsAccessor();
162 int holes = 0;
163 for (int i = 0; i < length; i += increment) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000164 if (!accessor->HasElement(array, i, elements)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400165 ++holes;
166 }
167 }
168 int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
169 kNumberOfHoleCheckSamples * length);
170 return Smi::FromInt(estimate);
171 }
172}
173
174
175// Returns an array that tells you where in the [0, length) interval an array
176// might have elements. Can either return an array of keys (positive integers
177// or undefined) or a number representing the positive length of an interval
178// starting at index 0.
179// Intervals can span over some keys that are not in the object.
180RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
181 HandleScope scope(isolate);
182 DCHECK(args.length() == 2);
183 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
184 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000185
Ben Murdoch097c5b22016-05-18 11:27:45 +0100186 if (array->HasFastStringWrapperElements()) {
187 int string_length =
188 String::cast(Handle<JSValue>::cast(array)->value())->length();
189 int backing_store_length = array->elements()->length();
190 return *isolate->factory()->NewNumberFromUint(
191 Min(length,
192 static_cast<uint32_t>(Max(string_length, backing_store_length))));
193 }
194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195 if (!array->elements()->IsDictionary()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400196 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements() ||
197 array->HasFastDoubleElements());
198 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
199 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
200 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201
Ben Murdoch097c5b22016-05-18 11:27:45 +0100202 KeyAccumulator accumulator(isolate, OWN_ONLY, ALL_PROPERTIES);
203 // No need to separate prototype levels since we only get element keys.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204 for (PrototypeIterator iter(isolate, array,
205 PrototypeIterator::START_AT_RECEIVER);
206 !iter.IsAtEnd(); iter.Advance()) {
207 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy() ||
208 PrototypeIterator::GetCurrent<JSObject>(iter)
209 ->HasIndexedInterceptor()) {
210 // Bail out if we find a proxy or interceptor, likely not worth
211 // collecting keys in that case.
212 return *isolate->factory()->NewNumberFromUint(length);
213 }
214 accumulator.NextPrototype();
215 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
Ben Murdochc5610432016-08-08 18:44:38 +0100216 accumulator.CollectOwnElementIndices(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 }
218 // Erase any keys >= length.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 Handle<FixedArray> keys = accumulator.GetKeys(KEEP_NUMBERS);
Ben Murdochda12d292016-06-02 14:46:10 +0100220 int j = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 for (int i = 0; i < keys->length(); i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100222 if (NumberToUint32(keys->get(i)) >= length) continue;
223 if (i != j) keys->set(j, keys->get(i));
224 j++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 }
Ben Murdochda12d292016-06-02 14:46:10 +0100226
227 if (j != keys->length()) {
228 isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
229 *keys, keys->length() - j);
230 }
231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 return *isolate->factory()->NewJSArrayWithElements(keys);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400233}
234
235
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236namespace {
237
238Object* ArrayConstructorCommon(Isolate* isolate, Handle<JSFunction> constructor,
239 Handle<JSReceiver> new_target,
240 Handle<AllocationSite> site,
241 Arguments* caller_args) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400242 Factory* factory = isolate->factory();
243
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 // If called through new, new.target can be:
245 // - a subclass of constructor,
246 // - a proxy wrapper around constructor, or
247 // - the constructor itself.
248 // If called through Reflect.construct, it's guaranteed to be a constructor by
249 // REFLECT_CONSTRUCT_PREPARE.
250 DCHECK(new_target->IsConstructor());
251
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400252 bool holey = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 bool can_use_type_feedback = !site.is_null();
254 bool can_inline_array_constructor = true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400255 if (caller_args->length() == 1) {
256 Handle<Object> argument_one = caller_args->at<Object>(0);
257 if (argument_one->IsSmi()) {
258 int value = Handle<Smi>::cast(argument_one)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 if (value < 0 ||
260 JSArray::SetLengthWouldNormalize(isolate->heap(), value)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400261 // the array is a dictionary in this case.
262 can_use_type_feedback = false;
263 } else if (value != 0) {
264 holey = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 if (value >= JSArray::kInitialMaxFastElementArray) {
266 can_inline_array_constructor = false;
267 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400268 }
269 } else {
270 // Non-smi length argument produces a dictionary
271 can_use_type_feedback = false;
272 }
273 }
274
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275 Handle<Map> initial_map;
276 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
277 isolate, initial_map,
278 JSFunction::GetDerivedMap(isolate, constructor, new_target));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400279
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280 ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
281 : initial_map->elements_kind();
282 if (holey && !IsFastHoleyElementsKind(to_kind)) {
283 to_kind = GetHoleyElementsKind(to_kind);
284 // Update the allocation site info to reflect the advice alteration.
285 if (!site.is_null()) site->SetElementsKind(to_kind);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400286 }
287
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 // We should allocate with an initial map that reflects the allocation site
289 // advice. Therefore we use AllocateJSObjectFromMap instead of passing
290 // the constructor.
291 if (to_kind != initial_map->elements_kind()) {
292 initial_map = Map::AsElementsKind(initial_map, to_kind);
293 }
294
295 // If we don't care to track arrays of to_kind ElementsKind, then
296 // don't emit a memento for them.
297 Handle<AllocationSite> allocation_site;
298 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
299 allocation_site = site;
300 }
301
302 Handle<JSArray> array = Handle<JSArray>::cast(
303 factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
304
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400305 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
306
307 ElementsKind old_kind = array->GetElementsKind();
308 RETURN_FAILURE_ON_EXCEPTION(
309 isolate, ArrayConstructInitializeElements(array, caller_args));
310 if (!site.is_null() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000311 (old_kind != array->GetElementsKind() || !can_use_type_feedback ||
312 !can_inline_array_constructor)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400313 // The arguments passed in caused a transition. This kind of complexity
314 // can't be dealt with in the inlined hydrogen array constructor case.
315 // We must mark the allocationsite as un-inlinable.
316 site->SetDoNotInlineCall();
317 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400319 return *array;
320}
321
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322} // namespace
323
324
325RUNTIME_FUNCTION(Runtime_NewArray) {
326 HandleScope scope(isolate);
327 DCHECK_LE(3, args.length());
328 int const argc = args.length() - 3;
329 // TODO(bmeurer): Remove this Arguments nonsense.
330 Arguments argv(argc, args.arguments() - 1);
331 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
332 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, argc + 1);
333 CONVERT_ARG_HANDLE_CHECKED(HeapObject, type_info, argc + 2);
334 // TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite.
335 Handle<AllocationSite> site = type_info->IsAllocationSite()
336 ? Handle<AllocationSite>::cast(type_info)
337 : Handle<AllocationSite>::null();
338 return ArrayConstructorCommon(isolate, constructor, new_target, site, &argv);
339}
340
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400341
342RUNTIME_FUNCTION(Runtime_ArrayConstructor) {
343 HandleScope scope(isolate);
344 // If we get 2 arguments then they are the stub parameters (constructor, type
345 // info). If we get 4, then the first one is a pointer to the arguments
346 // passed by the caller, and the last one is the length of the arguments
347 // passed to the caller (redundant, but useful to check on the deoptimizer
348 // with an assert).
349 Arguments empty_args(0, NULL);
350 bool no_caller_args = args.length() == 2;
351 DCHECK(no_caller_args || args.length() == 4);
352 int parameters_start = no_caller_args ? 0 : 1;
353 Arguments* caller_args =
354 no_caller_args ? &empty_args : reinterpret_cast<Arguments*>(args[0]);
355 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
356 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
357#ifdef DEBUG
358 if (!no_caller_args) {
359 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
360 DCHECK(arg_count == caller_args->length());
361 }
362#endif
363
364 Handle<AllocationSite> site;
365 if (!type_info.is_null() &&
366 *type_info != isolate->heap()->undefined_value()) {
367 site = Handle<AllocationSite>::cast(type_info);
368 DCHECK(!site->SitePointsToLiteral());
369 }
370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371 return ArrayConstructorCommon(isolate, constructor, constructor, site,
372 caller_args);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400373}
374
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400375RUNTIME_FUNCTION(Runtime_InternalArrayConstructor) {
376 HandleScope scope(isolate);
377 Arguments empty_args(0, NULL);
378 bool no_caller_args = args.length() == 1;
379 DCHECK(no_caller_args || args.length() == 3);
380 int parameters_start = no_caller_args ? 0 : 1;
381 Arguments* caller_args =
382 no_caller_args ? &empty_args : reinterpret_cast<Arguments*>(args[0]);
383 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
384#ifdef DEBUG
385 if (!no_caller_args) {
386 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
387 DCHECK(arg_count == caller_args->length());
388 }
389#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 return ArrayConstructorCommon(isolate, constructor, constructor,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400391 Handle<AllocationSite>::null(), caller_args);
392}
393
394
395RUNTIME_FUNCTION(Runtime_NormalizeElements) {
396 HandleScope scope(isolate);
397 DCHECK(args.length() == 1);
398 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000399 RUNTIME_ASSERT(!array->HasFixedTypedArrayElements() &&
400 !array->IsJSGlobalProxy());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400401 JSObject::NormalizeElements(array);
402 return *array;
403}
404
405
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000406// GrowArrayElements returns a sentinel Smi if the object was normalized.
407RUNTIME_FUNCTION(Runtime_GrowArrayElements) {
408 HandleScope scope(isolate);
409 DCHECK(args.length() == 2);
410 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
411 CONVERT_NUMBER_CHECKED(int, key, Int32, args[1]);
412
413 if (key < 0) {
414 return object->elements();
415 }
416
417 uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
418 uint32_t index = static_cast<uint32_t>(key);
419
420 if (index >= capacity) {
421 if (object->WouldConvertToSlowElements(index)) {
422 // We don't want to allow operations that cause lazy deopt. Return a Smi
423 // as a signal that optimized code should eagerly deoptimize.
424 return Smi::FromInt(0);
425 }
426
427 uint32_t new_capacity = JSObject::NewElementsCapacity(index + 1);
428 object->GetElementsAccessor()->GrowCapacityAndConvert(object, new_capacity);
429 }
430
431 // On success, return the fixed array elements.
432 return object->elements();
433}
434
435
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400436RUNTIME_FUNCTION(Runtime_HasComplexElements) {
437 HandleScope scope(isolate);
438 DCHECK(args.length() == 1);
439 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
440 for (PrototypeIterator iter(isolate, array,
441 PrototypeIterator::START_AT_RECEIVER);
442 !iter.IsAtEnd(); iter.Advance()) {
443 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
444 return isolate->heap()->true_value();
445 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400447 if (current->HasIndexedInterceptor()) {
448 return isolate->heap()->true_value();
449 }
450 if (!current->HasDictionaryElements()) continue;
451 if (current->element_dictionary()->HasComplexElements()) {
452 return isolate->heap()->true_value();
453 }
454 }
455 return isolate->heap()->false_value();
456}
457
Ben Murdochc5610432016-08-08 18:44:38 +0100458// ES6 22.1.2.2 Array.isArray
459RUNTIME_FUNCTION(Runtime_ArrayIsArray) {
460 HandleScope shs(isolate);
461 DCHECK(args.length() == 1);
462 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
463 Maybe<bool> result = Object::IsArray(object);
464 MAYBE_RETURN(result, isolate->heap()->exception());
465 return isolate->heap()->ToBoolean(result.FromJust());
466}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400467
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468RUNTIME_FUNCTION(Runtime_IsArray) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400469 SealHandleScope shs(isolate);
470 DCHECK(args.length() == 1);
471 CONVERT_ARG_CHECKED(Object, obj, 0);
472 return isolate->heap()->ToBoolean(obj->IsJSArray());
473}
474
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475RUNTIME_FUNCTION(Runtime_HasCachedArrayIndex) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400476 SealHandleScope shs(isolate);
477 DCHECK(args.length() == 1);
478 return isolate->heap()->false_value();
479}
480
481
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482RUNTIME_FUNCTION(Runtime_GetCachedArrayIndex) {
483 // This can never be reached, because Runtime_HasCachedArrayIndex always
484 // returns false.
485 UNIMPLEMENTED();
486 return nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400487}
488
489
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
491 HandleScope scope(isolate);
492 DCHECK(args.length() == 1);
493 CONVERT_ARG_HANDLE_CHECKED(Object, original_array, 0);
494 Handle<Object> constructor;
495 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
496 isolate, constructor,
497 Object::ArraySpeciesConstructor(isolate, original_array));
498 return *constructor;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400499}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000500
501} // namespace internal
502} // namespace v8