Chromium Code Reviews

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

Issue 2484003002: [builtins] implement JSBuiltinReducer for ArrayIteratorNext() (Closed)
Patch Set: bunch of changes Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
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...)
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;
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) {
Benedikt Meurer 2016/11/09 20:00:32 Nit: Can I haz an enum for this plz?
caitp 2016/11/09 20:55:24 Done.
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
Benedikt Meurer 2016/11/09 20:00:32 Please add a hint, that this is a potential, but h
caitp 2016/11/09 20:55:24 Done.
237 DCHECK_EQ(receiver_map->instance_type(), JS_TYPED_ARRAY_TYPE);
Benedikt Meurer 2016/11/09 20:00:32 Nit: DCHECK_EQ(JS_TYPED_ARRAY_TYPE, receiver_map->
caitp 2016/11/09 20:55:24 Done.
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);
caitp 2016/11/10 20:27:41 CheckIf does a DeoptimizeUnless(), so this is deop
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);
Benedikt Meurer 2016/11/09 20:00:32 This will most likely deopt on every hole, as it's
caitp 2016/11/09 20:55:24 Done. Also removed the "Check if we are allowed...
437 }
438
439 if (kind == IterationKind::kEntries) {
440 // Allocate elements for key/value pair
441 vtrue1 = etrue1 = graph()->NewNode(
442 javascript()->CreateKeyValueArray(), index, value, etrue1);
Benedikt Meurer 2016/11/09 20:00:32 Nice idea!
443 } else {
444 DCHECK_EQ(kind, IterationKind::kValues);
445 vtrue1 = value;
446 }
447 }
448 }
449
450 Node* vdone_false1;
451 Node* vfalse1;
452 Node* efalse1 = efalse0;
453 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
454 {
455 // iterator.[[NextIndex]] >= array.length, stop iterating.
456 vdone_false1 = jsgraph()->TrueConstant();
457 vfalse1 = jsgraph()->UndefinedConstant();
458 efalse1 = graph()->NewNode(
459 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
460 iterator, vfalse1, efalse1, if_false1);
461 }
462
463 if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
464 efalse0 =
465 graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
466 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
467 vtrue1, vfalse1, if_false0);
468 vdone_false0 =
469 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
470 vdone_true1, vdone_false1, if_false0);
471 }
472
473 Node* vdone_true0;
474 Node* vtrue0;
475 Node* etrue0 = effect;
476 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
477 {
478 // iterator.[[IteratedObject]] === undefined, the iterator is done.
479 vdone_true0 = jsgraph()->TrueConstant();
480 vtrue0 = jsgraph()->UndefinedConstant();
481 }
482
483 control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
484 effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
485 Node* value =
486 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
487 vfalse0, vtrue0, control);
488 Node* done =
489 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
490 vdone_false0, vdone_true0, control);
491
492 // Create IteratorResult object.
493 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
494 value, done, context, effect);
495 ReplaceWithValue(node, value, effect, control);
496 return Replace(value);
497 }
498
499 Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
500 Handle<Map> iterator_map, Node* node, IterationKind kind) {
501 Node* iterator = NodeProperties::GetValueInput(node, 1);
502 Node* effect = NodeProperties::GetEffectInput(node);
503 Node* control = NodeProperties::GetControlInput(node);
504 Node* context = NodeProperties::GetContextInput(node);
505
506 ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
507 iterator_map->instance_type());
508
509 Node* array = effect = graph()->NewNode(
510 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
511 iterator, effect, control);
512 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
513 jsgraph()->UndefinedConstant());
514 Node* branch0 =
515 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
516
517 Node* vdone_false0;
518 Node* vfalse0;
519 Node* efalse0 = effect;
520 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
521 {
522 // iterator.[[IteratedObject]] !== undefined, continue iterating.
523 Node* index = efalse0 = graph()->NewNode(
524 simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
525 JS_TYPED_ARRAY_TYPE, elements_kind)),
526 iterator, efalse0, if_false0);
527
528 // typedarray.[[ViewedArrayBuffer]]
529 Node* buffer = efalse0 = graph()->NewNode(
530 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
531 array, efalse0, if_false0);
532
533 Node* check1 = efalse0 = graph()->NewNode(
534 simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0);
535 efalse0 =
536 graph()->NewNode(simplified()->CheckIf(), check1, efalse0, if_false0);
537
538 Node* length = efalse0 = graph()->NewNode(
539 simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), array,
540 efalse0, if_false0);
541
542 Node* check2 =
543 graph()->NewNode(simplified()->NumberLessThan(), index, length);
544 Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
545 check2, if_false0);
546
547 Node* vdone_true2;
548 Node* vtrue2;
549 Node* etrue2 = efalse0;
550 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
551 {
552 // iterator.[[NextIndex]] < array.length, continue iterating
553 vdone_true2 = jsgraph()->FalseConstant();
554 if (kind == IterationKind::kKeys) {
555 vtrue2 = index;
556 }
557
558 Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
559 jsgraph()->OneConstant());
560 next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
561
562 etrue2 = graph()->NewNode(
563 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
564 JS_TYPED_ARRAY_TYPE, elements_kind)),
565 iterator, next_index, etrue2, if_true2);
566
567 if (kind != IterationKind::kKeys) {
568 Node* elements = etrue2 = graph()->NewNode(
569 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
570 array, etrue2, if_true2);
571 Node* base_ptr = etrue2 = graph()->NewNode(
572 simplified()->LoadField(
573 AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
574 elements, etrue2, if_true2);
575 Node* external_ptr = etrue2 = graph()->NewNode(
576 simplified()->LoadField(
577 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
578 elements, etrue2, if_true2);
579
580 ExternalArrayType array_type = kExternalInt8Array;
581 switch (elements_kind) {
582 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
583 case TYPE##_ELEMENTS: \
584 array_type = kExternal##Type##Array;
585 TYPED_ARRAYS(TYPED_ARRAY_CASE)
586 default:
587 UNREACHABLE();
588 #undef TYPED_ARRAY_CASE
589 }
590
591 Node* value = etrue2 =
592 graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer,
593 base_ptr, external_ptr, index, etrue2, if_true2);
594
595 if (kind == IterationKind::kEntries) {
596 // Allocate elements for key/value pair
597 vtrue2 = etrue2 = graph()->NewNode(
598 javascript()->CreateKeyValueArray(), index, value, etrue2);
599 } else {
600 DCHECK(kind == IterationKind::kValues);
601 vtrue2 = value;
602 }
603 }
604 }
605
606 Node* vdone_false2;
607 Node* vfalse2;
608 Node* efalse2 = efalse0;
609 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
610 {
611 // iterator.[[NextIndex]] >= array.length, stop iterating.
612 vdone_false2 = jsgraph()->TrueConstant();
613 vfalse2 = jsgraph()->UndefinedConstant();
614 efalse2 = graph()->NewNode(
615 simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
616 iterator, vfalse2, efalse2, if_false2);
617 }
618
619 if_false0 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
620 efalse0 =
621 graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_false0);
622 vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
623 vtrue2, vfalse2, if_false0);
624 vdone_false0 =
625 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
626 vdone_true2, vdone_false2, if_false0);
627 }
628
629 Node* vdone_true0;
630 Node* vtrue0;
631 Node* etrue0 = effect;
632 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
633 {
634 // iterator.[[IteratedObject]] === undefined, the iterator is done.
635 vdone_true0 = jsgraph()->TrueConstant();
636 vtrue0 = jsgraph()->UndefinedConstant();
637 }
638
639 control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
640 effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
641 Node* value =
642 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
643 vfalse0, vtrue0, control);
644 Node* done =
645 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
646 vdone_false0, vdone_true0, control);
647
648 // Create IteratorResult object.
649 value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
650 value, done, context, effect);
651 ReplaceWithValue(node, value, effect, control);
652 return Replace(value);
653 }
654
655 Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
656 Handle<Map> receiver_map;
657 if (GetMapWitness(node).ToHandle(&receiver_map)) {
658 switch (receiver_map->instance_type()) {
659 case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
660 return ReduceTypedArrayIteratorNext(receiver_map, node,
661 IterationKind::kKeys);
662
663 case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
664 return ReduceFastArrayIteratorNext(receiver_map, node,
665 IterationKind::kKeys);
666
667 case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
668 case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
669 case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
670 case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
671 case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
672 case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
673 case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
674 case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
675 case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
676 return ReduceTypedArrayIteratorNext(receiver_map, node,
677 IterationKind::kEntries);
678
679 case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
680 case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
681 case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE:
682 case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
683 case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
684 case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
685 return ReduceFastArrayIteratorNext(receiver_map, node,
686 IterationKind::kEntries);
687
688 case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
689 case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
690 case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
691 case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
692 case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
693 case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
694 case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
695 case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
696 case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
697 return ReduceTypedArrayIteratorNext(receiver_map, node,
698 IterationKind::kValues);
699
700 case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
701 case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
702 case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
703 case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
704 case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
705 case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
706 return ReduceFastArrayIteratorNext(receiver_map, node,
707 IterationKind::kValues);
708
709 default:
710 // Slow array iterators are not reduced
711 return NoChange();
712 }
713 }
714 return NoChange();
715 }
716
180 // ES6 section 22.1.3.17 Array.prototype.pop ( ) 717 // ES6 section 22.1.3.17 Array.prototype.pop ( )
181 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { 718 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) {
182 Handle<Map> receiver_map; 719 Handle<Map> receiver_map;
183 Node* receiver = NodeProperties::GetValueInput(node, 1); 720 Node* receiver = NodeProperties::GetValueInput(node, 1);
184 Node* effect = NodeProperties::GetEffectInput(node); 721 Node* effect = NodeProperties::GetEffectInput(node);
185 Node* control = NodeProperties::GetControlInput(node); 722 Node* control = NodeProperties::GetControlInput(node);
186 // TODO(turbofan): Extend this to also handle fast (holey) double elements 723 // TODO(turbofan): Extend this to also handle fast (holey) double elements
187 // once we got the hole NaN mess sorted out in TurboFan/V8. 724 // once we got the hole NaN mess sorted out in TurboFan/V8.
188 if (GetMapWitness(node).ToHandle(&receiver_map) && 725 if (GetMapWitness(node).ToHandle(&receiver_map) &&
189 CanInlineArrayResizeOperation(receiver_map) && 726 CanInlineArrayResizeOperation(receiver_map) &&
(...skipping 1063 matching lines...)
1253 return NoChange(); 1790 return NoChange();
1254 } 1791 }
1255 1792
1256 Reduction JSBuiltinReducer::Reduce(Node* node) { 1793 Reduction JSBuiltinReducer::Reduce(Node* node) {
1257 Reduction reduction = NoChange(); 1794 Reduction reduction = NoChange();
1258 JSCallReduction r(node); 1795 JSCallReduction r(node);
1259 1796
1260 // Dispatch according to the BuiltinFunctionId if present. 1797 // Dispatch according to the BuiltinFunctionId if present.
1261 if (!r.HasBuiltinFunctionId()) return NoChange(); 1798 if (!r.HasBuiltinFunctionId()) return NoChange();
1262 switch (r.GetBuiltinFunctionId()) { 1799 switch (r.GetBuiltinFunctionId()) {
1800 case kArrayEntries:
1801 return ReduceArrayIterator(node, IterationKind::kEntries);
1802 case kArrayKeys:
1803 return ReduceArrayIterator(node, IterationKind::kKeys);
1804 case kArrayValues:
1805 return ReduceArrayIterator(node, IterationKind::kValues);
1806 case kArrayIteratorNext:
1807 return ReduceArrayIteratorNext(node);
1263 case kArrayPop: 1808 case kArrayPop:
1264 return ReduceArrayPop(node); 1809 return ReduceArrayPop(node);
1265 case kArrayPush: 1810 case kArrayPush:
1266 return ReduceArrayPush(node); 1811 return ReduceArrayPush(node);
1267 case kDateGetTime: 1812 case kDateGetTime:
1268 return ReduceDateGetTime(node); 1813 return ReduceDateGetTime(node);
1269 case kGlobalIsFinite: 1814 case kGlobalIsFinite:
1270 reduction = ReduceGlobalIsFinite(node); 1815 reduction = ReduceGlobalIsFinite(node);
1271 break; 1816 break;
1272 case kGlobalIsNaN: 1817 case kGlobalIsNaN:
(...skipping 136 matching lines...)
1409 return ReduceArrayBufferViewAccessor( 1954 return ReduceArrayBufferViewAccessor(
1410 node, JS_TYPED_ARRAY_TYPE, 1955 node, JS_TYPED_ARRAY_TYPE,
1411 AccessBuilder::ForJSArrayBufferViewByteLength()); 1956 AccessBuilder::ForJSArrayBufferViewByteLength());
1412 case kTypedArrayByteOffset: 1957 case kTypedArrayByteOffset:
1413 return ReduceArrayBufferViewAccessor( 1958 return ReduceArrayBufferViewAccessor(
1414 node, JS_TYPED_ARRAY_TYPE, 1959 node, JS_TYPED_ARRAY_TYPE,
1415 AccessBuilder::ForJSArrayBufferViewByteOffset()); 1960 AccessBuilder::ForJSArrayBufferViewByteOffset());
1416 case kTypedArrayLength: 1961 case kTypedArrayLength:
1417 return ReduceArrayBufferViewAccessor( 1962 return ReduceArrayBufferViewAccessor(
1418 node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength()); 1963 node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
1964 case kTypedArrayEntries:
1965 return ReduceTypedArrayIterator(node, IterationKind::kEntries);
1966 case kTypedArrayKeys:
1967 return ReduceTypedArrayIterator(node, IterationKind::kKeys);
1968 case kTypedArrayValues:
1969 return ReduceTypedArrayIterator(node, IterationKind::kValues);
1419 default: 1970 default:
1420 break; 1971 break;
1421 } 1972 }
1422 1973
1423 // Replace builtin call assuming replacement nodes are pure values that don't 1974 // Replace builtin call assuming replacement nodes are pure values that don't
1424 // produce an effect. Replaces {node} with {reduction} and relaxes effects. 1975 // produce an effect. Replaces {node} with {reduction} and relaxes effects.
1425 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement()); 1976 if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement());
1426 1977
1427 return reduction; 1978 return reduction;
1428 } 1979 }
(...skipping 27 matching lines...)
1456 return jsgraph()->simplified(); 2007 return jsgraph()->simplified();
1457 } 2008 }
1458 2009
1459 JSOperatorBuilder* JSBuiltinReducer::javascript() const { 2010 JSOperatorBuilder* JSBuiltinReducer::javascript() const {
1460 return jsgraph()->javascript(); 2011 return jsgraph()->javascript();
1461 } 2012 }
1462 2013
1463 } // namespace compiler 2014 } // namespace compiler
1464 } // namespace internal 2015 } // namespace internal
1465 } // namespace v8 2016 } // namespace v8
OLDNEW

Powered by Google App Engine