OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/load-elimination.h" | 5 #include "src/compiler/load-elimination.h" |
6 | 6 |
7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
10 #include "src/compiler/simplified-operator.h" | 10 #include "src/compiler/simplified-operator.h" |
11 #include "src/factory.h" | |
12 #include "src/objects-inl.h" | |
11 | 13 |
12 namespace v8 { | 14 namespace v8 { |
13 namespace internal { | 15 namespace internal { |
14 namespace compiler { | 16 namespace compiler { |
15 | 17 |
16 namespace { | 18 namespace { |
17 | 19 |
18 enum Aliasing { kNoAlias, kMayAlias, kMustAlias }; | 20 enum Aliasing { kNoAlias, kMayAlias, kMustAlias }; |
19 | 21 |
20 Aliasing QueryAlias(Node* a, Node* b) { | 22 Aliasing QueryAlias(Node* a, Node* b) { |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
313 } | 315 } |
314 | 316 |
315 void LoadElimination::AbstractField::Print() const { | 317 void LoadElimination::AbstractField::Print() const { |
316 for (auto pair : info_for_node_) { | 318 for (auto pair : info_for_node_) { |
317 PrintF(" #%d:%s -> #%d:%s\n", pair.first->id(), | 319 PrintF(" #%d:%s -> #%d:%s\n", pair.first->id(), |
318 pair.first->op()->mnemonic(), pair.second->id(), | 320 pair.first->op()->mnemonic(), pair.second->id(), |
319 pair.second->op()->mnemonic()); | 321 pair.second->op()->mnemonic()); |
320 } | 322 } |
321 } | 323 } |
322 | 324 |
325 ZoneHandleSet<Map> LoadElimination::AbstractMaps::Lookup(Node* object) const { | |
326 for (auto pair : info_for_node_) { | |
327 if (MustAlias(object, pair.first)) return pair.second; | |
328 } | |
329 return ZoneHandleSet<Map>(); | |
330 } | |
331 | |
332 LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill( | |
333 Node* object, Zone* zone) const { | |
334 for (auto pair : this->info_for_node_) { | |
335 if (MayAlias(object, pair.first)) { | |
336 AbstractMaps* that = new (zone) AbstractMaps(zone); | |
337 for (auto pair : this->info_for_node_) { | |
338 if (!MayAlias(object, pair.first)) that->info_for_node_.insert(pair); | |
339 } | |
340 return that; | |
341 } | |
342 } | |
343 return this; | |
344 } | |
345 | |
346 void LoadElimination::AbstractMaps::Print() const { | |
347 for (auto pair : info_for_node_) { | |
348 PrintF(" #%d:%s\n", pair.first->id(), | |
349 pair.first->op()->mnemonic()); | |
350 OFStream os(stdout); | |
351 ZoneHandleSet<Map> const& maps = pair.second; | |
352 for (size_t i = 0; i < maps.size(); ++i) { | |
353 os << " - " << Brief(*maps[i]) << "\n"; | |
354 } | |
355 } | |
356 } | |
357 | |
323 bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { | 358 bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { |
324 if (this->checks_) { | 359 if (this->checks_) { |
325 if (!that->checks_ || !that->checks_->Equals(this->checks_)) { | 360 if (!that->checks_ || !that->checks_->Equals(this->checks_)) { |
326 return false; | 361 return false; |
327 } | 362 } |
328 } else if (that->checks_) { | 363 } else if (that->checks_) { |
329 return false; | 364 return false; |
330 } | 365 } |
331 if (this->elements_) { | 366 if (this->elements_) { |
332 if (!that->elements_ || !that->elements_->Equals(this->elements_)) { | 367 if (!that->elements_ || !that->elements_->Equals(this->elements_)) { |
333 return false; | 368 return false; |
334 } | 369 } |
335 } else if (that->elements_) { | 370 } else if (that->elements_) { |
336 return false; | 371 return false; |
337 } | 372 } |
338 for (size_t i = 0u; i < arraysize(fields_); ++i) { | 373 for (size_t i = 0u; i < arraysize(fields_); ++i) { |
339 AbstractField const* this_field = this->fields_[i]; | 374 AbstractField const* this_field = this->fields_[i]; |
340 AbstractField const* that_field = that->fields_[i]; | 375 AbstractField const* that_field = that->fields_[i]; |
341 if (this_field) { | 376 if (this_field) { |
342 if (!that_field || !that_field->Equals(this_field)) return false; | 377 if (!that_field || !that_field->Equals(this_field)) return false; |
343 } else if (that_field) { | 378 } else if (that_field) { |
344 return false; | 379 return false; |
345 } | 380 } |
346 } | 381 } |
382 if (this->maps_) { | |
383 if (!that->maps_ || !that->maps_->Equals(this->maps_)) { | |
384 return false; | |
385 } | |
386 } else if (that->maps_) { | |
387 return false; | |
388 } | |
347 return true; | 389 return true; |
348 } | 390 } |
349 | 391 |
350 void LoadElimination::AbstractState::Merge(AbstractState const* that, | 392 void LoadElimination::AbstractState::Merge(AbstractState const* that, |
351 Zone* zone) { | 393 Zone* zone) { |
352 // Merge the information we have about the checks. | 394 // Merge the information we have about the checks. |
353 if (this->checks_) { | 395 if (this->checks_) { |
354 this->checks_ = | 396 this->checks_ = |
355 that->checks_ ? that->checks_->Merge(this->checks_, zone) : nullptr; | 397 that->checks_ ? that->checks_->Merge(this->checks_, zone) : nullptr; |
356 } | 398 } |
357 | 399 |
358 // Merge the information we have about the elements. | 400 // Merge the information we have about the elements. |
359 if (this->elements_) { | 401 if (this->elements_) { |
360 this->elements_ = that->elements_ | 402 this->elements_ = that->elements_ |
361 ? that->elements_->Merge(this->elements_, zone) | 403 ? that->elements_->Merge(this->elements_, zone) |
362 : nullptr; | 404 : nullptr; |
363 } | 405 } |
364 | 406 |
365 // Merge the information we have about the fields. | 407 // Merge the information we have about the fields. |
366 for (size_t i = 0; i < arraysize(fields_); ++i) { | 408 for (size_t i = 0; i < arraysize(fields_); ++i) { |
367 if (this->fields_[i]) { | 409 if (this->fields_[i]) { |
368 if (that->fields_[i]) { | 410 if (that->fields_[i]) { |
369 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone); | 411 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone); |
370 } else { | 412 } else { |
371 this->fields_[i] = nullptr; | 413 this->fields_[i] = nullptr; |
372 } | 414 } |
373 } | 415 } |
374 } | 416 } |
417 | |
418 // Merge the information we have about the maps. | |
419 if (this->maps_) { | |
420 this->maps_ = that->maps_ ? that->maps_->Merge(this->maps_, zone) : nullptr; | |
421 } | |
375 } | 422 } |
376 | 423 |
377 Node* LoadElimination::AbstractState::LookupCheck(Node* node) const { | 424 Node* LoadElimination::AbstractState::LookupCheck(Node* node) const { |
378 return this->checks_ ? this->checks_->Lookup(node) : nullptr; | 425 return this->checks_ ? this->checks_->Lookup(node) : nullptr; |
379 } | 426 } |
380 | 427 |
381 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck( | 428 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck( |
382 Node* node, Zone* zone) const { | 429 Node* node, Zone* zone) const { |
383 AbstractState* that = new (zone) AbstractState(*this); | 430 AbstractState* that = new (zone) AbstractState(*this); |
384 if (that->checks_) { | 431 if (that->checks_) { |
385 that->checks_ = that->checks_->Extend(node, zone); | 432 that->checks_ = that->checks_->Extend(node, zone); |
386 } else { | 433 } else { |
387 that->checks_ = new (zone) AbstractChecks(node, zone); | 434 that->checks_ = new (zone) AbstractChecks(node, zone); |
388 } | 435 } |
389 return that; | 436 return that; |
390 } | 437 } |
391 | 438 |
439 ZoneHandleSet<Map> LoadElimination::AbstractState::LookupMaps( | |
440 Node* object) const { | |
441 if (this->maps_) { | |
442 return this->maps_->Lookup(object); | |
443 } | |
444 return ZoneHandleSet<Map>(); | |
445 } | |
446 | |
447 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddMaps( | |
448 Node* object, ZoneHandleSet<Map> maps, Zone* zone) const { | |
449 AbstractState* that = new (zone) AbstractState(*this); | |
450 if (that->maps_) { | |
451 that->maps_ = that->maps_->Extend(object, maps, zone); | |
452 } else { | |
453 that->maps_ = new (zone) AbstractMaps(object, maps, zone); | |
454 } | |
455 return that; | |
456 } | |
457 | |
458 LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps( | |
459 Node* object, Zone* zone) const { | |
460 if (this->maps_) { | |
461 AbstractMaps const* that_maps = this->maps_->Kill(object, zone); | |
462 if (this->maps_ != that_maps) { | |
463 AbstractState* that = new (zone) AbstractState(*this); | |
464 that->maps_ = that_maps; | |
465 return that; | |
466 } | |
467 } | |
468 return this; | |
469 } | |
470 | |
392 Node* LoadElimination::AbstractState::LookupElement(Node* object, | 471 Node* LoadElimination::AbstractState::LookupElement(Node* object, |
393 Node* index) const { | 472 Node* index) const { |
394 if (this->elements_) { | 473 if (this->elements_) { |
395 return this->elements_->Lookup(object, index); | 474 return this->elements_->Lookup(object, index); |
396 } | 475 } |
397 return nullptr; | 476 return nullptr; |
398 } | 477 } |
399 | 478 |
400 LoadElimination::AbstractState const* | 479 LoadElimination::AbstractState const* |
401 LoadElimination::AbstractState::AddElement(Node* object, Node* index, | 480 LoadElimination::AbstractState::AddElement(Node* object, Node* index, |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
454 return this_field->Lookup(object); | 533 return this_field->Lookup(object); |
455 } | 534 } |
456 return nullptr; | 535 return nullptr; |
457 } | 536 } |
458 | 537 |
459 void LoadElimination::AbstractState::Print() const { | 538 void LoadElimination::AbstractState::Print() const { |
460 if (checks_) { | 539 if (checks_) { |
461 PrintF(" checks:\n"); | 540 PrintF(" checks:\n"); |
462 checks_->Print(); | 541 checks_->Print(); |
463 } | 542 } |
543 if (maps_) { | |
544 PrintF(" maps:\n"); | |
545 maps_->Print(); | |
546 } | |
464 if (elements_) { | 547 if (elements_) { |
465 PrintF(" elements:\n"); | 548 PrintF(" elements:\n"); |
466 elements_->Print(); | 549 elements_->Print(); |
467 } | 550 } |
468 for (size_t i = 0; i < arraysize(fields_); ++i) { | 551 for (size_t i = 0; i < arraysize(fields_); ++i) { |
469 if (AbstractField const* const field = fields_[i]) { | 552 if (AbstractField const* const field = fields_[i]) { |
470 PrintF(" field %zu:\n", i); | 553 PrintF(" field %zu:\n", i); |
471 field->Print(); | 554 field->Print(); |
472 } | 555 } |
473 } | 556 } |
(...skipping 19 matching lines...) Expand all Loading... | |
493 if (state == nullptr) return NoChange(); | 576 if (state == nullptr) return NoChange(); |
494 if (Node* const check = state->LookupCheck(node)) { | 577 if (Node* const check = state->LookupCheck(node)) { |
495 ReplaceWithValue(node, check, effect); | 578 ReplaceWithValue(node, check, effect); |
496 return Replace(check); | 579 return Replace(check); |
497 } | 580 } |
498 state = state->AddCheck(node, zone()); | 581 state = state->AddCheck(node, zone()); |
499 return UpdateState(node, state); | 582 return UpdateState(node, state); |
500 } | 583 } |
501 | 584 |
502 Reduction LoadElimination::ReduceCheckMaps(Node* node) { | 585 Reduction LoadElimination::ReduceCheckMaps(Node* node) { |
586 ZoneHandleSet<Map> const maps = CheckMapsParametersOf(node->op()).maps(); | |
503 Node* const object = NodeProperties::GetValueInput(node, 0); | 587 Node* const object = NodeProperties::GetValueInput(node, 0); |
504 Node* const effect = NodeProperties::GetEffectInput(node); | 588 Node* const effect = NodeProperties::GetEffectInput(node); |
505 AbstractState const* state = node_states_.Get(effect); | 589 AbstractState const* state = node_states_.Get(effect); |
506 if (state == nullptr) return NoChange(); | 590 if (state == nullptr) return NoChange(); |
507 int const map_input_count = node->op()->ValueInputCount() - 1; | 591 ZoneHandleSet<Map> object_maps = state->LookupMaps(object); |
508 if (Node* const object_map = | 592 if (object_maps.contains(maps)) return Replace(effect); |
Jarin
2016/11/16 14:54:41
Still confused.
If I have MapCheck(m1, m2); MapCh
Benedikt Meurer
2016/12/21 08:36:49
Done.
| |
509 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { | 593 // TODO(intersect) |
510 for (int i = 0; i < map_input_count; ++i) { | 594 state = state->KillMaps(object, zone()); |
511 Node* map = NodeProperties::GetValueInput(node, 1 + i); | 595 state = state->AddMaps(object, maps, zone()); |
512 if (map == object_map) return Replace(effect); | |
513 } | |
514 } | |
515 if (map_input_count == 1) { | |
516 Node* const map0 = NodeProperties::GetValueInput(node, 1); | |
517 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), map0, | |
518 zone()); | |
519 } | |
520 return UpdateState(node, state); | 596 return UpdateState(node, state); |
521 } | 597 } |
522 | 598 |
523 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { | 599 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { |
524 Node* const object = NodeProperties::GetValueInput(node, 0); | 600 Node* const object = NodeProperties::GetValueInput(node, 0); |
525 Node* const elements = NodeProperties::GetValueInput(node, 1); | 601 Node* const elements = NodeProperties::GetValueInput(node, 1); |
526 Node* const effect = NodeProperties::GetEffectInput(node); | 602 Node* const effect = NodeProperties::GetEffectInput(node); |
527 AbstractState const* state = node_states_.Get(effect); | 603 AbstractState const* state = node_states_.Get(effect); |
528 if (state == nullptr) return NoChange(); | 604 if (state == nullptr) return NoChange(); |
529 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); | |
530 if (Node* const elements_map = | |
531 state->LookupField(elements, FieldIndexOf(HeapObject::kMapOffset))) { | |
532 // Check if the {elements} already have the fixed array map. | 605 // Check if the {elements} already have the fixed array map. |
533 if (elements_map == fixed_array_map) { | 606 ZoneHandleSet<Map> elements_maps = state->LookupMaps(elements); |
534 ReplaceWithValue(node, elements, effect); | 607 ZoneHandleSet<Map> fixed_array_map(factory()->fixed_array_map()); |
535 return Replace(elements); | 608 if (elements_maps == fixed_array_map) { |
536 } | 609 ReplaceWithValue(node, elements, effect); |
610 return Replace(elements); | |
537 } | 611 } |
538 // We know that the resulting elements have the fixed array map. | 612 // We know that the resulting elements have the fixed array map. |
539 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 613 state = state->AddMaps(node, fixed_array_map, zone()); |
540 fixed_array_map, zone()); | |
541 // Kill the previous elements on {object}. | 614 // Kill the previous elements on {object}. |
542 state = | 615 state = |
543 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 616 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
544 // Add the new elements on {object}. | 617 // Add the new elements on {object}. |
545 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, | 618 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, |
546 zone()); | 619 zone()); |
547 return UpdateState(node, state); | 620 return UpdateState(node, state); |
548 } | 621 } |
549 | 622 |
550 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { | 623 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { |
551 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); | 624 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); |
552 Node* const object = NodeProperties::GetValueInput(node, 0); | 625 Node* const object = NodeProperties::GetValueInput(node, 0); |
553 Node* const effect = NodeProperties::GetEffectInput(node); | 626 Node* const effect = NodeProperties::GetEffectInput(node); |
554 AbstractState const* state = node_states_.Get(effect); | 627 AbstractState const* state = node_states_.Get(effect); |
555 if (state == nullptr) return NoChange(); | 628 if (state == nullptr) return NoChange(); |
556 if (flags & GrowFastElementsFlag::kDoubleElements) { | 629 if (flags & GrowFastElementsFlag::kDoubleElements) { |
557 // We know that the resulting elements have the fixed double array map. | 630 // We know that the resulting elements have the fixed double array map. |
558 Node* fixed_double_array_map = jsgraph()->FixedDoubleArrayMapConstant(); | 631 state = state->AddMaps( |
559 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 632 node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone()); |
560 fixed_double_array_map, zone()); | |
561 } else { | 633 } else { |
562 // We know that the resulting elements have the fixed array map. | 634 // We know that the resulting elements have the fixed array map. |
563 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); | 635 state = state->AddMaps( |
564 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 636 node, ZoneHandleSet<Map>(factory()->fixed_array_map()), zone()); |
565 fixed_array_map, zone()); | |
566 } | 637 } |
567 if (flags & GrowFastElementsFlag::kArrayObject) { | 638 if (flags & GrowFastElementsFlag::kArrayObject) { |
568 // Kill the previous Array::length on {object}. | 639 // Kill the previous Array::length on {object}. |
569 state = | 640 state = |
570 state->KillField(object, FieldIndexOf(JSArray::kLengthOffset), zone()); | 641 state->KillField(object, FieldIndexOf(JSArray::kLengthOffset), zone()); |
571 } | 642 } |
572 // Kill the previous elements on {object}. | 643 // Kill the previous elements on {object}. |
573 state = | 644 state = |
574 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 645 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
575 // Add the new elements on {object}. | 646 // Add the new elements on {object}. |
576 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, | 647 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, |
577 zone()); | 648 zone()); |
578 return UpdateState(node, state); | 649 return UpdateState(node, state); |
579 } | 650 } |
580 | 651 |
581 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { | 652 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { |
582 Node* const object = NodeProperties::GetValueInput(node, 0); | 653 Node* const object = NodeProperties::GetValueInput(node, 0); |
583 Node* const source_map = NodeProperties::GetValueInput(node, 1); | 654 // Node* const source_map = NodeProperties::GetValueInput(node, 1); |
584 Node* const target_map = NodeProperties::GetValueInput(node, 2); | 655 // Node* const target_map = NodeProperties::GetValueInput(node, 2); |
585 Node* const effect = NodeProperties::GetEffectInput(node); | 656 Node* const effect = NodeProperties::GetEffectInput(node); |
586 AbstractState const* state = node_states_.Get(effect); | 657 AbstractState const* state = node_states_.Get(effect); |
587 if (state == nullptr) return NoChange(); | 658 if (state == nullptr) return NoChange(); |
659 // TODO(bmeurer): Put the map constants onto the operator. | |
660 // ZoneHandleSet<Map> object_maps = state->LookupMaps(object); | |
661 #if 0 | |
588 if (Node* const object_map = | 662 if (Node* const object_map = |
589 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { | 663 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { |
590 if (target_map == object_map) { | 664 if (target_map == object_map) { |
591 // The {object} already has the {target_map}, so this TransitionElements | 665 // The {object} already has the {target_map}, so this TransitionElements |
592 // {node} is fully redundant (independent of what {source_map} is). | 666 // {node} is fully redundant (independent of what {source_map} is). |
593 return Replace(effect); | 667 return Replace(effect); |
594 } | 668 } |
595 state = | 669 state = |
596 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); | 670 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); |
597 if (source_map == object_map) { | 671 if (source_map == object_map) { |
598 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), | 672 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), |
599 target_map, zone()); | 673 target_map, zone()); |
600 } | 674 } |
601 } else { | 675 } else { |
602 state = | 676 state = |
603 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); | 677 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); |
604 } | 678 } |
679 #else | |
680 state = state->KillMaps(object, zone()); | |
681 #endif | |
605 ElementsTransition transition = ElementsTransitionOf(node->op()); | 682 ElementsTransition transition = ElementsTransitionOf(node->op()); |
606 switch (transition) { | 683 switch (transition) { |
607 case ElementsTransition::kFastTransition: | 684 case ElementsTransition::kFastTransition: |
608 break; | 685 break; |
609 case ElementsTransition::kSlowTransition: | 686 case ElementsTransition::kSlowTransition: |
610 // Kill the elements as well. | 687 // Kill the elements as well. |
611 state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), | 688 state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), |
612 zone()); | 689 zone()); |
613 break; | 690 break; |
614 } | 691 } |
615 return UpdateState(node, state); | 692 return UpdateState(node, state); |
616 } | 693 } |
617 | 694 |
618 Reduction LoadElimination::ReduceLoadField(Node* node) { | 695 Reduction LoadElimination::ReduceLoadField(Node* node) { |
619 FieldAccess const& access = FieldAccessOf(node->op()); | 696 FieldAccess const& access = FieldAccessOf(node->op()); |
620 Node* const object = NodeProperties::GetValueInput(node, 0); | 697 Node* const object = NodeProperties::GetValueInput(node, 0); |
621 Node* const effect = NodeProperties::GetEffectInput(node); | 698 Node* const effect = NodeProperties::GetEffectInput(node); |
622 Node* const control = NodeProperties::GetControlInput(node); | 699 Node* const control = NodeProperties::GetControlInput(node); |
623 AbstractState const* state = node_states_.Get(effect); | 700 AbstractState const* state = node_states_.Get(effect); |
624 if (state == nullptr) return NoChange(); | 701 if (state == nullptr) return NoChange(); |
625 int field_index = FieldIndexOf(access); | 702 if (access.offset == HeapObject::kMapOffset) { |
626 if (field_index >= 0) { | 703 DCHECK_EQ(kTaggedBase, access.base_is_tagged); |
627 if (Node* replacement = state->LookupField(object, field_index)) { | 704 DCHECK(IsAnyTagged(access.machine_type.representation())); |
628 // Make sure we don't resurrect dead {replacement} nodes. | 705 ZoneHandleSet<Map> object_maps = state->LookupMaps(object); |
629 if (!replacement->IsDead()) { | 706 if (object_maps.size() == 1) { |
630 // We might need to guard the {replacement} if the type of the | 707 Node* value = jsgraph()->HeapConstant(object_maps[0]); |
631 // {node} is more precise than the type of the {replacement}. | 708 ReplaceWithValue(node, value, effect); |
632 Type* const node_type = NodeProperties::GetType(node); | 709 return Replace(value); |
633 if (!NodeProperties::GetType(replacement)->Is(node_type)) { | 710 } |
634 replacement = graph()->NewNode(common()->TypeGuard(node_type), | 711 } else { |
635 replacement, control); | 712 int field_index = FieldIndexOf(access); |
713 if (field_index >= 0) { | |
714 if (Node* replacement = state->LookupField(object, field_index)) { | |
715 // Make sure we don't resurrect dead {replacement} nodes. | |
716 if (!replacement->IsDead()) { | |
717 // We might need to guard the {replacement} if the type of the | |
718 // {node} is more precise than the type of the {replacement}. | |
719 Type* const node_type = NodeProperties::GetType(node); | |
720 if (!NodeProperties::GetType(replacement)->Is(node_type)) { | |
721 replacement = graph()->NewNode(common()->TypeGuard(node_type), | |
722 replacement, control); | |
723 } | |
724 ReplaceWithValue(node, replacement, effect); | |
725 return Replace(replacement); | |
636 } | 726 } |
637 ReplaceWithValue(node, replacement, effect); | |
638 return Replace(replacement); | |
639 } | 727 } |
728 state = state->AddField(object, field_index, node, zone()); | |
640 } | 729 } |
641 state = state->AddField(object, field_index, node, zone()); | |
642 } | 730 } |
643 return UpdateState(node, state); | 731 return UpdateState(node, state); |
644 } | 732 } |
645 | 733 |
646 Reduction LoadElimination::ReduceStoreField(Node* node) { | 734 Reduction LoadElimination::ReduceStoreField(Node* node) { |
647 FieldAccess const& access = FieldAccessOf(node->op()); | 735 FieldAccess const& access = FieldAccessOf(node->op()); |
648 Node* const object = NodeProperties::GetValueInput(node, 0); | 736 Node* const object = NodeProperties::GetValueInput(node, 0); |
649 Node* const new_value = NodeProperties::GetValueInput(node, 1); | 737 Node* const new_value = NodeProperties::GetValueInput(node, 1); |
650 Node* const effect = NodeProperties::GetEffectInput(node); | 738 Node* const effect = NodeProperties::GetEffectInput(node); |
651 AbstractState const* state = node_states_.Get(effect); | 739 AbstractState const* state = node_states_.Get(effect); |
652 if (state == nullptr) return NoChange(); | 740 if (state == nullptr) return NoChange(); |
653 int field_index = FieldIndexOf(access); | 741 if (access.offset == HeapObject::kMapOffset) { |
654 if (field_index >= 0) { | 742 DCHECK_EQ(kTaggedBase, access.base_is_tagged); |
655 Node* const old_value = state->LookupField(object, field_index); | 743 DCHECK(IsAnyTagged(access.machine_type.representation())); |
656 if (old_value == new_value) { | 744 // Kill all potential knowledge about the {object}s map. |
657 // This store is fully redundant. | 745 state = state->KillMaps(object, zone()); |
658 return Replace(effect); | 746 Type* const new_value_type = NodeProperties::GetType(new_value); |
747 if (new_value_type->IsConstant()) { | |
748 // Record the new {object} map information. | |
749 ZoneHandleSet<Map> object_maps( | |
750 Handle<Map>::cast(new_value_type->AsConstant()->Value())); | |
751 state = state->AddMaps(object, object_maps, zone()); | |
659 } | 752 } |
660 // Kill all potentially aliasing fields and record the new value. | |
661 state = state->KillField(object, field_index, zone()); | |
662 state = state->AddField(object, field_index, new_value, zone()); | |
663 } else { | 753 } else { |
664 // Unsupported StoreField operator. | 754 int field_index = FieldIndexOf(access); |
665 state = empty_state(); | 755 if (field_index >= 0) { |
756 Node* const old_value = state->LookupField(object, field_index); | |
757 if (old_value == new_value) { | |
758 // This store is fully redundant. | |
759 return Replace(effect); | |
760 } | |
761 // Kill all potentially aliasing fields and record the new value. | |
762 state = state->KillField(object, field_index, zone()); | |
763 state = state->AddField(object, field_index, new_value, zone()); | |
764 } else { | |
765 // Unsupported StoreField operator. | |
766 state = empty_state(); | |
767 } | |
666 } | 768 } |
667 return UpdateState(node, state); | 769 return UpdateState(node, state); |
668 } | 770 } |
669 | 771 |
670 Reduction LoadElimination::ReduceLoadElement(Node* node) { | 772 Reduction LoadElimination::ReduceLoadElement(Node* node) { |
671 Node* const object = NodeProperties::GetValueInput(node, 0); | 773 Node* const object = NodeProperties::GetValueInput(node, 0); |
672 Node* const index = NodeProperties::GetValueInput(node, 1); | 774 Node* const index = NodeProperties::GetValueInput(node, 1); |
673 Node* const effect = NodeProperties::GetEffectInput(node); | 775 Node* const effect = NodeProperties::GetEffectInput(node); |
674 Node* const control = NodeProperties::GetControlInput(node); | 776 Node* const control = NodeProperties::GetControlInput(node); |
675 AbstractState const* state = node_states_.Get(effect); | 777 AbstractState const* state = node_states_.Get(effect); |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
839 state = state->KillField( | 941 state = state->KillField( |
840 object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 942 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
841 if (flags & GrowFastElementsFlag::kArrayObject) { | 943 if (flags & GrowFastElementsFlag::kArrayObject) { |
842 state = state->KillField( | 944 state = state->KillField( |
843 object, FieldIndexOf(JSArray::kLengthOffset), zone()); | 945 object, FieldIndexOf(JSArray::kLengthOffset), zone()); |
844 } | 946 } |
845 break; | 947 break; |
846 } | 948 } |
847 case IrOpcode::kTransitionElementsKind: { | 949 case IrOpcode::kTransitionElementsKind: { |
848 Node* const object = NodeProperties::GetValueInput(current, 0); | 950 Node* const object = NodeProperties::GetValueInput(current, 0); |
849 state = state->KillField( | 951 state = state->KillMaps(object, zone()); |
850 object, FieldIndexOf(HeapObject::kMapOffset), zone()); | |
851 state = state->KillField( | 952 state = state->KillField( |
852 object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 953 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
853 break; | 954 break; |
854 } | 955 } |
855 case IrOpcode::kStoreField: { | 956 case IrOpcode::kStoreField: { |
856 FieldAccess const& access = FieldAccessOf(current->op()); | 957 FieldAccess const& access = FieldAccessOf(current->op()); |
857 Node* const object = NodeProperties::GetValueInput(current, 0); | 958 Node* const object = NodeProperties::GetValueInput(current, 0); |
858 int field_index = FieldIndexOf(access); | 959 int field_index = FieldIndexOf(access); |
859 if (field_index < 0) return empty_state(); | 960 if (field_index < 0) return empty_state(); |
860 state = state->KillField(object, field_index, zone()); | 961 state = state->KillField(object, field_index, zone()); |
(...skipping 20 matching lines...) Expand all Loading... | |
881 } | 982 } |
882 } | 983 } |
883 return state; | 984 return state; |
884 } | 985 } |
885 | 986 |
886 // static | 987 // static |
887 int LoadElimination::FieldIndexOf(int offset) { | 988 int LoadElimination::FieldIndexOf(int offset) { |
888 DCHECK_EQ(0, offset % kPointerSize); | 989 DCHECK_EQ(0, offset % kPointerSize); |
889 int field_index = offset / kPointerSize; | 990 int field_index = offset / kPointerSize; |
890 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; | 991 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; |
891 return field_index; | 992 DCHECK_LT(0, field_index); |
993 return field_index - 1; | |
892 } | 994 } |
893 | 995 |
894 // static | 996 // static |
895 int LoadElimination::FieldIndexOf(FieldAccess const& access) { | 997 int LoadElimination::FieldIndexOf(FieldAccess const& access) { |
896 MachineRepresentation rep = access.machine_type.representation(); | 998 MachineRepresentation rep = access.machine_type.representation(); |
897 switch (rep) { | 999 switch (rep) { |
898 case MachineRepresentation::kNone: | 1000 case MachineRepresentation::kNone: |
899 case MachineRepresentation::kBit: | 1001 case MachineRepresentation::kBit: |
900 UNREACHABLE(); | 1002 UNREACHABLE(); |
901 break; | 1003 break; |
(...skipping 20 matching lines...) Expand all Loading... | |
922 DCHECK_EQ(kTaggedBase, access.base_is_tagged); | 1024 DCHECK_EQ(kTaggedBase, access.base_is_tagged); |
923 return FieldIndexOf(access.offset); | 1025 return FieldIndexOf(access.offset); |
924 } | 1026 } |
925 | 1027 |
926 CommonOperatorBuilder* LoadElimination::common() const { | 1028 CommonOperatorBuilder* LoadElimination::common() const { |
927 return jsgraph()->common(); | 1029 return jsgraph()->common(); |
928 } | 1030 } |
929 | 1031 |
930 Graph* LoadElimination::graph() const { return jsgraph()->graph(); } | 1032 Graph* LoadElimination::graph() const { return jsgraph()->graph(); } |
931 | 1033 |
1034 Factory* LoadElimination::factory() const { return jsgraph()->factory(); } | |
1035 | |
932 } // namespace compiler | 1036 } // namespace compiler |
933 } // namespace internal | 1037 } // namespace internal |
934 } // namespace v8 | 1038 } // namespace v8 |
OLD | NEW |