Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: src/hydrogen-check-elimination.cc

Issue 181453002: Reset trunk to 3.24.35.4 (Closed) Base URL: https://v8.googlecode.com/svn/trunk
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.cc ('k') | src/hydrogen-flow-engine.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 HInstruction* check_; // The last check instruction. 51 HValue* 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 bool is_stable_;
54 }; 53 };
55 54
56 55
57 // The main data structure used during check elimination, which stores a 56 // The main datastructure used during check elimination, which stores a
58 // set of known maps for each object. 57 // set of known maps for each object.
59 class HCheckTable : public ZoneObject { 58 class HCheckTable : public ZoneObject {
60 public: 59 public:
61 static const int kMaxTrackedObjects = 10; 60 static const int kMaxTrackedObjects = 10;
62 61
63 explicit HCheckTable(HCheckEliminationPhase* phase) 62 explicit HCheckTable(HCheckEliminationPhase* phase)
64 : phase_(phase), 63 : phase_(phase),
65 cursor_(0), 64 cursor_(0),
66 size_(0) { 65 size_(0) {
67 } 66 }
(...skipping 29 matching lines...) Expand all
97 case HValue::kCheckMapValue: { 96 case HValue::kCheckMapValue: {
98 ReduceCheckMapValue(HCheckMapValue::cast(instr)); 97 ReduceCheckMapValue(HCheckMapValue::cast(instr));
99 break; 98 break;
100 } 99 }
101 case HValue::kCheckHeapObject: { 100 case HValue::kCheckHeapObject: {
102 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); 101 ReduceCheckHeapObject(HCheckHeapObject::cast(instr));
103 break; 102 break;
104 } 103 }
105 default: { 104 default: {
106 // If the instruction changes maps uncontrollably, drop everything. 105 // If the instruction changes maps uncontrollably, drop everything.
107 if (instr->CheckChangesFlag(kOsrEntries)) { 106 if (instr->CheckGVNFlag(kChangesMaps) ||
108 Reset(); 107 instr->CheckGVNFlag(kChangesOsrEntries)) {
109 } else if (instr->CheckChangesFlag(kMaps)) { 108 Kill();
110 KillUnstableEntries();
111 } 109 }
112 } 110 }
113 // Improvements possible: 111 // Improvements possible:
114 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions 112 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions
115 // - track which values have been HCheckHeapObject'd 113 // - track which values have been HCheckHeapObject'd
116 } 114 }
117 115
118 return this; 116 return this;
119 } 117 }
120 118
121 // Support for global analysis with HFlowEngine: Merge given state with 119 // Global analysis: Copy state to successor block.
122 // the other incoming state.
123 static HCheckTable* Merge(HCheckTable* succ_state, HBasicBlock* succ_block,
124 HCheckTable* pred_state, HBasicBlock* pred_block,
125 Zone* zone) {
126 if (pred_state == NULL || pred_block->IsUnreachable()) {
127 return succ_state;
128 }
129 if (succ_state == NULL) {
130 return pred_state->Copy(succ_block, pred_block, zone);
131 } else {
132 return succ_state->Merge(succ_block, pred_state, pred_block, zone);
133 }
134 }
135
136 // Support for global analysis with HFlowEngine: Given state merged with all
137 // the other incoming states, prepare it for use.
138 static HCheckTable* Finish(HCheckTable* state, HBasicBlock* block,
139 Zone* zone) {
140 if (state == NULL) {
141 block->MarkUnreachable();
142 }
143 return state;
144 }
145
146 private:
147 // Copy state to successor block.
148 HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block, Zone* zone) { 120 HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block, Zone* zone) {
149 HCheckTable* copy = new(phase_->zone()) HCheckTable(phase_); 121 HCheckTable* copy = new(phase_->zone()) HCheckTable(phase_);
150 for (int i = 0; i < size_; i++) { 122 for (int i = 0; i < size_; i++) {
151 HCheckTableEntry* old_entry = &entries_[i]; 123 HCheckTableEntry* old_entry = &entries_[i];
152 HCheckTableEntry* new_entry = &copy->entries_[i]; 124 HCheckTableEntry* new_entry = &copy->entries_[i];
125 // TODO(titzer): keep the check if this block dominates the successor?
153 new_entry->object_ = old_entry->object_; 126 new_entry->object_ = old_entry->object_;
127 new_entry->check_ = NULL;
154 new_entry->maps_ = old_entry->maps_->Copy(phase_->zone()); 128 new_entry->maps_ = old_entry->maps_->Copy(phase_->zone());
155 new_entry->is_stable_ = old_entry->is_stable_;
156 // Keep the check if the existing check's block dominates the successor.
157 if (old_entry->check_ != NULL &&
158 old_entry->check_->block()->Dominates(succ)) {
159 new_entry->check_ = old_entry->check_;
160 } else {
161 // Leave it NULL till we meet a new check instruction for this object
162 // in the control flow.
163 new_entry->check_ = NULL;
164 }
165 } 129 }
166 copy->cursor_ = cursor_; 130 copy->cursor_ = cursor_;
167 copy->size_ = size_; 131 copy->size_ = size_;
168 132
169 // Create entries for succ block's phis.
170 if (!succ->IsLoopHeader() && succ->phis()->length() > 0) {
171 int pred_index = succ->PredecessorIndexOf(from_block);
172 for (int phi_index = 0;
173 phi_index < succ->phis()->length();
174 ++phi_index) {
175 HPhi* phi = succ->phis()->at(phi_index);
176 HValue* phi_operand = phi->OperandAt(pred_index);
177
178 HCheckTableEntry* pred_entry = copy->Find(phi_operand);
179 if (pred_entry != NULL) {
180 // Create an entry for a phi in the table.
181 copy->Insert(phi, NULL, pred_entry->maps_->Copy(phase_->zone()),
182 pred_entry->is_stable_);
183 }
184 }
185 }
186
187 // Branch-sensitive analysis for certain comparisons may add more facts 133 // Branch-sensitive analysis for certain comparisons may add more facts
188 // to the state for the successor on the true branch. 134 // to the state for the successor on the true branch.
189 bool learned = false; 135 bool learned = false;
190 if (succ->predecessors()->length() == 1) { 136 HControlInstruction* end = succ->predecessors()->at(0)->end();
191 HControlInstruction* end = succ->predecessors()->at(0)->end(); 137 if (succ->predecessors()->length() == 1 && end->SuccessorAt(0) == succ) {
192 bool is_true_branch = end->SuccessorAt(0) == succ;
193 if (end->IsCompareMap()) { 138 if (end->IsCompareMap()) {
139 // Learn on the true branch of if(CompareMap(x)).
194 HCompareMap* cmp = HCompareMap::cast(end); 140 HCompareMap* cmp = HCompareMap::cast(end);
195 HValue* object = cmp->value()->ActualValue(); 141 HValue* object = cmp->value()->ActualValue();
196 HCheckTableEntry* entry = copy->Find(object); 142 HCheckTableEntry* entry = copy->Find(object);
197 if (is_true_branch) { 143 if (entry == NULL) {
198 // Learn on the true branch of if(CompareMap(x)). 144 copy->Insert(object, cmp->map());
199 if (entry == NULL) {
200 copy->Insert(object, cmp, cmp->map(), cmp->is_stable());
201 } else {
202 MapSet list = new(phase_->zone()) UniqueSet<Map>();
203 list->Add(cmp->map(), phase_->zone());
204 entry->maps_ = list;
205 entry->check_ = cmp;
206 entry->is_stable_ = cmp->is_stable();
207 }
208 } else { 145 } else {
209 // Learn on the false branch of if(CompareMap(x)). 146 MapSet list = new(phase_->zone()) UniqueSet<Map>();
210 if (entry != NULL) { 147 list->Add(cmp->map(), phase_->zone());
211 entry->maps_->Remove(cmp->map()); 148 entry->maps_ = list;
212 }
213 } 149 }
214 learned = true; 150 learned = true;
215 } else if (is_true_branch && end->IsCompareObjectEqAndBranch()) { 151 } else if (end->IsCompareObjectEqAndBranch()) {
216 // Learn on the true branch of if(CmpObjectEq(x, y)). 152 // Learn on the true branch of if(CmpObjectEq(x, y)).
217 HCompareObjectEqAndBranch* cmp = 153 HCompareObjectEqAndBranch* cmp =
218 HCompareObjectEqAndBranch::cast(end); 154 HCompareObjectEqAndBranch::cast(end);
219 HValue* left = cmp->left()->ActualValue(); 155 HValue* left = cmp->left()->ActualValue();
220 HValue* right = cmp->right()->ActualValue(); 156 HValue* right = cmp->right()->ActualValue();
221 HCheckTableEntry* le = copy->Find(left); 157 HCheckTableEntry* le = copy->Find(left);
222 HCheckTableEntry* re = copy->Find(right); 158 HCheckTableEntry* re = copy->Find(right);
223 if (le == NULL) { 159 if (le == NULL) {
224 if (re != NULL) { 160 if (re != NULL) {
225 copy->Insert(left, NULL, re->maps_->Copy(zone), re->is_stable_); 161 copy->Insert(left, NULL, re->maps_->Copy(zone));
226 } 162 }
227 } else if (re == NULL) { 163 } else if (re == NULL) {
228 copy->Insert(right, NULL, le->maps_->Copy(zone), le->is_stable_); 164 copy->Insert(right, NULL, le->maps_->Copy(zone));
229 } else { 165 } else {
230 MapSet intersect = le->maps_->Intersect(re->maps_, zone); 166 MapSet intersect = le->maps_->Intersect(re->maps_, zone);
231 le->maps_ = intersect; 167 le->maps_ = intersect;
232 re->maps_ = intersect->Copy(zone); 168 re->maps_ = intersect->Copy(zone);
233 } 169 }
234 learned = true; 170 learned = true;
235 } 171 }
236 // Learning on false branches requires storing negative facts. 172 // Learning on false branches requires storing negative facts.
237 } 173 }
238 174
239 if (FLAG_trace_check_elimination) { 175 if (FLAG_trace_check_elimination) {
240 PrintF("B%d checkmaps-table %s from B%d:\n", 176 PrintF("B%d checkmaps-table %s from B%d:\n",
241 succ->block_id(), 177 succ->block_id(),
242 learned ? "learned" : "copied", 178 learned ? "learned" : "copied",
243 from_block->block_id()); 179 from_block->block_id());
244 copy->Print(); 180 copy->Print();
245 } 181 }
246 182
247 return copy; 183 return copy;
248 } 184 }
249 185
250 // Merge this state with the other incoming state. 186 // Global analysis: Merge this state with the other incoming state.
251 HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that, 187 HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that,
252 HBasicBlock* pred_block, Zone* zone) { 188 HBasicBlock* that_block, Zone* zone) {
253 if (that->size_ == 0) { 189 if (that_block->IsReachable()) {
254 // If the other state is empty, simply reset. 190 if (that->size_ == 0) {
255 Reset(); 191 // If the other state is empty, simply reset.
256 } else { 192 size_ = 0;
257 int pred_index = succ->PredecessorIndexOf(pred_block); 193 cursor_ = 0;
258 bool compact = false; 194 } else {
259 for (int i = 0; i < size_; i++) { 195 bool compact = false;
260 HCheckTableEntry* this_entry = &entries_[i]; 196 for (int i = 0; i < size_; i++) {
261 HCheckTableEntry* that_entry; 197 HCheckTableEntry* this_entry = &entries_[i];
262 if (this_entry->object_->IsPhi() && 198 HCheckTableEntry* that_entry = that->Find(this_entry->object_);
263 this_entry->object_->block() == succ) { 199 if (that_entry == NULL) {
264 HPhi* phi = HPhi::cast(this_entry->object_); 200 this_entry->object_ = NULL;
265 HValue* phi_operand = phi->OperandAt(pred_index); 201 compact = true;
266 that_entry = that->Find(phi_operand); 202 } else {
267 203 this_entry->maps_ =
268 } else { 204 this_entry->maps_->Union(that_entry->maps_, phase_->zone());
269 that_entry = that->Find(this_entry->object_); 205 if (this_entry->check_ != that_entry->check_) {
206 this_entry->check_ = NULL;
207 }
208 ASSERT(this_entry->maps_->size() > 0);
209 }
270 } 210 }
271 211 if (compact) Compact();
272 if (that_entry == NULL) {
273 this_entry->object_ = NULL;
274 compact = true;
275 } else {
276 this_entry->maps_ =
277 this_entry->maps_->Union(that_entry->maps_, phase_->zone());
278 this_entry->is_stable_ =
279 this_entry->is_stable_ && that_entry->is_stable_;
280 if (this_entry->check_ != that_entry->check_) {
281 this_entry->check_ = NULL;
282 }
283 ASSERT(this_entry->maps_->size() > 0);
284 }
285 } 212 }
286 if (compact) Compact();
287 } 213 }
288
289 if (FLAG_trace_check_elimination) { 214 if (FLAG_trace_check_elimination) {
290 PrintF("B%d checkmaps-table merged with B%d table:\n", 215 PrintF("B%d checkmaps-table merged with B%d table:\n",
291 succ->block_id(), pred_block->block_id()); 216 succ->block_id(), that_block->block_id());
292 Print(); 217 Print();
293 } 218 }
294 return this; 219 return this;
295 } 220 }
296 221
297 void ReduceCheckMaps(HCheckMaps* instr) { 222 void ReduceCheckMaps(HCheckMaps* instr) {
298 HValue* object = instr->value()->ActualValue(); 223 HValue* object = instr->value()->ActualValue();
299 HCheckTableEntry* entry = Find(object); 224 HCheckTableEntry* entry = Find(object);
300 if (entry != NULL) { 225 if (entry != NULL) {
301 // entry found; 226 // entry found;
(...skipping 10 matching lines...) Expand all
312 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n", 237 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n",
313 instr->id(), instr->block()->block_id())); 238 instr->id(), instr->block()->block_id()));
314 // Mark check as dead but leave it in the graph as a checkpoint for 239 // Mark check as dead but leave it in the graph as a checkpoint for
315 // subsequent checks. 240 // subsequent checks.
316 instr->SetFlag(HValue::kIsDead); 241 instr->SetFlag(HValue::kIsDead);
317 entry->check_ = instr; 242 entry->check_ = instr;
318 INC_STAT(removed_); 243 INC_STAT(removed_);
319 } 244 }
320 return; 245 return;
321 } 246 }
322 MapSet intersection = i->Intersect(a, phase_->zone()); 247 i = i->Intersect(a, phase_->zone());
323 if (intersection->size() == 0) { 248 if (i->size() == 0) {
324 // Intersection is empty; probably megamorphic, which is likely to 249 // Intersection is empty; probably megamorphic, which is likely to
325 // deopt anyway, so just leave things as they are. 250 // deopt anyway, so just leave things as they are.
326 INC_STAT(empty_); 251 INC_STAT(empty_);
327 } else { 252 } else {
328 // Update set of maps in the entry. 253 // TODO(titzer): replace the first check with a more strict check
329 entry->maps_ = intersection; 254 INC_STAT(narrowed_);
330 if (intersection->size() != i->size()) {
331 // Narrow set of maps in the second check maps instruction.
332 HGraph* graph = instr->block()->graph();
333 if (entry->check_ != NULL &&
334 entry->check_->block() == instr->block() &&
335 entry->check_->IsCheckMaps()) {
336 // There is a check in the same block so replace it with a more
337 // strict check and eliminate the second check entirely.
338 HCheckMaps* check = HCheckMaps::cast(entry->check_);
339 TRACE(("CheckMaps #%d at B%d narrowed\n", check->id(),
340 check->block()->block_id()));
341 // Update map set and ensure that the check is alive.
342 check->set_map_set(intersection, graph->zone());
343 check->ClearFlag(HValue::kIsDead);
344 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n",
345 instr->id(), instr->block()->block_id(), entry->check_->id()));
346 instr->DeleteAndReplaceWith(entry->check_);
347 } else {
348 TRACE(("CheckMaps #%d at B%d narrowed\n", instr->id(),
349 instr->block()->block_id()));
350 instr->set_map_set(intersection, graph->zone());
351 entry->check_ = instr;
352 }
353
354 if (FLAG_trace_check_elimination) {
355 Print();
356 }
357 INC_STAT(narrowed_);
358 }
359 } 255 }
360 } else { 256 } else {
361 // No entry; insert a new one. 257 // No entry; insert a new one.
362 Insert(object, instr, instr->map_set().Copy(phase_->zone()), 258 Insert(object, instr, instr->map_set().Copy(phase_->zone()));
363 instr->is_stable());
364 } 259 }
365 } 260 }
366 261
367 void ReduceCheckValue(HCheckValue* instr) { 262 void ReduceCheckValue(HCheckValue* instr) {
368 // Canonicalize HCheckValues; they might have their values load-eliminated. 263 // Canonicalize HCheckValues; they might have their values load-eliminated.
369 HValue* value = instr->Canonicalize(); 264 HValue* value = instr->Canonicalize();
370 if (value == NULL) { 265 if (value == NULL) {
371 instr->DeleteAndReplaceWith(instr->value()); 266 instr->DeleteAndReplaceWith(instr->value());
372 INC_STAT(removed_); 267 INC_STAT(removed_);
373 } else if (value != instr) { 268 } else if (value != instr) {
(...skipping 16 matching lines...) Expand all
390 instr->DeleteAndReplaceWith(constant); 285 instr->DeleteAndReplaceWith(constant);
391 INC_STAT(loads_); 286 INC_STAT(loads_);
392 } 287 }
393 288
394 void ReduceCheckMapValue(HCheckMapValue* instr) { 289 void ReduceCheckMapValue(HCheckMapValue* instr) {
395 if (!instr->map()->IsConstant()) return; // Nothing to learn. 290 if (!instr->map()->IsConstant()) return; // Nothing to learn.
396 291
397 HValue* object = instr->value()->ActualValue(); 292 HValue* object = instr->value()->ActualValue();
398 // Match a HCheckMapValue(object, HConstant(map)) 293 // Match a HCheckMapValue(object, HConstant(map))
399 Unique<Map> map = MapConstant(instr->map()); 294 Unique<Map> map = MapConstant(instr->map());
400 295 MapSet maps = FindMaps(object);
401 HCheckTableEntry* entry = Find(object); 296 if (maps != NULL) {
402 if (entry != NULL) {
403 MapSet maps = entry->maps_;
404 if (maps->Contains(map)) { 297 if (maps->Contains(map)) {
405 if (maps->size() == 1) { 298 if (maps->size() == 1) {
406 // Object is known to have exactly this map. 299 // Object is known to have exactly this map.
407 if (entry->check_ != NULL) { 300 instr->DeleteAndReplaceWith(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 }
415 INC_STAT(removed_); 301 INC_STAT(removed_);
416 } else { 302 } else {
417 // Only one map survives the check. 303 // Only one map survives the check.
418 maps->Clear(); 304 maps->Clear();
419 maps->Add(map, phase_->zone()); 305 maps->Add(map, phase_->zone());
420 entry->check_ = instr;
421 } 306 }
422 } 307 }
423 } else { 308 } else {
424 // No prior information. 309 // No prior information.
425 // TODO(verwaest): Tag map constants with stability. 310 Insert(object, map);
426 Insert(object, instr, map, false);
427 } 311 }
428 } 312 }
429 313
430 void ReduceCheckHeapObject(HCheckHeapObject* instr) { 314 void ReduceCheckHeapObject(HCheckHeapObject* instr) {
431 if (FindMaps(instr->value()->ActualValue()) != NULL) { 315 if (FindMaps(instr->value()->ActualValue()) != NULL) {
432 // If the object has known maps, it's definitely a heap object. 316 // If the object has known maps, it's definitely a heap object.
433 instr->DeleteAndReplaceWith(instr->value()); 317 instr->DeleteAndReplaceWith(instr->value());
434 INC_STAT(removed_cho_); 318 INC_STAT(removed_cho_);
435 } 319 }
436 } 320 }
437 321
438 void ReduceStoreNamedField(HStoreNamedField* instr) { 322 void ReduceStoreNamedField(HStoreNamedField* instr) {
439 HValue* object = instr->object()->ActualValue(); 323 HValue* object = instr->object()->ActualValue();
440 if (instr->has_transition()) { 324 if (instr->has_transition()) {
441 // This store transitions the object to a new map. 325 // This store transitions the object to a new map.
442 Kill(object); 326 Kill(object);
443 Insert(object, NULL, MapConstant(instr->transition()), 327 Insert(object, MapConstant(instr->transition()));
444 instr->is_stable());
445 } else if (IsMapAccess(instr->access())) { 328 } else if (IsMapAccess(instr->access())) {
446 // This is a store directly to the map field of the object. 329 // This is a store directly to the map field of the object.
447 Kill(object); 330 Kill(object);
448 if (!instr->value()->IsConstant()) return; 331 if (!instr->value()->IsConstant()) return;
449 // TODO(verwaest): Tag with stability. 332 Insert(object, MapConstant(instr->value()));
450 Insert(object, NULL, MapConstant(instr->value()), false);
451 } else { 333 } else {
452 // If the instruction changes maps, it should be handled above. 334 // If the instruction changes maps, it should be handled above.
453 CHECK(!instr->CheckChangesFlag(kMaps)); 335 CHECK(!instr->CheckGVNFlag(kChangesMaps));
454 } 336 }
455 } 337 }
456 338
457 void ReduceCompareMap(HCompareMap* instr) { 339 void ReduceCompareMap(HCompareMap* instr) {
458 MapSet maps = FindMaps(instr->value()->ActualValue()); 340 MapSet maps = FindMaps(instr->value()->ActualValue());
459 if (maps == NULL) return; 341 if (maps == NULL) return;
460
461 int succ;
462 if (maps->Contains(instr->map())) { 342 if (maps->Contains(instr->map())) {
463 if (maps->size() != 1) { 343 if (maps->size() == 1) {
464 TRACE(("CompareMap #%d for #%d at B%d can't be eliminated: " 344 TRACE(("Marking redundant CompareMap #%d at B%d as true\n",
465 "ambiguous set of maps\n", instr->id(), instr->value()->id(), 345 instr->id(), instr->block()->block_id()));
466 instr->block()->block_id())); 346 instr->set_known_successor_index(0);
467 return; 347 INC_STAT(compares_true_);
468 } 348 }
469 succ = 0;
470 INC_STAT(compares_true_);
471 } else { 349 } else {
472 succ = 1; 350 TRACE(("Marking redundant CompareMap #%d at B%d as false\n",
351 instr->id(), instr->block()->block_id()));
352 instr->set_known_successor_index(1);
473 INC_STAT(compares_false_); 353 INC_STAT(compares_false_);
474 } 354 }
475
476 TRACE(("Marking redundant CompareMap #%d for #%d at B%d as %s\n",
477 instr->id(), instr->value()->id(), instr->block()->block_id(),
478 succ == 0 ? "true" : "false"));
479 instr->set_known_successor_index(succ);
480
481 int unreachable_succ = 1 - succ;
482 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
483 } 355 }
484 356
485 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { 357 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) {
486 MapSet maps = FindMaps(instr->object()->ActualValue()); 358 MapSet maps = FindMaps(instr->object()->ActualValue());
487 // Can only learn more about an object that already has a known set of maps. 359 // Can only learn more about an object that already has a known set of maps.
488 if (maps == NULL) return; 360 if (maps == NULL) return;
489 if (maps->Contains(instr->original_map())) { 361 if (maps->Contains(instr->original_map())) {
490 // If the object has the original map, it will be transitioned. 362 // If the object has the original map, it will be transitioned.
491 maps->Remove(instr->original_map()); 363 maps->Remove(instr->original_map());
492 maps->Add(instr->transitioned_map(), phase_->zone()); 364 maps->Add(instr->transitioned_map(), phase_->zone());
493 } else { 365 } else {
494 // Object does not have the given map, thus the transition is redundant. 366 // Object does not have the given map, thus the transition is redundant.
495 instr->DeleteAndReplaceWith(instr->object()); 367 instr->DeleteAndReplaceWith(instr->object());
496 INC_STAT(transitions_); 368 INC_STAT(transitions_);
497 } 369 }
498 } 370 }
499 371
500 // Reset the table. 372 // Kill everything in the table.
501 void Reset() { 373 void Kill() {
502 size_ = 0; 374 size_ = 0;
503 cursor_ = 0; 375 cursor_ = 0;
504 } 376 }
505 377
506 // Kill everything in the table.
507 void KillUnstableEntries() {
508 bool compact = false;
509 for (int i = 0; i < size_; i++) {
510 HCheckTableEntry* entry = &entries_[i];
511 ASSERT(entry->object_ != NULL);
512 if (!entry->is_stable_) {
513 entry->object_ = NULL;
514 compact = true;
515 }
516 }
517 if (compact) Compact();
518 }
519
520 // Kill everything in the table that may alias {object}. 378 // Kill everything in the table that may alias {object}.
521 void Kill(HValue* object) { 379 void Kill(HValue* object) {
522 bool compact = false; 380 bool compact = false;
523 for (int i = 0; i < size_; i++) { 381 for (int i = 0; i < size_; i++) {
524 HCheckTableEntry* entry = &entries_[i]; 382 HCheckTableEntry* entry = &entries_[i];
525 ASSERT(entry->object_ != NULL); 383 ASSERT(entry->object_ != NULL);
526 if (phase_->aliasing_->MayAlias(entry->object_, object)) { 384 if (phase_->aliasing_->MayAlias(entry->object_, object)) {
527 entry->object_ = NULL; 385 entry->object_ = NULL;
528 compact = true; 386 compact = true;
529 } 387 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 OS::MemMove(&entries_[R], &tmp_entries[0], L * sizeof(HCheckTableEntry)); 419 OS::MemMove(&entries_[R], &tmp_entries[0], L * sizeof(HCheckTableEntry));
562 } 420 }
563 421
564 cursor_ = size_; // Move cursor to end. 422 cursor_ = size_; // Move cursor to end.
565 } 423 }
566 424
567 void Print() { 425 void Print() {
568 for (int i = 0; i < size_; i++) { 426 for (int i = 0; i < size_; i++) {
569 HCheckTableEntry* entry = &entries_[i]; 427 HCheckTableEntry* entry = &entries_[i];
570 ASSERT(entry->object_ != NULL); 428 ASSERT(entry->object_ != NULL);
571 PrintF(" checkmaps-table @%d: %s #%d ", i, 429 PrintF(" checkmaps-table @%d: object #%d ", i, entry->object_->id());
572 entry->object_->IsPhi() ? "phi" : "object", entry->object_->id());
573 if (entry->check_ != NULL) { 430 if (entry->check_ != NULL) {
574 PrintF("check #%d ", entry->check_->id()); 431 PrintF("check #%d ", entry->check_->id());
575 } 432 }
576 MapSet list = entry->maps_; 433 MapSet list = entry->maps_;
577 PrintF("%d maps { ", list->size()); 434 PrintF("%d maps { ", list->size());
578 for (int j = 0; j < list->size(); j++) { 435 for (int j = 0; j < list->size(); j++) {
579 if (j > 0) PrintF(", "); 436 if (j > 0) PrintF(", ");
580 PrintF("%" V8PRIxPTR, list->at(j).Hashcode()); 437 PrintF("%" V8PRIxPTR, list->at(j).Hashcode());
581 } 438 }
582 PrintF(" }\n"); 439 PrintF(" }\n");
583 } 440 }
584 } 441 }
585 442
443 private:
586 HCheckTableEntry* Find(HValue* object) { 444 HCheckTableEntry* Find(HValue* object) {
587 for (int i = size_ - 1; i >= 0; i--) { 445 for (int i = size_ - 1; i >= 0; i--) {
588 // Search from most-recently-inserted to least-recently-inserted. 446 // Search from most-recently-inserted to least-recently-inserted.
589 HCheckTableEntry* entry = &entries_[i]; 447 HCheckTableEntry* entry = &entries_[i];
590 ASSERT(entry->object_ != NULL); 448 ASSERT(entry->object_ != NULL);
591 if (phase_->aliasing_->MustAlias(entry->object_, object)) return entry; 449 if (phase_->aliasing_->MustAlias(entry->object_, object)) return entry;
592 } 450 }
593 return NULL; 451 return NULL;
594 } 452 }
595 453
596 MapSet FindMaps(HValue* object) { 454 MapSet FindMaps(HValue* object) {
597 HCheckTableEntry* entry = Find(object); 455 HCheckTableEntry* entry = Find(object);
598 return entry == NULL ? NULL : entry->maps_; 456 return entry == NULL ? NULL : entry->maps_;
599 } 457 }
600 458
601 void Insert(HValue* object, 459 void Insert(HValue* object, Unique<Map> map) {
602 HInstruction* check,
603 Unique<Map> map,
604 bool is_stable) {
605 MapSet list = new(phase_->zone()) UniqueSet<Map>(); 460 MapSet list = new(phase_->zone()) UniqueSet<Map>();
606 list->Add(map, phase_->zone()); 461 list->Add(map, phase_->zone());
607 Insert(object, check, list, is_stable); 462 Insert(object, NULL, list);
608 } 463 }
609 464
610 void Insert(HValue* object, 465 void Insert(HValue* object, HCheckMaps* check, MapSet maps) {
611 HInstruction* check,
612 MapSet maps,
613 bool is_stable) {
614 HCheckTableEntry* entry = &entries_[cursor_++]; 466 HCheckTableEntry* entry = &entries_[cursor_++];
615 entry->object_ = object; 467 entry->object_ = object;
616 entry->check_ = check; 468 entry->check_ = check;
617 entry->maps_ = maps; 469 entry->maps_ = maps;
618 entry->is_stable_ = is_stable;
619 // If the table becomes full, wrap around and overwrite older entries. 470 // If the table becomes full, wrap around and overwrite older entries.
620 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; 471 if (cursor_ == kMaxTrackedObjects) cursor_ = 0;
621 if (size_ < kMaxTrackedObjects) size_++; 472 if (size_ < kMaxTrackedObjects) size_++;
622 } 473 }
623 474
624 bool IsMapAccess(HObjectAccess access) { 475 bool IsMapAccess(HObjectAccess access) {
625 return access.IsInobject() && access.offset() == JSObject::kMapOffset; 476 return access.IsInobject() && access.offset() == JSObject::kMapOffset;
626 } 477 }
627 478
628 Unique<Map> MapConstant(HValue* value) { 479 Unique<Map> MapConstant(HValue* value) {
629 return Unique<Map>::cast(HConstant::cast(value)->GetUnique()); 480 return Unique<Map>::cast(HConstant::cast(value)->GetUnique());
630 } 481 }
631 482
632 friend class HCheckMapsEffects; 483 friend class HCheckMapsEffects;
633 friend class HCheckEliminationPhase;
634 484
635 HCheckEliminationPhase* phase_; 485 HCheckEliminationPhase* phase_;
636 HCheckTableEntry entries_[kMaxTrackedObjects]; 486 HCheckTableEntry entries_[kMaxTrackedObjects];
637 int16_t cursor_; // Must be <= kMaxTrackedObjects 487 int16_t cursor_; // Must be <= kMaxTrackedObjects
638 int16_t size_; // Must be <= kMaxTrackedObjects 488 int16_t size_; // Must be <= kMaxTrackedObjects
639 // TODO(titzer): STATIC_ASSERT kMaxTrackedObjects < max(cursor_) 489 // TODO(titzer): STATIC_ASSERT kMaxTrackedObjects < max(cursor_)
640 }; 490 };
641 491
642 492
643 // Collects instructions that can cause effects that invalidate information 493 // Collects instructions that can cause effects that invalidate information
644 // needed for check elimination. 494 // needed for check elimination.
645 class HCheckMapsEffects : public ZoneObject { 495 class HCheckMapsEffects : public ZoneObject {
646 public: 496 public:
647 explicit HCheckMapsEffects(Zone* zone) 497 explicit HCheckMapsEffects(Zone* zone)
648 : stores_(5, zone) { } 498 : maps_stored_(false),
499 stores_(5, zone) { }
649 500
650 inline bool Disabled() { 501 inline bool Disabled() {
651 return false; // Effects are _not_ disabled. 502 return false; // Effects are _not_ disabled.
652 } 503 }
653 504
654 // Process a possibly side-effecting instruction. 505 // Process a possibly side-effecting instruction.
655 void Process(HInstruction* instr, Zone* zone) { 506 void Process(HInstruction* instr, Zone* zone) {
656 if (instr->IsStoreNamedField()) { 507 switch (instr->opcode()) {
657 stores_.Add(HStoreNamedField::cast(instr), zone); 508 case HValue::kStoreNamedField: {
658 } else { 509 stores_.Add(HStoreNamedField::cast(instr), zone);
659 flags_.Add(instr->ChangesFlags()); 510 break;
511 }
512 case HValue::kOsrEntry: {
513 // Kill everything. Loads must not be hoisted past the OSR entry.
514 maps_stored_ = true;
515 }
516 default: {
517 maps_stored_ |= (instr->CheckGVNFlag(kChangesMaps) |
518 instr->CheckGVNFlag(kChangesElementsKind));
519 }
660 } 520 }
661 } 521 }
662 522
663 // Apply these effects to the given check elimination table. 523 // Apply these effects to the given check elimination table.
664 void Apply(HCheckTable* table) { 524 void Apply(HCheckTable* table) {
665 if (flags_.Contains(kOsrEntries)) { 525 if (maps_stored_) {
666 table->Reset();
667 return;
668 }
669 if (flags_.Contains(kMaps) || flags_.Contains(kElementsKind)) {
670 // Uncontrollable map modifications; kill everything. 526 // Uncontrollable map modifications; kill everything.
671 table->KillUnstableEntries(); 527 table->Kill();
672 return; 528 return;
673 } 529 }
674 530
675 // Kill maps for each store contained in these effects. 531 // Kill maps for each store contained in these effects.
676 for (int i = 0; i < stores_.length(); i++) { 532 for (int i = 0; i < stores_.length(); i++) {
677 HStoreNamedField* s = stores_[i]; 533 HStoreNamedField* s = stores_[i];
678 if (table->IsMapAccess(s->access()) || s->has_transition()) { 534 if (table->IsMapAccess(s->access()) || s->has_transition()) {
679 table->Kill(s->object()->ActualValue()); 535 table->Kill(s->object()->ActualValue());
680 } 536 }
681 } 537 }
682 } 538 }
683 539
684 // Union these effects with the other effects. 540 // Union these effects with the other effects.
685 void Union(HCheckMapsEffects* that, Zone* zone) { 541 void Union(HCheckMapsEffects* that, Zone* zone) {
686 flags_.Add(that->flags_); 542 maps_stored_ |= that->maps_stored_;
687 for (int i = 0; i < that->stores_.length(); i++) { 543 for (int i = 0; i < that->stores_.length(); i++) {
688 stores_.Add(that->stores_[i], zone); 544 stores_.Add(that->stores_[i], zone);
689 } 545 }
690 } 546 }
691 547
692 private: 548 private:
693 GVNFlagSet flags_; 549 bool maps_stored_ : 1;
694 ZoneList<HStoreNamedField*> stores_; 550 ZoneList<HStoreNamedField*> stores_;
695 }; 551 };
696 552
697 553
698 // The main routine of the analysis phase. Use the HFlowEngine for either a 554 // The main routine of the analysis phase. Use the HFlowEngine for either a
699 // local or a global analysis. 555 // local or a global analysis.
700 void HCheckEliminationPhase::Run() { 556 void HCheckEliminationPhase::Run() {
701 HFlowEngine<HCheckTable, HCheckMapsEffects> engine(graph(), zone()); 557 HFlowEngine<HCheckTable, HCheckMapsEffects> engine(graph(), zone());
702 HCheckTable* table = new(zone()) HCheckTable(this); 558 HCheckTable* table = new(zone()) HCheckTable(this);
703 559
704 if (GLOBAL) { 560 if (GLOBAL) {
705 // Perform a global analysis. 561 // Perform a global analysis.
706 engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), table); 562 engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), table);
707 } else { 563 } else {
708 // Perform only local analysis. 564 // Perform only local analysis.
709 for (int i = 0; i < graph()->blocks()->length(); i++) { 565 for (int i = 0; i < graph()->blocks()->length(); i++) {
710 table->Reset(); 566 table->Kill();
711 engine.AnalyzeOneBlock(graph()->blocks()->at(i), table); 567 engine.AnalyzeOneBlock(graph()->blocks()->at(i), table);
712 } 568 }
713 } 569 }
714 570
715 if (FLAG_trace_check_elimination) PrintStats(); 571 if (FLAG_trace_check_elimination) PrintStats();
716 } 572 }
717 573
718 574
719 // Are we eliminated yet? 575 // Are we eliminated yet?
720 void HCheckEliminationPhase::PrintStats() { 576 void HCheckEliminationPhase::PrintStats() {
721 #if DEBUG 577 #if DEBUG
722 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_) 578 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_)
723 #else 579 #else
724 #define PRINT_STAT(x) 580 #define PRINT_STAT(x)
725 #endif 581 #endif
726 PRINT_STAT(redundant); 582 PRINT_STAT(redundant);
727 PRINT_STAT(removed); 583 PRINT_STAT(removed);
728 PRINT_STAT(removed_cho); 584 PRINT_STAT(removed_cho);
729 PRINT_STAT(narrowed); 585 PRINT_STAT(narrowed);
730 PRINT_STAT(loads); 586 PRINT_STAT(loads);
731 PRINT_STAT(empty); 587 PRINT_STAT(empty);
732 PRINT_STAT(compares_true); 588 PRINT_STAT(compares_true);
733 PRINT_STAT(compares_false); 589 PRINT_STAT(compares_false);
734 PRINT_STAT(transitions); 590 PRINT_STAT(transitions);
735 } 591 }
736 592
737 } } // namespace v8::internal 593 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.cc ('k') | src/hydrogen-flow-engine.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698