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

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

Issue 264693011: Various cleanups in check elimination. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: 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/arm64/lithium-codegen-arm64.cc ('k') | src/hydrogen-escape-analysis.cc » ('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 #include "hydrogen-alias-analysis.h" 6 #include "hydrogen-alias-analysis.h"
7 #include "hydrogen-flow-engine.h" 7 #include "hydrogen-flow-engine.h"
8 8
9 #define GLOBAL 1 9 #define GLOBAL 1
10 10
11 // Only collect stats in debug mode. 11 // Only collect stats in debug mode.
12 #if DEBUG 12 #if DEBUG
13 #define INC_STAT(x) phase_->x++ 13 #define INC_STAT(x) phase_->x++
14 #else 14 #else
15 #define INC_STAT(x) 15 #define INC_STAT(x)
16 #endif 16 #endif
17 17
18 // For code de-uglification. 18 // For code de-uglification.
19 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x 19 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x
20 20
21 namespace v8 { 21 namespace v8 {
22 namespace internal { 22 namespace internal {
23 23
24 typedef UniqueSet<Map>* MapSet; 24 typedef const UniqueSet<Map>* MapSet;
25 25
26 struct HCheckTableEntry { 26 struct HCheckTableEntry {
27 HValue* object_; // The object being approximated. NULL => invalid entry. 27 HValue* object_; // The object being approximated. NULL => invalid entry.
28 HInstruction* check_; // The last check instruction. 28 HInstruction* check_; // The last check instruction.
29 MapSet maps_; // The set of known maps for the object. 29 MapSet maps_; // The set of known maps for the object.
30 }; 30 };
31 31
32 32
33 // The main data structure used during check elimination, which stores a 33 // The main data structure used during check elimination, which stores a
34 // set of known maps for each object. 34 // set of known maps for each object.
35 class HCheckTable : public ZoneObject { 35 class HCheckTable : public ZoneObject {
36 public: 36 public:
37 static const int kMaxTrackedObjects = 10; 37 static const int kMaxTrackedObjects = 16;
38 38
39 explicit HCheckTable(HCheckEliminationPhase* phase) 39 explicit HCheckTable(HCheckEliminationPhase* phase)
40 : phase_(phase), 40 : phase_(phase),
41 cursor_(0), 41 cursor_(0),
42 size_(0) { 42 size_(0) {
43 } 43 }
44 44
45 // The main processing of instructions. 45 // The main processing of instructions.
46 HCheckTable* Process(HInstruction* instr, Zone* zone) { 46 HCheckTable* Process(HInstruction* instr, Zone* zone) {
47 switch (instr->opcode()) { 47 switch (instr->opcode()) {
(...skipping 25 matching lines...) Expand all
73 case HValue::kCheckMapValue: { 73 case HValue::kCheckMapValue: {
74 ReduceCheckMapValue(HCheckMapValue::cast(instr)); 74 ReduceCheckMapValue(HCheckMapValue::cast(instr));
75 break; 75 break;
76 } 76 }
77 case HValue::kCheckHeapObject: { 77 case HValue::kCheckHeapObject: {
78 ReduceCheckHeapObject(HCheckHeapObject::cast(instr)); 78 ReduceCheckHeapObject(HCheckHeapObject::cast(instr));
79 break; 79 break;
80 } 80 }
81 default: { 81 default: {
82 // If the instruction changes maps uncontrollably, drop everything. 82 // If the instruction changes maps uncontrollably, drop everything.
83 if (instr->CheckChangesFlag(kMaps) || 83 if (instr->CheckChangesFlag(kElementsKind) ||
84 instr->CheckChangesFlag(kMaps) ||
84 instr->CheckChangesFlag(kOsrEntries)) { 85 instr->CheckChangesFlag(kOsrEntries)) {
85 Kill(); 86 Kill();
86 } 87 }
87 } 88 }
88 // Improvements possible: 89 // Improvements possible:
89 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions 90 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions
90 // - track which values have been HCheckHeapObject'd 91 // - track which values have been HCheckHeapObject'd
91 } 92 }
92 93
93 return this; 94 return this;
(...skipping 26 matching lines...) Expand all
120 if (FLAG_trace_check_elimination) { 121 if (FLAG_trace_check_elimination) {
121 PrintF("Processing B%d, checkmaps-table:\n", block->block_id()); 122 PrintF("Processing B%d, checkmaps-table:\n", block->block_id());
122 Print(state); 123 Print(state);
123 } 124 }
124 return state; 125 return state;
125 } 126 }
126 127
127 private: 128 private:
128 // Copy state to successor block. 129 // Copy state to successor block.
129 HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block, Zone* zone) { 130 HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block, Zone* zone) {
130 HCheckTable* copy = new(phase_->zone()) HCheckTable(phase_); 131 HCheckTable* copy = new(zone) HCheckTable(phase_);
131 for (int i = 0; i < size_; i++) { 132 for (int i = 0; i < size_; i++) {
132 HCheckTableEntry* old_entry = &entries_[i]; 133 HCheckTableEntry* old_entry = &entries_[i];
133 ASSERT(old_entry->maps_->size() > 0); 134 ASSERT(old_entry->maps_->size() > 0);
134 HCheckTableEntry* new_entry = &copy->entries_[i]; 135 HCheckTableEntry* new_entry = &copy->entries_[i];
135 new_entry->object_ = old_entry->object_; 136 new_entry->object_ = old_entry->object_;
136 new_entry->maps_ = old_entry->maps_->Copy(phase_->zone()); 137 new_entry->maps_ = old_entry->maps_;
137 // Keep the check if the existing check's block dominates the successor. 138 // Keep the check if the existing check's block dominates the successor.
138 if (old_entry->check_ != NULL && 139 if (old_entry->check_ != NULL &&
139 old_entry->check_->block()->Dominates(succ)) { 140 old_entry->check_->block()->Dominates(succ)) {
140 new_entry->check_ = old_entry->check_; 141 new_entry->check_ = old_entry->check_;
141 } else { 142 } else {
142 // Leave it NULL till we meet a new check instruction for this object 143 // Leave it NULL till we meet a new check instruction for this object
143 // in the control flow. 144 // in the control flow.
144 new_entry->check_ = NULL; 145 new_entry->check_ = NULL;
145 } 146 }
146 } 147 }
147 copy->cursor_ = cursor_; 148 copy->cursor_ = cursor_;
148 copy->size_ = size_; 149 copy->size_ = size_;
149 150
150 // Create entries for succ block's phis. 151 // Create entries for succ block's phis.
151 if (!succ->IsLoopHeader() && succ->phis()->length() > 0) { 152 if (!succ->IsLoopHeader() && succ->phis()->length() > 0) {
152 int pred_index = succ->PredecessorIndexOf(from_block); 153 int pred_index = succ->PredecessorIndexOf(from_block);
153 for (int phi_index = 0; 154 for (int phi_index = 0;
154 phi_index < succ->phis()->length(); 155 phi_index < succ->phis()->length();
155 ++phi_index) { 156 ++phi_index) {
156 HPhi* phi = succ->phis()->at(phi_index); 157 HPhi* phi = succ->phis()->at(phi_index);
157 HValue* phi_operand = phi->OperandAt(pred_index); 158 HValue* phi_operand = phi->OperandAt(pred_index);
158 159
159 HCheckTableEntry* pred_entry = copy->Find(phi_operand); 160 HCheckTableEntry* pred_entry = copy->Find(phi_operand);
160 if (pred_entry != NULL) { 161 if (pred_entry != NULL) {
161 // Create an entry for a phi in the table. 162 // Create an entry for a phi in the table.
162 copy->Insert(phi, NULL, pred_entry->maps_->Copy(phase_->zone())); 163 copy->Insert(phi, NULL, pred_entry->maps_);
163 } 164 }
164 } 165 }
165 } 166 }
166 167
167 // Branch-sensitive analysis for certain comparisons may add more facts 168 // Branch-sensitive analysis for certain comparisons may add more facts
168 // to the state for the successor on the true branch. 169 // to the state for the successor on the true branch.
169 bool learned = false; 170 bool learned = false;
170 if (succ->predecessors()->length() == 1) { 171 if (succ->predecessors()->length() == 1) {
171 HControlInstruction* end = succ->predecessors()->at(0)->end(); 172 HControlInstruction* end = succ->predecessors()->at(0)->end();
172 bool is_true_branch = end->SuccessorAt(0) == succ; 173 bool is_true_branch = end->SuccessorAt(0) == succ;
173 if (end->IsCompareMap()) { 174 if (end->IsCompareMap()) {
174 HCompareMap* cmp = HCompareMap::cast(end); 175 HCompareMap* cmp = HCompareMap::cast(end);
175 HValue* object = cmp->value()->ActualValue(); 176 HValue* object = cmp->value()->ActualValue();
176 HCheckTableEntry* entry = copy->Find(object); 177 HCheckTableEntry* entry = copy->Find(object);
177 if (is_true_branch) { 178 if (is_true_branch) {
178 // Learn on the true branch of if(CompareMap(x)). 179 // Learn on the true branch of if(CompareMap(x)).
179 if (entry == NULL) { 180 if (entry == NULL) {
180 copy->Insert(object, cmp, cmp->map()); 181 copy->Insert(object, cmp, cmp->map());
181 } else { 182 } else {
182 MapSet list = new(phase_->zone()) UniqueSet<Map>(); 183 entry->maps_ = new(zone) UniqueSet<Map>(cmp->map(), zone);
183 list->Add(cmp->map(), phase_->zone());
184 entry->maps_ = list;
185 entry->check_ = cmp; 184 entry->check_ = cmp;
186 } 185 }
187 } else { 186 } else {
188 // Learn on the false branch of if(CompareMap(x)). 187 // Learn on the false branch of if(CompareMap(x)).
189 if (entry != NULL) { 188 if (entry != NULL) {
190 entry->maps_->Remove(cmp->map()); 189 UniqueSet<Map>* maps = entry->maps_->Copy(zone);
190 maps->Remove(cmp->map());
191 entry->maps_ = maps;
191 } 192 }
192 } 193 }
193 learned = true; 194 learned = true;
194 } else if (is_true_branch && end->IsCompareObjectEqAndBranch()) { 195 } else if (is_true_branch && end->IsCompareObjectEqAndBranch()) {
195 // Learn on the true branch of if(CmpObjectEq(x, y)). 196 // Learn on the true branch of if(CmpObjectEq(x, y)).
196 HCompareObjectEqAndBranch* cmp = 197 HCompareObjectEqAndBranch* cmp =
197 HCompareObjectEqAndBranch::cast(end); 198 HCompareObjectEqAndBranch::cast(end);
198 HValue* left = cmp->left()->ActualValue(); 199 HValue* left = cmp->left()->ActualValue();
199 HValue* right = cmp->right()->ActualValue(); 200 HValue* right = cmp->right()->ActualValue();
200 HCheckTableEntry* le = copy->Find(left); 201 HCheckTableEntry* le = copy->Find(left);
201 HCheckTableEntry* re = copy->Find(right); 202 HCheckTableEntry* re = copy->Find(right);
202 if (le == NULL) { 203 if (le == NULL) {
203 if (re != NULL) { 204 if (re != NULL) {
204 copy->Insert(left, NULL, re->maps_->Copy(zone)); 205 copy->Insert(left, NULL, re->maps_);
205 } 206 }
206 } else if (re == NULL) { 207 } else if (re == NULL) {
207 copy->Insert(right, NULL, le->maps_->Copy(zone)); 208 copy->Insert(right, NULL, le->maps_);
208 } else { 209 } else {
209 MapSet intersect = le->maps_->Intersect(re->maps_, zone); 210 le->maps_ = re->maps_ = le->maps_->Intersect(re->maps_, zone);
210 le->maps_ = intersect;
211 re->maps_ = intersect->Copy(zone);
212 } 211 }
213 learned = true; 212 learned = true;
214 } 213 }
215 // Learning on false branches requires storing negative facts. 214 // Learning on false branches requires storing negative facts.
216 } 215 }
217 216
218 if (FLAG_trace_check_elimination) { 217 if (FLAG_trace_check_elimination) {
219 PrintF("B%d checkmaps-table %s from B%d:\n", 218 PrintF("B%d checkmaps-table %s from B%d:\n",
220 succ->block_id(), 219 succ->block_id(),
221 learned ? "learned" : "copied", 220 learned ? "learned" : "copied",
(...skipping 25 matching lines...) Expand all
247 246
248 } else { 247 } else {
249 that_entry = that->Find(this_entry->object_); 248 that_entry = that->Find(this_entry->object_);
250 } 249 }
251 250
252 if (that_entry == NULL) { 251 if (that_entry == NULL) {
253 this_entry->object_ = NULL; 252 this_entry->object_ = NULL;
254 compact = true; 253 compact = true;
255 } else { 254 } else {
256 this_entry->maps_ = 255 this_entry->maps_ =
257 this_entry->maps_->Union(that_entry->maps_, phase_->zone()); 256 this_entry->maps_->Union(that_entry->maps_, zone);
258 if (this_entry->check_ != that_entry->check_) { 257 if (this_entry->check_ != that_entry->check_) {
259 this_entry->check_ = NULL; 258 this_entry->check_ = NULL;
260 } 259 }
261 ASSERT(this_entry->maps_->size() > 0); 260 ASSERT(this_entry->maps_->size() > 0);
262 } 261 }
263 } 262 }
264 if (compact) Compact(); 263 if (compact) Compact();
265 } 264 }
266 265
267 if (FLAG_trace_check_elimination) { 266 if (FLAG_trace_check_elimination) {
268 PrintF("B%d checkmaps-table merged with B%d table:\n", 267 PrintF("B%d checkmaps-table merged with B%d table:\n",
269 succ->block_id(), pred_block->block_id()); 268 succ->block_id(), pred_block->block_id());
270 Print(this); 269 Print(this);
271 } 270 }
272 return this; 271 return this;
273 } 272 }
274 273
275 void ReduceCheckMaps(HCheckMaps* instr) { 274 void ReduceCheckMaps(HCheckMaps* instr) {
276 HValue* object = instr->value()->ActualValue(); 275 HValue* object = instr->value()->ActualValue();
277 HCheckTableEntry* entry = Find(object); 276 HCheckTableEntry* entry = Find(object);
278 if (entry != NULL) { 277 if (entry != NULL) {
279 // entry found; 278 // entry found;
280 MapSet a = entry->maps_; 279 MapSet a = entry->maps_;
281 const UniqueSet<Map>* i = instr->map_set(); 280 const UniqueSet<Map>* i = instr->maps();
282 if (a->IsSubset(i)) { 281 if (a->IsSubset(i)) {
283 // The first check is more strict; the second is redundant. 282 // The first check is more strict; the second is redundant.
284 if (entry->check_ != NULL) { 283 if (entry->check_ != NULL) {
285 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n", 284 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n",
286 instr->id(), instr->block()->block_id(), entry->check_->id())); 285 instr->id(), instr->block()->block_id(), entry->check_->id()));
287 instr->DeleteAndReplaceWith(entry->check_); 286 instr->DeleteAndReplaceWith(entry->check_);
288 INC_STAT(redundant_); 287 INC_STAT(redundant_);
289 } else { 288 } else {
290 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n", 289 TRACE(("Marking redundant CheckMaps #%d at B%d as dead\n",
291 instr->id(), instr->block()->block_id())); 290 instr->id(), instr->block()->block_id()));
292 // Mark check as dead but leave it in the graph as a checkpoint for 291 // Mark check as dead but leave it in the graph as a checkpoint for
293 // subsequent checks. 292 // subsequent checks.
294 instr->SetFlag(HValue::kIsDead); 293 instr->SetFlag(HValue::kIsDead);
295 entry->check_ = instr; 294 entry->check_ = instr;
296 INC_STAT(removed_); 295 INC_STAT(removed_);
297 } 296 }
298 return; 297 return;
299 } 298 }
300 MapSet intersection = i->Intersect(a, phase_->zone()); 299 HGraph* graph = instr->block()->graph();
300 MapSet intersection = i->Intersect(a, graph->zone());
301 if (intersection->size() == 0) { 301 if (intersection->size() == 0) {
302 // Intersection is empty; probably megamorphic, which is likely to 302 // Intersection is empty; probably megamorphic, which is likely to
303 // deopt anyway, so just leave things as they are. 303 // deopt anyway, so just leave things as they are.
304 INC_STAT(empty_); 304 INC_STAT(empty_);
305 } else { 305 } else {
306 // Update set of maps in the entry. 306 // Update set of maps in the entry.
307 entry->maps_ = intersection; 307 entry->maps_ = intersection;
308 if (intersection->size() != i->size()) { 308 if (intersection->size() != i->size()) {
309 // Narrow set of maps in the second check maps instruction. 309 // Narrow set of maps in the second check maps instruction.
310 HGraph* graph = instr->block()->graph();
311 if (entry->check_ != NULL && 310 if (entry->check_ != NULL &&
312 entry->check_->block() == instr->block() && 311 entry->check_->block() == instr->block() &&
313 entry->check_->IsCheckMaps()) { 312 entry->check_->IsCheckMaps()) {
314 // There is a check in the same block so replace it with a more 313 // There is a check in the same block so replace it with a more
315 // strict check and eliminate the second check entirely. 314 // strict check and eliminate the second check entirely.
316 HCheckMaps* check = HCheckMaps::cast(entry->check_); 315 HCheckMaps* check = HCheckMaps::cast(entry->check_);
317 TRACE(("CheckMaps #%d at B%d narrowed\n", check->id(), 316 TRACE(("CheckMaps #%d at B%d narrowed\n", check->id(),
318 check->block()->block_id())); 317 check->block()->block_id()));
319 // Update map set and ensure that the check is alive. 318 // Update map set and ensure that the check is alive.
320 check->set_map_set(intersection, graph->zone()); 319 check->set_maps(intersection);
321 check->ClearFlag(HValue::kIsDead); 320 check->ClearFlag(HValue::kIsDead);
322 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n", 321 TRACE(("Replacing redundant CheckMaps #%d at B%d with #%d\n",
323 instr->id(), instr->block()->block_id(), entry->check_->id())); 322 instr->id(), instr->block()->block_id(), entry->check_->id()));
324 instr->DeleteAndReplaceWith(entry->check_); 323 instr->DeleteAndReplaceWith(entry->check_);
325 } else { 324 } else {
326 TRACE(("CheckMaps #%d at B%d narrowed\n", instr->id(), 325 TRACE(("CheckMaps #%d at B%d narrowed\n", instr->id(),
327 instr->block()->block_id())); 326 instr->block()->block_id()));
328 instr->set_map_set(intersection, graph->zone()); 327 instr->set_maps(intersection);
329 entry->check_ = instr; 328 entry->check_ = instr;
330 } 329 }
331 330
332 if (FLAG_trace_check_elimination) { 331 if (FLAG_trace_check_elimination) {
333 Print(this); 332 Print(this);
334 } 333 }
335 INC_STAT(narrowed_); 334 INC_STAT(narrowed_);
336 } 335 }
337 } 336 }
338 } else { 337 } else {
339 // No entry; insert a new one. 338 // No entry; insert a new one.
340 Insert(object, instr, instr->map_set()->Copy(phase_->zone())); 339 Insert(object, instr, instr->maps());
341 } 340 }
342 } 341 }
343 342
344 void ReduceLoadNamedField(HLoadNamedField* instr) { 343 void ReduceLoadNamedField(HLoadNamedField* instr) {
345 // Reduce a load of the map field when it is known to be a constant. 344 // Reduce a load of the map field when it is known to be a constant.
346 if (!IsMapAccess(instr->access())) { 345 if (!instr->access().IsMap()) {
347 // Check if we introduce field maps here. 346 // Check if we introduce field maps here.
348 if (instr->map_set()->size() != 0) { 347 if (instr->maps()->size() != 0) {
349 Insert(instr, instr, instr->map_set()->Copy(phase_->zone())); 348 Insert(instr, instr, instr->maps());
350 } 349 }
351 return; 350 return;
352 } 351 }
353 352
354 HValue* object = instr->object()->ActualValue(); 353 HValue* object = instr->object()->ActualValue();
355 MapSet maps = FindMaps(object); 354 MapSet maps = FindMaps(object);
356 if (maps == NULL || maps->size() != 1) return; // Not a constant. 355 if (maps == NULL || maps->size() != 1) return; // Not a constant.
357 356
358 Unique<Map> map = maps->at(0); 357 Unique<Map> map = maps->at(0);
359 HConstant* constant = HConstant::CreateAndInsertBefore( 358 HConstant* constant = HConstant::CreateAndInsertBefore(
360 instr->block()->graph()->zone(), map, true, instr); 359 instr->block()->graph()->zone(), map, true, instr);
361 instr->DeleteAndReplaceWith(constant); 360 instr->DeleteAndReplaceWith(constant);
362 INC_STAT(loads_); 361 INC_STAT(loads_);
363 } 362 }
364 363
365 void ReduceCheckMapValue(HCheckMapValue* instr) { 364 void ReduceCheckMapValue(HCheckMapValue* instr) {
366 if (!instr->map()->IsConstant()) return; // Nothing to learn. 365 if (!instr->map()->IsConstant()) return; // Nothing to learn.
367 366
368 HValue* object = instr->value()->ActualValue(); 367 HValue* object = instr->value()->ActualValue();
369 // Match a HCheckMapValue(object, HConstant(map)) 368 // Match a HCheckMapValue(object, HConstant(map))
370 Unique<Map> map = MapConstant(instr->map()); 369 Unique<Map> map = MapConstant(instr->map());
371 370
372 HCheckTableEntry* entry = Find(object); 371 HCheckTableEntry* entry = Find(object);
373 if (entry != NULL) { 372 if (entry != NULL) {
374 MapSet maps = entry->maps_; 373 if (entry->maps_->Contains(map)) {
375 if (maps->Contains(map)) { 374 if (entry->maps_->size() == 1) {
376 if (maps->size() == 1) {
377 // Object is known to have exactly this map. 375 // Object is known to have exactly this map.
378 if (entry->check_ != NULL) { 376 if (entry->check_ != NULL) {
379 instr->DeleteAndReplaceWith(entry->check_); 377 instr->DeleteAndReplaceWith(entry->check_);
380 } else { 378 } else {
381 // Mark check as dead but leave it in the graph as a checkpoint for 379 // Mark check as dead but leave it in the graph as a checkpoint for
382 // subsequent checks. 380 // subsequent checks.
383 instr->SetFlag(HValue::kIsDead); 381 instr->SetFlag(HValue::kIsDead);
384 entry->check_ = instr; 382 entry->check_ = instr;
385 } 383 }
386 INC_STAT(removed_); 384 INC_STAT(removed_);
387 } else { 385 } else {
388 // Only one map survives the check. 386 // Only one map survives the check.
389 maps->Clear(); 387 entry->maps_ = new(zone()) UniqueSet<Map>(map, zone());
390 maps->Add(map, phase_->zone());
391 entry->check_ = instr; 388 entry->check_ = instr;
392 } 389 }
393 } 390 }
394 } else { 391 } else {
395 // No prior information. 392 // No prior information.
396 Insert(object, instr, map); 393 Insert(object, instr, map);
397 } 394 }
398 } 395 }
399 396
400 void ReduceCheckHeapObject(HCheckHeapObject* instr) { 397 void ReduceCheckHeapObject(HCheckHeapObject* instr) {
401 if (FindMaps(instr->value()->ActualValue()) != NULL) { 398 if (FindMaps(instr->value()->ActualValue()) != NULL) {
402 // If the object has known maps, it's definitely a heap object. 399 // If the object has known maps, it's definitely a heap object.
403 instr->DeleteAndReplaceWith(instr->value()); 400 instr->DeleteAndReplaceWith(instr->value());
404 INC_STAT(removed_cho_); 401 INC_STAT(removed_cho_);
405 } 402 }
406 } 403 }
407 404
408 void ReduceStoreNamedField(HStoreNamedField* instr) { 405 void ReduceStoreNamedField(HStoreNamedField* instr) {
409 HValue* object = instr->object()->ActualValue(); 406 HValue* object = instr->object()->ActualValue();
410 if (instr->has_transition()) { 407 if (instr->has_transition()) {
411 // This store transitions the object to a new map. 408 // This store transitions the object to a new map.
412 Kill(object); 409 Kill(object);
413 Insert(object, NULL, MapConstant(instr->transition())); 410 Insert(object, NULL, MapConstant(instr->transition()));
414 } else if (IsMapAccess(instr->access())) { 411 } else if (instr->access().IsMap()) {
415 // This is a store directly to the map field of the object. 412 // This is a store directly to the map field of the object.
416 Kill(object); 413 Kill(object);
417 if (!instr->value()->IsConstant()) return; 414 if (!instr->value()->IsConstant()) return;
418 Insert(object, NULL, MapConstant(instr->value())); 415 Insert(object, NULL, MapConstant(instr->value()));
419 } else { 416 } else {
420 // If the instruction changes maps, it should be handled above. 417 // If the instruction changes maps, it should be handled above.
421 CHECK(!instr->CheckChangesFlag(kMaps)); 418 CHECK(!instr->CheckChangesFlag(kMaps));
422 } 419 }
423 } 420 }
424 421
(...skipping 23 matching lines...) Expand all
448 445
449 int unreachable_succ = 1 - succ; 446 int unreachable_succ = 1 - succ;
450 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); 447 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
451 } 448 }
452 449
453 void ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch* instr) { 450 void ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch* instr) {
454 MapSet maps_left = FindMaps(instr->left()->ActualValue()); 451 MapSet maps_left = FindMaps(instr->left()->ActualValue());
455 if (maps_left == NULL) return; 452 if (maps_left == NULL) return;
456 MapSet maps_right = FindMaps(instr->right()->ActualValue()); 453 MapSet maps_right = FindMaps(instr->right()->ActualValue());
457 if (maps_right == NULL) return; 454 if (maps_right == NULL) return;
458 MapSet intersection = maps_left->Intersect(maps_right, phase_->zone()); 455 MapSet intersection = maps_left->Intersect(maps_right, zone());
459 if (intersection->size() > 0) return; 456 if (intersection->size() > 0) return;
460 457
461 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n", 458 TRACE(("Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n",
462 instr->id(), instr->block()->block_id())); 459 instr->id(), instr->block()->block_id()));
463 int succ = 1; 460 int succ = 1;
464 instr->set_known_successor_index(succ); 461 instr->set_known_successor_index(succ);
465 462
466 int unreachable_succ = 1 - succ; 463 int unreachable_succ = 1 - succ;
467 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ); 464 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
468 } 465 }
469 466
470 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { 467 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) {
471 MapSet maps = FindMaps(instr->object()->ActualValue()); 468 HCheckTableEntry* entry = Find(instr->object()->ActualValue());
472 // Can only learn more about an object that already has a known set of maps. 469 // Can only learn more about an object that already has a known set of maps.
473 if (maps == NULL) return; 470 if (entry == NULL) return;
474 if (maps->Contains(instr->original_map())) { 471 if (entry->maps_->Contains(instr->original_map())) {
475 // If the object has the original map, it will be transitioned. 472 // If the object has the original map, it will be transitioned.
473 UniqueSet<Map>* maps = entry->maps_->Copy(zone());
476 maps->Remove(instr->original_map()); 474 maps->Remove(instr->original_map());
477 maps->Add(instr->transitioned_map(), phase_->zone()); 475 maps->Add(instr->transitioned_map(), zone());
476 entry->maps_ = maps;
478 } else { 477 } else {
479 // Object does not have the given map, thus the transition is redundant. 478 // Object does not have the given map, thus the transition is redundant.
480 instr->DeleteAndReplaceWith(instr->object()); 479 instr->DeleteAndReplaceWith(instr->object());
481 INC_STAT(transitions_); 480 INC_STAT(transitions_);
482 } 481 }
483 } 482 }
484 483
485 // Kill everything in the table. 484 // Kill everything in the table.
486 void Kill() { 485 void Kill() {
487 size_ = 0; 486 size_ = 0;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 } 567 }
569 return NULL; 568 return NULL;
570 } 569 }
571 570
572 MapSet FindMaps(HValue* object) { 571 MapSet FindMaps(HValue* object) {
573 HCheckTableEntry* entry = Find(object); 572 HCheckTableEntry* entry = Find(object);
574 return entry == NULL ? NULL : entry->maps_; 573 return entry == NULL ? NULL : entry->maps_;
575 } 574 }
576 575
577 void Insert(HValue* object, HInstruction* check, Unique<Map> map) { 576 void Insert(HValue* object, HInstruction* check, Unique<Map> map) {
578 MapSet list = new(phase_->zone()) UniqueSet<Map>(); 577 Insert(object, check, new(zone()) UniqueSet<Map>(map, zone()));
579 list->Add(map, phase_->zone());
580 Insert(object, check, list);
581 } 578 }
582 579
583 void Insert(HValue* object, HInstruction* check, MapSet maps) { 580 void Insert(HValue* object, HInstruction* check, MapSet maps) {
584 HCheckTableEntry* entry = &entries_[cursor_++]; 581 HCheckTableEntry* entry = &entries_[cursor_++];
585 entry->object_ = object; 582 entry->object_ = object;
586 entry->check_ = check; 583 entry->check_ = check;
587 entry->maps_ = maps; 584 entry->maps_ = maps;
588 // If the table becomes full, wrap around and overwrite older entries. 585 // If the table becomes full, wrap around and overwrite older entries.
589 if (cursor_ == kMaxTrackedObjects) cursor_ = 0; 586 if (cursor_ == kMaxTrackedObjects) cursor_ = 0;
590 if (size_ < kMaxTrackedObjects) size_++; 587 if (size_ < kMaxTrackedObjects) size_++;
591 } 588 }
592 589
593 bool IsMapAccess(HObjectAccess access) {
594 return access.IsInobject() && access.offset() == JSObject::kMapOffset;
595 }
596
597 Unique<Map> MapConstant(HValue* value) { 590 Unique<Map> MapConstant(HValue* value) {
598 return Unique<Map>::cast(HConstant::cast(value)->GetUnique()); 591 return Unique<Map>::cast(HConstant::cast(value)->GetUnique());
599 } 592 }
600 593
594 Zone* zone() const { return phase_->zone(); }
595
601 friend class HCheckMapsEffects; 596 friend class HCheckMapsEffects;
602 friend class HCheckEliminationPhase; 597 friend class HCheckEliminationPhase;
603 598
604 HCheckEliminationPhase* phase_; 599 HCheckEliminationPhase* phase_;
605 HCheckTableEntry entries_[kMaxTrackedObjects]; 600 HCheckTableEntry entries_[kMaxTrackedObjects];
606 int16_t cursor_; // Must be <= kMaxTrackedObjects 601 int16_t cursor_; // Must be <= kMaxTrackedObjects
607 int16_t size_; // Must be <= kMaxTrackedObjects 602 int16_t size_; // Must be <= kMaxTrackedObjects
608 // TODO(titzer): STATIC_ASSERT kMaxTrackedObjects < max(cursor_) 603 // TODO(titzer): STATIC_ASSERT kMaxTrackedObjects < max(cursor_)
609 }; 604 };
610 605
611 606
612 // Collects instructions that can cause effects that invalidate information 607 // Collects instructions that can cause effects that invalidate information
613 // needed for check elimination. 608 // needed for check elimination.
614 class HCheckMapsEffects : public ZoneObject { 609 class HCheckMapsEffects : public ZoneObject {
615 public: 610 public:
616 explicit HCheckMapsEffects(Zone* zone) 611 explicit HCheckMapsEffects(Zone* zone)
617 : maps_stored_(false), 612 : objects_(0, zone), maps_stored_(false) {}
618 stores_(5, zone) { }
619 613
620 inline bool Disabled() { 614 // Effects are _not_ disabled.
621 return false; // Effects are _not_ disabled. 615 inline bool Disabled() const { return false; }
622 }
623 616
624 // Process a possibly side-effecting instruction. 617 // Process a possibly side-effecting instruction.
625 void Process(HInstruction* instr, Zone* zone) { 618 void Process(HInstruction* instr, Zone* zone) {
626 switch (instr->opcode()) { 619 switch (instr->opcode()) {
627 case HValue::kStoreNamedField: { 620 case HValue::kStoreNamedField: {
628 stores_.Add(HStoreNamedField::cast(instr), zone); 621 HStoreNamedField* store = HStoreNamedField::cast(instr);
622 if (store->access().IsMap() && store->has_transition()) {
623 objects_.Add(store->object(), zone);
624 }
629 break; 625 break;
630 } 626 }
631 case HValue::kOsrEntry: { 627 case HValue::kTransitionElementsKind: {
632 // Kill everything. Loads must not be hoisted past the OSR entry. 628 objects_.Add(HTransitionElementsKind::cast(instr)->object(), zone);
633 maps_stored_ = true; 629 break;
634 } 630 }
635 default: { 631 default: {
636 maps_stored_ |= (instr->CheckChangesFlag(kMaps) | 632 maps_stored_ |= (instr->CheckChangesFlag(kMaps) |
633 instr->CheckChangesFlag(kOsrEntries) |
637 instr->CheckChangesFlag(kElementsKind)); 634 instr->CheckChangesFlag(kElementsKind));
638 } 635 }
639 } 636 }
640 } 637 }
641 638
642 // Apply these effects to the given check elimination table. 639 // Apply these effects to the given check elimination table.
643 void Apply(HCheckTable* table) { 640 void Apply(HCheckTable* table) {
644 if (maps_stored_) { 641 if (maps_stored_) {
645 // Uncontrollable map modifications; kill everything. 642 // Uncontrollable map modifications; kill everything.
646 table->Kill(); 643 table->Kill();
647 return; 644 return;
648 } 645 }
649 646
650 // Kill maps for each store contained in these effects. 647 // Kill maps for each object contained in these effects.
651 for (int i = 0; i < stores_.length(); i++) { 648 for (int i = 0; i < objects_.length(); ++i) {
652 HStoreNamedField* s = stores_[i]; 649 table->Kill(objects_[i]->ActualValue());
653 if (table->IsMapAccess(s->access()) || s->has_transition()) {
654 table->Kill(s->object()->ActualValue());
655 }
656 } 650 }
657 } 651 }
658 652
659 // Union these effects with the other effects. 653 // Union these effects with the other effects.
660 void Union(HCheckMapsEffects* that, Zone* zone) { 654 void Union(HCheckMapsEffects* that, Zone* zone) {
661 maps_stored_ |= that->maps_stored_; 655 maps_stored_ |= that->maps_stored_;
662 for (int i = 0; i < that->stores_.length(); i++) { 656 for (int i = 0; i < that->objects_.length(); ++i) {
663 stores_.Add(that->stores_[i], zone); 657 objects_.Add(that->objects_[i], zone);
664 } 658 }
665 } 659 }
666 660
667 private: 661 private:
662 ZoneList<HValue*> objects_;
668 bool maps_stored_ : 1; 663 bool maps_stored_ : 1;
669 ZoneList<HStoreNamedField*> stores_;
670 }; 664 };
671 665
672 666
673 // The main routine of the analysis phase. Use the HFlowEngine for either a 667 // The main routine of the analysis phase. Use the HFlowEngine for either a
674 // local or a global analysis. 668 // local or a global analysis.
675 void HCheckEliminationPhase::Run() { 669 void HCheckEliminationPhase::Run() {
676 HFlowEngine<HCheckTable, HCheckMapsEffects> engine(graph(), zone()); 670 HFlowEngine<HCheckTable, HCheckMapsEffects> engine(graph(), zone());
677 HCheckTable* table = new(zone()) HCheckTable(this); 671 HCheckTable* table = new(zone()) HCheckTable(this);
678 672
679 if (GLOBAL) { 673 if (GLOBAL) {
(...skipping 23 matching lines...) Expand all
703 PRINT_STAT(removed_cho); 697 PRINT_STAT(removed_cho);
704 PRINT_STAT(narrowed); 698 PRINT_STAT(narrowed);
705 PRINT_STAT(loads); 699 PRINT_STAT(loads);
706 PRINT_STAT(empty); 700 PRINT_STAT(empty);
707 PRINT_STAT(compares_true); 701 PRINT_STAT(compares_true);
708 PRINT_STAT(compares_false); 702 PRINT_STAT(compares_false);
709 PRINT_STAT(transitions); 703 PRINT_STAT(transitions);
710 } 704 }
711 705
712 } } // namespace v8::internal 706 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm64/lithium-codegen-arm64.cc ('k') | src/hydrogen-escape-analysis.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698