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

Side by Side Diff: src/compiler/js-builtin-reducer.cc

Issue 2484003002: [builtins] implement JSBuiltinReducer for ArrayIteratorNext() (Closed)
Patch Set: CheckIf() for ArrayBufferWasNeutered() rather than a branch, which hopefully can be eliminated, and… Created 4 years, 1 month 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
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 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 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/compiler/js-builtin-reducer.h" 5 #include "src/compiler/js-builtin-reducer.h"
6 6
7 #include "src/compilation-dependencies.h" 7 #include "src/compilation-dependencies.h"
8 #include "src/compiler/access-builder.h" 8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/js-graph.h" 9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/node-matchers.h" 10 #include "src/compiler/node-matchers.h"
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 } 168 }
169 return receiver_map->instance_type() == JS_ARRAY_TYPE && 169 return receiver_map->instance_type() == JS_ARRAY_TYPE &&
170 IsFastElementsKind(receiver_map->elements_kind()) && 170 IsFastElementsKind(receiver_map->elements_kind()) &&
171 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() && 171 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() &&
172 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) && 172 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
173 isolate->IsFastArrayConstructorPrototypeChainIntact() && 173 isolate->IsFastArrayConstructorPrototypeChainIntact() &&
174 isolate->IsAnyInitialArrayPrototype(receiver_prototype) && 174 isolate->IsAnyInitialArrayPrototype(receiver_prototype) &&
175 !IsReadOnlyLengthDescriptor(receiver_map); 175 !IsReadOnlyLengthDescriptor(receiver_map);
176 } 176 }
177 177
178 bool CanInlineJSArrayIteration(Handle<Map> receiver_map) {
179 Isolate* const isolate = receiver_map->GetIsolate();
180 // Ensure that the [[Prototype]] is actually an exotic Array
181 if (!receiver_map->prototype()->IsJSArray()) return false;
182
183 // Don't inline JSArrays with slow elements of any kind
184 if (!IsFastElementsKind(receiver_map->elements_kind())) return false;
185
186 // If the receiver map has packed elements, no need to check the prototype.
187 // This requires a MapCheck where this is used.
188 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) return true;
Benedikt Meurer 2016/11/09 05:37:05 Return true if non-holey.
caitp 2016/11/09 17:40:16 oop, good catch.
189
190 Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
191 isolate);
192 // Ensure all prototypes of the {receiver} are stable.
193 for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver);
194 !it.IsAtEnd(); it.Advance()) {
195 Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it);
196 if (!current->map()->is_stable()) return false;
197 }
198
199 // For holey Arrays, ensure that the array_protector cell is valid (must be
200 // a CompilationDependency), and the JSArray prototype has not been altered.
201 return receiver_map->instance_type() == JS_ARRAY_TYPE &&
202 (!receiver_map->is_dictionary_map() || receiver_map->is_stable()) &&
203 isolate->IsFastArrayConstructorPrototypeChainIntact() &&
204 isolate->IsAnyInitialArrayPrototype(receiver_prototype);
205 }
206
178 } // namespace 207 } // namespace
179 208
209 Reduction JSBuiltinReducer::ReduceArrayIterator(Node* node,
210 IterationKind kind) {
211 Handle<Map> receiver_map;
212 if (GetMapWitness(node).ToHandle(&receiver_map)) {
213 return ReduceArrayIterator(receiver_map, node, kind, false);
214 }
215 return NoChange();
216 }
217
218 Reduction JSBuiltinReducer::ReduceTypedArrayIterator(Node* node,
219 IterationKind kind) {
220 Handle<Map> receiver_map;
221 if (GetMapWitness(node).ToHandle(&receiver_map) &&
222 receiver_map->instance_type() == JS_TYPED_ARRAY_TYPE) {
223 return ReduceArrayIterator(receiver_map, node, kind, true);
224 }
225 return NoChange();
226 }
227
228 Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
229 Node* node, IterationKind kind,
230 bool for_typed_array) {
231 Node* receiver = NodeProperties::GetValueInput(node, 1);
232 Node* effect = NodeProperties::GetEffectInput(node);
233 Node* control = NodeProperties::GetControlInput(node);
234
235 if (for_typed_array) {
236 // For JSTypedArray iterator methods, deopt if the buffer is neutered
237 DCHECK_EQ(receiver_map->instance_type(), JS_TYPED_ARRAY_TYPE);
238 Node* buffer = effect = graph()->NewNode(
239 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
240 receiver, effect, control);
241
242 Node* check = effect = graph()->NewNode(
243 simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
244 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
245 }
246
247 int map_index = -1;
248 Node* object_map = jsgraph()->UndefinedConstant();
249 switch (receiver_map->instance_type()) {
250 case JS_ARRAY_TYPE:
251 if (kind == IterationKind::kKeys) {
252 map_index = Context::FAST_ARRAY_KEY_ITERATOR_MAP_INDEX;
253 } else {
254 map_index = kind == IterationKind::kValues
255 ? Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX
256 : Context::FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
257
258 if (CanInlineJSArrayIteration(receiver_map)) {
259 // Use `generic` elements for holey arrays if there may be elements
260 // on the prototype chain.
261 map_index += static_cast<int>(receiver_map->elements_kind());
262 object_map = jsgraph()->Constant(receiver_map);
263 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) {
264 Handle<JSObject> initial_array_prototype(
265 native_context()->initial_array_prototype(), isolate());
266 dependencies()->AssumePrototypeMapsStable(receiver_map,
267 initial_array_prototype);
268 }
269 } else {
270 map_index += (Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX -
271 Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX);
272 }
273 }
274 break;
275 case JS_TYPED_ARRAY_TYPE:
276 if (kind == IterationKind::kKeys) {
277 map_index = Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX;
278 } else {
279 DCHECK_GE(receiver_map->elements_kind(), UINT8_ELEMENTS);
280 DCHECK_LE(receiver_map->elements_kind(), UINT8_CLAMPED_ELEMENTS);
281 map_index = (kind == IterationKind::kValues
282 ? Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX
283 : Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX) +
284 (receiver_map->elements_kind() - UINT8_ELEMENTS);
285 }
286 break;
287 default:
288 if (kind == IterationKind::kKeys) {
289 map_index = Context::GENERIC_ARRAY_KEY_ITERATOR_MAP_INDEX;
290 } else if (kind == IterationKind::kValues) {
291 map_index = Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX;
292 } else {
293 map_index = Context::GENERIC_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
294 }
295 break;
296 }
297
298 DCHECK_GE(map_index, Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX);
299 DCHECK_LE(map_index, Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX);
300
301 Handle<Map> map(Map::cast(native_context()->get(map_index)), isolate());
302
303 // allocate new iterator
304 effect = graph()->NewNode(
305 common()->BeginRegion(RegionObservability::kNotObservable), effect);
306 Node* value = effect = graph()->NewNode(
307 simplified()->Allocate(NOT_TENURED),
308 jsgraph()->Constant(JSArrayIterator::kSize), effect, control);
309 effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
310 value, jsgraph()->Constant(map), effect, control);
311 effect = graph()->NewNode(
312 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value,
313 jsgraph()->EmptyFixedArrayConstant(), effect, control);
314 effect = graph()->NewNode(
315 simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
316 jsgraph()->EmptyFixedArrayConstant(), effect, control);
317
318 // attach the iterator to this object
319 effect = graph()->NewNode(
320 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
321 value, receiver, effect, control);
322 effect = graph()->NewNode(
323 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex()), value,
324 jsgraph()->ZeroConstant(), effect, control);
325 effect = graph()->NewNode(
326 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObjectMap()),
327 value, object_map, effect, control);
328
329 value = effect = graph()->NewNode(common()->FinishRegion(), value, effect);
330
331 // replace it
332 ReplaceWithValue(node, value, effect, control);
333 return Replace(value);
334 }
335
336 Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
337 Handle<Map> iterator_map, Node* node, IterationKind kind) {
338 Node* iterator = NodeProperties::GetValueInput(node, 1);
339 Node* effect = NodeProperties::GetEffectInput(node);
340 Node* control = NodeProperties::GetControlInput(node);
341 Node* context = NodeProperties::GetContextInput(node);
342
343 if (kind != IterationKind::kKeys && !isolate()->CanInlineArrayIterator()) {
344 // Avoid deopt loops for non-key iteration if the array_iterator_protector
345 // cell has been invalidated.
346 return NoChange();
347 }
348
349 ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
350 iterator_map->instance_type());
351
352 if (IsFastHoleyElementsKind(elements_kind)) {
353 if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
354 return NoChange();
355 } else {
356 Handle<JSObject> initial_array_prototype(
357 native_context()->initial_array_prototype(), isolate());
358 dependencies()->AssumePropertyCell(factory()->array_protector());
359 }
360 }
361
362 Node* array = effect = graph()->NewNode(
363 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
364 iterator, effect, control);
365 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
366 jsgraph()->UndefinedConstant());
367 Node* branch0 =
368 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
369
370 Node* vdone_false0;
371 Node* vfalse0;
372 Node* efalse0 = effect;
373 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
374 {
375 // iterator.[[IteratedObject]] !== undefined, continue iterating.
376 Node* index = efalse0 = graph()->NewNode(
377 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
378 JS_ARRAY_TYPE, elements_kind)),
379 iterator, efalse0, if_false0);
380
381 Node* length = efalse0 = graph()->NewNode(
382 simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)),
383 array, efalse0, if_false0);
384 Node* check1 =
385 graph()->NewNode(simplified()->NumberLessThan(), index, length);
386 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
387 check1, if_false0);
388
389 Node* vdone_true1;
390 Node* vtrue1;
391 Node* etrue1 = efalse0;
392 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
393 {
394 // iterator.[[NextIndex]] < array.length, continue iterating
395 vdone_true1 = jsgraph()->FalseConstant();
396 if (kind == IterationKind::kKeys) {
397 vtrue1 = index;
398 } else {
399 // For value/entry iteration, first step is a mapcheck to ensure
400 // inlining is still valid.
401 Node* orig_map = etrue1 =
402 graph()->NewNode(simplified()->LoadField(
403 AccessBuilder::ForJSArrayIteratorObjectMap()),
404 iterator, etrue1, if_true1);
405 etrue1 = graph()->NewNode(simplified()->CheckMaps(1), array, orig_map,
406 etrue1, if_true1);
407 }
408
409 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
410 jsgraph()->OneConstant());
411 next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
412
413 etrue1 = graph()->NewNode(
414 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
415 JS_ARRAY_TYPE, elements_kind)),
416 iterator, next_index, etrue1, if_true1);
417
418 if (kind != IterationKind::kKeys) {
419 Node* elements = etrue1 = graph()->NewNode(
420 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
421 array, etrue1, if_true1);
422 Node* value = etrue1 = graph()->NewNode(
423 simplified()->LoadElement(
424 AccessBuilder::ForFixedArrayElement(elements_kind)),
425 elements, index, etrue1, if_true1);
426
427 // Convert hole to undefined if needed.
428 if (elements_kind == FAST_HOLEY_ELEMENTS ||
429 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
430 value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(),
431 value);
432 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
433 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole;
434 // Check if we are allowed to return the hole directly.
435 value = etrue1 = graph()->NewNode(
436 simplified()->CheckFloat64Hole(mode), value, etrue1, if_true1);
437 }
438
439 if (kind == IterationKind::kEntries) {
440 // Allocate elements for key/value pair
441 etrue1 = graph()->NewNode(
442 common()->BeginRegion(RegionObservability::kNotObservable),
443 etrue1);
444 Node* elements = etrue1 = graph()->NewNode(
445 simplified()->Allocate(NOT_TENURED),
446 jsgraph()->Constant(FixedArray::SizeFor(2)), etrue1, if_true1);
447 etrue1 = graph()->NewNode(
448 simplified()->StoreField(AccessBuilder::ForMap()), elements,
449 jsgraph()->Constant(isolate()->factory()->fixed_array_map()),
450 etrue1, if_true1);
451 etrue1 = graph()->NewNode(
452 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()),
453 elements, jsgraph()->Constant(2));
454 etrue1 = graph()->NewNode(
455 simplified()->StoreElement(
456 AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)),
457 elements, jsgraph()->Constant(0), index, etrue1, if_true1);
458 etrue1 = graph()->NewNode(
459 simplified()->StoreElement(
460 AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)),
461 elements, jsgraph()->Constant(1), value, etrue1, if_true1);
462 elements = etrue1 =
463 graph()->NewNode(common()->FinishRegion(), elements, etrue1);
464
465 // Allocate JSArray for key/value pair
466 etrue1 = graph()->NewNode(
467 common()->BeginRegion(RegionObservability::kNotObservable),
468 etrue1);
469 Node* entry = etrue1 = graph()->NewNode(
470 simplified()->Allocate(NOT_TENURED),
471 jsgraph()->Constant(JSArray::kSize), etrue1, if_true1);
472 etrue1 = graph()->NewNode(
473 simplified()->StoreField(AccessBuilder::ForMap()), entry,
474 jsgraph()->Constant(
475 handle(native_context()->js_array_fast_elements_map_index())),
476 etrue1, if_true1);
477 etrue1 = graph()->NewNode(
478 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()),
479 entry, jsgraph()->EmptyFixedArrayConstant(), etrue1, if_true1);
480 etrue1 = graph()->NewNode(
481 simplified()->StoreField(AccessBuilder::ForJSObjectElements()),
482 entry, elements, etrue1, if_true1);
483 etrue1 = graph()->NewNode(
484 simplified()->StoreField(
485 AccessBuilder::ForJSArrayLength(elements_kind)),
486 entry, jsgraph()->Constant(2), etrue1, if_true1);
487 entry = etrue1 =
488 graph()->NewNode(common()->FinishRegion(), entry, etrue1);
489 vtrue1 = entry;
490 } else {
491 DCHECK_EQ(kind, IterationKind::kValues);
492 vtrue1 = value;
493 }
494 }
495 }
496
497 Node* vdone_false1;
498 Node* vfalse1;
499 Node* efalse1 = efalse0;
500 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
501 {
502 // iterator.[[NextIndex]] >= array.length, stop iterating.
503 vdone_false1 = jsgraph()->TrueConstant();
504 vfalse1 = jsgraph()->UndefinedConstant();
505 efalse1 = graph()->NewNode(
506 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
507 iterator, vfalse1, efalse1, if_false1);
508 }
509
510 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
511 efalse0 =
512 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
513 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
514 vtrue1, vfalse1, if_false0);
515 vdone_false0 =
516 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
517 vdone_true1, vdone_false1, if_false0);
518 }
519
520 Node* vdone_true0;
521 Node* vtrue0;
522 Node* etrue0 = effect;
523 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
524 {
525 // iterator.[[IteratedObject]] === undefined, the iterator is done.
526 vdone_true0 = jsgraph()->TrueConstant();
527 vtrue0 = jsgraph()->UndefinedConstant();
528 }
529
530 control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
531 effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
532 Node* value =
533 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
534 vfalse0, vtrue0, control);
535 Node* done =
536 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
537 vdone_false0, vdone_true0, control);
538
539 // Create IteratorResult object.
540 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
541 value, done, context, effect);
542 ReplaceWithValue(node, value, effect, control);
543 return Replace(value);
544 }
545
546 Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
547 Handle<Map> iterator_map, Node* node, IterationKind kind) {
548 Node* iterator = NodeProperties::GetValueInput(node, 1);
549 Node* effect = NodeProperties::GetEffectInput(node);
550 Node* control = NodeProperties::GetControlInput(node);
551 Node* context = NodeProperties::GetContextInput(node);
552
553 ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
554 iterator_map->instance_type());
555
556 Node* array = effect = graph()->NewNode(
557 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
558 iterator, effect, control);
559 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
560 jsgraph()->UndefinedConstant());
561 Node* branch0 =
562 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
563
564 Node* vdone_false0;
565 Node* vfalse0;
566 Node* efalse0 = effect;
567 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
568 {
569 // iterator.[[IteratedObject]] !== undefined, continue iterating.
570 Node* index = efalse0 = graph()->NewNode(
571 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
572 JS_TYPED_ARRAY_TYPE, elements_kind)),
573 iterator, efalse0, if_false0);
574
575 // typedarray.[[ViewedArrayBuffer]]
576 Node* buffer = efalse0 = graph()->NewNode(
577 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
578 array, efalse0, if_false0);
579
580 Node* check1 = efalse0 = graph()->NewNode(
581 simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0);
582 efalse0 =
583 graph()->NewNode(simplified()->CheckIf(), check1, efalse0, if_false0);
584
585 Node* length = efalse0 = graph()->NewNode(
586 simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), array,
587 efalse0, if_false0);
588
589 Node* check2 =
590 graph()->NewNode(simplified()->NumberLessThan(), index, length);
591 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
592 check2, if_false0);
593
594 Node* vdone_true2;
595 Node* vtrue2;
596 Node* etrue2 = efalse0;
597 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
598 {
599 // iterator.[[NextIndex]] < array.length, continue iterating
600 vdone_true2 = jsgraph()->FalseConstant();
601 if (kind == IterationKind::kKeys) {
602 vtrue2 = index;
603 }
604
605 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
606 jsgraph()->OneConstant());
607 next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
608
609 etrue2 = graph()->NewNode(
610 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
611 JS_TYPED_ARRAY_TYPE, elements_kind)),
612 iterator, next_index, etrue2, if_true2);
613
614 if (kind != IterationKind::kKeys) {
615 Node* elements = etrue2 = graph()->NewNode(
616 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
617 array, etrue2, if_true2);
618 Node* base_ptr = etrue2 = graph()->NewNode(
619 simplified()->LoadField(
620 AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
621 elements, etrue2, if_true2);
622 Node* external_ptr = etrue2 = graph()->NewNode(
623 simplified()->LoadField(
624 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
625 elements, etrue2, if_true2);
626
627 ExternalArrayType array_type = kExternalInt8Array;
628 switch (elements_kind) {
629 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
630 case TYPE##_ELEMENTS: \
631 array_type = kExternal##Type##Array;
632 TYPED_ARRAYS(TYPED_ARRAY_CASE)
633 default:
634 UNREACHABLE();
635 #undef TYPED_ARRAY_CASE
636 }
637
638 Node* value = etrue2 =
639 graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer,
640 base_ptr, external_ptr, index, etrue2, if_true2);
641
642 if (kind == IterationKind::kEntries) {
643 // Allocate elements for key/value pair
Camillo Bruni 2016/11/09 12:03:49 Could you somehow reuse the following snippet, thi
caitp 2016/11/09 17:40:16 Ah, I've created an opcode for this to avoid the d
644 etrue2 = graph()->NewNode(
645 common()->BeginRegion(RegionObservability::kNotObservable),
646 etrue2);
647 Node* elements = etrue2 = graph()->NewNode(
648 simplified()->Allocate(NOT_TENURED),
649 jsgraph()->Constant(FixedArray::SizeFor(2)), etrue2, if_true2);
650 etrue2 = graph()->NewNode(
651 simplified()->StoreField(AccessBuilder::ForMap()), elements,
652 jsgraph()->Constant(isolate()->factory()->fixed_array_map()),
653 etrue2, if_true2);
654 etrue2 = graph()->NewNode(
655 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()),
656 elements, jsgraph()->Constant(2));
657 etrue2 = graph()->NewNode(
658 simplified()->StoreElement(
659 AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)),
660 elements, jsgraph()->Constant(0), index, etrue2, if_true2);
661 etrue2 = graph()->NewNode(
662 simplified()->StoreElement(
663 AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)),
664 elements, jsgraph()->Constant(1), value, etrue2, if_true2);
665 elements = etrue2 =
666 graph()->NewNode(common()->FinishRegion(), elements, etrue2);
667
668 // Allocate JSArray for key/value pair
669 etrue2 = graph()->NewNode(
670 common()->BeginRegion(RegionObservability::kNotObservable),
671 etrue2);
672 Node* entry = etrue2 = graph()->NewNode(
673 simplified()->Allocate(NOT_TENURED),
674 jsgraph()->Constant(JSArray::kSize), etrue2, if_true2);
675 etrue2 = graph()->NewNode(
676 simplified()->StoreField(AccessBuilder::ForMap()), entry,
677 jsgraph()->Constant(
678 handle(native_context()->js_array_fast_elements_map_index())),
679 etrue2, if_true2);
680 etrue2 = graph()->NewNode(
681 simplified()->StoreField(AccessBuilder::ForJSObjectProperties()),
682 entry, jsgraph()->EmptyFixedArrayConstant(), etrue2, if_true2);
683 etrue2 = graph()->NewNode(
684 simplified()->StoreField(AccessBuilder::ForJSObjectElements()),
685 entry, elements, etrue2, if_true2);
686 etrue2 = graph()->NewNode(
687 simplified()->StoreField(
688 AccessBuilder::ForJSArrayLength(elements_kind)),
689 entry, jsgraph()->Constant(2), etrue2, if_true2);
690 entry = etrue2 =
691 graph()->NewNode(common()->FinishRegion(), entry, etrue2);
692 vtrue2 = entry;
693 } else {
694 DCHECK(kind == IterationKind::kValues);
695 vtrue2 = value;
696 }
697 }
698 }
699
700 Node* vdone_false2;
701 Node* vfalse2;
702 Node* efalse2 = efalse0;
703 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
704 {
705 // iterator.[[NextIndex]] >= array.length, stop iterating.
706 vdone_false2 = jsgraph()->TrueConstant();
707 vfalse2 = jsgraph()->UndefinedConstant();
708 efalse2 = graph()->NewNode(
709 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
710 iterator, vfalse2, efalse2, if_false2);
711 }
712
713 if_false0 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
714 efalse0 =
715 graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_false0);
716 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
717 vtrue2, vfalse2, if_false0);
718 vdone_false0 =
719 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
720 vdone_true2, vdone_false2, if_false0);
721 }
722
723 Node* vdone_true0;
724 Node* vtrue0;
725 Node* etrue0 = effect;
726 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
727 {
728 // iterator.[[IteratedObject]] === undefined, the iterator is done.
729 vdone_true0 = jsgraph()->TrueConstant();
730 vtrue0 = jsgraph()->UndefinedConstant();
731 }
732
733 control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
734 effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
735 Node* value =
736 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
737 vfalse0, vtrue0, control);
738 Node* done =
739 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
740 vdone_false0, vdone_true0, control);
741
742 // Create IteratorResult object.
743 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
744 value, done, context, effect);
745 ReplaceWithValue(node, value, effect, control);
746 return Replace(value);
747 }
748
749 Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
750 Handle<Map> receiver_map;
751 if (GetMapWitness(node).ToHandle(&receiver_map)) {
752 switch (receiver_map->instance_type()) {
753 case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
754 return ReduceTypedArrayIteratorNext(receiver_map, node,
755 IterationKind::kKeys);
756
757 case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
758 return ReduceFastArrayIteratorNext(receiver_map, node,
759 IterationKind::kKeys);
760
761 case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
762 case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
763 case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
764 case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
765 case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
766 case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
767 case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
768 case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
769 case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
770 return ReduceTypedArrayIteratorNext(receiver_map, node,
771 IterationKind::kEntries);
772
773 case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
774 case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
775 case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE:
776 case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
777 case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
778 case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
779 return ReduceFastArrayIteratorNext(receiver_map, node,
780 IterationKind::kEntries);
781
782 case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
783 case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
784 case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
785 case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
786 case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
787 case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
788 case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
789 case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
790 case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
791 return ReduceTypedArrayIteratorNext(receiver_map, node,
792 IterationKind::kValues);
793
794 case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
795 case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
796 case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
797 case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
798 case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
799 case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
800 return ReduceFastArrayIteratorNext(receiver_map, node,
801 IterationKind::kValues);
802
803 default:
804 // Slow array iterators are not reduced
805 return NoChange();
806 }
807 }
808 return NoChange();
809 }
810
180 // ES6 section 22.1.3.17 Array.prototype.pop ( ) 811 // ES6 section 22.1.3.17 Array.prototype.pop ( )
181 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { 812 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) {
182 Handle<Map> receiver_map; 813 Handle<Map> receiver_map;
183 Node* receiver = NodeProperties::GetValueInput(node, 1); 814 Node* receiver = NodeProperties::GetValueInput(node, 1);
184 Node* effect = NodeProperties::GetEffectInput(node); 815 Node* effect = NodeProperties::GetEffectInput(node);
185 Node* control = NodeProperties::GetControlInput(node); 816 Node* control = NodeProperties::GetControlInput(node);
186 // TODO(turbofan): Extend this to also handle fast (holey) double elements 817 // TODO(turbofan): Extend this to also handle fast (holey) double elements
187 // once we got the hole NaN mess sorted out in TurboFan/V8. 818 // once we got the hole NaN mess sorted out in TurboFan/V8.
188 if (GetMapWitness(node).ToHandle(&receiver_map) && 819 if (GetMapWitness(node).ToHandle(&receiver_map) &&
189 CanInlineArrayResizeOperation(receiver_map) && 820 CanInlineArrayResizeOperation(receiver_map) &&
(...skipping 1063 matching lines...) Expand 10 before | Expand all | Expand 10 after
1253 return NoChange(); 1884 return NoChange();
1254 } 1885 }
1255 1886
1256 Reduction JSBuiltinReducer::Reduce(Node* node) { 1887 Reduction JSBuiltinReducer::Reduce(Node* node) {
1257 Reduction reduction = NoChange(); 1888 Reduction reduction = NoChange();
1258 JSCallReduction r(node); 1889 JSCallReduction r(node);
1259 1890
1260 // Dispatch according to the BuiltinFunctionId if present. 1891 // Dispatch according to the BuiltinFunctionId if present.
1261 if (!r.HasBuiltinFunctionId()) return NoChange(); 1892 if (!r.HasBuiltinFunctionId()) return NoChange();
1262 switch (r.GetBuiltinFunctionId()) { 1893 switch (r.GetBuiltinFunctionId()) {
1894 case kArrayEntries:
1895 return ReduceArrayIterator(node, IterationKind::kEntries);
1896 case kArrayKeys:
1897 return ReduceArrayIterator(node, IterationKind::kKeys);
1898 case kArrayValues:
1899 return ReduceArrayIterator(node, IterationKind::kValues);
1900 case kArrayIteratorNext:
1901 return ReduceArrayIteratorNext(node);
1263 case kArrayPop: 1902 case kArrayPop:
1264 return ReduceArrayPop(node); 1903 return ReduceArrayPop(node);
1265 case kArrayPush: 1904 case kArrayPush:
1266 return ReduceArrayPush(node); 1905 return ReduceArrayPush(node);
1267 case kDateGetTime: 1906 case kDateGetTime:
1268 return ReduceDateGetTime(node); 1907 return ReduceDateGetTime(node);
1269 case kGlobalIsFinite: 1908 case kGlobalIsFinite:
1270 reduction = ReduceGlobalIsFinite(node); 1909 reduction = ReduceGlobalIsFinite(node);
1271 break; 1910 break;
1272 case kGlobalIsNaN: 1911 case kGlobalIsNaN:
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
1409 return ReduceArrayBufferViewAccessor( 2048 return ReduceArrayBufferViewAccessor(
1410 node, JS_TYPED_ARRAY_TYPE, 2049 node, JS_TYPED_ARRAY_TYPE,
1411 AccessBuilder::ForJSArrayBufferViewByteLength()); 2050 AccessBuilder::ForJSArrayBufferViewByteLength());
1412 case kTypedArrayByteOffset: 2051 case kTypedArrayByteOffset:
1413 return ReduceArrayBufferViewAccessor( 2052 return ReduceArrayBufferViewAccessor(
1414 node, JS_TYPED_ARRAY_TYPE, 2053 node, JS_TYPED_ARRAY_TYPE,
1415 AccessBuilder::ForJSArrayBufferViewByteOffset()); 2054 AccessBuilder::ForJSArrayBufferViewByteOffset());
1416 case kTypedArrayLength: 2055 case kTypedArrayLength:
1417 return ReduceArrayBufferViewAccessor( 2056 return ReduceArrayBufferViewAccessor(
1418 node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength()); 2057 node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
2058 case kTypedArrayEntries:
2059 return ReduceTypedArrayIterator(node, IterationKind::kEntries);
2060 case kTypedArrayKeys:
2061 return ReduceTypedArrayIterator(node, IterationKind::kKeys);
2062 case kTypedArrayValues:
2063 return ReduceTypedArrayIterator(node, IterationKind::kValues);
1419 default: 2064 default:
1420 break; 2065 break;
1421 } 2066 }
1422 2067
1423 // Replace builtin call assuming replacement nodes are pure values that don't 2068 // Replace builtin call assuming replacement nodes are pure values that don't
1424 // produce an effect. Replaces {node} with {reduction} and relaxes effects. 2069 // produce an effect. Replaces {node} with {reduction} and relaxes effects.
1425 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); 2070 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement());
1426 2071
1427 return reduction; 2072 return reduction;
1428 } 2073 }
(...skipping 27 matching lines...) Expand all
1456 return jsgraph()->simplified(); 2101 return jsgraph()->simplified();
1457 } 2102 }
1458 2103
1459 JSOperatorBuilder* JSBuiltinReducer::javascript() const { 2104 JSOperatorBuilder* JSBuiltinReducer::javascript() const {
1460 return jsgraph()->javascript(); 2105 return jsgraph()->javascript();
1461 } 2106 }
1462 2107
1463 } // namespace compiler 2108 } // namespace compiler
1464 } // namespace internal 2109 } // namespace internal
1465 } // namespace v8 2110 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698