36 #define INC_STAT(x) phase_->x++
42 #define TRACE(x) if (FLAG_trace_check_elimination) PrintF x
71 case HValue::kCheckMaps: {
72 ReduceCheckMaps(HCheckMaps::cast(instr));
75 case HValue::kCheckValue: {
76 ReduceCheckValue(HCheckValue::cast(instr));
79 case HValue::kLoadNamedField: {
80 ReduceLoadNamedField(HLoadNamedField::cast(instr));
83 case HValue::kStoreNamedField: {
84 ReduceStoreNamedField(HStoreNamedField::cast(instr));
87 case HValue::kCompareMap: {
88 ReduceCompareMap(HCompareMap::cast(instr));
91 case HValue::kCompareObjectEqAndBranch: {
95 case HValue::kTransitionElementsKind: {
96 ReduceTransitionElementsKind(
97 HTransitionElementsKind::cast(instr));
100 case HValue::kCheckMapValue: {
101 ReduceCheckMapValue(HCheckMapValue::cast(instr));
104 case HValue::kCheckHeapObject: {
105 ReduceCheckHeapObject(HCheckHeapObject::cast(instr));
128 if (pred_state ==
NULL || pred_block->IsUnreachable()) {
131 if (succ_state ==
NULL) {
132 return pred_state->Copy(succ_block, pred_block, zone);
134 return succ_state->
Merge(succ_block, pred_state, pred_block, zone);
143 block->MarkUnreachable();
144 }
else if (block->IsUnreachable()) {
147 if (FLAG_trace_check_elimination) {
148 PrintF(
"Processing B%d, checkmaps-table:\n", block->block_id());
156 HCheckTable* Copy(HBasicBlock* succ, HBasicBlock* from_block,
Zone* zone) {
158 for (
int i = 0; i < size_; i++) {
163 new_entry->maps_ = old_entry->
maps_->Copy(phase_->zone());
167 new_entry->check_ = old_entry->
check_;
171 new_entry->check_ =
NULL;
174 copy->cursor_ = cursor_;
178 if (!succ->IsLoopHeader() && succ->phis()->length() > 0) {
179 int pred_index = succ->PredecessorIndexOf(from_block);
180 for (
int phi_index = 0;
181 phi_index < succ->phis()->length();
183 HPhi* phi = succ->phis()->at(phi_index);
184 HValue* phi_operand = phi->OperandAt(pred_index);
186 HCheckTableEntry* pred_entry = copy->Find(phi_operand);
187 if (pred_entry !=
NULL) {
189 copy->Insert(phi,
NULL, pred_entry->maps_->Copy(phase_->zone()));
196 bool learned =
false;
197 if (succ->predecessors()->length() == 1) {
198 HControlInstruction* end = succ->predecessors()->at(0)->end();
199 bool is_true_branch = end->SuccessorAt(0) == succ;
200 if (end->IsCompareMap()) {
201 HCompareMap* cmp = HCompareMap::cast(end);
202 HValue*
object = cmp->value()->ActualValue();
203 HCheckTableEntry* entry = copy->Find(
object);
204 if (is_true_branch) {
207 copy->Insert(
object, cmp, cmp->map());
209 MapSet list =
new(phase_->zone()) UniqueSet<Map>();
210 list->Add(cmp->map(), phase_->zone());
217 entry->maps_->Remove(cmp->map());
221 }
else if (is_true_branch && end->IsCompareObjectEqAndBranch()) {
223 HCompareObjectEqAndBranch* cmp =
225 HValue* left = cmp->left()->ActualValue();
226 HValue* right = cmp->right()->ActualValue();
227 HCheckTableEntry*
le = copy->Find(left);
228 HCheckTableEntry* re = copy->Find(right);
231 copy->Insert(left,
NULL, re->maps_->Copy(zone));
233 }
else if (re ==
NULL) {
234 copy->Insert(right,
NULL, le->maps_->Copy(zone));
236 MapSet intersect = le->maps_->Intersect(re->maps_, zone);
237 le->maps_ = intersect;
238 re->maps_ = intersect->Copy(zone);
245 if (FLAG_trace_check_elimination) {
246 PrintF(
"B%d checkmaps-table %s from B%d:\n",
248 learned ?
"learned" :
"copied",
249 from_block->block_id());
258 HBasicBlock* pred_block, Zone* zone) {
259 if (that->size_ == 0) {
264 int pred_index = succ->PredecessorIndexOf(pred_block);
265 bool compact =
false;
266 for (
int i = 0; i < size_; i++) {
267 HCheckTableEntry* this_entry = &entries_[i];
268 HCheckTableEntry* that_entry;
269 if (this_entry->object_->IsPhi() &&
270 this_entry->object_->block() == succ) {
271 HPhi* phi = HPhi::cast(this_entry->object_);
272 HValue* phi_operand = phi->OperandAt(pred_index);
273 that_entry = that->Find(phi_operand);
276 that_entry = that->Find(this_entry->object_);
279 if (that_entry ==
NULL) {
280 this_entry->object_ =
NULL;
284 this_entry->maps_->Union(that_entry->maps_, phase_->zone());
285 if (this_entry->check_ != that_entry->check_) {
286 this_entry->check_ =
NULL;
288 ASSERT(this_entry->maps_->size() > 0);
291 if (compact) Compact();
294 if (FLAG_trace_check_elimination) {
295 PrintF(
"B%d checkmaps-table merged with B%d table:\n",
296 succ->block_id(), pred_block->block_id());
302 void ReduceCheckMaps(HCheckMaps* instr) {
303 HValue*
object = instr->value()->ActualValue();
304 HCheckTableEntry* entry = Find(
object);
308 MapSet i = instr->map_set().Copy(phase_->zone());
309 if (a->IsSubset(i)) {
311 if (entry->check_ !=
NULL) {
312 TRACE((
"Replacing redundant CheckMaps #%d at B%d with #%d\n",
313 instr->id(), instr->block()->block_id(), entry->check_->id()));
314 instr->DeleteAndReplaceWith(entry->check_);
317 TRACE((
"Marking redundant CheckMaps #%d at B%d as dead\n",
318 instr->id(), instr->block()->block_id()));
322 entry->check_ = instr;
327 MapSet intersection = i->Intersect(a, phase_->zone());
328 if (intersection->size() == 0) {
334 entry->maps_ = intersection;
335 if (intersection->size() != i->size()) {
337 HGraph* graph = instr->block()->graph();
338 if (entry->check_ !=
NULL &&
339 entry->check_->block() == instr->block() &&
340 entry->check_->IsCheckMaps()) {
343 HCheckMaps*
check = HCheckMaps::cast(entry->check_);
344 TRACE((
"CheckMaps #%d at B%d narrowed\n", check->id(),
345 check->block()->block_id()));
347 check->set_map_set(intersection, graph->zone());
349 TRACE((
"Replacing redundant CheckMaps #%d at B%d with #%d\n",
350 instr->id(), instr->block()->block_id(), entry->check_->id()));
351 instr->DeleteAndReplaceWith(entry->check_);
353 TRACE((
"CheckMaps #%d at B%d narrowed\n", instr->id(),
354 instr->block()->block_id()));
355 instr->set_map_set(intersection, graph->zone());
356 entry->check_ = instr;
359 if (FLAG_trace_check_elimination) {
367 Insert(
object, instr, instr->map_set().Copy(phase_->zone()));
371 void ReduceCheckValue(HCheckValue* instr) {
373 HValue* value = instr->Canonicalize();
375 instr->DeleteAndReplaceWith(instr->value());
377 }
else if (value != instr) {
378 instr->DeleteAndReplaceWith(value);
383 void ReduceLoadNamedField(HLoadNamedField* instr) {
385 if (!IsMapAccess(instr->access()))
return;
387 HValue*
object = instr->object()->ActualValue();
388 MapSet maps = FindMaps(
object);
389 if (maps ==
NULL || maps->size() != 1)
return;
391 Unique<Map>
map = maps->at(0);
392 HConstant* constant = HConstant::CreateAndInsertBefore(
393 instr->block()->graph()->zone(),
map,
true, instr);
394 instr->DeleteAndReplaceWith(constant);
398 void ReduceCheckMapValue(HCheckMapValue* instr) {
399 if (!instr->map()->IsConstant())
return;
401 HValue*
object = instr->value()->ActualValue();
403 Unique<Map> map = MapConstant(instr->map());
405 HCheckTableEntry* entry = Find(
object);
407 MapSet maps = entry->maps_;
408 if (maps->Contains(map)) {
409 if (maps->size() == 1) {
411 if (entry->check_ !=
NULL) {
412 instr->DeleteAndReplaceWith(entry->check_);
417 entry->check_ = instr;
423 maps->Add(map, phase_->zone());
424 entry->check_ = instr;
429 Insert(
object, instr, map);
433 void ReduceCheckHeapObject(HCheckHeapObject* instr) {
434 if (FindMaps(instr->value()->ActualValue()) !=
NULL) {
436 instr->DeleteAndReplaceWith(instr->value());
441 void ReduceStoreNamedField(HStoreNamedField* instr) {
442 HValue*
object = instr->object()->ActualValue();
443 if (instr->has_transition()) {
446 Insert(
object,
NULL, MapConstant(instr->transition()));
447 }
else if (IsMapAccess(instr->access())) {
450 if (!instr->value()->IsConstant())
return;
451 Insert(
object,
NULL, MapConstant(instr->value()));
454 CHECK(!instr->CheckChangesFlag(kMaps));
458 void ReduceCompareMap(HCompareMap* instr) {
459 MapSet maps = FindMaps(instr->value()->ActualValue());
460 if (maps ==
NULL)
return;
463 if (maps->Contains(instr->map())) {
464 if (maps->size() != 1) {
465 TRACE((
"CompareMap #%d for #%d at B%d can't be eliminated: "
466 "ambiguous set of maps\n", instr->id(), instr->value()->id(),
467 instr->block()->block_id()));
477 TRACE((
"Marking redundant CompareMap #%d for #%d at B%d as %s\n",
478 instr->id(), instr->value()->id(), instr->block()->block_id(),
479 succ == 0 ?
"true" :
"false"));
480 instr->set_known_successor_index(succ);
482 int unreachable_succ = 1 - succ;
483 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
486 void ReduceCompareObjectEqAndBranch(HCompareObjectEqAndBranch* instr) {
487 MapSet maps_left = FindMaps(instr->left()->ActualValue());
488 if (maps_left ==
NULL)
return;
489 MapSet maps_right = FindMaps(instr->right()->ActualValue());
490 if (maps_right ==
NULL)
return;
491 MapSet intersection = maps_left->Intersect(maps_right, phase_->zone());
492 if (intersection->size() > 0)
return;
494 TRACE((
"Marking redundant CompareObjectEqAndBranch #%d at B%d as false\n",
495 instr->id(), instr->block()->block_id()));
497 instr->set_known_successor_index(succ);
499 int unreachable_succ = 1 - succ;
500 instr->block()->MarkSuccEdgeUnreachable(unreachable_succ);
503 void ReduceTransitionElementsKind(HTransitionElementsKind* instr) {
504 MapSet maps = FindMaps(instr->object()->ActualValue());
506 if (maps ==
NULL)
return;
507 if (maps->Contains(instr->original_map())) {
509 maps->Remove(instr->original_map());
510 maps->Add(instr->transitioned_map(), phase_->zone());
513 instr->DeleteAndReplaceWith(instr->object());
525 void Kill(HValue*
object) {
526 bool compact =
false;
527 for (
int i = 0; i < size_; i++) {
528 HCheckTableEntry* entry = &entries_[i];
530 if (phase_->aliasing_->
MayAlias(entry->object_,
object)) {
531 entry->object_ =
NULL;
535 if (compact) Compact();
541 int max = size_, dest = 0, old_cursor = cursor_;
542 for (
int i = 0; i < max; i++) {
543 if (entries_[i].object_ !=
NULL) {
544 if (dest != i) entries_[dest] = entries_[i];
547 if (i < old_cursor) cursor_--;
555 if (cursor_ == size_)
return;
561 int R = size_ - cursor_;
563 OS::MemMove(&tmp_entries[0], &entries_[0], L *
sizeof(HCheckTableEntry));
564 OS::MemMove(&entries_[0], &entries_[L], R *
sizeof(HCheckTableEntry));
565 OS::MemMove(&entries_[R], &tmp_entries[0], L *
sizeof(HCheckTableEntry));
577 for (
int i = 0; i < table->size_; i++) {
578 HCheckTableEntry* entry = &table->entries_[i];
580 PrintF(
" checkmaps-table @%d: %s #%d ", i,
581 entry->object_->IsPhi() ?
"phi" :
"object", entry->object_->id());
582 if (entry->check_ !=
NULL) {
583 PrintF(
"check #%d ", entry->check_->id());
585 MapSet list = entry->maps_;
586 PrintF(
"%d maps { ", list->size());
587 for (
int j = 0; j < list->size(); j++) {
595 HCheckTableEntry* Find(HValue*
object) {
596 for (
int i = size_ - 1; i >= 0; i--) {
598 HCheckTableEntry* entry = &entries_[i];
600 if (phase_->aliasing_->
MustAlias(entry->object_,
object))
return entry;
605 MapSet FindMaps(HValue*
object) {
606 HCheckTableEntry* entry = Find(
object);
607 return entry ==
NULL ?
NULL : entry->maps_;
610 void Insert(HValue*
object, HInstruction* check, Unique<Map> map) {
611 MapSet list =
new(phase_->zone()) UniqueSet<Map>();
612 list->Add(map, phase_->zone());
613 Insert(
object, check, list);
616 void Insert(HValue*
object, HInstruction* check,
MapSet maps) {
617 HCheckTableEntry* entry = &entries_[cursor_++];
619 entry->check_ =
check;
626 bool IsMapAccess(HObjectAccess access) {
630 Unique<Map> MapConstant(HValue* value) {
631 return Unique<Map>::cast(HConstant::cast(value)->GetUnique());
650 : maps_stored_(
false),
659 switch (instr->
opcode()) {
660 case HValue::kStoreNamedField: {
661 stores_.
Add(HStoreNamedField::cast(instr), zone);
664 case HValue::kOsrEntry: {
684 for (
int i = 0; i < stores_.length(); i++) {
685 HStoreNamedField* s = stores_[i];
686 if (table->IsMapAccess(s->access()) || s->has_transition()) {
687 table->Kill(s->object()->ActualValue());
694 maps_stored_ |= that->maps_stored_;
695 for (
int i = 0; i < that->stores_.length(); i++) {
696 stores_.
Add(that->stores_[i], zone);
701 bool maps_stored_ : 1;
717 for (
int i = 0; i <
graph()->blocks()->length(); i++) {
723 if (FLAG_trace_check_elimination) PrintStats();
728 void HCheckEliminationPhase::PrintStats() {
730 #define PRINT_STAT(x) if (x##_ > 0) PrintF(" %-16s = %2d\n", #x, x##_)
732 #define PRINT_STAT(x)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
void PrintF(const char *format,...)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf map
bool CheckChangesFlag(GVNFlag f) const
HBasicBlock * block() const
void AnalyzeDominatedBlocks(HBasicBlock *root, State *initial)
#define ASSERT(condition)
void Process(HInstruction *instr, Zone *zone)
UniqueSet< Map > * MapSet
bool MayAlias(HValue *a, HValue *b)
void check(i::Vector< const uint8_t > string)
static void MemMove(void *dest, const void *src, size_t size)
static const int kMaxTrackedObjects
HCheckTable * Process(HInstruction *instr, Zone *zone)
HCheckMapsEffects(Zone *zone)
bool MustAlias(HValue *a, HValue *b)
void Union(HCheckMapsEffects *that, Zone *zone)
static HCheckTable * Merge(HCheckTable *succ_state, HBasicBlock *succ_block, HCheckTable *pred_state, HBasicBlock *pred_block, Zone *zone)
virtual Opcode opcode() const =0
static const int kMapOffset
State * AnalyzeOneBlock(HBasicBlock *block, State *state)
void Apply(HCheckTable *table)
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
HCheckTable(HCheckEliminationPhase *phase)
static HValue * cast(HValue *value)
static HCheckTable * Finish(HCheckTable *state, HBasicBlock *block, Zone *zone)