The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / hydrogen-check-elimination.cc @ f230a1cf

History | View | Annotate | Download (11.4 KB)

1
// Copyright 2013 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27

    
28
#include "hydrogen-check-elimination.h"
29
#include "hydrogen-alias-analysis.h"
30

    
31
namespace v8 {
32
namespace internal {
33

    
34
static const int kMaxTrackedObjects = 10;
35
typedef UniqueSet<Map>* MapSet;
36

    
37
// The main datastructure used during check elimination, which stores a
38
// set of known maps for each object.
39
class HCheckTable {
40
 public:
41
  explicit HCheckTable(Zone* zone) : zone_(zone) {
42
    Kill();
43
    redundant_ = 0;
44
    narrowed_ = 0;
45
    empty_ = 0;
46
    removed_ = 0;
47
    compares_true_ = 0;
48
    compares_false_ = 0;
49
    transitions_ = 0;
50
    loads_ = 0;
51
  }
52

    
53
  void ReduceCheckMaps(HCheckMaps* instr) {
54
    HValue* object = instr->value()->ActualValue();
55
    int index = Find(object);
56
    if (index >= 0) {
57
      // entry found;
58
      MapSet a = known_maps_[index];
59
      MapSet i = instr->map_set().Copy(zone_);
60
      if (a->IsSubset(i)) {
61
        // The first check is more strict; the second is redundant.
62
        if (checks_[index] != NULL) {
63
          instr->DeleteAndReplaceWith(checks_[index]);
64
          redundant_++;
65
        } else {
66
          instr->DeleteAndReplaceWith(instr->value());
67
          removed_++;
68
        }
69
        return;
70
      }
71
      i = i->Intersect(a, zone_);
72
      if (i->size() == 0) {
73
        // Intersection is empty; probably megamorphic, which is likely to
74
        // deopt anyway, so just leave things as they are.
75
        empty_++;
76
      } else {
77
        // TODO(titzer): replace the first check with a more strict check.
78
        narrowed_++;
79
      }
80
    } else {
81
      // No entry; insert a new one.
82
      Insert(object, instr, instr->map_set().Copy(zone_));
83
    }
84
  }
85

    
86
  void ReduceCheckValue(HCheckValue* instr) {
87
    // Canonicalize HCheckValues; they might have their values load-eliminated.
88
    HValue* value = instr->Canonicalize();
89
    if (value == NULL) {
90
      instr->DeleteAndReplaceWith(instr->value());
91
      removed_++;
92
    } else if (value != instr) {
93
      instr->DeleteAndReplaceWith(value);
94
      redundant_++;
95
    }
96
  }
97

    
98
  void ReduceLoadNamedField(HLoadNamedField* instr) {
99
    // Reduce a load of the map field when it is known to be a constant.
100
    if (!IsMapAccess(instr->access())) return;
101

    
102
    HValue* object = instr->object()->ActualValue();
103
    MapSet maps = FindMaps(object);
104
    if (maps == NULL || maps->size() != 1) return;  // Not a constant.
105

    
106
    Unique<Map> map = maps->at(0);
107
    HConstant* constant = HConstant::CreateAndInsertBefore(
108
        instr->block()->graph()->zone(), map, true, instr);
109
    instr->DeleteAndReplaceWith(constant);
110
    loads_++;
111
  }
112

    
113
  void ReduceCheckMapValue(HCheckMapValue* instr) {
114
    if (!instr->map()->IsConstant()) return;  // Nothing to learn.
115

    
116
    HValue* object = instr->value()->ActualValue();
117
    // Match a HCheckMapValue(object, HConstant(map))
118
    Unique<Map> map = MapConstant(instr->map());
119
    MapSet maps = FindMaps(object);
120
    if (maps != NULL) {
121
      if (maps->Contains(map)) {
122
        if (maps->size() == 1) {
123
          // Object is known to have exactly this map.
124
          instr->DeleteAndReplaceWith(NULL);
125
          removed_++;
126
        } else {
127
          // Only one map survives the check.
128
          maps->Clear();
129
          maps->Add(map, zone_);
130
        }
131
      }
132
    } else {
133
      // No prior information.
134
      Insert(object, map);
135
    }
136
  }
137

    
138
  void ReduceStoreNamedField(HStoreNamedField* instr) {
139
    HValue* object = instr->object()->ActualValue();
140
    if (instr->has_transition()) {
141
      // This store transitions the object to a new map.
142
      Kill(object);
143
      Insert(object, MapConstant(instr->transition()));
144
    } else if (IsMapAccess(instr->access())) {
145
      // This is a store directly to the map field of the object.
146
      Kill(object);
147
      if (!instr->value()->IsConstant()) return;
148
      Insert(object, MapConstant(instr->value()));
149
    } else if (instr->CheckGVNFlag(kChangesMaps)) {
150
      // This store indirectly changes the map of the object.
151
      Kill(instr->object());
152
      UNREACHABLE();
153
    }
154
  }
155

    
156
  void ReduceCompareMap(HCompareMap* instr) {
157
    MapSet maps = FindMaps(instr->value()->ActualValue());
158
    if (maps == NULL) return;
159
    if (maps->Contains(instr->map())) {
160
      // TODO(titzer): replace with goto true branch
161
      if (maps->size() == 1) compares_true_++;
162
    } else {
163
      // TODO(titzer): replace with goto false branch
164
      compares_false_++;
165
    }
166
  }
167

    
168
  void ReduceTransitionElementsKind(HTransitionElementsKind* instr) {
169
    MapSet maps = FindMaps(instr->object()->ActualValue());
170
    // Can only learn more about an object that already has a known set of maps.
171
    if (maps == NULL) return;
172
    if (maps->Contains(instr->original_map())) {
173
      // If the object has the original map, it will be transitioned.
174
      maps->Remove(instr->original_map());
175
      maps->Add(instr->transitioned_map(), zone_);
176
    } else {
177
      // Object does not have the given map, thus the transition is redundant.
178
      instr->DeleteAndReplaceWith(instr->object());
179
      transitions_++;
180
    }
181
  }
182

    
183
  // Kill everything in the table.
184
  void Kill() {
185
    memset(objects_, 0, sizeof(objects_));
186
  }
187

    
188
  // Kill everything in the table that may alias {object}.
189
  void Kill(HValue* object) {
190
    for (int i = 0; i < kMaxTrackedObjects; i++) {
191
      if (objects_[i] == NULL) continue;
192
      if (aliasing_.MayAlias(objects_[i], object)) objects_[i] = NULL;
193
    }
194
    ASSERT(Find(object) < 0);
195
  }
196

    
197
  void Print() {
198
    for (int i = 0; i < kMaxTrackedObjects; i++) {
199
      if (objects_[i] == NULL) continue;
200
      PrintF("  checkmaps-table @%d: object #%d ", i, objects_[i]->id());
201
      if (checks_[i] != NULL) {
202
        PrintF("check #%d ", checks_[i]->id());
203
      }
204
      MapSet list = known_maps_[i];
205
      PrintF("%d maps { ", list->size());
206
      for (int j = 0; j < list->size(); j++) {
207
        if (j > 0) PrintF(", ");
208
        PrintF("%" V8PRIxPTR, list->at(j).Hashcode());
209
      }
210
      PrintF(" }\n");
211
    }
212
  }
213

    
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:
226
  int Find(HValue* object) {
227
    for (int i = 0; i < kMaxTrackedObjects; i++) {
228
      if (objects_[i] == NULL) continue;
229
      if (aliasing_.MustAlias(objects_[i], object)) return i;
230
    }
231
    return -1;
232
  }
233

    
234
  MapSet FindMaps(HValue* object) {
235
    int index = Find(object);
236
    return index < 0 ? NULL : known_maps_[index];
237
  }
238

    
239
  void Insert(HValue* object, Unique<Map> map) {
240
    MapSet list = new(zone_) UniqueSet<Map>();
241
    list->Add(map, zone_);
242
    Insert(object, NULL, list);
243
  }
244

    
245
  void Insert(HValue* object, HCheckMaps* check, MapSet maps) {
246
    for (int i = 0; i < kMaxTrackedObjects; i++) {
247
      // TODO(titzer): drop old entries instead of disallowing new ones.
248
      if (objects_[i] == NULL) {
249
        objects_[i] = object;
250
        checks_[i] = check;
251
        known_maps_[i] = maps;
252
        return;
253
      }
254
    }
255
  }
256

    
257
  bool IsMapAccess(HObjectAccess access) {
258
    return access.IsInobject() && access.offset() == JSObject::kMapOffset;
259
  }
260

    
261
  Unique<Map> MapConstant(HValue* value) {
262
    return Unique<Map>::cast(HConstant::cast(value)->GetUnique());
263
  }
264

    
265
  Zone* zone_;
266
  HValue* objects_[kMaxTrackedObjects];
267
  HValue* checks_[kMaxTrackedObjects];
268
  MapSet known_maps_[kMaxTrackedObjects];
269
  HAliasAnalyzer aliasing_;
270
  int redundant_;
271
  int removed_;
272
  int narrowed_;
273
  int loads_;
274
  int empty_;
275
  int compares_true_;
276
  int compares_false_;
277
  int transitions_;
278
};
279

    
280

    
281
void HCheckEliminationPhase::Run() {
282
  for (int i = 0; i < graph()->blocks()->length(); i++) {
283
    EliminateLocalChecks(graph()->blocks()->at(i));
284
  }
285
}
286

    
287

    
288
// For code de-uglification.
289
#define TRACE(x) if (FLAG_trace_check_elimination) PrintF x
290

    
291

    
292
// Eliminate checks local to a block.
293
void HCheckEliminationPhase::EliminateLocalChecks(HBasicBlock* block) {
294
  HCheckTable table(zone());
295
  TRACE(("-- check-elim B%d ------------------------------------------------\n",
296
         block->block_id()));
297

    
298
  for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
299
    bool changed = false;
300
    HInstruction* instr = it.Current();
301

    
302
    switch (instr->opcode()) {
303
      case HValue::kCheckMaps: {
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
}
355

    
356

    
357
} }  // namespace v8::internal