v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
runtime-array.cc
Go to the documentation of this file.
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
8#include "src/heap/factory.h"
9#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
13
14namespace v8 {
15namespace internal {
16
17RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
18 HandleScope scope(isolate);
19 DCHECK_EQ(2, args.length());
20 DirectHandle<JSObject> object = args.at<JSObject>(0);
21 DirectHandle<Map> to_map = args.at<Map>(1);
22 ElementsKind to_kind = to_map->elements_kind();
23 ElementsAccessor::ForKind(to_kind)->TransitionElementsKind(object, to_map);
24 return *object;
25}
26
27RUNTIME_FUNCTION(Runtime_TransitionElementsKindWithKind) {
28 HandleScope scope(isolate);
29 DCHECK_EQ(2, args.length());
30 DirectHandle<JSObject> object = args.at<JSObject>(0);
31 ElementsKind to_kind = static_cast<ElementsKind>(args.smi_value_at(1));
32 JSObject::TransitionElementsKind(object, to_kind);
33 return *object;
34}
35
36RUNTIME_FUNCTION(Runtime_NewArray) {
37 HandleScope scope(isolate);
38 DCHECK_LE(3, args.length());
39 int const argc = args.length() - 3;
40 // argv points to the arguments constructed by the JavaScript call.
41 JavaScriptArguments argv(argc, args.address_of_arg_at(0));
42 DirectHandle<JSFunction> constructor = args.at<JSFunction>(argc);
44 Handle<HeapObject> type_info = args.at<HeapObject>(argc + 2);
45 // TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite.
46 DirectHandle<AllocationSite> site = IsAllocationSite(*type_info)
47 ? Cast<AllocationSite>(type_info)
49
50 Factory* factory = isolate->factory();
51
52 // If called through new, new.target can be:
53 // - a subclass of constructor,
54 // - a proxy wrapper around constructor, or
55 // - the constructor itself.
56 // If called through Reflect.construct, it's guaranteed to be a constructor by
57 // REFLECT_CONSTRUCT_PREPARE.
58 DCHECK(IsConstructor(*new_target));
59
60 bool holey = false;
61 bool can_use_type_feedback = !site.is_null();
62 bool can_inline_array_constructor = true;
63 if (argv.length() == 1) {
64 DirectHandle<Object> argument_one = argv.at<Object>(0);
65 if (IsSmi(*argument_one)) {
66 int value = Cast<Smi>(*argument_one).value();
67 if (value < 0 ||
68 JSArray::SetLengthWouldNormalize(isolate->heap(), value)) {
69 // the array is a dictionary in this case.
70 can_use_type_feedback = false;
71 } else if (value != 0) {
72 holey = true;
74 can_inline_array_constructor = false;
75 }
76 }
77 } else {
78 // Non-smi length argument produces a dictionary
79 can_use_type_feedback = false;
80 }
81 }
82
83 DirectHandle<Map> initial_map;
85 isolate, initial_map,
86 JSFunction::GetDerivedMap(isolate, constructor, new_target));
87
88 ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
89 : initial_map->elements_kind();
90 if (holey && !IsHoleyElementsKind(to_kind)) {
91 to_kind = GetHoleyElementsKind(to_kind);
92 // Update the allocation site info to reflect the advice alteration.
93 if (!site.is_null()) site->SetElementsKind(to_kind);
94 }
95
96 // We should allocate with an initial map that reflects the allocation site
97 // advice. Therefore we use AllocateJSObjectFromMap instead of passing
98 // the constructor.
99 initial_map = Map::AsElementsKind(isolate, initial_map, to_kind);
100
101 // If we don't care to track arrays of to_kind ElementsKind, then
102 // don't emit a memento for them.
103 DirectHandle<AllocationSite> allocation_site;
104 if (AllocationSite::ShouldTrack(to_kind)) {
105 allocation_site = site;
106 }
107
109 initial_map, AllocationType::kYoung, allocation_site));
110
111 factory->NewJSArrayStorage(
113
114 ElementsKind old_kind = array->GetElementsKind();
117 if (!site.is_null()) {
118 if ((old_kind != array->GetElementsKind() || !can_use_type_feedback ||
119 !can_inline_array_constructor)) {
120 // The arguments passed in caused a transition. This kind of complexity
121 // can't be dealt with in the inlined optimized array constructor case.
122 // We must mark the allocationsite as un-inlinable.
123 site->SetDoNotInlineCall();
124 }
125 } else {
126 if (old_kind != array->GetElementsKind() || !can_inline_array_constructor) {
127 // We don't have an AllocationSite for this Array constructor invocation,
128 // i.e. it might a call from Array#map or from an Array subclass, so we
129 // just flip the bit on the global protector cell instead.
130 // TODO(bmeurer): Find a better way to mark this. Global protectors
131 // tend to back-fire over time...
132 if (Protectors::IsArrayConstructorIntact(isolate)) {
133 Protectors::InvalidateArrayConstructor(isolate);
134 }
135 }
136 }
137
138 return *array;
139}
140
141RUNTIME_FUNCTION(Runtime_NormalizeElements) {
142 HandleScope scope(isolate);
143 DCHECK_EQ(1, args.length());
144 DirectHandle<JSObject> array = args.at<JSObject>(0);
145 CHECK(!array->HasTypedArrayOrRabGsabTypedArrayElements());
146 CHECK(!IsJSGlobalProxy(*array));
148 return *array;
149}
150
151// GrowArrayElements grows fast kind elements and returns a sentinel Smi if the
152// object was normalized or if the key is negative.
153RUNTIME_FUNCTION(Runtime_GrowArrayElements) {
154 HandleScope scope(isolate);
155 DCHECK_EQ(2, args.length());
156 DirectHandle<JSObject> object = args.at<JSObject>(0);
158 ElementsKind kind = object->GetElementsKind();
160 uint32_t index;
161 if (IsSmi(*key)) {
162 int value = Smi::ToInt(*key);
163 if (value < 0) return Smi::zero();
164 index = static_cast<uint32_t>(value);
165 } else {
166 CHECK(IsHeapNumber(*key));
167 double value = Cast<HeapNumber>(*key)->value();
168 if (value < 0 || value > std::numeric_limits<uint32_t>::max()) {
169 return Smi::zero();
170 }
171 index = static_cast<uint32_t>(value);
172 }
173
174 uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
175
176 if (index >= capacity) {
177 bool has_grown;
179 isolate, has_grown,
180 object->GetElementsAccessor()->GrowCapacity(object, index));
181 if (!has_grown) {
182 return Smi::zero();
183 }
184 }
185
186 return object->elements();
187}
188
189// ES6 22.1.2.2 Array.isArray
190RUNTIME_FUNCTION(Runtime_ArrayIsArray) {
191 HandleScope shs(isolate);
192 DCHECK_EQ(1, args.length());
193 DirectHandle<Object> object = args.at(0);
195 MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
196 return isolate->heap()->ToBoolean(result.FromJust());
197}
198
199RUNTIME_FUNCTION(Runtime_IsArray) {
200 SealHandleScope shs(isolate);
201 DCHECK_EQ(1, args.length());
202 Tagged<Object> obj = args[0];
203 return isolate->heap()->ToBoolean(IsJSArray(obj));
204}
205
206RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
207 HandleScope scope(isolate);
208 DCHECK_EQ(1, args.length());
209 DirectHandle<JSAny> original_array = args.at<JSAny>(0);
211 isolate, Object::ArraySpeciesConstructor(isolate, original_array));
212}
213
214// ES7 22.1.3.11 Array.prototype.includes
215RUNTIME_FUNCTION(Runtime_ArrayIncludes_Slow) {
216 HandleScope shs(isolate);
217 DCHECK_EQ(3, args.length());
218 DirectHandle<Object> search_element = args.at(1);
219 Handle<Object> from_index = args.at(2);
220
221 // Let O be ? ToObject(this value).
224 isolate, object,
225 Object::ToObject(isolate, Handle<Object>(args[0], isolate)));
226
227 // Let len be ? ToLength(? Get(O, "length")).
228 int64_t len;
229 {
230 if (object->map()->instance_type() == JS_ARRAY_TYPE) {
231 uint32_t len32 = 0;
232 bool success =
233 Object::ToArrayLength(Cast<JSArray>(*object)->length(), &len32);
234 DCHECK(success);
235 USE(success);
236 len = len32;
237 } else {
240 isolate, len_,
241 Object::GetProperty(isolate, object,
242 isolate->factory()->length_string()));
243
245 Object::ToLength(isolate, len_));
246 len = static_cast<int64_t>(Object::NumberValue(*len_));
247 DCHECK_EQ(len, Object::NumberValue(*len_));
248 }
249 }
250
251 if (len == 0) return ReadOnlyRoots(isolate).false_value();
252
253 // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
254 // produces the value 0.)
255 int64_t index = 0;
256 if (!IsUndefined(*from_index, isolate)) {
257 double start_from;
259 isolate, start_from, Object::IntegerValue(isolate, from_index));
260
261 if (start_from >= len) return ReadOnlyRoots(isolate).false_value();
262 if (V8_LIKELY(std::isfinite(start_from))) {
263 if (start_from < 0) {
264 index = static_cast<int64_t>(std::max<double>(start_from + len, 0));
265 } else {
266 index = start_from;
267 }
268 }
269
270 DCHECK_GE(index, 0);
271 }
272
273 // If the receiver is not a special receiver type, and the length is a valid
274 // element index, perform fast operation tailored to specific ElementsKinds.
275 if (!IsSpecialReceiverMap(object->map()) &&
279 ElementsAccessor* elements = obj->GetElementsAccessor();
281 elements->IncludesValue(isolate, obj, search_element, index, len);
282 MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
283 return *isolate->factory()->ToBoolean(result.FromJust());
284 }
285
286 // Otherwise, perform slow lookups for special receiver types.
287 for (; index < len; ++index) {
288 HandleScope iteration_hs(isolate);
289
290 // Let elementK be the result of ? Get(O, ! ToString(k)).
291 DirectHandle<Object> element_k;
292 {
293 PropertyKey key(isolate, static_cast<double>(index));
294 LookupIterator it(isolate, object, key);
295 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
297 }
298
299 // If SameValueZero(searchElement, elementK) is true, return true.
300 if (Object::SameValueZero(*search_element, *element_k)) {
301 return ReadOnlyRoots(isolate).true_value();
302 }
303 }
304 return ReadOnlyRoots(isolate).false_value();
305}
306
307RUNTIME_FUNCTION(Runtime_ArrayIndexOf) {
308 HandleScope hs(isolate);
309 DCHECK_EQ(3, args.length());
310 DirectHandle<Object> search_element = args.at(1);
311 Handle<Object> from_index = args.at(2);
312
313 // Let O be ? ToObject(this value).
316 isolate, object,
317 Object::ToObject(isolate, args.at(0), "Array.prototype.indexOf"));
318
319 // Let len be ? ToLength(? Get(O, "length")).
320 int64_t len;
321 {
322 if (IsJSArray(*object)) {
323 uint32_t len32 = 0;
324 bool success =
325 Object::ToArrayLength(Cast<JSArray>(*object)->length(), &len32);
326 DCHECK(success);
327 USE(success);
328 len = len32;
329 } else {
332 isolate, len_,
333 Object::GetProperty(isolate, object,
334 isolate->factory()->length_string()));
335
337 Object::ToLength(isolate, len_));
338 len = static_cast<int64_t>(Object::NumberValue(*len_));
339 DCHECK_EQ(len, Object::NumberValue(*len_));
340 }
341 }
342
343 if (len == 0) return Smi::FromInt(-1);
344
345 // Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step
346 // produces the value 0.)
347 int64_t start_from;
348 {
349 double fp;
351 isolate, fp, Object::IntegerValue(isolate, from_index));
352 if (fp > len) return Smi::FromInt(-1);
353 if (V8_LIKELY(fp >=
354 static_cast<double>(std::numeric_limits<int64_t>::min()))) {
355 DCHECK(fp < static_cast<double>(std::numeric_limits<int64_t>::max()));
356 start_from = static_cast<int64_t>(fp);
357 } else {
358 start_from = std::numeric_limits<int64_t>::min();
359 }
360 }
361
362 int64_t index;
363 if (start_from >= 0) {
364 index = start_from;
365 } else {
366 index = len + start_from;
367 if (index < 0) {
368 index = 0;
369 }
370 }
371
372 // If the receiver is not a special receiver type, and the length fits
373 // uint32_t, perform fast operation tailored to specific ElementsKinds.
374 if (!IsSpecialReceiverMap(object->map()) && len <= kMaxUInt32 &&
377 ElementsAccessor* elements = obj->GetElementsAccessor();
378 Maybe<int64_t> result = elements->IndexOfValue(isolate, obj, search_element,
379 static_cast<uint32_t>(index),
380 static_cast<uint32_t>(len));
381 MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
382 return *isolate->factory()->NewNumberFromInt64(result.FromJust());
383 }
384
385 // Otherwise, perform slow lookups for special receiver types.
386 for (; index < len; ++index) {
387 HandleScope iteration_hs(isolate);
388 // Let elementK be the result of ? Get(O, ! ToString(k)).
389 DirectHandle<Object> element_k;
390 {
391 PropertyKey key(isolate, static_cast<double>(index));
392 LookupIterator it(isolate, object, key);
394 MAYBE_RETURN(present, ReadOnlyRoots(isolate).exception());
395 if (!present.FromJust()) continue;
396 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_k,
398 if (Object::StrictEquals(*search_element, *element_k)) {
399 return *isolate->factory()->NewNumberFromInt64(index);
400 }
401 }
402 }
403 return Smi::FromInt(-1);
404}
405
406} // namespace internal
407} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
bool IsArray() const
Definition api.cc:3525
static bool ShouldTrack(ElementsKind boilerplate_elements_kind)
V8_INLINE int length() const
Definition arguments.h:89
V8_INLINE Handle< S > at(int index) const
static ElementsAccessor * ForKind(ElementsKind elements_kind)
Definition elements.h:29
virtual Maybe< bool > IncludesValue(Isolate *isolate, DirectHandle< JSObject > receiver, DirectHandle< Object > value, size_t start, size_t length)=0
virtual void TransitionElementsKind(DirectHandle< JSObject > object, DirectHandle< Map > map)=0
virtual Maybe< int64_t > IndexOfValue(Isolate *isolate, DirectHandle< JSObject > receiver, DirectHandle< Object > value, size_t start, size_t length)=0
void NewJSArrayStorage(DirectHandle< JSArray > array, int length, int capacity, ArrayStorageAllocationMode mode=ArrayStorageAllocationMode::DONT_INITIALIZE_ARRAY_ELEMENTS)
Definition factory.cc:3290
Handle< JSObject > NewJSObjectFromMap(DirectHandle< Map > map, AllocationType allocation=AllocationType::kYoung, DirectHandle< AllocationSite > allocation_site=DirectHandle< AllocationSite >::null(), NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Definition factory.cc:3135
bool SetLengthWouldNormalize(uint32_t new_length)
Definition objects.cc:4891
static const int kInitialMaxFastElementArray
Definition js-array.h:144
static V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT MaybeHandle< Map > GetDerivedMap(Isolate *isolate, DirectHandle< JSFunction > constructor, DirectHandle< JSReceiver > new_target)
static V8_EXPORT_PRIVATE DirectHandle< NumberDictionary > NormalizeElements(DirectHandle< JSObject > object)
static bool PrototypeHasNoElements(Isolate *isolate, Tagged< JSObject > object)
static V8_EXPORT_PRIVATE void TransitionElementsKind(DirectHandle< JSObject > object, ElementsKind to_kind)
static constexpr uint32_t kMaxElementCount
Definition js-objects.h:923
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > HasProperty(LookupIterator *it)
Definition js-objects.cc:98
static V8_EXPORT_PRIVATE Handle< Map > AsElementsKind(Isolate *isolate, DirectHandle< Map > map, ElementsKind kind)
Definition map.cc:1163
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > ToLength(Isolate *isolate, DirectHandle< Object > input)
static bool ToArrayLength(Tagged< Object > obj, uint32_t *index)
static bool SameValueZero(Tagged< Object > obj, Tagged< Object > other)
Definition objects.cc:1723
static V8_WARN_UNUSED_RESULT HandleType< JSReceiver >::MaybeType ToObject(Isolate *isolate, HandleType< T > object, const char *method_name=nullptr)
static double NumberValue(Tagged< Number > obj)
static V8_WARN_UNUSED_RESULT Maybe< double > IntegerValue(Isolate *isolate, HandleType< T > input)
static V8_EXPORT_PRIVATE bool StrictEquals(Tagged< Object > obj, Tagged< Object > that)
Definition objects.cc:986
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(LookupIterator *it, bool is_global_reference=false)
Definition objects.cc:1248
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > ArraySpeciesConstructor(Isolate *isolate, DirectHandle< JSAny > original_array)
Definition objects.cc:1742
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr Tagged< Smi > zero()
Definition smi.h:99
#define RUNTIME_FUNCTION(Name)
Definition arguments.h:162
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:284
#define RETURN_FAILURE_ON_EXCEPTION(isolate, call)
Definition isolate.h:368
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
#define RETURN_RESULT_OR_FAILURE(isolate, call)
Definition isolate.h:264
#define MAYBE_ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:448
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DirectHandle< Object > new_target
Definition execution.cc:75
ZoneVector< RpoNumber > & result
constexpr bool IsHoleyElementsKind(ElementsKind kind)
MaybeDirectHandle< Object > ArrayConstructInitializeElements(DirectHandle< JSArray > array, JavaScriptArguments *args)
Definition elements.cc:5579
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
bool IsSpecialReceiverMap(Tagged< Map > map)
ElementsKind GetHoleyElementsKind(ElementsKind packed_kind)
bool IsFastElementsKind(ElementsKind kind)
return value
Definition map-inl.h:893
constexpr uint32_t kMaxUInt32
Definition globals.h:387
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
#define V8_LIKELY(condition)
Definition v8config.h:661