OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |