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

Side by Side Diff: src/hydrogen.cc

Issue 16128004: Reorder switch clauses using newly-introduced execution counters in (Closed) Base URL: gh:v8/v8.git@master
Patch Set: tweak heuristic Created 7 years, 6 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
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-gvn.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 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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
(...skipping 1922 matching lines...) Expand 10 before | Expand all | Expand 10 after
1933 } 1933 }
1934 1934
1935 1935
1936 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) 1936 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
1937 : HGraphBuilder(info), 1937 : HGraphBuilder(info),
1938 function_state_(NULL), 1938 function_state_(NULL),
1939 initial_function_state_(this, info, NORMAL_RETURN), 1939 initial_function_state_(this, info, NORMAL_RETURN),
1940 ast_context_(NULL), 1940 ast_context_(NULL),
1941 break_scope_(NULL), 1941 break_scope_(NULL),
1942 inlined_count_(0), 1942 inlined_count_(0),
1943 deopt_counter_count_(0),
1943 globals_(10, info->zone()), 1944 globals_(10, info->zone()),
1944 inline_bailout_(false) { 1945 inline_bailout_(false) {
1945 // This is not initialized in the initializer list because the 1946 // This is not initialized in the initializer list because the
1946 // constructor for the initial state relies on function_state_ == NULL 1947 // constructor for the initial state relies on function_state_ == NULL
1947 // to know it's the initial state. 1948 // to know it's the initial state.
1948 function_state_= &initial_function_state_; 1949 function_state_= &initial_function_state_;
1949 InitializeAstVisitor(); 1950 InitializeAstVisitor();
1950 } 1951 }
1951 1952
1952 1953
(...skipping 2681 matching lines...) Expand 10 before | Expand all | Expand 10 after
4634 4635
4635 void HOptimizedGraphBuilder::AddSoftDeoptimize() { 4636 void HOptimizedGraphBuilder::AddSoftDeoptimize() {
4636 if (FLAG_always_opt) return; 4637 if (FLAG_always_opt) return;
4637 if (current_block()->IsDeoptimizing()) return; 4638 if (current_block()->IsDeoptimizing()) return;
4638 AddInstruction(new(zone()) HSoftDeoptimize()); 4639 AddInstruction(new(zone()) HSoftDeoptimize());
4639 current_block()->MarkAsDeoptimizing(); 4640 current_block()->MarkAsDeoptimizing();
4640 graph()->set_has_soft_deoptimize(true); 4641 graph()->set_has_soft_deoptimize(true);
4641 } 4642 }
4642 4643
4643 4644
4645 HDeoptCounter* HOptimizedGraphBuilder::AddDeoptCounter(int initial_value,
4646 int max_value) {
4647 HDeoptCounter* res = new(zone()) HDeoptCounter(deopt_counter_count_++,
4648 initial_value,
4649 max_value);
4650 AddInstruction(res);
4651 return res;
4652 }
4653
4654
4644 template <class Instruction> 4655 template <class Instruction>
4645 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) { 4656 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
4646 int count = call->argument_count(); 4657 int count = call->argument_count();
4647 ZoneList<HValue*> arguments(count, zone()); 4658 ZoneList<HValue*> arguments(count, zone());
4648 for (int i = 0; i < count; ++i) { 4659 for (int i = 0; i < count; ++i) {
4649 arguments.Add(Pop(), zone()); 4660 arguments.Add(Pop(), zone());
4650 } 4661 }
4651 4662
4652 while (!arguments.is_empty()) { 4663 while (!arguments.is_empty()) {
4653 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast())); 4664 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast()));
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
4920 4931
4921 4932
4922 void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) { 4933 void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) {
4923 ASSERT(!HasStackOverflow()); 4934 ASSERT(!HasStackOverflow());
4924 ASSERT(current_block() != NULL); 4935 ASSERT(current_block() != NULL);
4925 ASSERT(current_block()->HasPredecessor()); 4936 ASSERT(current_block()->HasPredecessor());
4926 return Bailout("WithStatement"); 4937 return Bailout("WithStatement");
4927 } 4938 }
4928 4939
4929 4940
4941 int HOptimizedGraphBuilder::ClauseMapping::HitCountOrder(
4942 ClauseMapping* const* a,
4943 ClauseMapping* const* b) {
4944 return (*a)->clause()->hit_count() == (*b)->clause()->hit_count() ? 0 :
4945 (*a)->clause()->hit_count() > (*b)->clause()->hit_count() ? -1 : 1;
4946 }
4947
4948
4930 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { 4949 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
4931 ASSERT(!HasStackOverflow()); 4950 ASSERT(!HasStackOverflow());
4932 ASSERT(current_block() != NULL); 4951 ASSERT(current_block() != NULL);
4933 ASSERT(current_block()->HasPredecessor()); 4952 ASSERT(current_block()->HasPredecessor());
4934 4953
4935 // We only optimize switch statements with smi-literal smi comparisons, 4954 // We only optimize switch statements with smi-literal smi comparisons,
4936 // with a bounded number of clauses. 4955 // with a bounded number of clauses.
4937 const int kCaseClauseLimit = 128; 4956 const int kCaseClauseLimit = 128;
4938 ZoneList<CaseClause*>* clauses = stmt->cases(); 4957 ZoneList<CaseClause*>* clauses = stmt->cases();
4939 int clause_count = clauses->length(); 4958 int clause_count = clauses->length();
(...skipping 22 matching lines...) Expand all
4962 first_test_block = graph()->CreateBasicBlock(); 4981 first_test_block = graph()->CreateBasicBlock();
4963 not_string_block = graph()->CreateBasicBlock(); 4982 not_string_block = graph()->CreateBasicBlock();
4964 4983
4965 string_check->SetSuccessorAt(0, first_test_block); 4984 string_check->SetSuccessorAt(0, first_test_block);
4966 string_check->SetSuccessorAt(1, not_string_block); 4985 string_check->SetSuccessorAt(1, not_string_block);
4967 current_block()->Finish(string_check); 4986 current_block()->Finish(string_check);
4968 4987
4969 set_current_block(first_test_block); 4988 set_current_block(first_test_block);
4970 } 4989 }
4971 4990
4991 // 0. Order clauses by hit count
4992 ZoneList<ClauseMapping*> ordered_clauses(clause_count, zone());
4993 ZoneList<HBasicBlock*> clause_test_blocks(clause_count, zone());
4994 int max_hit = 0;
4995 int min_hit = clause_count == 0 ? 0 : kMaxInt;
4996 for (int i = 0; i < clause_count; ++i) {
4997 int hits = clauses->at(i)->hit_count();
4998 if (hits > max_hit) max_hit = hits;
4999 if (hits < min_hit) min_hit = hits;
5000
5001 ordered_clauses.Add(new(zone()) ClauseMapping(i, clauses->at(i)), zone());
5002 clause_test_blocks.Add(NULL, zone());
5003 }
5004
5005 // Number of top cases that are executing at relatively the same speed.
5006 const int kClauseReorderSoftLimit = 5;
5007
5008 // Maximum percent of `min_hit / max_hit` at which optimization is
5009 // still allowed.
5010 const int kClauseMinDeltaHit = 50;
5011
5012 // Reorder clauses only if there's a significant difference between
5013 // maximum and minimum hit counts.
5014 bool reorder_clauses =
5015 max_hit == 0 ? false : ((100 * min_hit / max_hit) < kClauseMinDeltaHit);
5016
5017 HDeoptCounter* counter = NULL;
5018
5019 // If hit distribution doesn't change much - counter should always stay
5020 // below zero. Check that clauses above te soft mark have more weight than
5021 // clauses below the mark, and add CounterAdd instruction at the soft mark
5022 // boundary with +1, -1 values to catch distribution change.
5023 if (reorder_clauses) {
5024 ordered_clauses.Sort(ClauseMapping::HitCountOrder);
5025
5026 double above = 0;
5027 double below = 0;
5028 for (int i = 0; i < clause_count; ++i) {
5029 double hits =
5030 static_cast<double>(ordered_clauses.at(i)->clause()->hit_count());
5031 if (i < kClauseReorderSoftLimit) {
5032 above += hits;
5033 } else {
5034 below += hits;
5035 }
5036 }
5037
5038 double max = static_cast<double>(max_hit) * kClauseReorderSoftLimit;
5039 if (above > below && max < Smi::kMaxValue && Smi::IsValid(max)) {
5040 counter = AddDeoptCounter(max_hit, max);
5041 }
5042 }
5043
4972 // 1. Build all the tests, with dangling true branches 5044 // 1. Build all the tests, with dangling true branches
4973 BailoutId default_id = BailoutId::None(); 5045 BailoutId default_id = BailoutId::None();
4974 for (int i = 0; i < clause_count; ++i) { 5046 for (int i = 0; i < clause_count; ++i) {
4975 CaseClause* clause = clauses->at(i); 5047 int index = ordered_clauses.at(i)->index();
5048 CaseClause* clause = ordered_clauses.at(i)->clause();
5049
4976 if (clause->is_default()) { 5050 if (clause->is_default()) {
4977 default_id = clause->EntryId(); 5051 default_id = clause->EntryId();
4978 continue; 5052 continue;
4979 } 5053 }
4980 5054
4981 // Generate a compare and branch. 5055 // Generate a compare and branch.
4982 CHECK_ALIVE(VisitForValue(clause->label())); 5056 CHECK_ALIVE(VisitForValue(clause->label()));
4983 HValue* label_value = Pop(); 5057 HValue* label_value = Pop();
4984 5058
5059 // Save test block for later traversal in AST-order
5060 clause_test_blocks[index] = current_block();
4985 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); 5061 HBasicBlock* next_test_block = graph()->CreateBasicBlock();
4986 HBasicBlock* body_block = graph()->CreateBasicBlock(); 5062 HBasicBlock* body_block = graph()->CreateBasicBlock();
4987 5063
4988 HControlInstruction* compare; 5064 HControlInstruction* compare;
4989 5065
5066 // Deoptimize when balance shifts from top clauses to bottom ones
5067 if (counter != NULL) {
5068 if (i == 0 || i == kClauseReorderSoftLimit) {
5069 AddInstruction(new(zone()) HDeoptCounterAdd(counter, i == 0 ? 2 : -3));
5070 }
5071 }
5072
4990 if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { 5073 if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) {
4991 if (!clause->IsSmiCompare()) { 5074 if (!clause->IsSmiCompare()) {
4992 // Finish with deoptimize and add uses of enviroment values to 5075 // Finish with deoptimize and add uses of enviroment values to
4993 // account for invisible uses. 5076 // account for invisible uses.
4994 current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll); 5077 current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
4995 set_current_block(NULL); 5078 set_current_block(NULL);
4996 break; 5079 break;
4997 } 5080 }
4998 5081
4999 HCompareIDAndBranch* compare_ = 5082 HCompareIDAndBranch* compare_ =
(...skipping 20 matching lines...) Expand all
5020 // exit. This block is NULL if we deoptimized. 5103 // exit. This block is NULL if we deoptimized.
5021 HBasicBlock* last_block = current_block(); 5104 HBasicBlock* last_block = current_block();
5022 5105
5023 if (not_string_block != NULL) { 5106 if (not_string_block != NULL) {
5024 BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId(); 5107 BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId();
5025 last_block = CreateJoin(last_block, not_string_block, join_id); 5108 last_block = CreateJoin(last_block, not_string_block, join_id);
5026 } 5109 }
5027 5110
5028 // 2. Loop over the clauses and the linked list of tests in lockstep, 5111 // 2. Loop over the clauses and the linked list of tests in lockstep,
5029 // translating the clause bodies. 5112 // translating the clause bodies.
5030 HBasicBlock* curr_test_block = first_test_block;
5031 HBasicBlock* fall_through_block = NULL; 5113 HBasicBlock* fall_through_block = NULL;
5032 5114
5033 BreakAndContinueInfo break_info(stmt); 5115 BreakAndContinueInfo break_info(stmt);
5034 { BreakAndContinueScope push(&break_info, this); 5116 { BreakAndContinueScope push(&break_info, this);
5035 for (int i = 0; i < clause_count; ++i) { 5117 for (int i = 0; i < clause_count; ++i) {
5118 HBasicBlock* curr_test_block = clause_test_blocks.at(i);
5036 CaseClause* clause = clauses->at(i); 5119 CaseClause* clause = clauses->at(i);
5037 5120
5038 // Identify the block where normal (non-fall-through) control flow 5121 // Identify the block where normal (non-fall-through) control flow
5039 // goes to. 5122 // goes to.
5040 HBasicBlock* normal_block = NULL; 5123 HBasicBlock* normal_block = NULL;
5041 if (clause->is_default()) { 5124 if (clause->is_default()) {
5042 if (last_block != NULL) { 5125 if (last_block != NULL) {
5043 normal_block = last_block; 5126 normal_block = last_block;
5044 last_block = NULL; // Cleared to indicate we've handled it. 5127 last_block = NULL; // Cleared to indicate we've handled it.
5045 } 5128 }
5046 } else if (!curr_test_block->end()->IsDeoptimize()) { 5129 } else if (!curr_test_block->end()->IsDeoptimize()) {
5047 normal_block = curr_test_block->end()->FirstSuccessor(); 5130 normal_block = curr_test_block->end()->FirstSuccessor();
5048 curr_test_block = curr_test_block->end()->SecondSuccessor();
5049 } 5131 }
5050 5132
5051 // Identify a block to emit the body into. 5133 // Identify a block to emit the body into.
5052 if (normal_block == NULL) { 5134 if (normal_block == NULL) {
5053 if (fall_through_block == NULL) { 5135 if (fall_through_block == NULL) {
5054 // (a) Unreachable. 5136 // (a) Unreachable.
5055 if (clause->is_default()) { 5137 if (clause->is_default()) {
5056 continue; // Might still be reachable clause bodies. 5138 continue; // Might still be reachable clause bodies.
5057 } else { 5139 } else {
5058 break; 5140 break;
(...skipping 6439 matching lines...) Expand 10 before | Expand all | Expand 10 after
11498 } 11580 }
11499 } 11581 }
11500 11582
11501 #ifdef DEBUG 11583 #ifdef DEBUG
11502 if (graph_ != NULL) graph_->Verify(false); // No full verify. 11584 if (graph_ != NULL) graph_->Verify(false); // No full verify.
11503 if (allocator_ != NULL) allocator_->Verify(); 11585 if (allocator_ != NULL) allocator_->Verify();
11504 #endif 11586 #endif
11505 } 11587 }
11506 11588
11507 } } // namespace v8::internal 11589 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-gvn.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698