Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(547)

Side by Side Diff: src/builtins/builtins-array-gen.cc

Issue 2752143004: [refactor] Separate generated builtins and C++ builtins into separate files (Closed)
Patch Set: tentative gcmole fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-array.cc ('k') | src/builtins/builtins-async.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/builtins/builtins-utils-gen.h"
5 #include "src/builtins/builtins.h" 6 #include "src/builtins/builtins.h"
6 #include "src/builtins/builtins-utils.h"
7
8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h" 7 #include "src/code-stub-assembler.h"
10 #include "src/contexts.h"
11 #include "src/counters.h"
12 #include "src/elements.h"
13 #include "src/isolate.h"
14 #include "src/lookup.h"
15 #include "src/objects-inl.h"
16 #include "src/prototype.h"
17 8
18 namespace v8 { 9 namespace v8 {
19 namespace internal { 10 namespace internal {
20 11
21 namespace {
22
23 inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) {
24 // This is an extended version of ECMA-262 7.1.11 handling signed values
25 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
26 if (object->IsSmi()) {
27 *out = Smi::cast(object)->value();
28 return true;
29 } else if (object->IsHeapNumber()) {
30 double value = HeapNumber::cast(object)->value();
31 if (std::isnan(value)) {
32 *out = 0;
33 } else if (value > kMaxInt) {
34 *out = kMaxInt;
35 } else if (value < kMinInt) {
36 *out = kMinInt;
37 } else {
38 *out = static_cast<int>(value);
39 }
40 return true;
41 } else if (object->IsNullOrUndefined(isolate)) {
42 *out = 0;
43 return true;
44 } else if (object->IsBoolean()) {
45 *out = object->IsTrue(isolate);
46 return true;
47 }
48 return false;
49 }
50
51 inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object,
52 int* out) {
53 Context* context = *isolate->native_context();
54 Map* map = object->map();
55 if (map != context->sloppy_arguments_map() &&
56 map != context->strict_arguments_map() &&
57 map != context->fast_aliased_arguments_map()) {
58 return false;
59 }
60 DCHECK(object->HasFastElements() || object->HasFastArgumentsElements());
61 Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex);
62 if (!len_obj->IsSmi()) return false;
63 *out = Max(0, Smi::cast(len_obj)->value());
64
65 FixedArray* parameters = FixedArray::cast(object->elements());
66 if (object->HasSloppyArgumentsElements()) {
67 FixedArray* arguments = FixedArray::cast(parameters->get(1));
68 return *out <= arguments->length();
69 }
70 return *out <= parameters->length();
71 }
72
73 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
74 JSArray* receiver) {
75 return JSObject::PrototypeHasNoElements(isolate, receiver);
76 }
77
78 inline bool HasSimpleElements(JSObject* current) {
79 return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER &&
80 !current->GetElementsAccessor()->HasAccessors(current);
81 }
82
83 inline bool HasOnlySimpleReceiverElements(Isolate* isolate,
84 JSObject* receiver) {
85 // Check that we have no accessors on the receiver's elements.
86 if (!HasSimpleElements(receiver)) return false;
87 return JSObject::PrototypeHasNoElements(isolate, receiver);
88 }
89
90 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) {
91 DisallowHeapAllocation no_gc;
92 PrototypeIterator iter(isolate, receiver, kStartAtReceiver);
93 for (; !iter.IsAtEnd(); iter.Advance()) {
94 if (iter.GetCurrent()->IsJSProxy()) return false;
95 JSObject* current = iter.GetCurrent<JSObject>();
96 if (!HasSimpleElements(current)) return false;
97 }
98 return true;
99 }
100
101 // Returns |false| if not applicable.
102 MUST_USE_RESULT
103 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate,
104 Handle<Object> receiver,
105 BuiltinArguments* args,
106 int first_added_arg) {
107 if (!receiver->IsJSArray()) return false;
108 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
109 ElementsKind origin_kind = array->GetElementsKind();
110 if (IsDictionaryElementsKind(origin_kind)) return false;
111 if (!array->map()->is_extensible()) return false;
112 if (args == nullptr) return true;
113
114 // If there may be elements accessors in the prototype chain, the fast path
115 // cannot be used if there arguments to add to the array.
116 if (!IsJSArrayFastElementMovingAllowed(isolate, *array)) return false;
117
118 // Adding elements to the array prototype would break code that makes sure
119 // it has no elements. Handle that elsewhere.
120 if (isolate->IsAnyInitialArrayPrototype(array)) return false;
121
122 // Need to ensure that the arguments passed in args can be contained in
123 // the array.
124 int args_length = args->length();
125 if (first_added_arg >= args_length) return true;
126
127 if (IsFastObjectElementsKind(origin_kind)) return true;
128 ElementsKind target_kind = origin_kind;
129 {
130 DisallowHeapAllocation no_gc;
131 for (int i = first_added_arg; i < args_length; i++) {
132 Object* arg = (*args)[i];
133 if (arg->IsHeapObject()) {
134 if (arg->IsHeapNumber()) {
135 target_kind = FAST_DOUBLE_ELEMENTS;
136 } else {
137 target_kind = FAST_ELEMENTS;
138 break;
139 }
140 }
141 }
142 }
143 if (target_kind != origin_kind) {
144 // Use a short-lived HandleScope to avoid creating several copies of the
145 // elements handle which would cause issues when left-trimming later-on.
146 HandleScope scope(isolate);
147 JSObject::TransitionElementsKind(array, target_kind);
148 }
149 return true;
150 }
151
152 MUST_USE_RESULT static Object* CallJsIntrinsic(Isolate* isolate,
153 Handle<JSFunction> function,
154 BuiltinArguments args) {
155 HandleScope handleScope(isolate);
156 int argc = args.length() - 1;
157 ScopedVector<Handle<Object>> argv(argc);
158 for (int i = 0; i < argc; ++i) {
159 argv[i] = args.at(i + 1);
160 }
161 RETURN_RESULT_OR_FAILURE(
162 isolate,
163 Execution::Call(isolate, function, args.receiver(), argc, argv.start()));
164 }
165 } // namespace
166
167 BUILTIN(ArrayPush) {
168 HandleScope scope(isolate);
169 Handle<Object> receiver = args.receiver();
170 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) {
171 return CallJsIntrinsic(isolate, isolate->array_push(), args);
172 }
173 // Fast Elements Path
174 int to_add = args.length() - 1;
175 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
176 int len = Smi::cast(array->length())->value();
177 if (to_add == 0) return Smi::FromInt(len);
178
179 // Currently fixed arrays cannot grow too big, so we should never hit this.
180 DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value());
181
182 if (JSArray::HasReadOnlyLength(array)) {
183 return CallJsIntrinsic(isolate, isolate->array_push(), args);
184 }
185
186 ElementsAccessor* accessor = array->GetElementsAccessor();
187 int new_length = accessor->Push(array, &args, to_add);
188 return Smi::FromInt(new_length);
189 }
190
191 TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
192 Variable arg_index(this, MachineType::PointerRepresentation());
193 Label default_label(this, &arg_index);
194 Label smi_transition(this);
195 Label object_push_pre(this);
196 Label object_push(this, &arg_index);
197 Label double_push(this, &arg_index);
198 Label double_transition(this);
199 Label runtime(this, Label::kDeferred);
200
201 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
202 Node* context = Parameter(BuiltinDescriptor::kContext);
203 Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
204
205 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
206 Node* receiver = args.GetReceiver();
207 Node* kind = nullptr;
208
209 Label fast(this);
210 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS,
211 &fast, &runtime);
212
213 Bind(&fast);
214 {
215 // Disallow pushing onto prototypes. It might be the JSArray prototype.
216 // Disallow pushing onto non-extensible objects.
217 Comment("Disallow pushing onto prototypes");
218 Node* map = LoadMap(receiver);
219 Node* bit_field2 = LoadMapBitField2(map);
220 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
221 (1 << Map::kIsExtensible);
222 Node* test = Word32And(bit_field2, Int32Constant(mask));
223 GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)),
224 &runtime);
225
226 // Disallow pushing onto arrays in dictionary named property mode. We need
227 // to figure out whether the length property is still writable.
228 Comment("Disallow pushing onto arrays in dictionary named property mode");
229 GotoIf(IsDictionaryMap(map), &runtime);
230
231 // Check whether the length property is writable. The length property is the
232 // only default named property on arrays. It's nonconfigurable, hence is
233 // guaranteed to stay the first property.
234 Node* descriptors = LoadMapDescriptors(map);
235 Node* details =
236 LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
237 GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask),
238 &runtime);
239
240 arg_index.Bind(IntPtrConstant(0));
241 kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
242
243 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
244 &object_push_pre);
245
246 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver,
247 args, arg_index, &smi_transition);
248 args.PopAndReturn(new_length);
249 }
250
251 // If the argument is not a smi, then use a heavyweight SetProperty to
252 // transition the array for only the single next element. If the argument is
253 // a smi, the failure is due to some other reason and we should fall back on
254 // the most generic implementation for the rest of the array.
255 Bind(&smi_transition);
256 {
257 Node* arg = args.AtIndex(arg_index.value());
258 GotoIf(TaggedIsSmi(arg), &default_label);
259 Node* length = LoadJSArrayLength(receiver);
260 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
261 // calling into the runtime to do the elements transition is overkill.
262 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
263 SmiConstant(STRICT));
264 Increment(arg_index);
265 // The runtime SetProperty call could have converted the array to dictionary
266 // mode, which must be detected to abort the fast-path.
267 Node* map = LoadMap(receiver);
268 Node* bit_field2 = LoadMapBitField2(map);
269 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
270 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
271 &default_label);
272
273 GotoIfNotNumber(arg, &object_push);
274 Goto(&double_push);
275 }
276
277 Bind(&object_push_pre);
278 {
279 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
280 &double_push, &object_push);
281 }
282
283 Bind(&object_push);
284 {
285 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver,
286 args, arg_index, &default_label);
287 args.PopAndReturn(new_length);
288 }
289
290 Bind(&double_push);
291 {
292 Node* new_length =
293 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args,
294 arg_index, &double_transition);
295 args.PopAndReturn(new_length);
296 }
297
298 // If the argument is not a double, then use a heavyweight SetProperty to
299 // transition the array for only the single next element. If the argument is
300 // a double, the failure is due to some other reason and we should fall back
301 // on the most generic implementation for the rest of the array.
302 Bind(&double_transition);
303 {
304 Node* arg = args.AtIndex(arg_index.value());
305 GotoIfNumber(arg, &default_label);
306 Node* length = LoadJSArrayLength(receiver);
307 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
308 // calling into the runtime to do the elements transition is overkill.
309 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
310 SmiConstant(STRICT));
311 Increment(arg_index);
312 // The runtime SetProperty call could have converted the array to dictionary
313 // mode, which must be detected to abort the fast-path.
314 Node* map = LoadMap(receiver);
315 Node* bit_field2 = LoadMapBitField2(map);
316 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
317 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
318 &default_label);
319 Goto(&object_push);
320 }
321
322 // Fallback that stores un-processed arguments using the full, heavyweight
323 // SetProperty machinery.
324 Bind(&default_label);
325 {
326 args.ForEach(
327 [this, receiver, context](Node* arg) {
328 Node* length = LoadJSArrayLength(receiver);
329 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
330 SmiConstant(STRICT));
331 },
332 arg_index.value());
333 args.PopAndReturn(LoadJSArrayLength(receiver));
334 }
335
336 Bind(&runtime);
337 {
338 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
339 MachineType::TaggedPointer());
340 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target,
341 argc);
342 }
343 }
344
345 BUILTIN(ArrayPop) {
346 HandleScope scope(isolate);
347 Handle<Object> receiver = args.receiver();
348 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) {
349 return CallJsIntrinsic(isolate, isolate->array_pop(), args);
350 }
351
352 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
353
354 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value());
355 if (len == 0) return isolate->heap()->undefined_value();
356
357 if (JSArray::HasReadOnlyLength(array)) {
358 return CallJsIntrinsic(isolate, isolate->array_pop(), args);
359 }
360
361 Handle<Object> result;
362 if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
363 // Fast Elements Path
364 result = array->GetElementsAccessor()->Pop(array);
365 } else {
366 // Use Slow Lookup otherwise
367 uint32_t new_length = len - 1;
368 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
369 isolate, result, JSReceiver::GetElement(isolate, array, new_length));
370 JSArray::SetLength(array, new_length);
371 }
372 return *result;
373 }
374
375 BUILTIN(ArrayShift) {
376 HandleScope scope(isolate);
377 Heap* heap = isolate->heap();
378 Handle<Object> receiver = args.receiver();
379 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0) ||
380 !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
381 return CallJsIntrinsic(isolate, isolate->array_shift(), args);
382 }
383 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
384
385 int len = Smi::cast(array->length())->value();
386 if (len == 0) return heap->undefined_value();
387
388 if (JSArray::HasReadOnlyLength(array)) {
389 return CallJsIntrinsic(isolate, isolate->array_shift(), args);
390 }
391
392 Handle<Object> first = array->GetElementsAccessor()->Shift(array);
393 return *first;
394 }
395
396 BUILTIN(ArrayUnshift) {
397 HandleScope scope(isolate);
398 Handle<Object> receiver = args.receiver();
399 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) {
400 return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
401 }
402 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
403 int to_add = args.length() - 1;
404 if (to_add == 0) return array->length();
405
406 // Currently fixed arrays cannot grow too big, so we should never hit this.
407 DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value());
408
409 if (JSArray::HasReadOnlyLength(array)) {
410 return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
411 }
412
413 ElementsAccessor* accessor = array->GetElementsAccessor();
414 int new_length = accessor->Unshift(array, &args, to_add);
415 return Smi::FromInt(new_length);
416 }
417
418 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { 12 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
419 public: 13 public:
420 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) 14 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state)
421 : CodeStubAssembler(state) {} 15 : CodeStubAssembler(state) {}
422 16
423 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator; 17 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator;
424 typedef std::function<void(Node* a, Node* pK, Node* value)> 18 typedef std::function<void(Node* a, Node* pK, Node* value)>
425 CallResultProcessor; 19 CallResultProcessor;
426 20
427 void GenerateArrayIteratingBuiltinBody( 21 void GenerateArrayIteratingBuiltinBody(
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 // No exception, return success 253 // No exception, return success
660 Return(a); 254 Return(a);
661 255
662 Bind(&array_changed); 256 Bind(&array_changed);
663 k.Bind(ParameterToTagged(last_index, mode)); 257 k.Bind(ParameterToTagged(last_index, mode));
664 Goto(slow); 258 Goto(slow);
665 } 259 }
666 } 260 }
667 }; 261 };
668 262
263 TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
264 Variable arg_index(this, MachineType::PointerRepresentation());
265 Label default_label(this, &arg_index);
266 Label smi_transition(this);
267 Label object_push_pre(this);
268 Label object_push(this, &arg_index);
269 Label double_push(this, &arg_index);
270 Label double_transition(this);
271 Label runtime(this, Label::kDeferred);
272
273 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
274 Node* context = Parameter(BuiltinDescriptor::kContext);
275 Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
276
277 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
278 Node* receiver = args.GetReceiver();
279 Node* kind = nullptr;
280
281 Label fast(this);
282 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS,
283 &fast, &runtime);
284
285 Bind(&fast);
286 {
287 // Disallow pushing onto prototypes. It might be the JSArray prototype.
288 // Disallow pushing onto non-extensible objects.
289 Comment("Disallow pushing onto prototypes");
290 Node* map = LoadMap(receiver);
291 Node* bit_field2 = LoadMapBitField2(map);
292 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
293 (1 << Map::kIsExtensible);
294 Node* test = Word32And(bit_field2, Int32Constant(mask));
295 GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)),
296 &runtime);
297
298 // Disallow pushing onto arrays in dictionary named property mode. We need
299 // to figure out whether the length property is still writable.
300 Comment("Disallow pushing onto arrays in dictionary named property mode");
301 GotoIf(IsDictionaryMap(map), &runtime);
302
303 // Check whether the length property is writable. The length property is the
304 // only default named property on arrays. It's nonconfigurable, hence is
305 // guaranteed to stay the first property.
306 Node* descriptors = LoadMapDescriptors(map);
307 Node* details =
308 LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
309 GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask),
310 &runtime);
311
312 arg_index.Bind(IntPtrConstant(0));
313 kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
314
315 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)),
316 &object_push_pre);
317
318 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver,
319 args, arg_index, &smi_transition);
320 args.PopAndReturn(new_length);
321 }
322
323 // If the argument is not a smi, then use a heavyweight SetProperty to
324 // transition the array for only the single next element. If the argument is
325 // a smi, the failure is due to some other reason and we should fall back on
326 // the most generic implementation for the rest of the array.
327 Bind(&smi_transition);
328 {
329 Node* arg = args.AtIndex(arg_index.value());
330 GotoIf(TaggedIsSmi(arg), &default_label);
331 Node* length = LoadJSArrayLength(receiver);
332 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
333 // calling into the runtime to do the elements transition is overkill.
334 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
335 SmiConstant(STRICT));
336 Increment(arg_index);
337 // The runtime SetProperty call could have converted the array to dictionary
338 // mode, which must be detected to abort the fast-path.
339 Node* map = LoadMap(receiver);
340 Node* bit_field2 = LoadMapBitField2(map);
341 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
342 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
343 &default_label);
344
345 GotoIfNotNumber(arg, &object_push);
346 Goto(&double_push);
347 }
348
349 Bind(&object_push_pre);
350 {
351 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)),
352 &double_push, &object_push);
353 }
354
355 Bind(&object_push);
356 {
357 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver,
358 args, arg_index, &default_label);
359 args.PopAndReturn(new_length);
360 }
361
362 Bind(&double_push);
363 {
364 Node* new_length =
365 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args,
366 arg_index, &double_transition);
367 args.PopAndReturn(new_length);
368 }
369
370 // If the argument is not a double, then use a heavyweight SetProperty to
371 // transition the array for only the single next element. If the argument is
372 // a double, the failure is due to some other reason and we should fall back
373 // on the most generic implementation for the rest of the array.
374 Bind(&double_transition);
375 {
376 Node* arg = args.AtIndex(arg_index.value());
377 GotoIfNumber(arg, &default_label);
378 Node* length = LoadJSArrayLength(receiver);
379 // TODO(danno): Use the KeyedStoreGeneric stub here when possible,
380 // calling into the runtime to do the elements transition is overkill.
381 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
382 SmiConstant(STRICT));
383 Increment(arg_index);
384 // The runtime SetProperty call could have converted the array to dictionary
385 // mode, which must be detected to abort the fast-path.
386 Node* map = LoadMap(receiver);
387 Node* bit_field2 = LoadMapBitField2(map);
388 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
389 GotoIf(Word32Equal(kind, Int32Constant(DICTIONARY_ELEMENTS)),
390 &default_label);
391 Goto(&object_push);
392 }
393
394 // Fallback that stores un-processed arguments using the full, heavyweight
395 // SetProperty machinery.
396 Bind(&default_label);
397 {
398 args.ForEach(
399 [this, receiver, context](Node* arg) {
400 Node* length = LoadJSArrayLength(receiver);
401 CallRuntime(Runtime::kSetProperty, context, receiver, length, arg,
402 SmiConstant(STRICT));
403 },
404 arg_index.value());
405 args.PopAndReturn(LoadJSArrayLength(receiver));
406 }
407
408 Bind(&runtime);
409 {
410 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
411 MachineType::TaggedPointer());
412 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target,
413 argc);
414 }
415 }
416
669 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { 417 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) {
670 Node* receiver = Parameter(ForEachDescriptor::kReceiver); 418 Node* receiver = Parameter(ForEachDescriptor::kReceiver);
671 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); 419 Node* callbackfn = Parameter(ForEachDescriptor::kCallback);
672 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); 420 Node* this_arg = Parameter(ForEachDescriptor::kThisArg);
673 Node* context = Parameter(ForEachDescriptor::kContext); 421 Node* context = Parameter(ForEachDescriptor::kContext);
674 422
675 GenerateArrayIteratingBuiltinBody( 423 GenerateArrayIteratingBuiltinBody(
676 "Array.prototype.forEach", receiver, callbackfn, this_arg, context, 424 "Array.prototype.forEach", receiver, callbackfn, this_arg, context,
677 [=](Node*, Node*) { return UndefinedConstant(); }, 425 [=](Node*, Node*) { return UndefinedConstant(); },
678 [](Node* a, Node* p_k, Node* value) {}); 426 [](Node* a, Node* p_k, Node* value) {});
(...skipping 28 matching lines...) Expand all
707 [=](Node*, Node*) { return FalseConstant(); }, 455 [=](Node*, Node*) { return FalseConstant(); },
708 [=](Node* a, Node* p_k, Node* value) { 456 [=](Node* a, Node* p_k, Node* value) {
709 Label false_continue(this), return_true(this); 457 Label false_continue(this), return_true(this);
710 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); 458 BranchIfToBooleanIsTrue(value, &return_true, &false_continue);
711 Bind(&return_true); 459 Bind(&return_true);
712 Return(TrueConstant()); 460 Return(TrueConstant());
713 Bind(&false_continue); 461 Bind(&false_continue);
714 }); 462 });
715 } 463 }
716 464
717 BUILTIN(ArraySlice) {
718 HandleScope scope(isolate);
719 Handle<Object> receiver = args.receiver();
720 int len = -1;
721 int relative_start = 0;
722 int relative_end = 0;
723
724 if (receiver->IsJSArray()) {
725 DisallowHeapAllocation no_gc;
726 JSArray* array = JSArray::cast(*receiver);
727 if (V8_UNLIKELY(!array->HasFastElements() ||
728 !IsJSArrayFastElementMovingAllowed(isolate, array) ||
729 !isolate->IsArraySpeciesLookupChainIntact() ||
730 // If this is a subclass of Array, then call out to JS
731 !array->HasArrayPrototype(isolate))) {
732 AllowHeapAllocation allow_allocation;
733 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
734 }
735 len = Smi::cast(array->length())->value();
736 } else if (receiver->IsJSObject() &&
737 GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver),
738 &len)) {
739 // Array.prototype.slice.call(arguments, ...) is quite a common idiom
740 // (notably more than 50% of invocations in Web apps).
741 // Treat it in C++ as well.
742 DCHECK(JSObject::cast(*receiver)->HasFastElements() ||
743 JSObject::cast(*receiver)->HasFastArgumentsElements());
744 } else {
745 AllowHeapAllocation allow_allocation;
746 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
747 }
748 DCHECK_LE(0, len);
749 int argument_count = args.length() - 1;
750 // Note carefully chosen defaults---if argument is missing,
751 // it's undefined which gets converted to 0 for relative_start
752 // and to len for relative_end.
753 relative_start = 0;
754 relative_end = len;
755 if (argument_count > 0) {
756 DisallowHeapAllocation no_gc;
757 if (!ClampedToInteger(isolate, args[1], &relative_start)) {
758 AllowHeapAllocation allow_allocation;
759 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
760 }
761 if (argument_count > 1) {
762 Object* end_arg = args[2];
763 // slice handles the end_arg specially
764 if (end_arg->IsUndefined(isolate)) {
765 relative_end = len;
766 } else if (!ClampedToInteger(isolate, end_arg, &relative_end)) {
767 AllowHeapAllocation allow_allocation;
768 return CallJsIntrinsic(isolate, isolate->array_slice(), args);
769 }
770 }
771 }
772
773 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
774 uint32_t actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
775 : Min(relative_start, len);
776
777 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
778 uint32_t actual_end =
779 (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len);
780
781 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
782 ElementsAccessor* accessor = object->GetElementsAccessor();
783 return *accessor->Slice(object, actual_start, actual_end);
784 }
785
786 BUILTIN(ArraySplice) {
787 HandleScope scope(isolate);
788 Handle<Object> receiver = args.receiver();
789 if (V8_UNLIKELY(
790 !EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3) ||
791 // If this is a subclass of Array, then call out to JS.
792 !Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) ||
793 // If anything with @@species has been messed with, call out to JS.
794 !isolate->IsArraySpeciesLookupChainIntact())) {
795 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
796 }
797 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
798
799 int argument_count = args.length() - 1;
800 int relative_start = 0;
801 if (argument_count > 0) {
802 DisallowHeapAllocation no_gc;
803 if (!ClampedToInteger(isolate, args[1], &relative_start)) {
804 AllowHeapAllocation allow_allocation;
805 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
806 }
807 }
808 int len = Smi::cast(array->length())->value();
809 // clip relative start to [0, len]
810 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
811 : Min(relative_start, len);
812
813 int actual_delete_count;
814 if (argument_count == 1) {
815 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
816 // given as a request to delete all the elements from the start.
817 // And it differs from the case of undefined delete count.
818 // This does not follow ECMA-262, but we do the same for compatibility.
819 DCHECK(len - actual_start >= 0);
820 actual_delete_count = len - actual_start;
821 } else {
822 int delete_count = 0;
823 DisallowHeapAllocation no_gc;
824 if (argument_count > 1) {
825 if (!ClampedToInteger(isolate, args[2], &delete_count)) {
826 AllowHeapAllocation allow_allocation;
827 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
828 }
829 }
830 actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
831 }
832
833 int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
834 int new_length = len - actual_delete_count + add_count;
835
836 if (new_length != len && JSArray::HasReadOnlyLength(array)) {
837 AllowHeapAllocation allow_allocation;
838 return CallJsIntrinsic(isolate, isolate->array_splice(), args);
839 }
840 ElementsAccessor* accessor = array->GetElementsAccessor();
841 Handle<JSArray> result_array = accessor->Splice(
842 array, actual_start, actual_delete_count, &args, add_count);
843 return *result_array;
844 }
845
846 // Array Concat -------------------------------------------------------------
847
848 namespace {
849
850 /**
851 * A simple visitor visits every element of Array's.
852 * The backend storage can be a fixed array for fast elements case,
853 * or a dictionary for sparse array. Since Dictionary is a subtype
854 * of FixedArray, the class can be used by both fast and slow cases.
855 * The second parameter of the constructor, fast_elements, specifies
856 * whether the storage is a FixedArray or Dictionary.
857 *
858 * An index limit is used to deal with the situation that a result array
859 * length overflows 32-bit non-negative integer.
860 */
861 class ArrayConcatVisitor {
862 public:
863 ArrayConcatVisitor(Isolate* isolate, Handle<HeapObject> storage,
864 bool fast_elements)
865 : isolate_(isolate),
866 storage_(isolate->global_handles()->Create(*storage)),
867 index_offset_(0u),
868 bit_field_(
869 FastElementsField::encode(fast_elements) |
870 ExceedsLimitField::encode(false) |
871 IsFixedArrayField::encode(storage->IsFixedArray()) |
872 HasSimpleElementsField::encode(storage->IsFixedArray() ||
873 storage->map()->instance_type() >
874 LAST_CUSTOM_ELEMENTS_RECEIVER)) {
875 DCHECK(!(this->fast_elements() && !is_fixed_array()));
876 }
877
878 ~ArrayConcatVisitor() { clear_storage(); }
879
880 MUST_USE_RESULT bool visit(uint32_t i, Handle<Object> elm) {
881 uint32_t index = index_offset_ + i;
882
883 if (i >= JSObject::kMaxElementCount - index_offset_) {
884 set_exceeds_array_limit(true);
885 // Exception hasn't been thrown at this point. Return true to
886 // break out, and caller will throw. !visit would imply that
887 // there is already a pending exception.
888 return true;
889 }
890
891 if (!is_fixed_array()) {
892 LookupIterator it(isolate_, storage_, index, LookupIterator::OWN);
893 MAYBE_RETURN(
894 JSReceiver::CreateDataProperty(&it, elm, Object::THROW_ON_ERROR),
895 false);
896 return true;
897 }
898
899 if (fast_elements()) {
900 if (index < static_cast<uint32_t>(storage_fixed_array()->length())) {
901 storage_fixed_array()->set(index, *elm);
902 return true;
903 }
904 // Our initial estimate of length was foiled, possibly by
905 // getters on the arrays increasing the length of later arrays
906 // during iteration.
907 // This shouldn't happen in anything but pathological cases.
908 SetDictionaryMode();
909 // Fall-through to dictionary mode.
910 }
911 DCHECK(!fast_elements());
912 Handle<SeededNumberDictionary> dict(
913 SeededNumberDictionary::cast(*storage_));
914 // The object holding this backing store has just been allocated, so
915 // it cannot yet be used as a prototype.
916 Handle<JSObject> not_a_prototype_holder;
917 Handle<SeededNumberDictionary> result = SeededNumberDictionary::AtNumberPut(
918 dict, index, elm, not_a_prototype_holder);
919 if (!result.is_identical_to(dict)) {
920 // Dictionary needed to grow.
921 clear_storage();
922 set_storage(*result);
923 }
924 return true;
925 }
926
927 void increase_index_offset(uint32_t delta) {
928 if (JSObject::kMaxElementCount - index_offset_ < delta) {
929 index_offset_ = JSObject::kMaxElementCount;
930 } else {
931 index_offset_ += delta;
932 }
933 // If the initial length estimate was off (see special case in visit()),
934 // but the array blowing the limit didn't contain elements beyond the
935 // provided-for index range, go to dictionary mode now.
936 if (fast_elements() &&
937 index_offset_ >
938 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
939 SetDictionaryMode();
940 }
941 }
942
943 bool exceeds_array_limit() const {
944 return ExceedsLimitField::decode(bit_field_);
945 }
946
947 Handle<JSArray> ToArray() {
948 DCHECK(is_fixed_array());
949 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
950 Handle<Object> length =
951 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
952 Handle<Map> map = JSObject::GetElementsTransitionMap(
953 array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
954 array->set_map(*map);
955 array->set_length(*length);
956 array->set_elements(*storage_fixed_array());
957 return array;
958 }
959
960 // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever
961 // (otherwise)
962 Handle<FixedArray> storage_fixed_array() {
963 DCHECK(is_fixed_array());
964 DCHECK(has_simple_elements());
965 return Handle<FixedArray>::cast(storage_);
966 }
967 Handle<JSReceiver> storage_jsreceiver() {
968 DCHECK(!is_fixed_array());
969 return Handle<JSReceiver>::cast(storage_);
970 }
971 bool has_simple_elements() const {
972 return HasSimpleElementsField::decode(bit_field_);
973 }
974
975 private:
976 // Convert storage to dictionary mode.
977 void SetDictionaryMode() {
978 DCHECK(fast_elements() && is_fixed_array());
979 Handle<FixedArray> current_storage = storage_fixed_array();
980 Handle<SeededNumberDictionary> slow_storage(
981 SeededNumberDictionary::New(isolate_, current_storage->length()));
982 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
983 FOR_WITH_HANDLE_SCOPE(
984 isolate_, uint32_t, i = 0, i, i < current_length, i++, {
985 Handle<Object> element(current_storage->get(i), isolate_);
986 if (!element->IsTheHole(isolate_)) {
987 // The object holding this backing store has just been allocated, so
988 // it cannot yet be used as a prototype.
989 Handle<JSObject> not_a_prototype_holder;
990 Handle<SeededNumberDictionary> new_storage =
991 SeededNumberDictionary::AtNumberPut(slow_storage, i, element,
992 not_a_prototype_holder);
993 if (!new_storage.is_identical_to(slow_storage)) {
994 slow_storage = loop_scope.CloseAndEscape(new_storage);
995 }
996 }
997 });
998 clear_storage();
999 set_storage(*slow_storage);
1000 set_fast_elements(false);
1001 }
1002
1003 inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); }
1004
1005 inline void set_storage(FixedArray* storage) {
1006 DCHECK(is_fixed_array());
1007 DCHECK(has_simple_elements());
1008 storage_ = isolate_->global_handles()->Create(storage);
1009 }
1010
1011 class FastElementsField : public BitField<bool, 0, 1> {};
1012 class ExceedsLimitField : public BitField<bool, 1, 1> {};
1013 class IsFixedArrayField : public BitField<bool, 2, 1> {};
1014 class HasSimpleElementsField : public BitField<bool, 3, 1> {};
1015
1016 bool fast_elements() const { return FastElementsField::decode(bit_field_); }
1017 void set_fast_elements(bool fast) {
1018 bit_field_ = FastElementsField::update(bit_field_, fast);
1019 }
1020 void set_exceeds_array_limit(bool exceeds) {
1021 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
1022 }
1023 bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); }
1024
1025 Isolate* isolate_;
1026 Handle<Object> storage_; // Always a global handle.
1027 // Index after last seen index. Always less than or equal to
1028 // JSObject::kMaxElementCount.
1029 uint32_t index_offset_;
1030 uint32_t bit_field_;
1031 };
1032
1033 uint32_t EstimateElementCount(Handle<JSArray> array) {
1034 DisallowHeapAllocation no_gc;
1035 uint32_t length = static_cast<uint32_t>(array->length()->Number());
1036 int element_count = 0;
1037 switch (array->GetElementsKind()) {
1038 case FAST_SMI_ELEMENTS:
1039 case FAST_HOLEY_SMI_ELEMENTS:
1040 case FAST_ELEMENTS:
1041 case FAST_HOLEY_ELEMENTS: {
1042 // Fast elements can't have lengths that are not representable by
1043 // a 32-bit signed integer.
1044 DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
1045 int fast_length = static_cast<int>(length);
1046 Isolate* isolate = array->GetIsolate();
1047 FixedArray* elements = FixedArray::cast(array->elements());
1048 for (int i = 0; i < fast_length; i++) {
1049 if (!elements->get(i)->IsTheHole(isolate)) element_count++;
1050 }
1051 break;
1052 }
1053 case FAST_DOUBLE_ELEMENTS:
1054 case FAST_HOLEY_DOUBLE_ELEMENTS: {
1055 // Fast elements can't have lengths that are not representable by
1056 // a 32-bit signed integer.
1057 DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
1058 int fast_length = static_cast<int>(length);
1059 if (array->elements()->IsFixedArray()) {
1060 DCHECK(FixedArray::cast(array->elements())->length() == 0);
1061 break;
1062 }
1063 FixedDoubleArray* elements = FixedDoubleArray::cast(array->elements());
1064 for (int i = 0; i < fast_length; i++) {
1065 if (!elements->is_the_hole(i)) element_count++;
1066 }
1067 break;
1068 }
1069 case DICTIONARY_ELEMENTS: {
1070 SeededNumberDictionary* dictionary =
1071 SeededNumberDictionary::cast(array->elements());
1072 Isolate* isolate = dictionary->GetIsolate();
1073 int capacity = dictionary->Capacity();
1074 for (int i = 0; i < capacity; i++) {
1075 Object* key = dictionary->KeyAt(i);
1076 if (dictionary->IsKey(isolate, key)) {
1077 element_count++;
1078 }
1079 }
1080 break;
1081 }
1082 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
1083
1084 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1085 #undef TYPED_ARRAY_CASE
1086 // External arrays are always dense.
1087 return length;
1088 case NO_ELEMENTS:
1089 return 0;
1090 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1091 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
1092 case FAST_STRING_WRAPPER_ELEMENTS:
1093 case SLOW_STRING_WRAPPER_ELEMENTS:
1094 UNREACHABLE();
1095 return 0;
1096 }
1097 // As an estimate, we assume that the prototype doesn't contain any
1098 // inherited elements.
1099 return element_count;
1100 }
1101
1102 // Used for sorting indices in a List<uint32_t>.
1103 int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
1104 uint32_t a = *ap;
1105 uint32_t b = *bp;
1106 return (a == b) ? 0 : (a < b) ? -1 : 1;
1107 }
1108
1109 void CollectElementIndices(Handle<JSObject> object, uint32_t range,
1110 List<uint32_t>* indices) {
1111 Isolate* isolate = object->GetIsolate();
1112 ElementsKind kind = object->GetElementsKind();
1113 switch (kind) {
1114 case FAST_SMI_ELEMENTS:
1115 case FAST_ELEMENTS:
1116 case FAST_HOLEY_SMI_ELEMENTS:
1117 case FAST_HOLEY_ELEMENTS: {
1118 DisallowHeapAllocation no_gc;
1119 FixedArray* elements = FixedArray::cast(object->elements());
1120 uint32_t length = static_cast<uint32_t>(elements->length());
1121 if (range < length) length = range;
1122 for (uint32_t i = 0; i < length; i++) {
1123 if (!elements->get(i)->IsTheHole(isolate)) {
1124 indices->Add(i);
1125 }
1126 }
1127 break;
1128 }
1129 case FAST_HOLEY_DOUBLE_ELEMENTS:
1130 case FAST_DOUBLE_ELEMENTS: {
1131 if (object->elements()->IsFixedArray()) {
1132 DCHECK(object->elements()->length() == 0);
1133 break;
1134 }
1135 Handle<FixedDoubleArray> elements(
1136 FixedDoubleArray::cast(object->elements()));
1137 uint32_t length = static_cast<uint32_t>(elements->length());
1138 if (range < length) length = range;
1139 for (uint32_t i = 0; i < length; i++) {
1140 if (!elements->is_the_hole(i)) {
1141 indices->Add(i);
1142 }
1143 }
1144 break;
1145 }
1146 case DICTIONARY_ELEMENTS: {
1147 DisallowHeapAllocation no_gc;
1148 SeededNumberDictionary* dict =
1149 SeededNumberDictionary::cast(object->elements());
1150 uint32_t capacity = dict->Capacity();
1151 FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, j = 0, j, j < capacity, j++, {
1152 Object* k = dict->KeyAt(j);
1153 if (!dict->IsKey(isolate, k)) continue;
1154 DCHECK(k->IsNumber());
1155 uint32_t index = static_cast<uint32_t>(k->Number());
1156 if (index < range) {
1157 indices->Add(index);
1158 }
1159 });
1160 break;
1161 }
1162 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
1163
1164 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1165 #undef TYPED_ARRAY_CASE
1166 {
1167 uint32_t length = static_cast<uint32_t>(
1168 FixedArrayBase::cast(object->elements())->length());
1169 if (range <= length) {
1170 length = range;
1171 // We will add all indices, so we might as well clear it first
1172 // and avoid duplicates.
1173 indices->Clear();
1174 }
1175 for (uint32_t i = 0; i < length; i++) {
1176 indices->Add(i);
1177 }
1178 if (length == range) return; // All indices accounted for already.
1179 break;
1180 }
1181 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1182 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
1183 ElementsAccessor* accessor = object->GetElementsAccessor();
1184 for (uint32_t i = 0; i < range; i++) {
1185 if (accessor->HasElement(object, i)) {
1186 indices->Add(i);
1187 }
1188 }
1189 break;
1190 }
1191 case FAST_STRING_WRAPPER_ELEMENTS:
1192 case SLOW_STRING_WRAPPER_ELEMENTS: {
1193 DCHECK(object->IsJSValue());
1194 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1195 DCHECK(js_value->value()->IsString());
1196 Handle<String> string(String::cast(js_value->value()), isolate);
1197 uint32_t length = static_cast<uint32_t>(string->length());
1198 uint32_t i = 0;
1199 uint32_t limit = Min(length, range);
1200 for (; i < limit; i++) {
1201 indices->Add(i);
1202 }
1203 ElementsAccessor* accessor = object->GetElementsAccessor();
1204 for (; i < range; i++) {
1205 if (accessor->HasElement(object, i)) {
1206 indices->Add(i);
1207 }
1208 }
1209 break;
1210 }
1211 case NO_ELEMENTS:
1212 break;
1213 }
1214
1215 PrototypeIterator iter(isolate, object);
1216 if (!iter.IsAtEnd()) {
1217 // The prototype will usually have no inherited element indices,
1218 // but we have to check.
1219 CollectElementIndices(PrototypeIterator::GetCurrent<JSObject>(iter), range,
1220 indices);
1221 }
1222 }
1223
1224 bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver,
1225 uint32_t length, ArrayConcatVisitor* visitor) {
1226 FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, ++i, {
1227 Maybe<bool> maybe = JSReceiver::HasElement(receiver, i);
1228 if (!maybe.IsJust()) return false;
1229 if (maybe.FromJust()) {
1230 Handle<Object> element_value;
1231 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1232 isolate, element_value, JSReceiver::GetElement(isolate, receiver, i),
1233 false);
1234 if (!visitor->visit(i, element_value)) return false;
1235 }
1236 });
1237 visitor->increase_index_offset(length);
1238 return true;
1239 }
1240 /**
1241 * A helper function that visits "array" elements of a JSReceiver in numerical
1242 * order.
1243 *
1244 * The visitor argument called for each existing element in the array
1245 * with the element index and the element's value.
1246 * Afterwards it increments the base-index of the visitor by the array
1247 * length.
1248 * Returns false if any access threw an exception, otherwise true.
1249 */
1250 bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
1251 ArrayConcatVisitor* visitor) {
1252 uint32_t length = 0;
1253
1254 if (receiver->IsJSArray()) {
1255 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
1256 length = static_cast<uint32_t>(array->length()->Number());
1257 } else {
1258 Handle<Object> val;
1259 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1260 isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false);
1261 // TODO(caitp): Support larger element indexes (up to 2^53-1).
1262 if (!val->ToUint32(&length)) {
1263 length = 0;
1264 }
1265 // TODO(cbruni): handle other element kind as well
1266 return IterateElementsSlow(isolate, receiver, length, visitor);
1267 }
1268
1269 if (!HasOnlySimpleElements(isolate, *receiver) ||
1270 !visitor->has_simple_elements()) {
1271 return IterateElementsSlow(isolate, receiver, length, visitor);
1272 }
1273 Handle<JSObject> array = Handle<JSObject>::cast(receiver);
1274
1275 switch (array->GetElementsKind()) {
1276 case FAST_SMI_ELEMENTS:
1277 case FAST_ELEMENTS:
1278 case FAST_HOLEY_SMI_ELEMENTS:
1279 case FAST_HOLEY_ELEMENTS: {
1280 // Run through the elements FixedArray and use HasElement and GetElement
1281 // to check the prototype for missing elements.
1282 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
1283 int fast_length = static_cast<int>(length);
1284 DCHECK(fast_length <= elements->length());
1285 FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, {
1286 Handle<Object> element_value(elements->get(j), isolate);
1287 if (!element_value->IsTheHole(isolate)) {
1288 if (!visitor->visit(j, element_value)) return false;
1289 } else {
1290 Maybe<bool> maybe = JSReceiver::HasElement(array, j);
1291 if (!maybe.IsJust()) return false;
1292 if (maybe.FromJust()) {
1293 // Call GetElement on array, not its prototype, or getters won't
1294 // have the correct receiver.
1295 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1296 isolate, element_value,
1297 JSReceiver::GetElement(isolate, array, j), false);
1298 if (!visitor->visit(j, element_value)) return false;
1299 }
1300 }
1301 });
1302 break;
1303 }
1304 case FAST_HOLEY_DOUBLE_ELEMENTS:
1305 case FAST_DOUBLE_ELEMENTS: {
1306 // Empty array is FixedArray but not FixedDoubleArray.
1307 if (length == 0) break;
1308 // Run through the elements FixedArray and use HasElement and GetElement
1309 // to check the prototype for missing elements.
1310 if (array->elements()->IsFixedArray()) {
1311 DCHECK(array->elements()->length() == 0);
1312 break;
1313 }
1314 Handle<FixedDoubleArray> elements(
1315 FixedDoubleArray::cast(array->elements()));
1316 int fast_length = static_cast<int>(length);
1317 DCHECK(fast_length <= elements->length());
1318 FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, {
1319 if (!elements->is_the_hole(j)) {
1320 double double_value = elements->get_scalar(j);
1321 Handle<Object> element_value =
1322 isolate->factory()->NewNumber(double_value);
1323 if (!visitor->visit(j, element_value)) return false;
1324 } else {
1325 Maybe<bool> maybe = JSReceiver::HasElement(array, j);
1326 if (!maybe.IsJust()) return false;
1327 if (maybe.FromJust()) {
1328 // Call GetElement on array, not its prototype, or getters won't
1329 // have the correct receiver.
1330 Handle<Object> element_value;
1331 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1332 isolate, element_value,
1333 JSReceiver::GetElement(isolate, array, j), false);
1334 if (!visitor->visit(j, element_value)) return false;
1335 }
1336 }
1337 });
1338 break;
1339 }
1340
1341 case DICTIONARY_ELEMENTS: {
1342 Handle<SeededNumberDictionary> dict(array->element_dictionary());
1343 List<uint32_t> indices(dict->Capacity() / 2);
1344 // Collect all indices in the object and the prototypes less
1345 // than length. This might introduce duplicates in the indices list.
1346 CollectElementIndices(array, length, &indices);
1347 indices.Sort(&compareUInt32);
1348 int n = indices.length();
1349 FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < n, (void)0, {
1350 uint32_t index = indices[j];
1351 Handle<Object> element;
1352 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1353 isolate, element, JSReceiver::GetElement(isolate, array, index),
1354 false);
1355 if (!visitor->visit(index, element)) return false;
1356 // Skip to next different index (i.e., omit duplicates).
1357 do {
1358 j++;
1359 } while (j < n && indices[j] == index);
1360 });
1361 break;
1362 }
1363 case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
1364 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
1365 FOR_WITH_HANDLE_SCOPE(
1366 isolate, uint32_t, index = 0, index, index < length, index++, {
1367 Handle<Object> element;
1368 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1369 isolate, element, JSReceiver::GetElement(isolate, array, index),
1370 false);
1371 if (!visitor->visit(index, element)) return false;
1372 });
1373 break;
1374 }
1375 case NO_ELEMENTS:
1376 break;
1377 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
1378 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1379 #undef TYPED_ARRAY_CASE
1380 return IterateElementsSlow(isolate, receiver, length, visitor);
1381 case FAST_STRING_WRAPPER_ELEMENTS:
1382 case SLOW_STRING_WRAPPER_ELEMENTS:
1383 // |array| is guaranteed to be an array or typed array.
1384 UNREACHABLE();
1385 break;
1386 }
1387 visitor->increase_index_offset(length);
1388 return true;
1389 }
1390
1391 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) {
1392 HandleScope handle_scope(isolate);
1393 if (!obj->IsJSReceiver()) return Just(false);
1394 if (!isolate->IsIsConcatSpreadableLookupChainIntact(JSReceiver::cast(*obj))) {
1395 // Slow path if @@isConcatSpreadable has been used.
1396 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol());
1397 Handle<Object> value;
1398 MaybeHandle<Object> maybeValue =
1399 i::Runtime::GetObjectProperty(isolate, obj, key);
1400 if (!maybeValue.ToHandle(&value)) return Nothing<bool>();
1401 if (!value->IsUndefined(isolate)) return Just(value->BooleanValue());
1402 }
1403 return Object::IsArray(obj);
1404 }
1405
1406 Object* Slow_ArrayConcat(BuiltinArguments* args, Handle<Object> species,
1407 Isolate* isolate) {
1408 int argument_count = args->length();
1409
1410 bool is_array_species = *species == isolate->context()->array_function();
1411
1412 // Pass 1: estimate the length and number of elements of the result.
1413 // The actual length can be larger if any of the arguments have getters
1414 // that mutate other arguments (but will otherwise be precise).
1415 // The number of elements is precise if there are no inherited elements.
1416
1417 ElementsKind kind = FAST_SMI_ELEMENTS;
1418
1419 uint32_t estimate_result_length = 0;
1420 uint32_t estimate_nof_elements = 0;
1421 FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < argument_count, i++, {
1422 Handle<Object> obj((*args)[i], isolate);
1423 uint32_t length_estimate;
1424 uint32_t element_estimate;
1425 if (obj->IsJSArray()) {
1426 Handle<JSArray> array(Handle<JSArray>::cast(obj));
1427 length_estimate = static_cast<uint32_t>(array->length()->Number());
1428 if (length_estimate != 0) {
1429 ElementsKind array_kind =
1430 GetPackedElementsKind(array->GetElementsKind());
1431 kind = GetMoreGeneralElementsKind(kind, array_kind);
1432 }
1433 element_estimate = EstimateElementCount(array);
1434 } else {
1435 if (obj->IsHeapObject()) {
1436 kind = GetMoreGeneralElementsKind(
1437 kind, obj->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS);
1438 }
1439 length_estimate = 1;
1440 element_estimate = 1;
1441 }
1442 // Avoid overflows by capping at kMaxElementCount.
1443 if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) {
1444 estimate_result_length = JSObject::kMaxElementCount;
1445 } else {
1446 estimate_result_length += length_estimate;
1447 }
1448 if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) {
1449 estimate_nof_elements = JSObject::kMaxElementCount;
1450 } else {
1451 estimate_nof_elements += element_estimate;
1452 }
1453 });
1454
1455 // If estimated number of elements is more than half of length, a
1456 // fixed array (fast case) is more time and space-efficient than a
1457 // dictionary.
1458 bool fast_case = is_array_species &&
1459 (estimate_nof_elements * 2) >= estimate_result_length &&
1460 isolate->IsIsConcatSpreadableLookupChainIntact();
1461
1462 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
1463 Handle<FixedArrayBase> storage =
1464 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
1465 int j = 0;
1466 bool failure = false;
1467 if (estimate_result_length > 0) {
1468 Handle<FixedDoubleArray> double_storage =
1469 Handle<FixedDoubleArray>::cast(storage);
1470 for (int i = 0; i < argument_count; i++) {
1471 Handle<Object> obj((*args)[i], isolate);
1472 if (obj->IsSmi()) {
1473 double_storage->set(j, Smi::cast(*obj)->value());
1474 j++;
1475 } else if (obj->IsNumber()) {
1476 double_storage->set(j, obj->Number());
1477 j++;
1478 } else {
1479 DisallowHeapAllocation no_gc;
1480 JSArray* array = JSArray::cast(*obj);
1481 uint32_t length = static_cast<uint32_t>(array->length()->Number());
1482 switch (array->GetElementsKind()) {
1483 case FAST_HOLEY_DOUBLE_ELEMENTS:
1484 case FAST_DOUBLE_ELEMENTS: {
1485 // Empty array is FixedArray but not FixedDoubleArray.
1486 if (length == 0) break;
1487 FixedDoubleArray* elements =
1488 FixedDoubleArray::cast(array->elements());
1489 for (uint32_t i = 0; i < length; i++) {
1490 if (elements->is_the_hole(i)) {
1491 // TODO(jkummerow/verwaest): We could be a bit more clever
1492 // here: Check if there are no elements/getters on the
1493 // prototype chain, and if so, allow creation of a holey
1494 // result array.
1495 // Same thing below (holey smi case).
1496 failure = true;
1497 break;
1498 }
1499 double double_value = elements->get_scalar(i);
1500 double_storage->set(j, double_value);
1501 j++;
1502 }
1503 break;
1504 }
1505 case FAST_HOLEY_SMI_ELEMENTS:
1506 case FAST_SMI_ELEMENTS: {
1507 Object* the_hole = isolate->heap()->the_hole_value();
1508 FixedArray* elements(FixedArray::cast(array->elements()));
1509 for (uint32_t i = 0; i < length; i++) {
1510 Object* element = elements->get(i);
1511 if (element == the_hole) {
1512 failure = true;
1513 break;
1514 }
1515 int32_t int_value = Smi::cast(element)->value();
1516 double_storage->set(j, int_value);
1517 j++;
1518 }
1519 break;
1520 }
1521 case FAST_HOLEY_ELEMENTS:
1522 case FAST_ELEMENTS:
1523 case DICTIONARY_ELEMENTS:
1524 case NO_ELEMENTS:
1525 DCHECK_EQ(0u, length);
1526 break;
1527 default:
1528 UNREACHABLE();
1529 }
1530 }
1531 if (failure) break;
1532 }
1533 }
1534 if (!failure) {
1535 return *isolate->factory()->NewJSArrayWithElements(storage, kind, j);
1536 }
1537 // In case of failure, fall through.
1538 }
1539
1540 Handle<HeapObject> storage;
1541 if (fast_case) {
1542 // The backing storage array must have non-existing elements to preserve
1543 // holes across concat operations.
1544 storage =
1545 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
1546 } else if (is_array_species) {
1547 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
1548 uint32_t at_least_space_for =
1549 estimate_nof_elements + (estimate_nof_elements >> 2);
1550 storage = SeededNumberDictionary::New(isolate, at_least_space_for);
1551 } else {
1552 DCHECK(species->IsConstructor());
1553 Handle<Object> length(Smi::kZero, isolate);
1554 Handle<Object> storage_object;
1555 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1556 isolate, storage_object,
1557 Execution::New(isolate, species, species, 1, &length));
1558 storage = Handle<HeapObject>::cast(storage_object);
1559 }
1560
1561 ArrayConcatVisitor visitor(isolate, storage, fast_case);
1562
1563 for (int i = 0; i < argument_count; i++) {
1564 Handle<Object> obj((*args)[i], isolate);
1565 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj);
1566 MAYBE_RETURN(spreadable, isolate->heap()->exception());
1567 if (spreadable.FromJust()) {
1568 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj);
1569 if (!IterateElements(isolate, object, &visitor)) {
1570 return isolate->heap()->exception();
1571 }
1572 } else {
1573 if (!visitor.visit(0, obj)) return isolate->heap()->exception();
1574 visitor.increase_index_offset(1);
1575 }
1576 }
1577
1578 if (visitor.exceeds_array_limit()) {
1579 THROW_NEW_ERROR_RETURN_FAILURE(
1580 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength));
1581 }
1582
1583 if (is_array_species) {
1584 return *visitor.ToArray();
1585 } else {
1586 return *visitor.storage_jsreceiver();
1587 }
1588 }
1589
1590 bool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) {
1591 DisallowHeapAllocation no_gc;
1592 Map* map = obj->map();
1593 // If there is only the 'length' property we are fine.
1594 if (map->prototype() ==
1595 isolate->native_context()->initial_array_prototype() &&
1596 map->NumberOfOwnDescriptors() == 1) {
1597 return true;
1598 }
1599 // TODO(cbruni): slower lookup for array subclasses and support slow
1600 // @@IsConcatSpreadable lookup.
1601 return false;
1602 }
1603
1604 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate,
1605 BuiltinArguments* args) {
1606 if (!isolate->IsIsConcatSpreadableLookupChainIntact()) {
1607 return MaybeHandle<JSArray>();
1608 }
1609 // We shouldn't overflow when adding another len.
1610 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
1611 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
1612 STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt);
1613 USE(kHalfOfMaxInt);
1614
1615 int n_arguments = args->length();
1616 int result_len = 0;
1617 {
1618 DisallowHeapAllocation no_gc;
1619 // Iterate through all the arguments performing checks
1620 // and calculating total length.
1621 for (int i = 0; i < n_arguments; i++) {
1622 Object* arg = (*args)[i];
1623 if (!arg->IsJSArray()) return MaybeHandle<JSArray>();
1624 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) {
1625 return MaybeHandle<JSArray>();
1626 }
1627 // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS.
1628 if (!JSObject::cast(arg)->HasFastElements()) {
1629 return MaybeHandle<JSArray>();
1630 }
1631 Handle<JSArray> array(JSArray::cast(arg), isolate);
1632 if (!IsSimpleArray(isolate, array)) {
1633 return MaybeHandle<JSArray>();
1634 }
1635 // The Array length is guaranted to be <= kHalfOfMaxInt thus we won't
1636 // overflow.
1637 result_len += Smi::cast(array->length())->value();
1638 DCHECK(result_len >= 0);
1639 // Throw an Error if we overflow the FixedArray limits
1640 if (FixedDoubleArray::kMaxLength < result_len ||
1641 FixedArray::kMaxLength < result_len) {
1642 AllowHeapAllocation gc;
1643 THROW_NEW_ERROR(isolate,
1644 NewRangeError(MessageTemplate::kInvalidArrayLength),
1645 JSArray);
1646 }
1647 }
1648 }
1649 return ElementsAccessor::Concat(isolate, args, n_arguments, result_len);
1650 }
1651
1652 } // namespace
1653
1654 // ES6 22.1.3.1 Array.prototype.concat
1655 BUILTIN(ArrayConcat) {
1656 HandleScope scope(isolate);
1657
1658 Handle<Object> receiver = args.receiver();
1659 // TODO(bmeurer): Do we really care about the exact exception message here?
1660 if (receiver->IsNullOrUndefined(isolate)) {
1661 THROW_NEW_ERROR_RETURN_FAILURE(
1662 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
1663 isolate->factory()->NewStringFromAsciiChecked(
1664 "Array.prototype.concat")));
1665 }
1666 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1667 isolate, receiver, Object::ToObject(isolate, args.receiver()));
1668 args[0] = *receiver;
1669
1670 Handle<JSArray> result_array;
1671
1672 // Avoid a real species read to avoid extra lookups to the array constructor
1673 if (V8_LIKELY(receiver->IsJSArray() &&
1674 Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) &&
1675 isolate->IsArraySpeciesLookupChainIntact())) {
1676 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
1677 return *result_array;
1678 }
1679 if (isolate->has_pending_exception()) return isolate->heap()->exception();
1680 }
1681 // Reading @@species happens before anything else with a side effect, so
1682 // we can do it here to determine whether to take the fast path.
1683 Handle<Object> species;
1684 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1685 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver));
1686 if (*species == *isolate->array_function()) {
1687 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
1688 return *result_array;
1689 }
1690 if (isolate->has_pending_exception()) return isolate->heap()->exception();
1691 }
1692 return Slow_ArrayConcat(&args, species, isolate);
1693 }
1694
1695 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { 465 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
1696 Node* object = Parameter(1); 466 Node* object = Parameter(1);
1697 Node* context = Parameter(4); 467 Node* context = Parameter(4);
1698 468
1699 Label call_runtime(this), return_true(this), return_false(this); 469 Label call_runtime(this), return_true(this), return_false(this);
1700 470
1701 GotoIf(TaggedIsSmi(object), &return_false); 471 GotoIf(TaggedIsSmi(object), &return_false);
1702 Node* instance_type = LoadInstanceType(object); 472 Node* instance_type = LoadInstanceType(object);
1703 473
1704 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), 474 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)),
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1742 Node* const len = LoadAndUntagObjectField(array, JSArray::kLengthOffset); 512 Node* const len = LoadAndUntagObjectField(array, JSArray::kLengthOffset);
1743 513
1744 GotoIf(IsUndefined(start_from), &select_loop); 514 GotoIf(IsUndefined(start_from), &select_loop);
1745 515
1746 // Bailout to slow path if startIndex is not an Smi. 516 // Bailout to slow path if startIndex is not an Smi.
1747 Branch(TaggedIsSmi(start_from), &init_k, &call_runtime); 517 Branch(TaggedIsSmi(start_from), &init_k, &call_runtime);
1748 518
1749 Bind(&init_k); 519 Bind(&init_k);
1750 CSA_ASSERT(this, TaggedIsSmi(start_from)); 520 CSA_ASSERT(this, TaggedIsSmi(start_from));
1751 Node* const untagged_start_from = SmiToWord(start_from); 521 Node* const untagged_start_from = SmiToWord(start_from);
1752 index_var.Bind(Select( 522 index_var.Bind(
1753 IntPtrGreaterThanOrEqual(untagged_start_from, IntPtrConstant(0)), 523 Select(IntPtrGreaterThanOrEqual(untagged_start_from, IntPtrConstant(0)),
1754 [=]() { return untagged_start_from; }, 524 [=]() { return untagged_start_from; },
1755 [=]() { 525 [=]() {
1756 Node* const index = IntPtrAdd(len, untagged_start_from); 526 Node* const index = IntPtrAdd(len, untagged_start_from);
1757 return SelectConstant(IntPtrLessThan(index, IntPtrConstant(0)), 527 return SelectConstant(IntPtrLessThan(index, IntPtrConstant(0)),
1758 IntPtrConstant(0), index, 528 IntPtrConstant(0), index,
1759 MachineType::PointerRepresentation()); 529 MachineType::PointerRepresentation());
1760 }, 530 },
1761 MachineType::PointerRepresentation())); 531 MachineType::PointerRepresentation()));
1762 532
1763 Goto(&select_loop); 533 Goto(&select_loop);
1764 Bind(&select_loop); 534 Bind(&select_loop);
1765 static int32_t kElementsKind[] = { 535 static int32_t kElementsKind[] = {
1766 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, 536 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS,
1767 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, 537 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS,
1768 }; 538 };
1769 539
1770 Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this); 540 Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this);
1771 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, 541 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects,
(...skipping 967 matching lines...) Expand 10 before | Expand all | Expand 10 after
2739 { 1509 {
2740 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); 1510 Node* message = SmiConstant(MessageTemplate::kDetachedOperation);
2741 CallRuntime(Runtime::kThrowTypeError, context, message, 1511 CallRuntime(Runtime::kThrowTypeError, context, message,
2742 HeapConstant(operation)); 1512 HeapConstant(operation));
2743 Unreachable(); 1513 Unreachable();
2744 } 1514 }
2745 } 1515 }
2746 1516
2747 } // namespace internal 1517 } // namespace internal
2748 } // namespace v8 1518 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-array.cc ('k') | src/builtins/builtins-async.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698