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

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

Issue 112863002: Merge bleeding_edge 18021:18297 (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 7 years 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-check-elimination.h ('k') | src/hydrogen-dce.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 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution. 11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its 12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived 13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission. 14 // from this software without specific prior written permission.
15 // 15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "hydrogen-check-elimination.h" 28 #include "hydrogen-check-elimination.h"
29 #include "hydrogen-alias-analysis.h" 29 #include "hydrogen-alias-analysis.h"
30 #include "hydrogen-flow-engine.h"
31
32 #define GLOBAL 1
33
34 // Only collect stats in debug mode.
35 #if DEBUG
36 #define INC_STAT(x) phase_->x++
37 #else
38 #define INC_STAT(x)
39 #endif
40
41 // For code de-uglification.
42 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x
30 43
31 namespace v8 { 44 namespace v8 {
32 namespace internal { 45 namespace internal {
33 46
34 static const int kMaxTrackedObjects = 10;
35 typedef UniqueSet<Map>* MapSet; 47 typedef UniqueSet<Map>* MapSet;
36 48
49 struct HCheckTableEntry {
50 HValue* object_; // The object being approximated. NULL => invalid entry.
51 HValue* check_; // The last check instruction.
52 MapSet maps_; // The set of known maps for the object.
53 };
54
55
37 // The main datastructure used during check elimination, which stores a 56 // The main datastructure used during check elimination, which stores a
38 // set of known maps for each object. 57 // set of known maps for each object.
39 class HCheckTable { 58 class HCheckTable : public ZoneObject {
40 public: 59 public:
41 explicit HCheckTable(Zone* zone) : zone_(zone) { 60 static const int kMaxTrackedObjects = 10;
42 Kill(); 61
43 redundant_ = 0; 62 explicit HCheckTable(HCheckEliminationPhase* phase)
44 narrowed_ = 0; 63 : phase_(phase),
45 empty_ = 0; 64 cursor_(0),
46 removed_ = 0; 65 size_(0) {
47 compares_true_ = 0; 66 }
48 compares_false_ = 0; 67
49 transitions_ = 0; 68 // The main processing of instructions.
50 loads_ = 0; 69 HCheckTable* Process(HInstruction* instr, Zone* zone) {
70 switch (instr->opcode()) {
71 case HValue::kCheckMaps: {
72 ReduceCheckMaps(HCheckMaps::cast(instr));
73 break;
74 }
75 case HValue::kCheckValue: {
76 ReduceCheckValue(HCheckValue::cast(instr));
77 break;
78 }
79 case HValue::kLoadNamedField: {
80 ReduceLoadNamedField(HLoadNamedField::cast(instr));
81 break;
82 }
83 case HValue::kStoreNamedField: {
84 ReduceStoreNamedField(HStoreNamedField::cast(instr));
85 break;
86 }
87 case HValue::kCompareMap: {
88 ReduceCompareMap(HCompareMap::cast(instr));
89 break;
90 }
91 case HValue::kTransitionElementsKind: {
92 ReduceTransitionElementsKind(
93 HTransitionElementsKind::cast(instr));
94 break;
95 }
96 case HValue::kCheckMapValue: {
97 ReduceCheckMapValue(HCheckMapValue::cast(instr));
98 break;
99 }
100 case HValue::kCheckHeapObject: {
101 ReduceCheckHeapObject(HCheckHeapObject::cast(instr));
102 break;
103 }
104 default: {
105 // If the instruction changes maps uncontrollably, drop everything.
106 if (instr->CheckGVNFlag(kChangesMaps) ||
107 instr->CheckGVNFlag(kChangesOsrEntries)) {
108 Kill();
109 }
110 }
111 // Improvements possible:
112 // - eliminate redundant HCheckSmi, HCheckInstanceType instructions
113 // - track which values have been HCheckHeapObject'd
114 }
115
116 return this;
117 }
118
119 // Global analysis: Copy state to successor block.
120 HCheckTable* Copy(HBasicBlock* succ, Zone* zone) {
121 HCheckTable* copy = new(phase_->zone()) HCheckTable(phase_);
122 for (int i = 0; i < size_; i++) {
123 HCheckTableEntry* old_entry = &entries_[i];
124 HCheckTableEntry* new_entry = &copy->entries_[i];
125 // TODO(titzer): keep the check if this block dominates the successor?
126 new_entry->object_ = old_entry->object_;
127 new_entry->check_ = NULL;
128 new_entry->maps_ = old_entry->maps_->Copy(phase_->zone());
129 }
130 if (succ->predecessors()->length() == 1) {
131 HControlInstruction* end = succ->predecessors()->at(0)->end();
132 if (end->IsCompareMap() && end->SuccessorAt(0) == succ) {
133 // Learn on the true branch of if(CompareMap(x)).
134 HCompareMap* cmp = HCompareMap::cast(end);
135 HValue* object = cmp->value()->ActualValue();
136 HCheckTableEntry* entry = copy->Find(object);
137 if (entry == NULL) {
138 copy->Insert(object, cmp->map());
139 } else {
140 MapSet list = new(phase_->zone()) UniqueSet<Map>();
141 list->Add(cmp->map(), phase_->zone());
142 entry->maps_ = list;
143 }
144 }
145 // TODO(titzer): is it worthwhile to learn on false branch too?
146 }
147 return copy;
148 }
149
150 // Global analysis: Merge this state with the other incoming state.
151 HCheckTable* Merge(HBasicBlock* succ, HCheckTable* that, Zone* zone) {
152 if (that->size_ == 0) {
153 // If the other state is empty, simply reset.
154 size_ = 0;
155 cursor_ = 0;
156 return this;
157 }
158 bool compact = false;
159 for (int i = 0; i < size_; i++) {
160 HCheckTableEntry* this_entry = &entries_[i];
161 HCheckTableEntry* that_entry = that->Find(this_entry->object_);
162 if (that_entry == NULL) {
163 this_entry->object_ = NULL;
164 compact = true;
165 } else {
166 this_entry->maps_ = this_entry->maps_->Union(
167 that_entry->maps_, phase_->zone());
168 if (this_entry->check_ != that_entry->check_) this_entry->check_ = NULL;
169 ASSERT(this_entry->maps_->size() > 0);
170 }
171 }
172 if (compact) Compact();
173 return this;
51 } 174 }
52 175
53 void ReduceCheckMaps(HCheckMaps* instr) { 176 void ReduceCheckMaps(HCheckMaps* instr) {
54 HValue* object = instr->value()->ActualValue(); 177 HValue* object = instr->value()->ActualValue();
55 int index = Find(object); 178 HCheckTableEntry* entry = Find(object);
56 if (index >= 0) { 179 if (entry != NULL) {
57 // entry found; 180 // entry found;
58 MapSet a = known_maps_[index]; 181 MapSet a = entry->maps_;
59 MapSet i = instr->map_set().Copy(zone_); 182 MapSet i = instr->map_set().Copy(phase_->zone());
60 if (a->IsSubset(i)) { 183 if (a->IsSubset(i)) {
61 // The first check is more strict; the second is redundant. 184 // The first check is more strict; the second is redundant.
62 if (checks_[index] != NULL) { 185 if (entry->check_ != NULL) {
63 instr->DeleteAndReplaceWith(checks_[index]); 186 instr->DeleteAndReplaceWith(entry->check_);
64 redundant_++; 187 INC_STAT(redundant_);
65 } else { 188 } else {
66 instr->DeleteAndReplaceWith(instr->value()); 189 instr->DeleteAndReplaceWith(instr->value());
67 removed_++; 190 INC_STAT(removed_);
68 } 191 }
69 return; 192 return;
70 } 193 }
71 i = i->Intersect(a, zone_); 194 i = i->Intersect(a, phase_->zone());
72 if (i->size() == 0) { 195 if (i->size() == 0) {
73 // Intersection is empty; probably megamorphic, which is likely to 196 // Intersection is empty; probably megamorphic, which is likely to
74 // deopt anyway, so just leave things as they are. 197 // deopt anyway, so just leave things as they are.
75 empty_++; 198 INC_STAT(empty_);
76 } else { 199 } else {
77 // TODO(titzer): replace the first check with a more strict check. 200 // TODO(titzer): replace the first check with a more strict check
78 narrowed_++; 201 INC_STAT(narrowed_);
79 } 202 }
80 } else { 203 } else {
81 // No entry; insert a new one. 204 // No entry; insert a new one.
82 Insert(object, instr, instr->map_set().Copy(zone_)); 205 Insert(object, instr, instr->map_set().Copy(phase_->zone()));
83 } 206 }
84 } 207 }
85 208
86 void ReduceCheckValue(HCheckValue* instr) { 209 void ReduceCheckValue(HCheckValue* instr) {
87 // Canonicalize HCheckValues; they might have their values load-eliminated. 210 // Canonicalize HCheckValues; they might have their values load-eliminated.
88 HValue* value = instr->Canonicalize(); 211 HValue* value = instr->Canonicalize();
89 if (value == NULL) { 212 if (value == NULL) {
90 instr->DeleteAndReplaceWith(instr->value()); 213 instr->DeleteAndReplaceWith(instr->value());
91 removed_++; 214 INC_STAT(removed_);
92 } else if (value != instr) { 215 } else if (value != instr) {
93 instr->DeleteAndReplaceWith(value); 216 instr->DeleteAndReplaceWith(value);
94 redundant_++; 217 INC_STAT(redundant_);
95 } 218 }
96 } 219 }
97 220
98 void ReduceLoadNamedField(HLoadNamedField* instr) { 221 void ReduceLoadNamedField(HLoadNamedField* instr) {
99 // Reduce a load of the map field when it is known to be a constant. 222 // Reduce a load of the map field when it is known to be a constant.
100 if (!IsMapAccess(instr->access())) return; 223 if (!IsMapAccess(instr->access())) return;
101 224
102 HValue* object = instr->object()->ActualValue(); 225 HValue* object = instr->object()->ActualValue();
103 MapSet maps = FindMaps(object); 226 MapSet maps = FindMaps(object);
104 if (maps == NULL || maps->size() != 1) return; // Not a constant. 227 if (maps == NULL || maps->size() != 1) return; // Not a constant.
105 228
106 Unique<Map> map = maps->at(0); 229 Unique<Map> map = maps->at(0);
107 HConstant* constant = HConstant::CreateAndInsertBefore( 230 HConstant* constant = HConstant::CreateAndInsertBefore(
108 instr->block()->graph()->zone(), map, true, instr); 231 instr->block()->graph()->zone(), map, true, instr);
109 instr->DeleteAndReplaceWith(constant); 232 instr->DeleteAndReplaceWith(constant);
110 loads_++; 233 INC_STAT(loads_);
111 } 234 }
112 235
113 void ReduceCheckMapValue(HCheckMapValue* instr) { 236 void ReduceCheckMapValue(HCheckMapValue* instr) {
114 if (!instr->map()->IsConstant()) return; // Nothing to learn. 237 if (!instr->map()->IsConstant()) return; // Nothing to learn.
115 238
116 HValue* object = instr->value()->ActualValue(); 239 HValue* object = instr->value()->ActualValue();
117 // Match a HCheckMapValue(object, HConstant(map)) 240 // Match a HCheckMapValue(object, HConstant(map))
118 Unique<Map> map = MapConstant(instr->map()); 241 Unique<Map> map = MapConstant(instr->map());
119 MapSet maps = FindMaps(object); 242 MapSet maps = FindMaps(object);
120 if (maps != NULL) { 243 if (maps != NULL) {
121 if (maps->Contains(map)) { 244 if (maps->Contains(map)) {
122 if (maps->size() == 1) { 245 if (maps->size() == 1) {
123 // Object is known to have exactly this map. 246 // Object is known to have exactly this map.
124 instr->DeleteAndReplaceWith(NULL); 247 instr->DeleteAndReplaceWith(NULL);
125 removed_++; 248 INC_STAT(removed_);
126 } else { 249 } else {
127 // Only one map survives the check. 250 // Only one map survives the check.
128 maps->Clear(); 251 maps->Clear();
129 maps->Add(map, zone_); 252 maps->Add(map, phase_->zone());
130 } 253 }
131 } 254 }
132 } else { 255 } else {
133 // No prior information. 256 // No prior information.
134 Insert(object, map); 257 Insert(object, map);
135 } 258 }
136 } 259 }
137 260
261 void ReduceCheckHeapObject(HCheckHeapObject* instr) {
262 if (FindMaps(instr->value()->ActualValue()) != NULL) {
263 // If the object has known maps, it's definitely a heap object.
264 instr->DeleteAndReplaceWith(instr->value());
265 INC_STAT(removed_cho_);
266 }
267 }
268
138 void ReduceStoreNamedField(HStoreNamedField* instr) { 269 void ReduceStoreNamedField(HStoreNamedField* instr) {
139 HValue* object = instr->object()->ActualValue(); 270 HValue* object = instr->object()->ActualValue();
140 if (instr->has_transition()) { 271 if (instr->has_transition()) {
141 // This store transitions the object to a new map. 272 // This store transitions the object to a new map.
142 Kill(object); 273 Kill(object);
143 Insert(object, MapConstant(instr->transition())); 274 Insert(object, MapConstant(instr->transition()));
144 } else if (IsMapAccess(instr->access())) { 275 } else if (IsMapAccess(instr->access())) {
145 // This is a store directly to the map field of the object. 276 // This is a store directly to the map field of the object.
146 Kill(object); 277 Kill(object);
147 if (!instr->value()->IsConstant()) return; 278 if (!instr->value()->IsConstant()) return;
148 Insert(object, MapConstant(instr->value())); 279 Insert(object, MapConstant(instr->value()));
149 } else if (instr->CheckGVNFlag(kChangesMaps)) { 280 } else {
150 // This store indirectly changes the map of the object. 281 // If the instruction changes maps, it should be handled above.
151 Kill(instr->object()); 282 CHECK(!instr->CheckGVNFlag(kChangesMaps));
152 UNREACHABLE();
153 } 283 }
154 } 284 }
155 285
156 void ReduceCompareMap(HCompareMap* instr) { 286 void ReduceCompareMap(HCompareMap* instr) {
157 MapSet maps = FindMaps(instr->value()->ActualValue()); 287 MapSet maps = FindMaps(instr->value()->ActualValue());
158 if (maps == NULL) return; 288 if (maps == NULL) return;
159 if (maps->Contains(instr->map())) { 289 if (maps->Contains(instr->map())) {
160 // TODO(titzer): replace with goto true branch 290 if (maps->size() == 1) {
161 if (maps->size() == 1) compares_true_++; 291 // TODO(titzer): replace with goto true branch
292 INC_STAT(compares_true_);
293 }
162 } else { 294 } else {
163 // TODO(titzer): replace with goto false branch 295 // TODO(titzer): replace with goto false branch
164 compares_false_++; 296 INC_STAT(compares_false_);
165 } 297 }
166 } 298 }
167 299
168 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) { 300 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) {
169 MapSet maps = FindMaps(instr->object()->ActualValue()); 301 MapSet maps = FindMaps(instr->object()->ActualValue());
170 // Can only learn more about an object that already has a known set of maps. 302 // Can only learn more about an object that already has a known set of maps.
171 if (maps == NULL) return; 303 if (maps == NULL) return;
172 if (maps->Contains(instr->original_map())) { 304 if (maps->Contains(instr->original_map())) {
173 // If the object has the original map, it will be transitioned. 305 // If the object has the original map, it will be transitioned.
174 maps->Remove(instr->original_map()); 306 maps->Remove(instr->original_map());
175 maps->Add(instr->transitioned_map(), zone_); 307 maps->Add(instr->transitioned_map(), phase_->zone());
176 } else { 308 } else {
177 // Object does not have the given map, thus the transition is redundant. 309 // Object does not have the given map, thus the transition is redundant.
178 instr->DeleteAndReplaceWith(instr->object()); 310 instr->DeleteAndReplaceWith(instr->object());
179 transitions_++; 311 INC_STAT(transitions_);
180 } 312 }
181 } 313 }
182 314
183 // Kill everything in the table. 315 // Kill everything in the table.
184 void Kill() { 316 void Kill() {
185 memset(objects_, 0, sizeof(objects_)); 317 size_ = 0;
318 cursor_ = 0;
186 } 319 }
187 320
188 // Kill everything in the table that may alias {object}. 321 // Kill everything in the table that may alias {object}.
189 void Kill(HValue* object) { 322 void Kill(HValue* object) {
190 for (int i = 0; i < kMaxTrackedObjects; i++) { 323 bool compact = false;
191 if (objects_[i] == NULL) continue; 324 for (int i = 0; i < size_; i++) {
192 if (aliasing_.MayAlias(objects_[i], object)) objects_[i] = NULL; 325 HCheckTableEntry* entry = &entries_[i];
326 ASSERT(entry->object_ != NULL);
327 if (phase_->aliasing_->MayAlias(entry->object_, object)) {
328 entry->object_ = NULL;
329 compact = true;
330 }
193 } 331 }
194 ASSERT(Find(object) < 0); 332 if (compact) Compact();
333 ASSERT(Find(object) == NULL);
334 }
335
336 void Compact() {
337 // First, compact the array in place.
338 int max = size_, dest = 0, old_cursor = cursor_;
339 for (int i = 0; i < max; i++) {
340 if (entries_[i].object_ != NULL) {
341 if (dest != i) entries_[dest] = entries_[i];
342 dest++;
343 } else {
344 if (i < old_cursor) cursor_--;
345 size_--;
346 }
347 }
348 ASSERT(size_ == dest);
349 ASSERT(cursor_ <= size_);
350
351 // Preserve the age of the entries by moving the older entries to the end.
352 if (cursor_ == size_) return; // Cursor already points at end.
353 if (cursor_ != 0) {
354 // | L = oldest | R = newest | |
355 // ^ cursor ^ size ^ MAX
356 HCheckTableEntry tmp_entries[kMaxTrackedObjects];
357 int L = cursor_;
358 int R = size_ - cursor_;
359
360 OS::MemMove(&tmp_entries[0], &entries_[0], L * sizeof(HCheckTableEntry));
361 OS::MemMove(&entries_[0], &entries_[L], R * sizeof(HCheckTableEntry));
362 OS::MemMove(&entries_[R], &tmp_entries[0], L * sizeof(HCheckTableEntry));
363 }
364
365 cursor_ = size_; // Move cursor to end.
195 } 366 }
196 367
197 void Print() { 368 void Print() {
198 for (int i = 0; i < kMaxTrackedObjects; i++) { 369 for (int i = 0; i < size_; i++) {
199 if (objects_[i] == NULL) continue; 370 HCheckTableEntry* entry = &entries_[i];
200 PrintF(" checkmaps-table @%d: object #%d ", i, objects_[i]->id()); 371 ASSERT(entry->object_ != NULL);
201 if (checks_[i] != NULL) { 372 PrintF(" checkmaps-table @%d: object #%d ", i, entry->object_->id());
202 PrintF("check #%d ", checks_[i]->id()); 373 if (entry->check_ != NULL) {
374 PrintF("check #%d ", entry->check_->id());
203 } 375 }
204 MapSet list = known_maps_[i]; 376 MapSet list = entry->maps_;
205 PrintF("%d maps { ", list->size()); 377 PrintF("%d maps { ", list->size());
206 for (int j = 0; j < list->size(); j++) { 378 for (int j = 0; j < list->size(); j++) {
207 if (j > 0) PrintF(", "); 379 if (j > 0) PrintF(", ");
208 PrintF("%" V8PRIxPTR, list->at(j).Hashcode()); 380 PrintF("%" V8PRIxPTR, list->at(j).Hashcode());
209 } 381 }
210 PrintF(" }\n"); 382 PrintF(" }\n");
211 } 383 }
212 } 384 }
213 385
214 void PrintStats() {
215 if (redundant_ > 0) PrintF(" redundant = %2d\n", redundant_);
216 if (removed_ > 0) PrintF(" removed = %2d\n", removed_);
217 if (narrowed_ > 0) PrintF(" narrowed = %2d\n", narrowed_);
218 if (loads_ > 0) PrintF(" loads = %2d\n", loads_);
219 if (empty_ > 0) PrintF(" empty = %2d\n", empty_);
220 if (compares_true_ > 0) PrintF(" cmp_true = %2d\n", compares_true_);
221 if (compares_false_ > 0) PrintF(" cmp_false = %2d\n", compares_false_);
222 if (transitions_ > 0) PrintF(" transitions = %2d\n", transitions_);
223 }
224
225 private: 386 private:
226 int Find(HValue* object) { 387 HCheckTableEntry* Find(HValue* object) {
227 for (int i = 0; i < kMaxTrackedObjects; i++) { 388 for (int i = size_ - 1; i >= 0; i--) {
228 if (objects_[i] == NULL) continue; 389 // Search from most-recently-inserted to least-recently-inserted.
229 if (aliasing_.MustAlias(objects_[i], object)) return i; 390 HCheckTableEntry* entry = &entries_[i];
391 ASSERT(entry->object_ != NULL);
392 if (phase_->aliasing_->MustAlias(entry->object_, object)) return entry;
230 } 393 }
231 return -1; 394 return NULL;
232 } 395 }
233 396
234 MapSet FindMaps(HValue* object) { 397 MapSet FindMaps(HValue* object) {
235 int index = Find(object); 398 HCheckTableEntry* entry = Find(object);
236 return index < 0 ? NULL : known_maps_[index]; 399 return entry == NULL ? NULL : entry->maps_;
237 } 400 }
238 401
239 void Insert(HValue* object, Unique<Map> map) { 402 void Insert(HValue* object, Unique<Map> map) {
240 MapSet list = new(zone_) UniqueSet<Map>(); 403 MapSet list = new(phase_->zone()) UniqueSet<Map>();
241 list->Add(map, zone_); 404 list->Add(map, phase_->zone());
242 Insert(object, NULL, list); 405 Insert(object, NULL, list);
243 } 406 }
244 407
245 void Insert(HValue* object, HCheckMaps* check, MapSet maps) { 408 void Insert(HValue* object, HCheckMaps* check, MapSet maps) {
246 for (int i = 0; i < kMaxTrackedObjects; i++) { 409 HCheckTableEntry* entry = &entries_[cursor_++];
247 // TODO(titzer): drop old entries instead of disallowing new ones. 410 entry->object_ = object;
248 if (objects_[i] == NULL) { 411 entry->check_ = check;
249 objects_[i] = object; 412 entry->maps_ = maps;
250 checks_[i] = check; 413 // If the table becomes full, wrap around and overwrite older entries.
251 known_maps_[i] = maps; 414 if (cursor_ == kMaxTrackedObjects) cursor_ = 0;
252 return; 415 if (size_ < kMaxTrackedObjects) size_++;
253 }
254 }
255 } 416 }
256 417
257 bool IsMapAccess(HObjectAccess access) { 418 bool IsMapAccess(HObjectAccess access) {
258 return access.IsInobject() && access.offset() == JSObject::kMapOffset; 419 return access.IsInobject() && access.offset() == JSObject::kMapOffset;
259 } 420 }
260 421
261 Unique<Map> MapConstant(HValue* value) { 422 Unique<Map> MapConstant(HValue* value) {
262 return Unique<Map>::cast(HConstant::cast(value)->GetUnique()); 423 return Unique<Map>::cast(HConstant::cast(value)->GetUnique());
263 } 424 }
264 425
265 Zone* zone_; 426 friend class HCheckMapsEffects;
266 HValue* objects_[kMaxTrackedObjects]; 427
267 HValue* checks_[kMaxTrackedObjects]; 428 HCheckEliminationPhase* phase_;
268 MapSet known_maps_[kMaxTrackedObjects]; 429 HCheckTableEntry entries_[kMaxTrackedObjects];
269 HAliasAnalyzer aliasing_; 430 int16_t cursor_; // Must be <= kMaxTrackedObjects
270 int redundant_; 431 int16_t size_; // Must be <= kMaxTrackedObjects
271 int removed_; 432 // TODO(titzer): STATIC_ASSERT kMaxTrackedObjects < max(cursor_)
272 int narrowed_;
273 int loads_;
274 int empty_;
275 int compares_true_;
276 int compares_false_;
277 int transitions_;
278 }; 433 };
279 434
280 435
436 // Collects instructions that can cause effects that invalidate information
437 // needed for check elimination.
438 class HCheckMapsEffects : public ZoneObject {
439 public:
440 explicit HCheckMapsEffects(Zone* zone)
441 : maps_stored_(false),
442 stores_(5, zone) { }
443
444 inline bool Disabled() {
445 return false; // Effects are _not_ disabled.
446 }
447
448 // Process a possibly side-effecting instruction.
449 void Process(HInstruction* instr, Zone* zone) {
450 switch (instr->opcode()) {
451 case HValue::kStoreNamedField: {
452 stores_.Add(HStoreNamedField::cast(instr), zone);
453 break;
454 }
455 case HValue::kOsrEntry: {
456 // Kill everything. Loads must not be hoisted past the OSR entry.
457 maps_stored_ = true;
458 }
459 default: {
460 maps_stored_ |= (instr->CheckGVNFlag(kChangesMaps) |
461 instr->CheckGVNFlag(kChangesElementsKind));
462 }
463 }
464 }
465
466 // Apply these effects to the given check elimination table.
467 void Apply(HCheckTable* table) {
468 if (maps_stored_) {
469 // Uncontrollable map modifications; kill everything.
470 table->Kill();
471 return;
472 }
473
474 // Kill maps for each store contained in these effects.
475 for (int i = 0; i < stores_.length(); i++) {
476 HStoreNamedField* s = stores_[i];
477 if (table->IsMapAccess(s->access()) || s->has_transition()) {
478 table->Kill(s->object()->ActualValue());
479 }
480 }
481 }
482
483 // Union these effects with the other effects.
484 void Union(HCheckMapsEffects* that, Zone* zone) {
485 maps_stored_ |= that->maps_stored_;
486 for (int i = 0; i < that->stores_.length(); i++) {
487 stores_.Add(that->stores_[i], zone);
488 }
489 }
490
491 private:
492 bool maps_stored_ : 1;
493 ZoneList<HStoreNamedField*> stores_;
494 };
495
496
497 // The main routine of the analysis phase. Use the HFlowEngine for either a
498 // local or a global analysis.
281 void HCheckEliminationPhase::Run() { 499 void HCheckEliminationPhase::Run() {
282 for (int i = 0; i < graph()->blocks()->length(); i++) { 500 HFlowEngine<HCheckTable, HCheckMapsEffects> engine(graph(), zone());
283 EliminateLocalChecks(graph()->blocks()->at(i)); 501 HCheckTable* table = new(zone()) HCheckTable(this);
502
503 if (GLOBAL) {
504 // Perform a global analysis.
505 engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), table);
506 } else {
507 // Perform only local analysis.
508 for (int i = 0; i < graph()->blocks()->length(); i++) {
509 table->Kill();
510 engine.AnalyzeOneBlock(graph()->blocks()->at(i), table);
511 }
284 } 512 }
513
514 if (FLAG_trace_check_elimination) PrintStats();
285 } 515 }
286 516
287 517
288 // For code de-uglification. 518 // Are we eliminated yet?
289 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x 519 void HCheckEliminationPhase::PrintStats() {
290 520 #if DEBUG
291 521 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_)
292 // Eliminate checks local to a block. 522 #else
293 void HCheckEliminationPhase::EliminateLocalChecks(HBasicBlock* block) { 523 #define PRINT_STAT(x)
294 HCheckTable table(zone()); 524 #endif
295 TRACE(("-- check-elim B%d ------------------------------------------------\n", 525 PRINT_STAT(redundant);
296 block->block_id())); 526 PRINT_STAT(removed);
297 527 PRINT_STAT(removed_cho);
298 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { 528 PRINT_STAT(narrowed);
299 bool changed = false; 529 PRINT_STAT(loads);
300 HInstruction* instr = it.Current(); 530 PRINT_STAT(empty);
301 531 PRINT_STAT(compares_true);
302 switch (instr->opcode()) { 532 PRINT_STAT(compares_false);
303 case HValue::kCheckMaps: { 533 PRINT_STAT(transitions);
304 table.ReduceCheckMaps(HCheckMaps::cast(instr));
305 changed = true;
306 break;
307 }
308 case HValue::kCheckValue: {
309 table.ReduceCheckValue(HCheckValue::cast(instr));
310 changed = true;
311 break;
312 }
313 case HValue::kLoadNamedField: {
314 table.ReduceLoadNamedField(HLoadNamedField::cast(instr));
315 changed = true;
316 break;
317 }
318 case HValue::kStoreNamedField: {
319 table.ReduceStoreNamedField(HStoreNamedField::cast(instr));
320 changed = true;
321 break;
322 }
323 case HValue::kCompareMap: {
324 table.ReduceCompareMap(HCompareMap::cast(instr));
325 changed = true;
326 break;
327 }
328 case HValue::kTransitionElementsKind: {
329 table.ReduceTransitionElementsKind(
330 HTransitionElementsKind::cast(instr));
331 changed = true;
332 break;
333 }
334 case HValue::kCheckMapValue: {
335 table.ReduceCheckMapValue(HCheckMapValue::cast(instr));
336 changed = true;
337 break;
338 }
339 default: {
340 // If the instruction changes maps uncontrollably, kill the whole town.
341 if (instr->CheckGVNFlag(kChangesMaps)) {
342 table.Kill();
343 changed = true;
344 }
345 }
346 // Improvements possible:
347 // - eliminate HCheckSmi and HCheckHeapObject
348 }
349
350 if (changed && FLAG_trace_check_elimination) table.Print();
351 }
352
353 if (FLAG_trace_check_elimination) table.PrintStats();
354 } 534 }
355 535
356
357 } } // namespace v8::internal 536 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen-check-elimination.h ('k') | src/hydrogen-dce.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698