| 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 |