| Index: src/compiler/load-elimination.cc
|
| diff --git a/src/compiler/load-elimination.cc b/src/compiler/load-elimination.cc
|
| index 6131fc57d4ec333ef6eac76a01640aac21607d53..2ad21d02ccf1f8b724b3e5cc95cb3561b80308e4 100644
|
| --- a/src/compiler/load-elimination.cc
|
| +++ b/src/compiler/load-elimination.cc
|
| @@ -55,6 +55,8 @@ bool MustAlias(Node* a, Node* b) { return QueryAlias(a, b) == kMustAlias; }
|
|
|
| Reduction LoadElimination::Reduce(Node* node) {
|
| switch (node->opcode()) {
|
| + case IrOpcode::kArrayBufferWasNeutered:
|
| + return ReduceArrayBufferWasNeutered(node);
|
| case IrOpcode::kCheckMaps:
|
| return ReduceCheckMaps(node);
|
| case IrOpcode::kEnsureWritableFastElements:
|
| @@ -85,6 +87,65 @@ Reduction LoadElimination::Reduce(Node* node) {
|
| return NoChange();
|
| }
|
|
|
| +namespace {
|
| +
|
| +bool IsCompatibleCheck(Node const* a, Node const* b) {
|
| + if (a->op() != b->op()) return false;
|
| + for (int i = a->op()->ValueInputCount(); --i >= 0;) {
|
| + if (!MustAlias(a->InputAt(i), b->InputAt(i))) return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +Node* LoadElimination::AbstractChecks::Lookup(Node* node) const {
|
| + for (Node* const check : nodes_) {
|
| + if (check && IsCompatibleCheck(check, node)) {
|
| + return check;
|
| + }
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| +bool LoadElimination::AbstractChecks::Equals(AbstractChecks const* that) const {
|
| + if (this == that) return true;
|
| + for (size_t i = 0; i < arraysize(nodes_); ++i) {
|
| + if (Node* this_node = this->nodes_[i]) {
|
| + for (size_t j = 0;; ++j) {
|
| + if (j == arraysize(nodes_)) return false;
|
| + if (that->nodes_[j] == this_node) break;
|
| + }
|
| + }
|
| + }
|
| + for (size_t i = 0; i < arraysize(nodes_); ++i) {
|
| + if (Node* that_node = that->nodes_[i]) {
|
| + for (size_t j = 0;; ++j) {
|
| + if (j == arraysize(nodes_)) return false;
|
| + if (this->nodes_[j] == that_node) break;
|
| + }
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +LoadElimination::AbstractChecks const* LoadElimination::AbstractChecks::Merge(
|
| + AbstractChecks const* that, Zone* zone) const {
|
| + if (this->Equals(that)) return this;
|
| + AbstractChecks* copy = new (zone) AbstractChecks(zone);
|
| + for (Node* const this_node : this->nodes_) {
|
| + if (this_node == nullptr) continue;
|
| + for (Node* const that_node : that->nodes_) {
|
| + if (this_node == that_node) {
|
| + copy->nodes_[copy->next_index_++] = this_node;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + copy->next_index_ %= arraysize(nodes_);
|
| + return copy;
|
| +}
|
| +
|
| Node* LoadElimination::AbstractElements::Lookup(Node* object,
|
| Node* index) const {
|
| for (Element const element : elements_) {
|
| @@ -165,6 +226,7 @@ LoadElimination::AbstractElements::Merge(AbstractElements const* that,
|
| this_element.index == that_element.index &&
|
| this_element.value == that_element.value) {
|
| copy->elements_[copy->next_index_++] = this_element;
|
| + break;
|
| }
|
| }
|
| }
|
| @@ -194,6 +256,13 @@ LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill(
|
| }
|
|
|
| bool LoadElimination::AbstractState::Equals(AbstractState const* that) const {
|
| + if (this->checks_) {
|
| + if (!that->checks_ || !that->checks_->Equals(this->checks_)) {
|
| + return false;
|
| + }
|
| + } else if (that->checks_) {
|
| + return false;
|
| + }
|
| if (this->elements_) {
|
| if (!that->elements_ || !that->elements_->Equals(this->elements_)) {
|
| return false;
|
| @@ -215,6 +284,12 @@ bool LoadElimination::AbstractState::Equals(AbstractState const* that) const {
|
|
|
| void LoadElimination::AbstractState::Merge(AbstractState const* that,
|
| Zone* zone) {
|
| + // Merge the information we have about the checks.
|
| + if (this->checks_) {
|
| + this->checks_ =
|
| + that->checks_ ? that->checks_->Merge(this->checks_, zone) : nullptr;
|
| + }
|
| +
|
| // Merge the information we have about the elements.
|
| if (this->elements_) {
|
| this->elements_ = that->elements_
|
| @@ -234,6 +309,21 @@ void LoadElimination::AbstractState::Merge(AbstractState const* that,
|
| }
|
| }
|
|
|
| +Node* LoadElimination::AbstractState::LookupCheck(Node* node) const {
|
| + return this->checks_ ? this->checks_->Lookup(node) : nullptr;
|
| +}
|
| +
|
| +LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck(
|
| + Node* node, Zone* zone) const {
|
| + AbstractState* that = new (zone) AbstractState(*this);
|
| + if (that->checks_) {
|
| + that->checks_ = that->checks_->Extend(node, zone);
|
| + } else {
|
| + that->checks_ = new (zone) AbstractChecks(node, zone);
|
| + }
|
| + return that;
|
| +}
|
| +
|
| Node* LoadElimination::AbstractState::LookupElement(Node* object,
|
| Node* index) const {
|
| if (this->elements_) {
|
| @@ -315,6 +405,18 @@ void LoadElimination::AbstractStateForEffectNodes::Set(
|
| info_for_node_[id] = state;
|
| }
|
|
|
| +Reduction LoadElimination::ReduceArrayBufferWasNeutered(Node* node) {
|
| + Node* const effect = NodeProperties::GetEffectInput(node);
|
| + AbstractState const* state = node_states_.Get(effect);
|
| + if (state == nullptr) return NoChange();
|
| + if (Node* const check = state->LookupCheck(node)) {
|
| + ReplaceWithValue(node, check, effect);
|
| + return Replace(check);
|
| + }
|
| + state = state->AddCheck(node, zone());
|
| + return UpdateState(node, state);
|
| +}
|
| +
|
| Reduction LoadElimination::ReduceCheckMaps(Node* node) {
|
| Node* const object = NodeProperties::GetValueInput(node, 0);
|
| Node* const effect = NodeProperties::GetEffectInput(node);
|
|
|