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

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

Issue 266083007: Use stability to only conditionally flush information from the map check table. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: REBASE Created 6 years, 7 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-instructions.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 // 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 "hydrogen-check-elimination.h" 5 #include "hydrogen-check-elimination.h"
6
Igor Sheludko 2014/05/07 16:53:26 Spurious change?
Benedikt Meurer 2014/05/08 04:45:49 Updated to follow Google C++ Style Guide.
6 #include "hydrogen-alias-analysis.h" 7 #include "hydrogen-alias-analysis.h"
7 #include "hydrogen-flow-engine.h" 8 #include "hydrogen-flow-engine.h"
8 9
9 #define GLOBAL 1 10 #define GLOBAL 1
10 11
11 // Only collect stats in debug mode. 12 // Only collect stats in debug mode.
12 #if DEBUG 13 #if DEBUG
13 #define INC_STAT(x) phase_->x++ 14 #define INC_STAT(x) phase_->x++
14 #else 15 #else
15 #define INC_STAT(x) 16 #define INC_STAT(x)
16 #endif 17 #endif
17 18
18 // For code de-uglification. 19 // For code de-uglification.
19 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x 20 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x
20 21
21 namespace v8 { 22 namespace v8 {
22 namespace internal { 23 namespace internal {
23 24
24 typedef const UniqueSet<Map>* MapSet; 25 typedef const UniqueSet<Map>* MapSet;
25 26
26 struct HCheckTableEntry { 27 struct HCheckTableEntry {
28 enum State {
29 CHECKED,
Igor Sheludko 2014/05/07 16:53:26 Please add comments about meaning of the states.
Benedikt Meurer 2014/05/08 04:45:49 Done.
30 CHECKED_STABLE,
31 UNCHECKED_STABLE
32 };
33
34 static const char* State2String(State state) {
35 switch (state) {
36 case CHECKED: return "checked";
37 case CHECKED_STABLE: return "checked stable";
38 case UNCHECKED_STABLE: return "unchecked stable";
39 }
40 UNREACHABLE();
41 return NULL;
42 }
43
44 static State StateMerge(State state1, State state2) {
45 if (state1 == state2) return state1;
46 if ((state1 == CHECKED && state2 == CHECKED_STABLE) ||
47 (state2 == CHECKED && state1 == CHECKED_STABLE)) {
48 return CHECKED;
49 }
50 ASSERT((state1 == CHECKED_STABLE && state2 == UNCHECKED_STABLE) ||
51 (state2 == CHECKED_STABLE && state1 == UNCHECKED_STABLE));
52 return UNCHECKED_STABLE;
53 }
54
27 HValue* object_; // The object being approximated. NULL => invalid entry. 55 HValue* object_; // The object being approximated. NULL => invalid entry.
28 HInstruction* check_; // The last check instruction. 56 HInstruction* check_; // The last check instruction.
29 MapSet maps_; // The set of known maps for the object. 57 MapSet maps_; // The set of known maps for the object.
58 State state_; // The state of this entry.
30 }; 59 };
31 60
32 61
33 // The main data structure used during check elimination, which stores a 62 // The main data structure used during check elimination, which stores a
34 // set of known maps for each object. 63 // set of known maps for each object.
35 class HCheckTable : public ZoneObject { 64 class HCheckTable : public ZoneObject {
36 public: 65 public:
37 static const int kMaxTrackedObjects = 16; 66 static const int kMaxTrackedObjects = 16;
38 67
39 explicit HCheckTable(HCheckEliminationPhase* phase) 68 explicit HCheckTable(HCheckEliminationPhase* phase)
(...skipping 29 matching lines...) Expand all
69 ReduceTransitionElementsKind( 98 ReduceTransitionElementsKind(
70 HTransitionElementsKind::cast(instr)); 99 HTransitionElementsKind::cast(instr));
71 break; 100 break;
72 } 101 }
73 case HValue::kCheckHeapObject: { 102 case HValue::kCheckHeapObject: {
74 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); 103 ReduceCheckHeapObject(HCheckHeapObject::cast(instr));
75 break; 104 break;
76 } 105 }
77 default: { 106 default: {
78 // If the instruction changes maps uncontrollably, drop everything. 107 // If the instruction changes maps uncontrollably, drop everything.
108 if (instr->CheckChangesFlag(kOsrEntries)) {
109 Kill();
110 break;
111 }
79 if (instr->CheckChangesFlag(kElementsKind) || 112 if (instr->CheckChangesFlag(kElementsKind) ||
80 instr->CheckChangesFlag(kMaps) || 113 instr->CheckChangesFlag(kMaps)) {
81 instr->CheckChangesFlag(kOsrEntries)) { 114 KillUnstableEntries();
82 Kill();
83 } 115 }
84 } 116 }
85 // Improvements possible: 117 // Improvements possible:
86 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions 118 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions
87 // - track which values have been HCheckHeapObject'd 119 // - track which values have been HCheckHeapObject'd
88 } 120 }
89 121
90 return this; 122 return this;
91 } 123 }
92 124
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 private: 156 private:
125 // Copy state to successor block. 157 // Copy state to successor block.
126 HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block, Zone* zone) { 158 HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block, Zone* zone) {
127 HCheckTable* copy = new(zone) HCheckTable(phase_); 159 HCheckTable* copy = new(zone) HCheckTable(phase_);
128 for (int i = 0; i < size_; i++) { 160 for (int i = 0; i < size_; i++) {
129 HCheckTableEntry* old_entry = &entries_[i]; 161 HCheckTableEntry* old_entry = &entries_[i];
130 ASSERT(old_entry->maps_->size() > 0); 162 ASSERT(old_entry->maps_->size() > 0);
131 HCheckTableEntry* new_entry = &copy->entries_[i]; 163 HCheckTableEntry* new_entry = &copy->entries_[i];
132 new_entry->object_ = old_entry->object_; 164 new_entry->object_ = old_entry->object_;
133 new_entry->maps_ = old_entry->maps_; 165 new_entry->maps_ = old_entry->maps_;
166 new_entry->state_ = old_entry->state_;
134 // Keep the check if the existing check's block dominates the successor. 167 // Keep the check if the existing check's block dominates the successor.
135 if (old_entry->check_ != NULL && 168 if (old_entry->check_ != NULL &&
136 old_entry->check_->block()->Dominates(succ)) { 169 old_entry->check_->block()->Dominates(succ)) {
137 new_entry->check_ = old_entry->check_; 170 new_entry->check_ = old_entry->check_;
138 } else { 171 } else {
139 // Leave it NULL till we meet a new check instruction for this object 172 // Leave it NULL till we meet a new check instruction for this object
140 // in the control flow. 173 // in the control flow.
141 new_entry->check_ = NULL; 174 new_entry->check_ = NULL;
142 } 175 }
143 } 176 }
144 copy->cursor_ = cursor_; 177 copy->cursor_ = cursor_;
145 copy->size_ = size_; 178 copy->size_ = size_;
146 179
147 // Create entries for succ block's phis. 180 // Create entries for succ block's phis.
148 if (!succ->IsLoopHeader() && succ->phis()->length() > 0) { 181 if (!succ->IsLoopHeader() && succ->phis()->length() > 0) {
149 int pred_index = succ->PredecessorIndexOf(from_block); 182 int pred_index = succ->PredecessorIndexOf(from_block);
150 for (int phi_index = 0; 183 for (int phi_index = 0;
151 phi_index < succ->phis()->length(); 184 phi_index < succ->phis()->length();
152 ++phi_index) { 185 ++phi_index) {
153 HPhi* phi = succ->phis()->at(phi_index); 186 HPhi* phi = succ->phis()->at(phi_index);
154 HValue* phi_operand = phi->OperandAt(pred_index); 187 HValue* phi_operand = phi->OperandAt(pred_index);
155 188
156 HCheckTableEntry* pred_entry = copy->Find(phi_operand); 189 HCheckTableEntry* pred_entry = copy->Find(phi_operand);
157 if (pred_entry != NULL) { 190 if (pred_entry != NULL) {
158 // Create an entry for a phi in the table. 191 // Create an entry for a phi in the table.
159 copy->Insert(phi, NULL, pred_entry->maps_); 192 copy->Insert(phi, NULL, pred_entry->maps_, pred_entry->state_);
160 } 193 }
161 } 194 }
162 } 195 }
163 196
164 // Branch-sensitive analysis for certain comparisons may add more facts 197 // Branch-sensitive analysis for certain comparisons may add more facts
165 // to the state for the successor on the true branch. 198 // to the state for the successor on the true branch.
166 bool learned = false; 199 bool learned = false;
167 if (succ->predecessors()->length() == 1) { 200 if (succ->predecessors()->length() == 1) {
168 HControlInstruction* end = succ->predecessors()->at(0)->end(); 201 HControlInstruction* end = succ->predecessors()->at(0)->end();
169 bool is_true_branch = end->SuccessorAt(0) == succ; 202 bool is_true_branch = end->SuccessorAt(0) == succ;
170 if (end->IsCompareMap()) { 203 if (end->IsCompareMap()) {
171 HCompareMap* cmp = HCompareMap::cast(end); 204 HCompareMap* cmp = HCompareMap::cast(end);
172 HValue* object = cmp->value()->ActualValue(); 205 HValue* object = cmp->value()->ActualValue();
173 HCheckTableEntry* entry = copy->Find(object); 206 HCheckTableEntry* entry = copy->Find(object);
174 if (is_true_branch) { 207 if (is_true_branch) {
208 HCheckTableEntry::State state = cmp->map_is_stable()
209 ? HCheckTableEntry::CHECKED_STABLE
210 : HCheckTableEntry::CHECKED;
175 // Learn on the true branch of if(CompareMap(x)). 211 // Learn on the true branch of if(CompareMap(x)).
176 if (entry == NULL) { 212 if (entry == NULL) {
177 copy->Insert(object, cmp, cmp->map()); 213 copy->Insert(object, cmp, cmp->map(), state);
178 } else { 214 } else {
179 entry->maps_ = new(zone) UniqueSet<Map>(cmp->map(), zone); 215 entry->maps_ = new(zone) UniqueSet<Map>(cmp->map(), zone);
180 entry->check_ = cmp; 216 entry->check_ = cmp;
217 entry->state_ = state;
181 } 218 }
182 } else { 219 } else {
183 // Learn on the false branch of if(CompareMap(x)). 220 // Learn on the false branch of if(CompareMap(x)).
184 if (entry != NULL) { 221 if (entry != NULL) {
222 EnsureChecked(entry, object, cmp);
185 UniqueSet<Map>* maps = entry->maps_->Copy(zone); 223 UniqueSet<Map>* maps = entry->maps_->Copy(zone);
186 maps->Remove(cmp->map()); 224 maps->Remove(cmp->map());
187 entry->maps_ = maps; 225 entry->maps_ = maps;
226 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_);
188 } 227 }
189 } 228 }
190 learned = true; 229 learned = true;
191 } else if (is_true_branch && end->IsCompareObjectEqAndBranch()) { 230 } else if (is_true_branch && end->IsCompareObjectEqAndBranch()) {
192 // Learn on the true branch of if(CmpObjectEq(x, y)). 231 // Learn on the true branch of if(CmpObjectEq(x, y)).
193 HCompareObjectEqAndBranch* cmp = 232 HCompareObjectEqAndBranch* cmp =
194 HCompareObjectEqAndBranch::cast(end); 233 HCompareObjectEqAndBranch::cast(end);
195 HValue* left = cmp->left()->ActualValue(); 234 HValue* left = cmp->left()->ActualValue();
196 HValue* right = cmp->right()->ActualValue(); 235 HValue* right = cmp->right()->ActualValue();
197 HCheckTableEntry* le = copy->Find(left); 236 HCheckTableEntry* le = copy->Find(left);
198 HCheckTableEntry* re = copy->Find(right); 237 HCheckTableEntry* re = copy->Find(right);
199 if (le == NULL) { 238 if (le == NULL) {
200 if (re != NULL) { 239 if (re != NULL) {
201 copy->Insert(left, NULL, re->maps_); 240 copy->Insert(left, NULL, re->maps_, re->state_);
202 } 241 }
203 } else if (re == NULL) { 242 } else if (re == NULL) {
204 copy->Insert(right, NULL, le->maps_); 243 copy->Insert(right, NULL, le->maps_, le->state_);
205 } else { 244 } else {
245 EnsureChecked(le, cmp->left(), cmp);
246 EnsureChecked(re, cmp->right(), cmp);
206 le->maps_ = re->maps_ = le->maps_->Intersect(re->maps_, zone); 247 le->maps_ = re->maps_ = le->maps_->Intersect(re->maps_, zone);
248 le->state_ = re->state_ = HCheckTableEntry::StateMerge(
249 le->state_, re->state_);
250 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, le->state_);
251 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, re->state_);
207 } 252 }
208 learned = true; 253 learned = true;
209 } 254 }
210 // Learning on false branches requires storing negative facts. 255 // Learning on false branches requires storing negative facts.
211 } 256 }
212 257
213 if (FLAG_trace_check_elimination) { 258 if (FLAG_trace_check_elimination) {
214 PrintF("B%d checkmaps-table %s from B%d:\n", 259 PrintF("B%d checkmaps-table %s from B%d:\n",
215 succ->block_id(), 260 succ->block_id(),
216 learned ? "learned" : "copied", 261 learned ? "learned" : "copied",
(...skipping 20 matching lines...) Expand all
237 if (this_entry->object_->IsPhi() && 282 if (this_entry->object_->IsPhi() &&
238 this_entry->object_->block() == succ) { 283 this_entry->object_->block() == succ) {
239 HPhi* phi = HPhi::cast(this_entry->object_); 284 HPhi* phi = HPhi::cast(this_entry->object_);
240 HValue* phi_operand = phi->OperandAt(pred_index); 285 HValue* phi_operand = phi->OperandAt(pred_index);
241 that_entry = that->Find(phi_operand); 286 that_entry = that->Find(phi_operand);
242 287
243 } else { 288 } else {
244 that_entry = that->Find(this_entry->object_); 289 that_entry = that->Find(this_entry->object_);
245 } 290 }
246 291
247 if (that_entry == NULL) { 292 if (that_entry == NULL ||
293 (that_entry->state_ == HCheckTableEntry::CHECKED &&
294 this_entry->state_ == HCheckTableEntry::UNCHECKED_STABLE) ||
295 (this_entry->state_ == HCheckTableEntry::CHECKED &&
296 that_entry->state_ == HCheckTableEntry::UNCHECKED_STABLE)) {
248 this_entry->object_ = NULL; 297 this_entry->object_ = NULL;
249 compact = true; 298 compact = true;
250 } else { 299 } else {
251 this_entry->maps_ = 300 this_entry->maps_ =
252 this_entry->maps_->Union(that_entry->maps_, zone); 301 this_entry->maps_->Union(that_entry->maps_, zone);
302 this_entry->state_ = HCheckTableEntry::StateMerge(
303 this_entry->state_, that_entry->state_);
253 if (this_entry->check_ != that_entry->check_) { 304 if (this_entry->check_ != that_entry->check_) {
254 this_entry->check_ = NULL; 305 this_entry->check_ = NULL;
255 } 306 }
256 ASSERT(this_entry->maps_->size() > 0); 307 ASSERT(this_entry->maps_->size() > 0);
257 } 308 }
258 } 309 }
259 if (compact) Compact(); 310 if (compact) Compact();
260 } 311 }
261 312
262 if (FLAG_trace_check_elimination) { 313 if (FLAG_trace_check_elimination) {
263 PrintF("B%d checkmaps-table merged with B%d table:\n", 314 PrintF("B%d checkmaps-table merged with B%d table:\n",
264 succ->block_id(), pred_block->block_id()); 315 succ->block_id(), pred_block->block_id());
265 Print(this); 316 Print(this);
266 } 317 }
267 return this; 318 return this;
268 } 319 }
269 320
270 void ReduceCheckMaps(HCheckMaps* instr) { 321 void ReduceCheckMaps(HCheckMaps* instr) {
271 HValue* object = instr->value()->ActualValue(); 322 HValue* object = instr->value()->ActualValue();
272 HCheckTableEntry* entry = Find(object); 323 HCheckTableEntry* entry = Find(object);
273 if (entry != NULL) { 324 if (entry != NULL) {
274 // entry found; 325 // entry found;
275 MapSet a = entry->maps_; 326 HGraph* graph = instr->block()->graph();
276 const UniqueSet<Map>* i = instr->maps(); 327 if (entry->maps_->IsSubset(instr->maps())) {
277 if (a->IsSubset(i)) {
278 // The first check is more strict; the second is redundant. 328 // The first check is more strict; the second is redundant.
279 if (entry->check_ != NULL) { 329 if (entry->check_ != NULL) {
330 ASSERT_NE(HCheckTableEntry::UNCHECKED_STABLE, entry->state_);
280 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n", 331 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n",
281 instr->id(), instr->block()->block_id(), entry->check_->id())); 332 instr->id(), instr->block()->block_id(), entry->check_->id()));
282 instr->DeleteAndReplaceWith(entry->check_); 333 instr->DeleteAndReplaceWith(entry->check_);
283 INC_STAT(redundant_); 334 INC_STAT(redundant_);
284 } else { 335 } else if (entry->state_ == HCheckTableEntry::UNCHECKED_STABLE) {
336 ASSERT_EQ(NULL, entry->check_);
337 TRACE(("Marking redundant CheckMaps #%d at B%d as stability check\n",
338 instr->id(), instr->block()->block_id()));
339 instr->set_maps(entry->maps_->Copy(graph->zone()));
340 instr->MarkAsStabilityCheck();
341 entry->state_ = HCheckTableEntry::CHECKED_STABLE;
342 } else if (!instr->IsStabilityCheck()) {
285 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n", 343 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n",
286 instr->id(), instr->block()->block_id())); 344 instr->id(), instr->block()->block_id()));
287 // Mark check as dead but leave it in the graph as a checkpoint for 345 // Mark check as dead but leave it in the graph as a checkpoint for
288 // subsequent checks. 346 // subsequent checks.
289 instr->SetFlag(HValue::kIsDead); 347 instr->SetFlag(HValue::kIsDead);
290 entry->check_ = instr; 348 entry->check_ = instr;
291 INC_STAT(removed_); 349 INC_STAT(removed_);
292 } 350 }
293 return; 351 return;
294 } 352 }
295 HGraph* graph = instr->block()->graph(); 353 MapSet intersection = instr->maps()->Intersect(
296 MapSet intersection = i->Intersect(a, graph->zone()); 354 entry->maps_, graph->zone());
297 if (intersection->size() == 0) { 355 if (intersection->size() == 0) {
298 // Intersection is empty; probably megamorphic, which is likely to 356 // Intersection is empty; probably megamorphic.
299 // deopt anyway, so just leave things as they are.
300 INC_STAT(empty_); 357 INC_STAT(empty_);
358 entry->object_ = NULL;
359 Compact();
301 } else { 360 } else {
302 // Update set of maps in the entry. 361 // Update set of maps in the entry.
303 entry->maps_ = intersection; 362 entry->maps_ = intersection;
304 if (intersection->size() != i->size()) { 363 entry->state_ = instr->maps_are_stable()
Igor Sheludko 2014/05/07 16:53:26 || entry->check_->maps_are_stable()?
Benedikt Meurer 2014/05/08 04:45:49 entry->check_ may be NULL at this point. But entry
364 ? HCheckTableEntry::CHECKED_STABLE
365 : HCheckTableEntry::CHECKED;
366 if (intersection->size() != instr->maps()->size()) {
305 // Narrow set of maps in the second check maps instruction. 367 // Narrow set of maps in the second check maps instruction.
306 if (entry->check_ != NULL && 368 if (entry->check_ != NULL &&
307 entry->check_->block() == instr->block() && 369 entry->check_->block() == instr->block() &&
308 entry->check_->IsCheckMaps()) { 370 entry->check_->IsCheckMaps()) {
309 // There is a check in the same block so replace it with a more 371 // There is a check in the same block so replace it with a more
310 // strict check and eliminate the second check entirely. 372 // strict check and eliminate the second check entirely.
311 HCheckMaps* check = HCheckMaps::cast(entry->check_); 373 HCheckMaps* check = HCheckMaps::cast(entry->check_);
374 ASSERT(!check->IsStabilityCheck());
312 TRACE(("CheckMaps #%d at B%d narrowed\n", check->id(), 375 TRACE(("CheckMaps #%d at B%d narrowed\n", check->id(),
313 check->block()->block_id())); 376 check->block()->block_id()));
314 // Update map set and ensure that the check is alive. 377 // Update map set and ensure that the check is alive.
315 check->set_maps(intersection); 378 check->set_maps(intersection);
316 check->ClearFlag(HValue::kIsDead); 379 check->ClearFlag(HValue::kIsDead);
317 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n", 380 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n",
318 instr->id(), instr->block()->block_id(), entry->check_->id())); 381 instr->id(), instr->block()->block_id(), entry->check_->id()));
319 instr->DeleteAndReplaceWith(entry->check_); 382 instr->DeleteAndReplaceWith(entry->check_);
320 } else { 383 } else {
321 TRACE(("CheckMaps #%d at B%d narrowed\n", instr->id(), 384 TRACE(("CheckMaps #%d at B%d narrowed\n", instr->id(),
322 instr->block()->block_id())); 385 instr->block()->block_id()));
323 instr->set_maps(intersection); 386 instr->set_maps(intersection);
324 entry->check_ = instr; 387 entry->check_ = instr->IsStabilityCheck() ? NULL : instr;
325 } 388 }
326 389
327 if (FLAG_trace_check_elimination) { 390 if (FLAG_trace_check_elimination) {
328 Print(this); 391 Print(this);
329 } 392 }
330 INC_STAT(narrowed_); 393 INC_STAT(narrowed_);
331 } 394 }
332 } 395 }
333 } else { 396 } else {
334 // No entry; insert a new one. 397 // No entry; insert a new one.
335 Insert(object, instr, instr->maps()); 398 HCheckTableEntry::State state = instr->maps_are_stable()
399 ? HCheckTableEntry::CHECKED_STABLE
400 : HCheckTableEntry::CHECKED;
401 HCheckMaps* check = instr->IsStabilityCheck() ? NULL : instr;
402 Insert(object, check, instr->maps(), state);
336 } 403 }
337 } 404 }
338 405
339 void ReduceLoadNamedField(HLoadNamedField* instr) { 406 void ReduceLoadNamedField(HLoadNamedField* instr) {
340 // Reduce a load of the map field when it is known to be a constant. 407 // Reduce a load of the map field when it is known to be a constant.
341 if (!instr->access().IsMap()) { 408 if (!instr->access().IsMap()) {
342 // Check if we introduce field maps here. 409 // Check if we introduce field maps here.
343 MapSet maps = instr->maps(); 410 MapSet maps = instr->maps();
344 if (maps != NULL) { 411 if (maps != NULL) {
345 ASSERT_NE(0, maps->size()); 412 ASSERT_NE(0, maps->size());
346 Insert(instr, NULL, maps); 413 Insert(instr, NULL, maps, HCheckTableEntry::UNCHECKED_STABLE);
347 } 414 }
348 return; 415 return;
349 } 416 }
350 417
351 HValue* object = instr->object()->ActualValue(); 418 HValue* object = instr->object()->ActualValue();
352 MapSet maps = FindMaps(object); 419 HCheckTableEntry* entry = Find(object);
353 if (maps == NULL || maps->size() != 1) return; // Not a constant. 420 if (entry == NULL || entry->maps_->size() != 1) return; // Not a constant.
354 421
355 Unique<Map> map = maps->at(0); 422 EnsureChecked(entry, object, instr);
423 Unique<Map> map = entry->maps_->at(0);
424 bool map_is_stable = (entry->state_ != HCheckTableEntry::CHECKED);
356 HConstant* constant = HConstant::CreateAndInsertBefore( 425 HConstant* constant = HConstant::CreateAndInsertBefore(
357 instr->block()->graph()->zone(), map, true, instr); 426 instr->block()->graph()->zone(), map, map_is_stable, instr);
358 instr->DeleteAndReplaceWith(constant); 427 instr->DeleteAndReplaceWith(constant);
359 INC_STAT(loads_); 428 INC_STAT(loads_);
360 } 429 }
361 430
362 void ReduceCheckHeapObject(HCheckHeapObject* instr) { 431 void ReduceCheckHeapObject(HCheckHeapObject* instr) {
363 if (FindMaps(instr->value()->ActualValue()) != NULL) { 432 HValue* value = instr->value()->ActualValue();
433 if (Find(value) != NULL) {
364 // If the object has known maps, it's definitely a heap object. 434 // If the object has known maps, it's definitely a heap object.
365 instr->DeleteAndReplaceWith(instr->value()); 435 instr->DeleteAndReplaceWith(value);
366 INC_STAT(removed_cho_); 436 INC_STAT(removed_cho_);
367 } 437 }
368 } 438 }
369 439
370 void ReduceStoreNamedField(HStoreNamedField* instr) { 440 void ReduceStoreNamedField(HStoreNamedField* instr) {
371 HValue* object = instr->object()->ActualValue(); 441 HValue* object = instr->object()->ActualValue();
372 if (instr->has_transition()) { 442 if (instr->has_transition()) {
373 // This store transitions the object to a new map. 443 // This store transitions the object to a new map.
374 Kill(object); 444 Kill(object);
375 Insert(object, NULL, HConstant::cast(instr->transition())->MapValue()); 445 HConstant* c_transition = HConstant::cast(instr->transition());
446 HCheckTableEntry::State state = c_transition->HasStableMapValue()
447 ? HCheckTableEntry::CHECKED_STABLE
448 : HCheckTableEntry::CHECKED;
449 Insert(object, NULL, c_transition->MapValue(), state);
376 } else if (instr->access().IsMap()) { 450 } else if (instr->access().IsMap()) {
377 // This is a store directly to the map field of the object. 451 // This is a store directly to the map field of the object.
378 Kill(object); 452 Kill(object);
379 if (!instr->value()->IsConstant()) return; 453 if (!instr->value()->IsConstant()) return;
380 Insert(object, NULL, HConstant::cast(instr->value())->MapValue()); 454 HConstant* c_value = HConstant::cast(instr->value());
455 HCheckTableEntry::State state = c_value->HasStableMapValue()
456 ? HCheckTableEntry::CHECKED_STABLE
457 : HCheckTableEntry::CHECKED;
458 Insert(object, NULL, c_value->MapValue(), state);
381 } else { 459 } else {
382 // If the instruction changes maps, it should be handled above. 460 // If the instruction changes maps, it should be handled above.
383 CHECK(!instr->CheckChangesFlag(kMaps)); 461 CHECK(!instr->CheckChangesFlag(kMaps));
384 } 462 }
385 } 463 }
386 464
387 void ReduceCompareMap(HCompareMap* instr) { 465 void ReduceCompareMap(HCompareMap* instr) {
388 MapSet maps = FindMaps(instr->value()->ActualValue()); 466 HCheckTableEntry* entry = Find(instr->value()->ActualValue());
389 if (maps == NULL) return; 467 if (entry == NULL) return;
468
469 EnsureChecked(entry, instr->value(), instr);
390 470
391 int succ; 471 int succ;
392 if (maps->Contains(instr->map())) { 472 if (entry->maps_->Contains(instr->map())) {
393 if (maps->size() != 1) { 473 if (entry->maps_->size() != 1) {
394 TRACE(("CompareMap #%d for #%d at B%d can't be eliminated: " 474 TRACE(("CompareMap #%d for #%d at B%d can't be eliminated: "
395 "ambiguous set of maps\n", instr->id(), instr->value()->id(), 475 "ambiguous set of maps\n", instr->id(), instr->value()->id(),
396 instr->block()->block_id())); 476 instr->block()->block_id()));
397 return; 477 return;
398 } 478 }
399 succ = 0; 479 succ = 0;
400 INC_STAT(compares_true_); 480 INC_STAT(compares_true_);
401 } else { 481 } else {
402 succ = 1; 482 succ = 1;
403 INC_STAT(compares_false_); 483 INC_STAT(compares_false_);
404 } 484 }
405 485
406 TRACE(("Marking redundant CompareMap #%d for #%d at B%d as %s\n", 486 TRACE(("Marking redundant CompareMap #%d for #%d at B%d as %s\n",
407 instr->id(), instr->value()->id(), instr->block()->block_id(), 487 instr->id(), instr->value()->id(), instr->block()->block_id(),
408 succ == 0 ? "true" : "false")); 488 succ == 0 ? "true" : "false"));
409 instr->set_known_successor_index(succ); 489 instr->set_known_successor_index(succ);
410 490
411 int unreachable_succ = 1 - succ; 491 int unreachable_succ = 1 - succ;
412 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); 492 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
413 } 493 }
414 494
415 void ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch* instr) { 495 void ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch* instr) {
416 MapSet maps_left = FindMaps(instr->left()->ActualValue()); 496 HValue* left = instr->left()->ActualValue();
417 if (maps_left == NULL) return; 497 HCheckTableEntry* le = Find(left);
418 MapSet maps_right = FindMaps(instr->right()->ActualValue()); 498 if (le == NULL) return;
419 if (maps_right == NULL) return; 499 HValue* right = instr->right()->ActualValue();
420 MapSet intersection = maps_left->Intersect(maps_right, zone()); 500 HCheckTableEntry* re = Find(right);
501 if (re == NULL) return;
502
503 EnsureChecked(le, left, instr);
504 EnsureChecked(re, right, instr);
505
506 // TODO(bmeurer): Add a predicate here instead of computing the intersection
507 MapSet intersection = le->maps_->Intersect(re->maps_, zone());
421 if (intersection->size() > 0) return; 508 if (intersection->size() > 0) return;
422 509
423 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n", 510 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n",
424 instr->id(), instr->block()->block_id())); 511 instr->id(), instr->block()->block_id()));
425 int succ = 1; 512 int succ = 1;
426 instr->set_known_successor_index(succ); 513 instr->set_known_successor_index(succ);
427 514
428 int unreachable_succ = 1 - succ; 515 int unreachable_succ = 1 - succ;
429 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); 516 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
430 } 517 }
431 518
432 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { 519 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) {
433 HCheckTableEntry* entry = Find(instr->object()->ActualValue()); 520 HValue* object = instr->object()->ActualValue();
521 HCheckTableEntry* entry = Find(object);
434 // Can only learn more about an object that already has a known set of maps. 522 // Can only learn more about an object that already has a known set of maps.
435 if (entry == NULL) return; 523 if (entry == NULL) return;
524 EnsureChecked(entry, object, instr);
436 if (entry->maps_->Contains(instr->original_map())) { 525 if (entry->maps_->Contains(instr->original_map())) {
437 // If the object has the original map, it will be transitioned. 526 // If the object has the original map, it will be transitioned.
438 UniqueSet<Map>* maps = entry->maps_->Copy(zone()); 527 UniqueSet<Map>* maps = entry->maps_->Copy(zone());
439 maps->Remove(instr->original_map()); 528 maps->Remove(instr->original_map());
440 maps->Add(instr->transitioned_map(), zone()); 529 maps->Add(instr->transitioned_map(), zone());
441 entry->maps_ = maps; 530 entry->maps_ = maps;
442 } else { 531 } else {
443 // Object does not have the given map, thus the transition is redundant. 532 // Object does not have the given map, thus the transition is redundant.
444 instr->DeleteAndReplaceWith(instr->object()); 533 instr->DeleteAndReplaceWith(object);
445 INC_STAT(transitions_); 534 INC_STAT(transitions_);
446 } 535 }
447 } 536 }
448 537
538 void EnsureChecked(HCheckTableEntry* entry,
539 HValue* value,
540 HInstruction* instr) {
541 if (entry->state_ != HCheckTableEntry::UNCHECKED_STABLE) return;
542 HGraph* graph = instr->block()->graph();
543 HCheckMaps* check = HCheckMaps::CreateAndInsertBefore(
544 graph->zone(), value, entry->maps_->Copy(graph->zone()), true, instr);
545 check->MarkAsStabilityCheck();
546 entry->state_ = HCheckTableEntry::CHECKED_STABLE;
547 entry->check_ = NULL;
548 }
549
449 // Kill everything in the table. 550 // Kill everything in the table.
450 void Kill() { 551 void Kill() {
451 size_ = 0; 552 size_ = 0;
452 cursor_ = 0; 553 cursor_ = 0;
453 } 554 }
454 555
556 // Kill all unstable entries in the table.
557 void KillUnstableEntries() {
558 bool compact = false;
559 for (int i = 0; i < size_; ++i) {
560 HCheckTableEntry* entry = &entries_[i];
561 ASSERT_NOT_NULL(entry->object_);
562 if (entry->state_ == HCheckTableEntry::CHECKED) {
563 entry->object_ = NULL;
564 compact = true;
565 } else {
566 // All checked stable entries become unchecked stable.
567 entry->state_ = HCheckTableEntry::UNCHECKED_STABLE;
Igor Sheludko 2014/05/07 16:53:26 Does it mean that we could end up adding multiple
Benedikt Meurer 2014/05/08 04:45:49 This is not an issue, because the stability checks
568 entry->check_ = NULL;
569 }
570 }
571 if (compact) Compact();
572 }
573
455 // Kill everything in the table that may alias {object}. 574 // Kill everything in the table that may alias {object}.
456 void Kill(HValue* object) { 575 void Kill(HValue* object) {
457 bool compact = false; 576 bool compact = false;
458 for (int i = 0; i < size_; i++) { 577 for (int i = 0; i < size_; i++) {
459 HCheckTableEntry* entry = &entries_[i]; 578 HCheckTableEntry* entry = &entries_[i];
460 ASSERT(entry->object_ != NULL); 579 ASSERT(entry->object_ != NULL);
461 if (phase_->aliasing_->MayAlias(entry->object_, object)) { 580 if (phase_->aliasing_->MayAlias(entry->object_, object)) {
462 entry->object_ = NULL; 581 entry->object_ = NULL;
463 compact = true; 582 compact = true;
464 } 583 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
507 626
508 for (int i = 0; i < table->size_; i++) { 627 for (int i = 0; i < table->size_; i++) {
509 HCheckTableEntry* entry = &table->entries_[i]; 628 HCheckTableEntry* entry = &table->entries_[i];
510 ASSERT(entry->object_ != NULL); 629 ASSERT(entry->object_ != NULL);
511 PrintF(" checkmaps-table @%d: %s #%d ", i, 630 PrintF(" checkmaps-table @%d: %s #%d ", i,
512 entry->object_->IsPhi() ? "phi" : "object", entry->object_->id()); 631 entry->object_->IsPhi() ? "phi" : "object", entry->object_->id());
513 if (entry->check_ != NULL) { 632 if (entry->check_ != NULL) {
514 PrintF("check #%d ", entry->check_->id()); 633 PrintF("check #%d ", entry->check_->id());
515 } 634 }
516 MapSet list = entry->maps_; 635 MapSet list = entry->maps_;
517 PrintF("%d maps { ", list->size()); 636 PrintF("%d %s maps { ", list->size(),
637 HCheckTableEntry::State2String(entry->state_));
518 for (int j = 0; j < list->size(); j++) { 638 for (int j = 0; j < list->size(); j++) {
519 if (j > 0) PrintF(", "); 639 if (j > 0) PrintF(", ");
520 PrintF("%" V8PRIxPTR, list->at(j).Hashcode()); 640 PrintF("%" V8PRIxPTR, list->at(j).Hashcode());
521 } 641 }
522 PrintF(" }\n"); 642 PrintF(" }\n");
523 } 643 }
524 } 644 }
525 645
526 HCheckTableEntry* Find(HValue* object) { 646 HCheckTableEntry* Find(HValue* object) {
527 for (int i = size_ - 1; i >= 0; i--) { 647 for (int i = size_ - 1; i >= 0; i--) {
528 // Search from most-recently-inserted to least-recently-inserted. 648 // Search from most-recently-inserted to least-recently-inserted.
529 HCheckTableEntry* entry = &entries_[i]; 649 HCheckTableEntry* entry = &entries_[i];
530 ASSERT(entry->object_ != NULL); 650 ASSERT(entry->object_ != NULL);
531 if (phase_->aliasing_->MustAlias(entry->object_, object)) return entry; 651 if (phase_->aliasing_->MustAlias(entry->object_, object)) return entry;
532 } 652 }
533 return NULL; 653 return NULL;
534 } 654 }
535 655
536 MapSet FindMaps(HValue* object) { 656 void Insert(HValue* object,
537 HCheckTableEntry* entry = Find(object); 657 HInstruction* check,
538 return entry == NULL ? NULL : entry->maps_; 658 Unique<Map> map,
659 HCheckTableEntry::State state) {
660 Insert(object, check, new(zone()) UniqueSet<Map>(map, zone()), state);
539 } 661 }
540 662
541 void Insert(HValue* object, HInstruction* check, Unique<Map> map) { 663 void Insert(HValue* object,
542 Insert(object, check, new(zone()) UniqueSet<Map>(map, zone())); 664 HInstruction* check,
543 } 665 MapSet maps,
544 666 HCheckTableEntry::State state) {
545 void Insert(HValue* object, HInstruction* check, MapSet maps) { 667 ASSERT(state != HCheckTableEntry::UNCHECKED_STABLE || check == NULL);
546 HCheckTableEntry* entry = &entries_[cursor_++]; 668 HCheckTableEntry* entry = &entries_[cursor_++];
547 entry->object_ = object; 669 entry->object_ = object;
548 entry->check_ = check; 670 entry->check_ = check;
549 entry->maps_ = maps; 671 entry->maps_ = maps;
672 entry->state_ = state;
550 // If the table becomes full, wrap around and overwrite older entries. 673 // If the table becomes full, wrap around and overwrite older entries.
551 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; 674 if (cursor_ == kMaxTrackedObjects) cursor_ = 0;
552 if (size_ < kMaxTrackedObjects) size_++; 675 if (size_ < kMaxTrackedObjects) size_++;
553 } 676 }
554 677
555 Zone* zone() const { return phase_->zone(); } 678 Zone* zone() const { return phase_->zone(); }
556 679
557 friend class HCheckMapsEffects; 680 friend class HCheckMapsEffects;
558 friend class HCheckEliminationPhase; 681 friend class HCheckEliminationPhase;
559 682
560 HCheckEliminationPhase* phase_; 683 HCheckEliminationPhase* phase_;
561 HCheckTableEntry entries_[kMaxTrackedObjects]; 684 HCheckTableEntry entries_[kMaxTrackedObjects];
562 int16_t cursor_; // Must be <= kMaxTrackedObjects 685 int16_t cursor_; // Must be <= kMaxTrackedObjects
563 int16_t size_; // Must be <= kMaxTrackedObjects 686 int16_t size_; // Must be <= kMaxTrackedObjects
564 // TODO(titzer): STATIC_ASSERT kMaxTrackedObjects < max(cursor_) 687 STATIC_ASSERT(kMaxTrackedObjects < (1 << 15));
565 }; 688 };
566 689
567 690
568 // Collects instructions that can cause effects that invalidate information 691 // Collects instructions that can cause effects that invalidate information
569 // needed for check elimination. 692 // needed for check elimination.
570 class HCheckMapsEffects : public ZoneObject { 693 class HCheckMapsEffects : public ZoneObject {
571 public: 694 public:
572 explicit HCheckMapsEffects(Zone* zone) 695 explicit HCheckMapsEffects(Zone* zone)
573 : objects_(0, zone), maps_stored_(false) {} 696 : objects_(0, zone), maps_stored_(false), osr_entries_(false) { }
574 697
575 // Effects are _not_ disabled. 698 // Effects are _not_ disabled.
576 inline bool Disabled() const { return false; } 699 inline bool Disabled() const { return false; }
577 700
578 // Process a possibly side-effecting instruction. 701 // Process a possibly side-effecting instruction.
579 void Process(HInstruction* instr, Zone* zone) { 702 void Process(HInstruction* instr, Zone* zone) {
580 switch (instr->opcode()) { 703 switch (instr->opcode()) {
581 case HValue::kStoreNamedField: { 704 case HValue::kStoreNamedField: {
582 HStoreNamedField* store = HStoreNamedField::cast(instr); 705 HStoreNamedField* store = HStoreNamedField::cast(instr);
583 if (store->access().IsMap() && store->has_transition()) { 706 if (store->access().IsMap() && store->has_transition()) {
584 objects_.Add(store->object(), zone); 707 objects_.Add(store->object(), zone);
585 } 708 }
586 break; 709 break;
587 } 710 }
588 case HValue::kTransitionElementsKind: { 711 case HValue::kTransitionElementsKind: {
589 objects_.Add(HTransitionElementsKind::cast(instr)->object(), zone); 712 objects_.Add(HTransitionElementsKind::cast(instr)->object(), zone);
590 break; 713 break;
591 } 714 }
592 default: { 715 default: {
593 maps_stored_ |= (instr->CheckChangesFlag(kMaps) | 716 if (instr->CheckChangesFlag(kMaps) ||
594 instr->CheckChangesFlag(kOsrEntries) | 717 instr->CheckChangesFlag(kElementsKind)) {
595 instr->CheckChangesFlag(kElementsKind)); 718 maps_stored_ = true;
719 }
720 if (instr->CheckChangesFlag(kOsrEntries)) {
721 osr_entries_ = true;
722 }
596 } 723 }
597 } 724 }
598 } 725 }
599 726
600 // Apply these effects to the given check elimination table. 727 // Apply these effects to the given check elimination table.
601 void Apply(HCheckTable* table) { 728 void Apply(HCheckTable* table) {
602 if (maps_stored_) { 729 if (osr_entries_) {
603 // Uncontrollable map modifications; kill everything. 730 // Uncontrollable map modifications; kill everything.
604 table->Kill(); 731 table->Kill();
605 return; 732 return;
606 } 733 }
607 734
735 // Kill all unstable entries.
736 if (maps_stored_) {
737 table->KillUnstableEntries();
Igor Sheludko 2014/05/07 16:53:26 I think you can return at this point as all the en
Benedikt Meurer 2014/05/08 04:45:49 No, because we can have stored maps to objects wit
738 }
739
608 // Kill maps for each object contained in these effects. 740 // Kill maps for each object contained in these effects.
609 for (int i = 0; i < objects_.length(); ++i) { 741 for (int i = 0; i < objects_.length(); ++i) {
610 table->Kill(objects_[i]->ActualValue()); 742 table->Kill(objects_[i]->ActualValue());
611 } 743 }
612 } 744 }
613 745
614 // Union these effects with the other effects. 746 // Union these effects with the other effects.
615 void Union(HCheckMapsEffects* that, Zone* zone) { 747 void Union(HCheckMapsEffects* that, Zone* zone) {
616 maps_stored_ |= that->maps_stored_; 748 maps_stored_ |= that->maps_stored_;
749 osr_entries_ |= that->osr_entries_;
617 for (int i = 0; i < that->objects_.length(); ++i) { 750 for (int i = 0; i < that->objects_.length(); ++i) {
618 objects_.Add(that->objects_[i], zone); 751 objects_.Add(that->objects_[i], zone);
619 } 752 }
620 } 753 }
621 754
622 private: 755 private:
623 ZoneList<HValue*> objects_; 756 ZoneList<HValue*> objects_;
624 bool maps_stored_ : 1; 757 bool maps_stored_ : 1;
758 bool osr_entries_ : 1;
Igor Sheludko 2014/05/07 16:53:26 Consider using GVNFlags instead of set of booleans
Benedikt Meurer 2014/05/08 04:45:49 Done.
625 }; 759 };
626 760
627 761
628 // The main routine of the analysis phase. Use the HFlowEngine for either a 762 // The main routine of the analysis phase. Use the HFlowEngine for either a
629 // local or a global analysis. 763 // local or a global analysis.
630 void HCheckEliminationPhase::Run() { 764 void HCheckEliminationPhase::Run() {
631 HFlowEngine<HCheckTable, HCheckMapsEffects> engine(graph(), zone()); 765 HFlowEngine<HCheckTable, HCheckMapsEffects> engine(graph(), zone());
632 HCheckTable* table = new(zone()) HCheckTable(this); 766 HCheckTable* table = new(zone()) HCheckTable(this);
633 767
634 if (GLOBAL) { 768 if (GLOBAL) {
(...skipping 23 matching lines...) Expand all
658 PRINT_STAT(removed_cho); 792 PRINT_STAT(removed_cho);
659 PRINT_STAT(narrowed); 793 PRINT_STAT(narrowed);
660 PRINT_STAT(loads); 794 PRINT_STAT(loads);
661 PRINT_STAT(empty); 795 PRINT_STAT(empty);
662 PRINT_STAT(compares_true); 796 PRINT_STAT(compares_true);
663 PRINT_STAT(compares_false); 797 PRINT_STAT(compares_false);
664 PRINT_STAT(transitions); 798 PRINT_STAT(transitions);
665 } 799 }
666 800
667 } } // namespace v8::internal 801 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.cc ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698