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

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