| Index: src/hydrogen-check-elimination.cc
|
| diff --git a/src/hydrogen-check-elimination.cc b/src/hydrogen-check-elimination.cc
|
| index e12f14a13fb16b740fe6f4327970c5d77f7edca2..5d1323b08b5754516e5144e3715761dee8f7ad93 100644
|
| --- a/src/hydrogen-check-elimination.cc
|
| +++ b/src/hydrogen-check-elimination.cc
|
| @@ -48,12 +48,12 @@ typedef UniqueSet<Map>* MapSet;
|
|
|
| struct HCheckTableEntry {
|
| HValue* object_; // The object being approximated. NULL => invalid entry.
|
| - HValue* check_; // The last check instruction.
|
| - MapSet maps_; // The set of known maps for the object.
|
| + HInstruction* check_; // The last check instruction.
|
| + MapSet maps_; // The set of known maps for the object.
|
| };
|
|
|
|
|
| -// The main datastructure used during check elimination, which stores a
|
| +// The main data structure used during check elimination, which stores a
|
| // set of known maps for each object.
|
| class HCheckTable : public ZoneObject {
|
| public:
|
| @@ -130,6 +130,23 @@ class HCheckTable : public ZoneObject {
|
| copy->cursor_ = cursor_;
|
| copy->size_ = size_;
|
|
|
| + // Create entries for succ block's phis.
|
| + if (succ->phis()->length() > 0) {
|
| + int pred_index = succ->PredecessorIndexOf(from_block);
|
| + for (int phi_index = 0;
|
| + phi_index < succ->phis()->length();
|
| + ++phi_index) {
|
| + HPhi* phi = succ->phis()->at(phi_index);
|
| + HValue* phi_operand = phi->OperandAt(pred_index);
|
| +
|
| + HCheckTableEntry* pred_entry = copy->Find(phi_operand);
|
| + if (pred_entry != NULL) {
|
| + // Create an entry for a phi in the table.
|
| + copy->Insert(phi, NULL, pred_entry->maps_->Copy(phase_->zone()));
|
| + }
|
| + }
|
| + }
|
| +
|
| // Branch-sensitive analysis for certain comparisons may add more facts
|
| // to the state for the successor on the true branch.
|
| bool learned = false;
|
| @@ -185,17 +202,28 @@ class HCheckTable : public ZoneObject {
|
|
|
| // Global analysis: Merge this state with the other incoming state.
|
| HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that,
|
| - HBasicBlock* that_block, Zone* zone) {
|
| - if (that_block->IsReachable()) {
|
| + HBasicBlock* pred_block, Zone* zone) {
|
| + if (pred_block->IsReachable()) {
|
| if (that->size_ == 0) {
|
| // If the other state is empty, simply reset.
|
| size_ = 0;
|
| cursor_ = 0;
|
| } else {
|
| + int pred_index = succ->PredecessorIndexOf(pred_block);
|
| bool compact = false;
|
| for (int i = 0; i < size_; i++) {
|
| HCheckTableEntry* this_entry = &entries_[i];
|
| - HCheckTableEntry* that_entry = that->Find(this_entry->object_);
|
| + HCheckTableEntry* that_entry;
|
| + if (this_entry->object_->IsPhi() &&
|
| + this_entry->object_->block() == succ) {
|
| + HPhi* phi = HPhi::cast(this_entry->object_);
|
| + HValue* phi_operand = phi->OperandAt(pred_index);
|
| + that_entry = that->Find(phi_operand);
|
| +
|
| + } else {
|
| + that_entry = that->Find(this_entry->object_);
|
| + }
|
| +
|
| if (that_entry == NULL) {
|
| this_entry->object_ = NULL;
|
| compact = true;
|
| @@ -213,7 +241,7 @@ class HCheckTable : public ZoneObject {
|
| }
|
| if (FLAG_trace_check_elimination) {
|
| PrintF("B%d checkmaps-table merged with B%d table:\n",
|
| - succ->block_id(), that_block->block_id());
|
| + succ->block_id(), pred_block->block_id());
|
| Print();
|
| }
|
| return this;
|
| @@ -244,14 +272,41 @@ class HCheckTable : public ZoneObject {
|
| }
|
| return;
|
| }
|
| - i = i->Intersect(a, phase_->zone());
|
| - if (i->size() == 0) {
|
| + MapSet intersection = i->Intersect(a, phase_->zone());
|
| + if (intersection->size() == 0) {
|
| // Intersection is empty; probably megamorphic, which is likely to
|
| // deopt anyway, so just leave things as they are.
|
| INC_STAT(empty_);
|
| } else {
|
| - // TODO(titzer): replace the first check with a more strict check
|
| - INC_STAT(narrowed_);
|
| + // Update set of maps in the entry.
|
| + entry->maps_ = intersection;
|
| + if (intersection->size() != i->size()) {
|
| + // Narrow set of maps in the second check maps instruction.
|
| + HGraph* graph = instr->block()->graph();
|
| + if (entry->check_ != NULL &&
|
| + entry->check_->block() == instr->block() &&
|
| + entry->check_->IsCheckMaps()) {
|
| + // There is a check in the same block so replace it with a more
|
| + // strict check and eliminate the second check entirely.
|
| + HCheckMaps* check = HCheckMaps::cast(entry->check_);
|
| + TRACE(("CheckMaps #%d at B%d narrowed\n", check->id(),
|
| + check->block()->block_id()));
|
| + check->set_map_set(intersection, graph->zone());
|
| + TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n",
|
| + instr->id(), instr->block()->block_id(), entry->check_->id()));
|
| + instr->DeleteAndReplaceWith(entry->check_);
|
| + } else {
|
| + TRACE(("CheckMaps #%d at B%d narrowed\n", instr->id(),
|
| + instr->block()->block_id()));
|
| + instr->set_map_set(intersection, graph->zone());
|
| + entry->check_ = instr;
|
| + }
|
| +
|
| + if (FLAG_trace_check_elimination) {
|
| + Print();
|
| + }
|
| + INC_STAT(narrowed_);
|
| + }
|
| }
|
| } else {
|
| // No entry; insert a new one.
|
| @@ -426,7 +481,9 @@ class HCheckTable : public ZoneObject {
|
| for (int i = 0; i < size_; i++) {
|
| HCheckTableEntry* entry = &entries_[i];
|
| ASSERT(entry->object_ != NULL);
|
| - PrintF(" checkmaps-table @%d: object #%d ", i, entry->object_->id());
|
| + PrintF(" checkmaps-table @%d: %s #%d ", i,
|
| + entry->object_->IsPhi() ? "phi" : "object",
|
| + entry->object_->id());
|
| if (entry->check_ != NULL) {
|
| PrintF("check #%d ", entry->check_->id());
|
| }
|
|
|