| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 // For code de-uglification. | 41 // For code de-uglification. |
| 42 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x | 42 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x |
| 43 | 43 |
| 44 namespace v8 { | 44 namespace v8 { |
| 45 namespace internal { | 45 namespace internal { |
| 46 | 46 |
| 47 typedef UniqueSet<Map>* MapSet; | 47 typedef UniqueSet<Map>* MapSet; |
| 48 | 48 |
| 49 struct HCheckTableEntry { | 49 struct HCheckTableEntry { |
| 50 HValue* object_; // The object being approximated. NULL => invalid entry. | 50 HValue* object_; // The object being approximated. NULL => invalid entry. |
| 51 HValue* check_; // The last check instruction. | 51 HInstruction* check_; // The last check instruction. |
| 52 MapSet maps_; // The set of known maps for the object. | 52 MapSet maps_; // The set of known maps for the object. |
| 53 }; | 53 }; |
| 54 | 54 |
| 55 | 55 |
| 56 // The main datastructure used during check elimination, which stores a | 56 // The main data structure used during check elimination, which stores a |
| 57 // set of known maps for each object. | 57 // set of known maps for each object. |
| 58 class HCheckTable : public ZoneObject { | 58 class HCheckTable : public ZoneObject { |
| 59 public: | 59 public: |
| 60 static const int kMaxTrackedObjects = 10; | 60 static const int kMaxTrackedObjects = 10; |
| 61 | 61 |
| 62 explicit HCheckTable(HCheckEliminationPhase* phase) | 62 explicit HCheckTable(HCheckEliminationPhase* phase) |
| 63 : phase_(phase), | 63 : phase_(phase), |
| 64 cursor_(0), | 64 cursor_(0), |
| 65 size_(0) { | 65 size_(0) { |
| 66 } | 66 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 96 case HValue::kCheckMapValue: { | 96 case HValue::kCheckMapValue: { |
| 97 ReduceCheckMapValue(HCheckMapValue::cast(instr)); | 97 ReduceCheckMapValue(HCheckMapValue::cast(instr)); |
| 98 break; | 98 break; |
| 99 } | 99 } |
| 100 case HValue::kCheckHeapObject: { | 100 case HValue::kCheckHeapObject: { |
| 101 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); | 101 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); |
| 102 break; | 102 break; |
| 103 } | 103 } |
| 104 default: { | 104 default: { |
| 105 // If the instruction changes maps uncontrollably, drop everything. | 105 // If the instruction changes maps uncontrollably, drop everything. |
| 106 if (instr->CheckGVNFlag(kChangesMaps) || | 106 if (instr->CheckChangesFlag(kMaps) || |
| 107 instr->CheckGVNFlag(kChangesOsrEntries)) { | 107 instr->CheckChangesFlag(kOsrEntries)) { |
| 108 Kill(); | 108 Kill(); |
| 109 } | 109 } |
| 110 } | 110 } |
| 111 // Improvements possible: | 111 // Improvements possible: |
| 112 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions | 112 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions |
| 113 // - track which values have been HCheckHeapObject'd | 113 // - track which values have been HCheckHeapObject'd |
| 114 } | 114 } |
| 115 | 115 |
| 116 return this; | 116 return this; |
| 117 } | 117 } |
| 118 | 118 |
| 119 // Global analysis: Copy state to successor block. | 119 // Support for global analysis with HFlowEngine: Merge given state with |
| 120 HCheckTable* Copy(HBasicBlock* succ, Zone* zone) { | 120 // the other incoming state. |
| 121 static HCheckTable* Merge(HCheckTable* succ_state, HBasicBlock* succ_block, |
| 122 HCheckTable* pred_state, HBasicBlock* pred_block, |
| 123 Zone* zone) { |
| 124 if (pred_state == NULL || pred_block->IsUnreachable()) { |
| 125 return succ_state; |
| 126 } |
| 127 if (succ_state == NULL) { |
| 128 return pred_state->Copy(succ_block, pred_block, zone); |
| 129 } else { |
| 130 return succ_state->Merge(succ_block, pred_state, pred_block, zone); |
| 131 } |
| 132 } |
| 133 |
| 134 // Support for global analysis with HFlowEngine: Given state merged with all |
| 135 // the other incoming states, prepare it for use. |
| 136 static HCheckTable* Finish(HCheckTable* state, HBasicBlock* block, |
| 137 Zone* zone) { |
| 138 if (state == NULL) { |
| 139 block->MarkUnreachable(); |
| 140 } else if (block->IsUnreachable()) { |
| 141 state = NULL; |
| 142 } |
| 143 if (FLAG_trace_check_elimination) { |
| 144 PrintF("Processing B%d, checkmaps-table:\n", block->block_id()); |
| 145 Print(state); |
| 146 } |
| 147 return state; |
| 148 } |
| 149 |
| 150 private: |
| 151 // Copy state to successor block. |
| 152 HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block, Zone* zone) { |
| 121 HCheckTable* copy = new(phase_->zone()) HCheckTable(phase_); | 153 HCheckTable* copy = new(phase_->zone()) HCheckTable(phase_); |
| 122 for (int i = 0; i < size_; i++) { | 154 for (int i = 0; i < size_; i++) { |
| 123 HCheckTableEntry* old_entry = &entries_[i]; | 155 HCheckTableEntry* old_entry = &entries_[i]; |
| 156 ASSERT(old_entry->maps_->size() > 0); |
| 124 HCheckTableEntry* new_entry = ©->entries_[i]; | 157 HCheckTableEntry* new_entry = ©->entries_[i]; |
| 125 // TODO(titzer): keep the check if this block dominates the successor? | |
| 126 new_entry->object_ = old_entry->object_; | 158 new_entry->object_ = old_entry->object_; |
| 127 new_entry->check_ = NULL; | |
| 128 new_entry->maps_ = old_entry->maps_->Copy(phase_->zone()); | 159 new_entry->maps_ = old_entry->maps_->Copy(phase_->zone()); |
| 160 // Keep the check if the existing check's block dominates the successor. |
| 161 if (old_entry->check_ != NULL && |
| 162 old_entry->check_->block()->Dominates(succ)) { |
| 163 new_entry->check_ = old_entry->check_; |
| 164 } else { |
| 165 // Leave it NULL till we meet a new check instruction for this object |
| 166 // in the control flow. |
| 167 new_entry->check_ = NULL; |
| 168 } |
| 129 } | 169 } |
| 130 copy->cursor_ = cursor_; | 170 copy->cursor_ = cursor_; |
| 131 copy->size_ = size_; | 171 copy->size_ = size_; |
| 132 | 172 |
| 173 // Create entries for succ block's phis. |
| 174 if (!succ->IsLoopHeader() && succ->phis()->length() > 0) { |
| 175 int pred_index = succ->PredecessorIndexOf(from_block); |
| 176 for (int phi_index = 0; |
| 177 phi_index < succ->phis()->length(); |
| 178 ++phi_index) { |
| 179 HPhi* phi = succ->phis()->at(phi_index); |
| 180 HValue* phi_operand = phi->OperandAt(pred_index); |
| 181 |
| 182 HCheckTableEntry* pred_entry = copy->Find(phi_operand); |
| 183 if (pred_entry != NULL) { |
| 184 // Create an entry for a phi in the table. |
| 185 copy->Insert(phi, NULL, pred_entry->maps_->Copy(phase_->zone())); |
| 186 } |
| 187 } |
| 188 } |
| 189 |
| 133 // Branch-sensitive analysis for certain comparisons may add more facts | 190 // Branch-sensitive analysis for certain comparisons may add more facts |
| 134 // to the state for the successor on the true branch. | 191 // to the state for the successor on the true branch. |
| 135 HControlInstruction* end = succ->predecessors()->at(0)->end(); | 192 bool learned = false; |
| 136 if (succ->predecessors()->length() == 1 && end->SuccessorAt(0) == succ) { | 193 if (succ->predecessors()->length() == 1) { |
| 194 HControlInstruction* end = succ->predecessors()->at(0)->end(); |
| 195 bool is_true_branch = end->SuccessorAt(0) == succ; |
| 137 if (end->IsCompareMap()) { | 196 if (end->IsCompareMap()) { |
| 138 // Learn on the true branch of if(CompareMap(x)). | |
| 139 HCompareMap* cmp = HCompareMap::cast(end); | 197 HCompareMap* cmp = HCompareMap::cast(end); |
| 140 HValue* object = cmp->value()->ActualValue(); | 198 HValue* object = cmp->value()->ActualValue(); |
| 141 HCheckTableEntry* entry = copy->Find(object); | 199 HCheckTableEntry* entry = copy->Find(object); |
| 142 if (entry == NULL) { | 200 if (is_true_branch) { |
| 143 copy->Insert(object, cmp->map()); | 201 // Learn on the true branch of if(CompareMap(x)). |
| 202 if (entry == NULL) { |
| 203 copy->Insert(object, cmp, cmp->map()); |
| 204 } else { |
| 205 MapSet list = new(phase_->zone()) UniqueSet<Map>(); |
| 206 list->Add(cmp->map(), phase_->zone()); |
| 207 entry->maps_ = list; |
| 208 entry->check_ = cmp; |
| 209 } |
| 144 } else { | 210 } else { |
| 145 MapSet list = new(phase_->zone()) UniqueSet<Map>(); | 211 // Learn on the false branch of if(CompareMap(x)). |
| 146 list->Add(cmp->map(), phase_->zone()); | 212 if (entry != NULL) { |
| 147 entry->maps_ = list; | 213 entry->maps_->Remove(cmp->map()); |
| 214 } |
| 148 } | 215 } |
| 149 } else if (end->IsCompareObjectEqAndBranch()) { | 216 learned = true; |
| 217 } else if (is_true_branch && end->IsCompareObjectEqAndBranch()) { |
| 150 // Learn on the true branch of if(CmpObjectEq(x, y)). | 218 // Learn on the true branch of if(CmpObjectEq(x, y)). |
| 151 HCompareObjectEqAndBranch* cmp = | 219 HCompareObjectEqAndBranch* cmp = |
| 152 HCompareObjectEqAndBranch::cast(end); | 220 HCompareObjectEqAndBranch::cast(end); |
| 153 HValue* left = cmp->left()->ActualValue(); | 221 HValue* left = cmp->left()->ActualValue(); |
| 154 HValue* right = cmp->right()->ActualValue(); | 222 HValue* right = cmp->right()->ActualValue(); |
| 155 HCheckTableEntry* le = copy->Find(left); | 223 HCheckTableEntry* le = copy->Find(left); |
| 156 HCheckTableEntry* re = copy->Find(right); | 224 HCheckTableEntry* re = copy->Find(right); |
| 157 if (le == NULL) { | 225 if (le == NULL) { |
| 158 if (re != NULL) { | 226 if (re != NULL) { |
| 159 copy->Insert(left, NULL, re->maps_->Copy(zone)); | 227 copy->Insert(left, NULL, re->maps_->Copy(zone)); |
| 160 } | 228 } |
| 161 } else if (re == NULL) { | 229 } else if (re == NULL) { |
| 162 copy->Insert(right, NULL, le->maps_->Copy(zone)); | 230 copy->Insert(right, NULL, le->maps_->Copy(zone)); |
| 163 } else { | 231 } else { |
| 164 MapSet intersect = le->maps_->Intersect(re->maps_, zone); | 232 MapSet intersect = le->maps_->Intersect(re->maps_, zone); |
| 165 le->maps_ = intersect; | 233 le->maps_ = intersect; |
| 166 re->maps_ = intersect->Copy(zone); | 234 re->maps_ = intersect->Copy(zone); |
| 167 } | 235 } |
| 236 learned = true; |
| 168 } | 237 } |
| 169 // Learning on false branches requires storing negative facts. | 238 // Learning on false branches requires storing negative facts. |
| 170 } | 239 } |
| 171 | 240 |
| 241 if (FLAG_trace_check_elimination) { |
| 242 PrintF("B%d checkmaps-table %s from B%d:\n", |
| 243 succ->block_id(), |
| 244 learned ? "learned" : "copied", |
| 245 from_block->block_id()); |
| 246 Print(copy); |
| 247 } |
| 248 |
| 172 return copy; | 249 return copy; |
| 173 } | 250 } |
| 174 | 251 |
| 175 // Global analysis: Merge this state with the other incoming state. | 252 // Merge this state with the other incoming state. |
| 176 HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that, Zone* zone) { | 253 HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that, |
| 254 HBasicBlock* pred_block, Zone* zone) { |
| 177 if (that->size_ == 0) { | 255 if (that->size_ == 0) { |
| 178 // If the other state is empty, simply reset. | 256 // If the other state is empty, simply reset. |
| 179 size_ = 0; | 257 size_ = 0; |
| 180 cursor_ = 0; | 258 cursor_ = 0; |
| 181 return this; | 259 } else { |
| 260 int pred_index = succ->PredecessorIndexOf(pred_block); |
| 261 bool compact = false; |
| 262 for (int i = 0; i < size_; i++) { |
| 263 HCheckTableEntry* this_entry = &entries_[i]; |
| 264 HCheckTableEntry* that_entry; |
| 265 if (this_entry->object_->IsPhi() && |
| 266 this_entry->object_->block() == succ) { |
| 267 HPhi* phi = HPhi::cast(this_entry->object_); |
| 268 HValue* phi_operand = phi->OperandAt(pred_index); |
| 269 that_entry = that->Find(phi_operand); |
| 270 |
| 271 } else { |
| 272 that_entry = that->Find(this_entry->object_); |
| 273 } |
| 274 |
| 275 if (that_entry == NULL) { |
| 276 this_entry->object_ = NULL; |
| 277 compact = true; |
| 278 } else { |
| 279 this_entry->maps_ = |
| 280 this_entry->maps_->Union(that_entry->maps_, phase_->zone()); |
| 281 if (this_entry->check_ != that_entry->check_) { |
| 282 this_entry->check_ = NULL; |
| 283 } |
| 284 ASSERT(this_entry->maps_->size() > 0); |
| 285 } |
| 286 } |
| 287 if (compact) Compact(); |
| 182 } | 288 } |
| 183 bool compact = false; | 289 |
| 184 for (int i = 0; i < size_; i++) { | 290 if (FLAG_trace_check_elimination) { |
| 185 HCheckTableEntry* this_entry = &entries_[i]; | 291 PrintF("B%d checkmaps-table merged with B%d table:\n", |
| 186 HCheckTableEntry* that_entry = that->Find(this_entry->object_); | 292 succ->block_id(), pred_block->block_id()); |
| 187 if (that_entry == NULL) { | 293 Print(this); |
| 188 this_entry->object_ = NULL; | |
| 189 compact = true; | |
| 190 } else { | |
| 191 this_entry->maps_ = this_entry->maps_->Union( | |
| 192 that_entry->maps_, phase_->zone()); | |
| 193 if (this_entry->check_ != that_entry->check_) this_entry->check_ = NULL; | |
| 194 ASSERT(this_entry->maps_->size() > 0); | |
| 195 } | |
| 196 } | 294 } |
| 197 if (compact) Compact(); | |
| 198 return this; | 295 return this; |
| 199 } | 296 } |
| 200 | 297 |
| 201 void ReduceCheckMaps(HCheckMaps* instr) { | 298 void ReduceCheckMaps(HCheckMaps* instr) { |
| 202 HValue* object = instr->value()->ActualValue(); | 299 HValue* object = instr->value()->ActualValue(); |
| 203 HCheckTableEntry* entry = Find(object); | 300 HCheckTableEntry* entry = Find(object); |
| 204 if (entry != NULL) { | 301 if (entry != NULL) { |
| 205 // entry found; | 302 // entry found; |
| 206 MapSet a = entry->maps_; | 303 MapSet a = entry->maps_; |
| 207 MapSet i = instr->map_set().Copy(phase_->zone()); | 304 MapSet i = instr->map_set().Copy(phase_->zone()); |
| 208 if (a->IsSubset(i)) { | 305 if (a->IsSubset(i)) { |
| 209 // The first check is more strict; the second is redundant. | 306 // The first check is more strict; the second is redundant. |
| 210 if (entry->check_ != NULL) { | 307 if (entry->check_ != NULL) { |
| 308 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n", |
| 309 instr->id(), instr->block()->block_id(), entry->check_->id())); |
| 211 instr->DeleteAndReplaceWith(entry->check_); | 310 instr->DeleteAndReplaceWith(entry->check_); |
| 212 INC_STAT(redundant_); | 311 INC_STAT(redundant_); |
| 213 } else { | 312 } else { |
| 214 instr->DeleteAndReplaceWith(instr->value()); | 313 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n", |
| 314 instr->id(), instr->block()->block_id())); |
| 315 // Mark check as dead but leave it in the graph as a checkpoint for |
| 316 // subsequent checks. |
| 317 instr->SetFlag(HValue::kIsDead); |
| 318 entry->check_ = instr; |
| 215 INC_STAT(removed_); | 319 INC_STAT(removed_); |
| 216 } | 320 } |
| 217 return; | 321 return; |
| 218 } | 322 } |
| 219 i = i->Intersect(a, phase_->zone()); | 323 MapSet intersection = i->Intersect(a, phase_->zone()); |
| 220 if (i->size() == 0) { | 324 if (intersection->size() == 0) { |
| 221 // Intersection is empty; probably megamorphic, which is likely to | 325 // Intersection is empty; probably megamorphic, which is likely to |
| 222 // deopt anyway, so just leave things as they are. | 326 // deopt anyway, so just leave things as they are. |
| 223 INC_STAT(empty_); | 327 INC_STAT(empty_); |
| 224 } else { | 328 } else { |
| 225 // TODO(titzer): replace the first check with a more strict check | 329 // Update set of maps in the entry. |
| 226 INC_STAT(narrowed_); | 330 entry->maps_ = intersection; |
| 331 if (intersection->size() != i->size()) { |
| 332 // Narrow set of maps in the second check maps instruction. |
| 333 HGraph* graph = instr->block()->graph(); |
| 334 if (entry->check_ != NULL && |
| 335 entry->check_->block() == instr->block() && |
| 336 entry->check_->IsCheckMaps()) { |
| 337 // There is a check in the same block so replace it with a more |
| 338 // strict check and eliminate the second check entirely. |
| 339 HCheckMaps* check = HCheckMaps::cast(entry->check_); |
| 340 TRACE(("CheckMaps #%d at B%d narrowed\n", check->id(), |
| 341 check->block()->block_id())); |
| 342 // Update map set and ensure that the check is alive. |
| 343 check->set_map_set(intersection, graph->zone()); |
| 344 check->ClearFlag(HValue::kIsDead); |
| 345 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n", |
| 346 instr->id(), instr->block()->block_id(), entry->check_->id())); |
| 347 instr->DeleteAndReplaceWith(entry->check_); |
| 348 } else { |
| 349 TRACE(("CheckMaps #%d at B%d narrowed\n", instr->id(), |
| 350 instr->block()->block_id())); |
| 351 instr->set_map_set(intersection, graph->zone()); |
| 352 entry->check_ = instr; |
| 353 } |
| 354 |
| 355 if (FLAG_trace_check_elimination) { |
| 356 Print(this); |
| 357 } |
| 358 INC_STAT(narrowed_); |
| 359 } |
| 227 } | 360 } |
| 228 } else { | 361 } else { |
| 229 // No entry; insert a new one. | 362 // No entry; insert a new one. |
| 230 Insert(object, instr, instr->map_set().Copy(phase_->zone())); | 363 Insert(object, instr, instr->map_set().Copy(phase_->zone())); |
| 231 } | 364 } |
| 232 } | 365 } |
| 233 | 366 |
| 234 void ReduceCheckValue(HCheckValue* instr) { | 367 void ReduceCheckValue(HCheckValue* instr) { |
| 235 // Canonicalize HCheckValues; they might have their values load-eliminated. | 368 // Canonicalize HCheckValues; they might have their values load-eliminated. |
| 236 HValue* value = instr->Canonicalize(); | 369 HValue* value = instr->Canonicalize(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 257 instr->DeleteAndReplaceWith(constant); | 390 instr->DeleteAndReplaceWith(constant); |
| 258 INC_STAT(loads_); | 391 INC_STAT(loads_); |
| 259 } | 392 } |
| 260 | 393 |
| 261 void ReduceCheckMapValue(HCheckMapValue* instr) { | 394 void ReduceCheckMapValue(HCheckMapValue* instr) { |
| 262 if (!instr->map()->IsConstant()) return; // Nothing to learn. | 395 if (!instr->map()->IsConstant()) return; // Nothing to learn. |
| 263 | 396 |
| 264 HValue* object = instr->value()->ActualValue(); | 397 HValue* object = instr->value()->ActualValue(); |
| 265 // Match a HCheckMapValue(object, HConstant(map)) | 398 // Match a HCheckMapValue(object, HConstant(map)) |
| 266 Unique<Map> map = MapConstant(instr->map()); | 399 Unique<Map> map = MapConstant(instr->map()); |
| 267 MapSet maps = FindMaps(object); | 400 |
| 268 if (maps != NULL) { | 401 HCheckTableEntry* entry = Find(object); |
| 402 if (entry != NULL) { |
| 403 MapSet maps = entry->maps_; |
| 269 if (maps->Contains(map)) { | 404 if (maps->Contains(map)) { |
| 270 if (maps->size() == 1) { | 405 if (maps->size() == 1) { |
| 271 // Object is known to have exactly this map. | 406 // Object is known to have exactly this map. |
| 272 instr->DeleteAndReplaceWith(NULL); | 407 if (entry->check_ != NULL) { |
| 408 instr->DeleteAndReplaceWith(entry->check_); |
| 409 } else { |
| 410 // Mark check as dead but leave it in the graph as a checkpoint for |
| 411 // subsequent checks. |
| 412 instr->SetFlag(HValue::kIsDead); |
| 413 entry->check_ = instr; |
| 414 } |
| 273 INC_STAT(removed_); | 415 INC_STAT(removed_); |
| 274 } else { | 416 } else { |
| 275 // Only one map survives the check. | 417 // Only one map survives the check. |
| 276 maps->Clear(); | 418 maps->Clear(); |
| 277 maps->Add(map, phase_->zone()); | 419 maps->Add(map, phase_->zone()); |
| 420 entry->check_ = instr; |
| 278 } | 421 } |
| 279 } | 422 } |
| 280 } else { | 423 } else { |
| 281 // No prior information. | 424 // No prior information. |
| 282 Insert(object, map); | 425 Insert(object, instr, map); |
| 283 } | 426 } |
| 284 } | 427 } |
| 285 | 428 |
| 286 void ReduceCheckHeapObject(HCheckHeapObject* instr) { | 429 void ReduceCheckHeapObject(HCheckHeapObject* instr) { |
| 287 if (FindMaps(instr->value()->ActualValue()) != NULL) { | 430 if (FindMaps(instr->value()->ActualValue()) != NULL) { |
| 288 // If the object has known maps, it's definitely a heap object. | 431 // If the object has known maps, it's definitely a heap object. |
| 289 instr->DeleteAndReplaceWith(instr->value()); | 432 instr->DeleteAndReplaceWith(instr->value()); |
| 290 INC_STAT(removed_cho_); | 433 INC_STAT(removed_cho_); |
| 291 } | 434 } |
| 292 } | 435 } |
| 293 | 436 |
| 294 void ReduceStoreNamedField(HStoreNamedField* instr) { | 437 void ReduceStoreNamedField(HStoreNamedField* instr) { |
| 295 HValue* object = instr->object()->ActualValue(); | 438 HValue* object = instr->object()->ActualValue(); |
| 296 if (instr->has_transition()) { | 439 if (instr->has_transition()) { |
| 297 // This store transitions the object to a new map. | 440 // This store transitions the object to a new map. |
| 298 Kill(object); | 441 Kill(object); |
| 299 Insert(object, MapConstant(instr->transition())); | 442 Insert(object, NULL, MapConstant(instr->transition())); |
| 300 } else if (IsMapAccess(instr->access())) { | 443 } else if (IsMapAccess(instr->access())) { |
| 301 // This is a store directly to the map field of the object. | 444 // This is a store directly to the map field of the object. |
| 302 Kill(object); | 445 Kill(object); |
| 303 if (!instr->value()->IsConstant()) return; | 446 if (!instr->value()->IsConstant()) return; |
| 304 Insert(object, MapConstant(instr->value())); | 447 Insert(object, NULL, MapConstant(instr->value())); |
| 305 } else { | 448 } else { |
| 306 // If the instruction changes maps, it should be handled above. | 449 // If the instruction changes maps, it should be handled above. |
| 307 CHECK(!instr->CheckGVNFlag(kChangesMaps)); | 450 CHECK(!instr->CheckChangesFlag(kMaps)); |
| 308 } | 451 } |
| 309 } | 452 } |
| 310 | 453 |
| 311 void ReduceCompareMap(HCompareMap* instr) { | 454 void ReduceCompareMap(HCompareMap* instr) { |
| 312 MapSet maps = FindMaps(instr->value()->ActualValue()); | 455 MapSet maps = FindMaps(instr->value()->ActualValue()); |
| 313 if (maps == NULL) return; | 456 if (maps == NULL) return; |
| 457 |
| 458 int succ; |
| 314 if (maps->Contains(instr->map())) { | 459 if (maps->Contains(instr->map())) { |
| 315 if (maps->size() == 1) { | 460 if (maps->size() != 1) { |
| 316 // TODO(titzer): replace with goto true branch | 461 TRACE(("CompareMap #%d for #%d at B%d can't be eliminated: " |
| 317 INC_STAT(compares_true_); | 462 "ambiguous set of maps\n", instr->id(), instr->value()->id(), |
| 463 instr->block()->block_id())); |
| 464 return; |
| 318 } | 465 } |
| 466 succ = 0; |
| 467 INC_STAT(compares_true_); |
| 319 } else { | 468 } else { |
| 320 // TODO(titzer): replace with goto false branch | 469 succ = 1; |
| 321 INC_STAT(compares_false_); | 470 INC_STAT(compares_false_); |
| 322 } | 471 } |
| 472 |
| 473 TRACE(("Marking redundant CompareMap #%d for #%d at B%d as %s\n", |
| 474 instr->id(), instr->value()->id(), instr->block()->block_id(), |
| 475 succ == 0 ? "true" : "false")); |
| 476 instr->set_known_successor_index(succ); |
| 477 |
| 478 int unreachable_succ = 1 - succ; |
| 479 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); |
| 323 } | 480 } |
| 324 | 481 |
| 325 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { | 482 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { |
| 326 MapSet maps = FindMaps(instr->object()->ActualValue()); | 483 MapSet maps = FindMaps(instr->object()->ActualValue()); |
| 327 // Can only learn more about an object that already has a known set of maps. | 484 // Can only learn more about an object that already has a known set of maps. |
| 328 if (maps == NULL) return; | 485 if (maps == NULL) return; |
| 329 if (maps->Contains(instr->original_map())) { | 486 if (maps->Contains(instr->original_map())) { |
| 330 // If the object has the original map, it will be transitioned. | 487 // If the object has the original map, it will be transitioned. |
| 331 maps->Remove(instr->original_map()); | 488 maps->Remove(instr->original_map()); |
| 332 maps->Add(instr->transitioned_map(), phase_->zone()); | 489 maps->Add(instr->transitioned_map(), phase_->zone()); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 int R = size_ - cursor_; | 540 int R = size_ - cursor_; |
| 384 | 541 |
| 385 OS::MemMove(&tmp_entries[0], &entries_[0], L * sizeof(HCheckTableEntry)); | 542 OS::MemMove(&tmp_entries[0], &entries_[0], L * sizeof(HCheckTableEntry)); |
| 386 OS::MemMove(&entries_[0], &entries_[L], R * sizeof(HCheckTableEntry)); | 543 OS::MemMove(&entries_[0], &entries_[L], R * sizeof(HCheckTableEntry)); |
| 387 OS::MemMove(&entries_[R], &tmp_entries[0], L * sizeof(HCheckTableEntry)); | 544 OS::MemMove(&entries_[R], &tmp_entries[0], L * sizeof(HCheckTableEntry)); |
| 388 } | 545 } |
| 389 | 546 |
| 390 cursor_ = size_; // Move cursor to end. | 547 cursor_ = size_; // Move cursor to end. |
| 391 } | 548 } |
| 392 | 549 |
| 393 void Print() { | 550 static void Print(HCheckTable* table) { |
| 394 for (int i = 0; i < size_; i++) { | 551 if (table == NULL) { |
| 395 HCheckTableEntry* entry = &entries_[i]; | 552 PrintF(" unreachable\n"); |
| 553 return; |
| 554 } |
| 555 |
| 556 for (int i = 0; i < table->size_; i++) { |
| 557 HCheckTableEntry* entry = &table->entries_[i]; |
| 396 ASSERT(entry->object_ != NULL); | 558 ASSERT(entry->object_ != NULL); |
| 397 PrintF(" checkmaps-table @%d: object #%d ", i, entry->object_->id()); | 559 PrintF(" checkmaps-table @%d: %s #%d ", i, |
| 560 entry->object_->IsPhi() ? "phi" : "object", entry->object_->id()); |
| 398 if (entry->check_ != NULL) { | 561 if (entry->check_ != NULL) { |
| 399 PrintF("check #%d ", entry->check_->id()); | 562 PrintF("check #%d ", entry->check_->id()); |
| 400 } | 563 } |
| 401 MapSet list = entry->maps_; | 564 MapSet list = entry->maps_; |
| 402 PrintF("%d maps { ", list->size()); | 565 PrintF("%d maps { ", list->size()); |
| 403 for (int j = 0; j < list->size(); j++) { | 566 for (int j = 0; j < list->size(); j++) { |
| 404 if (j > 0) PrintF(", "); | 567 if (j > 0) PrintF(", "); |
| 405 PrintF("%" V8PRIxPTR, list->at(j).Hashcode()); | 568 PrintF("%" V8PRIxPTR, list->at(j).Hashcode()); |
| 406 } | 569 } |
| 407 PrintF(" }\n"); | 570 PrintF(" }\n"); |
| 408 } | 571 } |
| 409 } | 572 } |
| 410 | 573 |
| 411 private: | |
| 412 HCheckTableEntry* Find(HValue* object) { | 574 HCheckTableEntry* Find(HValue* object) { |
| 413 for (int i = size_ - 1; i >= 0; i--) { | 575 for (int i = size_ - 1; i >= 0; i--) { |
| 414 // Search from most-recently-inserted to least-recently-inserted. | 576 // Search from most-recently-inserted to least-recently-inserted. |
| 415 HCheckTableEntry* entry = &entries_[i]; | 577 HCheckTableEntry* entry = &entries_[i]; |
| 416 ASSERT(entry->object_ != NULL); | 578 ASSERT(entry->object_ != NULL); |
| 417 if (phase_->aliasing_->MustAlias(entry->object_, object)) return entry; | 579 if (phase_->aliasing_->MustAlias(entry->object_, object)) return entry; |
| 418 } | 580 } |
| 419 return NULL; | 581 return NULL; |
| 420 } | 582 } |
| 421 | 583 |
| 422 MapSet FindMaps(HValue* object) { | 584 MapSet FindMaps(HValue* object) { |
| 423 HCheckTableEntry* entry = Find(object); | 585 HCheckTableEntry* entry = Find(object); |
| 424 return entry == NULL ? NULL : entry->maps_; | 586 return entry == NULL ? NULL : entry->maps_; |
| 425 } | 587 } |
| 426 | 588 |
| 427 void Insert(HValue* object, Unique<Map> map) { | 589 void Insert(HValue* object, HInstruction* check, Unique<Map> map) { |
| 428 MapSet list = new(phase_->zone()) UniqueSet<Map>(); | 590 MapSet list = new(phase_->zone()) UniqueSet<Map>(); |
| 429 list->Add(map, phase_->zone()); | 591 list->Add(map, phase_->zone()); |
| 430 Insert(object, NULL, list); | 592 Insert(object, check, list); |
| 431 } | 593 } |
| 432 | 594 |
| 433 void Insert(HValue* object, HCheckMaps* check, MapSet maps) { | 595 void Insert(HValue* object, HInstruction* check, MapSet maps) { |
| 434 HCheckTableEntry* entry = &entries_[cursor_++]; | 596 HCheckTableEntry* entry = &entries_[cursor_++]; |
| 435 entry->object_ = object; | 597 entry->object_ = object; |
| 436 entry->check_ = check; | 598 entry->check_ = check; |
| 437 entry->maps_ = maps; | 599 entry->maps_ = maps; |
| 438 // If the table becomes full, wrap around and overwrite older entries. | 600 // If the table becomes full, wrap around and overwrite older entries. |
| 439 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; | 601 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; |
| 440 if (size_ < kMaxTrackedObjects) size_++; | 602 if (size_ < kMaxTrackedObjects) size_++; |
| 441 } | 603 } |
| 442 | 604 |
| 443 bool IsMapAccess(HObjectAccess access) { | 605 bool IsMapAccess(HObjectAccess access) { |
| 444 return access.IsInobject() && access.offset() == JSObject::kMapOffset; | 606 return access.IsInobject() && access.offset() == JSObject::kMapOffset; |
| 445 } | 607 } |
| 446 | 608 |
| 447 Unique<Map> MapConstant(HValue* value) { | 609 Unique<Map> MapConstant(HValue* value) { |
| 448 return Unique<Map>::cast(HConstant::cast(value)->GetUnique()); | 610 return Unique<Map>::cast(HConstant::cast(value)->GetUnique()); |
| 449 } | 611 } |
| 450 | 612 |
| 451 friend class HCheckMapsEffects; | 613 friend class HCheckMapsEffects; |
| 614 friend class HCheckEliminationPhase; |
| 452 | 615 |
| 453 HCheckEliminationPhase* phase_; | 616 HCheckEliminationPhase* phase_; |
| 454 HCheckTableEntry entries_[kMaxTrackedObjects]; | 617 HCheckTableEntry entries_[kMaxTrackedObjects]; |
| 455 int16_t cursor_; // Must be <= kMaxTrackedObjects | 618 int16_t cursor_; // Must be <= kMaxTrackedObjects |
| 456 int16_t size_; // Must be <= kMaxTrackedObjects | 619 int16_t size_; // Must be <= kMaxTrackedObjects |
| 457 // TODO(titzer): STATIC_ASSERT kMaxTrackedObjects < max(cursor_) | 620 // TODO(titzer): STATIC_ASSERT kMaxTrackedObjects < max(cursor_) |
| 458 }; | 621 }; |
| 459 | 622 |
| 460 | 623 |
| 461 // Collects instructions that can cause effects that invalidate information | 624 // Collects instructions that can cause effects that invalidate information |
| (...skipping 13 matching lines...) Expand all Loading... |
| 475 switch (instr->opcode()) { | 638 switch (instr->opcode()) { |
| 476 case HValue::kStoreNamedField: { | 639 case HValue::kStoreNamedField: { |
| 477 stores_.Add(HStoreNamedField::cast(instr), zone); | 640 stores_.Add(HStoreNamedField::cast(instr), zone); |
| 478 break; | 641 break; |
| 479 } | 642 } |
| 480 case HValue::kOsrEntry: { | 643 case HValue::kOsrEntry: { |
| 481 // Kill everything. Loads must not be hoisted past the OSR entry. | 644 // Kill everything. Loads must not be hoisted past the OSR entry. |
| 482 maps_stored_ = true; | 645 maps_stored_ = true; |
| 483 } | 646 } |
| 484 default: { | 647 default: { |
| 485 maps_stored_ |= (instr->CheckGVNFlag(kChangesMaps) | | 648 maps_stored_ |= (instr->CheckChangesFlag(kMaps) | |
| 486 instr->CheckGVNFlag(kChangesElementsKind)); | 649 instr->CheckChangesFlag(kElementsKind)); |
| 487 } | 650 } |
| 488 } | 651 } |
| 489 } | 652 } |
| 490 | 653 |
| 491 // Apply these effects to the given check elimination table. | 654 // Apply these effects to the given check elimination table. |
| 492 void Apply(HCheckTable* table) { | 655 void Apply(HCheckTable* table) { |
| 493 if (maps_stored_) { | 656 if (maps_stored_) { |
| 494 // Uncontrollable map modifications; kill everything. | 657 // Uncontrollable map modifications; kill everything. |
| 495 table->Kill(); | 658 table->Kill(); |
| 496 return; | 659 return; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 PRINT_STAT(removed_cho); | 715 PRINT_STAT(removed_cho); |
| 553 PRINT_STAT(narrowed); | 716 PRINT_STAT(narrowed); |
| 554 PRINT_STAT(loads); | 717 PRINT_STAT(loads); |
| 555 PRINT_STAT(empty); | 718 PRINT_STAT(empty); |
| 556 PRINT_STAT(compares_true); | 719 PRINT_STAT(compares_true); |
| 557 PRINT_STAT(compares_false); | 720 PRINT_STAT(compares_false); |
| 558 PRINT_STAT(transitions); | 721 PRINT_STAT(transitions); |
| 559 } | 722 } |
| 560 | 723 |
| 561 } } // namespace v8::internal | 724 } } // namespace v8::internal |
| OLD | NEW |