Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 529 | 529 |
| 530 void HBasicBlock::FinishExit(HControlInstruction* instruction) { | 530 void HBasicBlock::FinishExit(HControlInstruction* instruction) { |
| 531 Finish(instruction); | 531 Finish(instruction); |
| 532 ClearEnvironment(); | 532 ClearEnvironment(); |
| 533 } | 533 } |
| 534 | 534 |
| 535 | 535 |
| 536 HGraph::HGraph(CompilationInfo* info) | 536 HGraph::HGraph(CompilationInfo* info) |
| 537 : HSubgraph(this), | 537 : HSubgraph(this), |
| 538 next_block_id_(0), | 538 next_block_id_(0), |
| 539 info_(info), | |
| 540 blocks_(8), | 539 blocks_(8), |
| 541 values_(16), | 540 values_(16), |
| 542 phi_list_(NULL) { | 541 phi_list_(NULL) { |
| 543 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); | 542 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); |
| 544 start_environment_->set_ast_id(info->function()->id()); | 543 start_environment_->set_ast_id(info->function()->id()); |
| 545 } | 544 } |
| 546 | 545 |
| 547 | 546 |
| 548 bool HGraph::AllowCodeMotion() const { | 547 Handle<Code> HGraph::Compile(CompilationInfo* info) { |
| 549 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; | |
| 550 } | |
| 551 | |
| 552 | |
| 553 Handle<Code> HGraph::Compile() { | |
| 554 int values = GetMaximumValueID(); | 548 int values = GetMaximumValueID(); |
| 555 if (values > LAllocator::max_initial_value_ids()) { | 549 if (values > LAllocator::max_initial_value_ids()) { |
| 556 if (FLAG_trace_bailout) PrintF("Function is too big\n"); | 550 if (FLAG_trace_bailout) PrintF("Function is too big\n"); |
| 557 return Handle<Code>::null(); | 551 return Handle<Code>::null(); |
| 558 } | 552 } |
| 559 | 553 |
| 560 LAllocator allocator(values, this); | 554 LAllocator allocator(values, this); |
| 561 LChunkBuilder builder(this, &allocator); | 555 LChunkBuilder builder(info, this, &allocator); |
| 562 LChunk* chunk = builder.Build(); | 556 LChunk* chunk = builder.Build(); |
| 563 if (chunk == NULL) return Handle<Code>::null(); | 557 if (chunk == NULL) return Handle<Code>::null(); |
| 564 | 558 |
| 565 if (!FLAG_alloc_lithium) return Handle<Code>::null(); | 559 if (!FLAG_alloc_lithium) return Handle<Code>::null(); |
| 566 | 560 |
| 567 allocator.Allocate(chunk); | 561 allocator.Allocate(chunk); |
| 568 | 562 |
| 569 if (!FLAG_use_lithium) return Handle<Code>::null(); | 563 if (!FLAG_use_lithium) return Handle<Code>::null(); |
| 570 | 564 |
| 571 MacroAssembler assembler(NULL, 0); | 565 MacroAssembler assembler(NULL, 0); |
| 572 LCodeGen generator(chunk, &assembler, info()); | 566 LCodeGen generator(chunk, &assembler, info); |
| 573 | 567 |
| 574 if (FLAG_eliminate_empty_blocks) { | 568 if (FLAG_eliminate_empty_blocks) { |
| 575 chunk->MarkEmptyBlocks(); | 569 chunk->MarkEmptyBlocks(); |
| 576 } | 570 } |
| 577 | 571 |
| 578 if (generator.GenerateCode()) { | 572 if (generator.GenerateCode()) { |
| 579 if (FLAG_trace_codegen) { | 573 if (FLAG_trace_codegen) { |
| 580 PrintF("Crankshaft Compiler - "); | 574 PrintF("Crankshaft Compiler - "); |
| 581 } | 575 } |
| 582 CodeGenerator::MakeCodePrologue(info()); | 576 CodeGenerator::MakeCodePrologue(info); |
| 583 Code::Flags flags = | 577 Code::Flags flags = |
| 584 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP); | 578 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP); |
| 585 Handle<Code> code = | 579 Handle<Code> code = |
| 586 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info()); | 580 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info); |
| 587 generator.FinishCode(code); | 581 generator.FinishCode(code); |
| 588 CodeGenerator::PrintCode(code, info()); | 582 CodeGenerator::PrintCode(code, info); |
| 589 return code; | 583 return code; |
| 590 } | 584 } |
| 591 return Handle<Code>::null(); | 585 return Handle<Code>::null(); |
| 592 } | 586 } |
| 593 | 587 |
| 594 | 588 |
| 595 HBasicBlock* HGraph::CreateBasicBlock() { | 589 HBasicBlock* HGraph::CreateBasicBlock() { |
| 596 HBasicBlock* result = new HBasicBlock(this); | 590 HBasicBlock* result = new HBasicBlock(this); |
| 597 blocks_.Add(result); | 591 blocks_.Add(result); |
| 598 return result; | 592 return result; |
| (...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1169 HGoto::cast(instr)->set_include_stack_check(false); | 1163 HGoto::cast(instr)->set_include_stack_check(false); |
| 1170 return; | 1164 return; |
| 1171 } | 1165 } |
| 1172 instr = instr->next(); | 1166 instr = instr->next(); |
| 1173 } | 1167 } |
| 1174 } | 1168 } |
| 1175 | 1169 |
| 1176 | 1170 |
| 1177 class HGlobalValueNumberer BASE_EMBEDDED { | 1171 class HGlobalValueNumberer BASE_EMBEDDED { |
| 1178 public: | 1172 public: |
| 1179 explicit HGlobalValueNumberer(HGraph* graph) | 1173 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) |
| 1180 : graph_(graph), | 1174 : graph_(graph), |
| 1175 info_(info), | |
| 1181 block_side_effects_(graph_->blocks()->length()), | 1176 block_side_effects_(graph_->blocks()->length()), |
| 1182 loop_side_effects_(graph_->blocks()->length()) { | 1177 loop_side_effects_(graph_->blocks()->length()) { |
| 1183 ASSERT(Heap::allow_allocation(false)); | 1178 ASSERT(Heap::allow_allocation(false)); |
| 1184 block_side_effects_.AddBlock(0, graph_->blocks()->length()); | 1179 block_side_effects_.AddBlock(0, graph_->blocks()->length()); |
| 1185 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); | 1180 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); |
| 1186 } | 1181 } |
| 1187 ~HGlobalValueNumberer() { | 1182 ~HGlobalValueNumberer() { |
| 1188 ASSERT(!Heap::allow_allocation(true)); | 1183 ASSERT(!Heap::allow_allocation(true)); |
| 1189 } | 1184 } |
| 1190 | 1185 |
| 1191 void Analyze(); | 1186 void Analyze(); |
| 1192 | 1187 |
| 1193 private: | 1188 private: |
| 1194 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); | 1189 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); |
| 1195 void ComputeBlockSideEffects(); | 1190 void ComputeBlockSideEffects(); |
| 1196 void LoopInvariantCodeMotion(); | 1191 void LoopInvariantCodeMotion(); |
| 1197 void ProcessLoopBlock(HBasicBlock* block, | 1192 void ProcessLoopBlock(HBasicBlock* block, |
| 1198 HBasicBlock* before_loop, | 1193 HBasicBlock* before_loop, |
| 1199 int loop_kills); | 1194 int loop_kills); |
| 1195 bool AllowCodeMotion(); | |
| 1200 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); | 1196 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); |
| 1201 | 1197 |
| 1198 HGraph* graph() { return graph_; } | |
| 1199 CompilationInfo* info() { return info_; } | |
| 1200 | |
| 1202 HGraph* graph_; | 1201 HGraph* graph_; |
| 1202 CompilationInfo* info_; | |
| 1203 | 1203 |
| 1204 // A map of block IDs to their side effects. | 1204 // A map of block IDs to their side effects. |
| 1205 ZoneList<int> block_side_effects_; | 1205 ZoneList<int> block_side_effects_; |
| 1206 | 1206 |
| 1207 // A map of loop header block IDs to their loop's side effects. | 1207 // A map of loop header block IDs to their loop's side effects. |
| 1208 ZoneList<int> loop_side_effects_; | 1208 ZoneList<int> loop_side_effects_; |
| 1209 }; | 1209 }; |
| 1210 | 1210 |
| 1211 | 1211 |
| 1212 void HGlobalValueNumberer::Analyze() { | 1212 void HGlobalValueNumberer::Analyze() { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1293 // Move the instruction out of the loop. | 1293 // Move the instruction out of the loop. |
| 1294 instr->Unlink(); | 1294 instr->Unlink(); |
| 1295 instr->InsertBefore(pre_header->end()); | 1295 instr->InsertBefore(pre_header->end()); |
| 1296 } | 1296 } |
| 1297 } | 1297 } |
| 1298 instr = next; | 1298 instr = next; |
| 1299 } | 1299 } |
| 1300 } | 1300 } |
| 1301 | 1301 |
| 1302 | 1302 |
| 1303 bool HGlobalValueNumberer::AllowCodeMotion() { | |
| 1304 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; | |
| 1305 } | |
| 1306 | |
| 1307 | |
| 1303 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, | 1308 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, |
| 1304 HBasicBlock* loop_header) { | 1309 HBasicBlock* loop_header) { |
| 1305 // If we've disabled code motion, don't move any instructions. | 1310 // If we've disabled code motion, don't move any instructions. |
| 1306 if (!graph_->AllowCodeMotion()) return false; | 1311 if (!AllowCodeMotion()) return false; |
| 1307 | 1312 |
| 1308 // If --aggressive-loop-invariant-motion, move everything except change | 1313 // If --aggressive-loop-invariant-motion, move everything except change |
| 1309 // instructions. | 1314 // instructions. |
| 1310 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { | 1315 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { |
| 1311 return true; | 1316 return true; |
| 1312 } | 1317 } |
| 1313 | 1318 |
| 1314 // Otherwise only move instructions that postdominate the loop header | 1319 // Otherwise only move instructions that postdominate the loop header |
| 1315 // (i.e. are always executed inside the loop). This is to avoid | 1320 // (i.e. are always executed inside the loop). This is to avoid |
| 1316 // unnecessary deoptimizations assuming the loop is executed at least | 1321 // unnecessary deoptimizations assuming the loop is executed at least |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1841 ASSERT(visited.IsEmpty()); | 1846 ASSERT(visited.IsEmpty()); |
| 1842 PropagateMinusZeroChecks(change->value(), &visited); | 1847 PropagateMinusZeroChecks(change->value(), &visited); |
| 1843 visited.Clear(); | 1848 visited.Clear(); |
| 1844 } | 1849 } |
| 1845 } | 1850 } |
| 1846 } | 1851 } |
| 1847 } | 1852 } |
| 1848 } | 1853 } |
| 1849 | 1854 |
| 1850 | 1855 |
| 1856 // Implementation of utility class to encapsulate the translation state for | |
| 1857 // a (possibly inlined) function. | |
| 1858 FunctionState::FunctionState(HGraphBuilder* owner, | |
| 1859 CompilationInfo* info, | |
| 1860 TypeFeedbackOracle* oracle) | |
| 1861 : owner_(owner), | |
| 1862 compilation_info_(info), | |
| 1863 oracle_(oracle), | |
| 1864 call_context_(NULL), | |
| 1865 function_return_(NULL), | |
| 1866 test_context_(NULL), | |
| 1867 outer_(owner->function_state()) { | |
| 1868 if (outer_ != NULL) { | |
| 1869 // State for an inline function. | |
| 1870 if (owner->ast_context()->IsTest()) { | |
| 1871 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | |
| 1872 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | |
| 1873 if_true->MarkAsInlineReturnTarget(); | |
| 1874 if_false->MarkAsInlineReturnTarget(); | |
| 1875 // The AstContext constructor pushed on the context stack. This newed | |
| 1876 // instance is the reason that AstContext can't be BASE_EMBEDDED. | |
| 1877 test_context_ = new TestContext(owner, if_true, if_false); | |
| 1878 } else { | |
| 1879 function_return_ = owner->graph()->CreateBasicBlock(); | |
| 1880 function_return()->MarkAsInlineReturnTarget(); | |
| 1881 } | |
| 1882 // Set this after possibly allocating a new TestContext above. | |
| 1883 call_context_ = owner->ast_context(); | |
| 1884 } | |
| 1885 | |
| 1886 // Push on the state stack. | |
| 1887 owner->set_function_state(this); | |
| 1888 } | |
| 1889 | |
| 1890 | |
| 1891 FunctionState::~FunctionState() { | |
| 1892 delete test_context_; | |
| 1893 owner_->set_function_state(outer_); | |
| 1894 } | |
| 1895 | |
| 1896 | |
| 1851 // Implementation of utility classes to represent an expression's context in | 1897 // Implementation of utility classes to represent an expression's context in |
| 1852 // the AST. | 1898 // the AST. |
| 1853 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 1899 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
| 1854 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { | 1900 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { |
| 1855 owner->set_ast_context(this); // Push. | 1901 owner->set_ast_context(this); // Push. |
| 1856 #ifdef DEBUG | 1902 #ifdef DEBUG |
| 1857 original_length_ = owner->environment()->length(); | 1903 original_length_ = owner->environment()->length(); |
| 1858 #endif | 1904 #endif |
| 1859 } | 1905 } |
| 1860 | 1906 |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2011 | 2057 |
| 2012 private: | 2058 private: |
| 2013 HGraphBuilder* builder_; | 2059 HGraphBuilder* builder_; |
| 2014 HSubgraph* old_subgraph_; | 2060 HSubgraph* old_subgraph_; |
| 2015 HSubgraph* subgraph_; | 2061 HSubgraph* subgraph_; |
| 2016 }; | 2062 }; |
| 2017 | 2063 |
| 2018 | 2064 |
| 2019 void HGraphBuilder::Bailout(const char* reason) { | 2065 void HGraphBuilder::Bailout(const char* reason) { |
| 2020 if (FLAG_trace_bailout) { | 2066 if (FLAG_trace_bailout) { |
| 2021 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); | 2067 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); |
| 2022 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *debug_name, reason); | 2068 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason); |
| 2023 } | 2069 } |
| 2024 SetStackOverflow(); | 2070 SetStackOverflow(); |
| 2025 } | 2071 } |
| 2026 | 2072 |
| 2027 | 2073 |
| 2028 void HGraphBuilder::VisitForEffect(Expression* expr) { | 2074 void HGraphBuilder::VisitForEffect(Expression* expr) { |
| 2029 EffectContext for_effect(this); | 2075 EffectContext for_effect(this); |
| 2030 Visit(expr); | 2076 Visit(expr); |
| 2031 } | 2077 } |
| 2032 | 2078 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 2059 } | 2105 } |
| 2060 | 2106 |
| 2061 | 2107 |
| 2062 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { | 2108 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { |
| 2063 for (int i = 0; i < exprs->length(); ++i) { | 2109 for (int i = 0; i < exprs->length(); ++i) { |
| 2064 VISIT_FOR_VALUE(exprs->at(i)); | 2110 VISIT_FOR_VALUE(exprs->at(i)); |
| 2065 } | 2111 } |
| 2066 } | 2112 } |
| 2067 | 2113 |
| 2068 | 2114 |
| 2069 HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { | 2115 HGraph* HGraphBuilder::CreateGraph() { |
| 2070 ASSERT(subgraph() == NULL); | 2116 ASSERT(subgraph() == NULL); |
| 2071 graph_ = new HGraph(info); | 2117 graph_ = new HGraph(info()); |
| 2072 | 2118 |
| 2073 { | 2119 { |
| 2074 HPhase phase("Block building"); | 2120 HPhase phase("Block building"); |
| 2075 graph()->Initialize(CreateBasicBlock(graph()->start_environment())); | 2121 graph()->Initialize(CreateBasicBlock(graph()->start_environment())); |
| 2076 current_subgraph_ = graph(); | 2122 current_subgraph_ = graph(); |
| 2077 | 2123 |
| 2078 Scope* scope = info->scope(); | 2124 Scope* scope = info()->scope(); |
| 2079 if (scope->HasIllegalRedeclaration()) { | 2125 if (scope->HasIllegalRedeclaration()) { |
| 2080 Bailout("function with illegal redeclaration"); | 2126 Bailout("function with illegal redeclaration"); |
| 2081 return NULL; | 2127 return NULL; |
| 2082 } | 2128 } |
| 2083 SetupScope(scope); | 2129 SetupScope(scope); |
| 2084 VisitDeclarations(scope->declarations()); | 2130 VisitDeclarations(scope->declarations()); |
| 2085 AddInstruction(new HStackCheck()); | 2131 AddInstruction(new HStackCheck()); |
| 2086 | 2132 |
| 2087 // Add an edge to the body entry. This is warty: the graph's start | 2133 // Add an edge to the body entry. This is warty: the graph's start |
| 2088 // environment will be used by the Lithium translation as the initial | 2134 // environment will be used by the Lithium translation as the initial |
| 2089 // environment on graph entry, but it has now been mutated by the | 2135 // environment on graph entry, but it has now been mutated by the |
| 2090 // Hydrogen translation of the instructions in the start block. This | 2136 // Hydrogen translation of the instructions in the start block. This |
| 2091 // environment uses values which have not been defined yet. These | 2137 // environment uses values which have not been defined yet. These |
| 2092 // Hydrogen instructions will then be replayed by the Lithium | 2138 // Hydrogen instructions will then be replayed by the Lithium |
| 2093 // translation, so they cannot have an environment effect. The edge to | 2139 // translation, so they cannot have an environment effect. The edge to |
| 2094 // the body's entry block (along with some special logic for the start | 2140 // the body's entry block (along with some special logic for the start |
| 2095 // block in HInstruction::InsertAfter) seals the start block from | 2141 // block in HInstruction::InsertAfter) seals the start block from |
| 2096 // getting unwanted instructions inserted. | 2142 // getting unwanted instructions inserted. |
| 2097 // | 2143 // |
| 2098 // TODO(kmillikin): Fix this. Stop mutating the initial environment. | 2144 // TODO(kmillikin): Fix this. Stop mutating the initial environment. |
| 2099 // Make the Hydrogen instructions in the initial block into Hydrogen | 2145 // Make the Hydrogen instructions in the initial block into Hydrogen |
| 2100 // values (but not instructions), present in the initial environment and | 2146 // values (but not instructions), present in the initial environment and |
| 2101 // not replayed by the Lithium translation. | 2147 // not replayed by the Lithium translation. |
| 2102 HEnvironment* initial_env = environment()->CopyWithoutHistory(); | 2148 HEnvironment* initial_env = environment()->CopyWithoutHistory(); |
| 2103 HBasicBlock* body_entry = CreateBasicBlock(initial_env); | 2149 HBasicBlock* body_entry = CreateBasicBlock(initial_env); |
| 2104 current_block()->Goto(body_entry); | 2150 current_block()->Goto(body_entry); |
| 2105 body_entry->SetJoinId(info->function()->id()); | 2151 body_entry->SetJoinId(info()->function()->id()); |
| 2106 set_current_block(body_entry); | 2152 set_current_block(body_entry); |
| 2107 VisitStatements(info->function()->body()); | 2153 VisitStatements(info()->function()->body()); |
| 2108 if (HasStackOverflow()) return NULL; | 2154 if (HasStackOverflow()) return NULL; |
| 2109 | 2155 |
| 2110 if (current_block() != NULL) { | 2156 if (current_block() != NULL) { |
| 2111 HReturn* instr = new HReturn(graph()->GetConstantUndefined()); | 2157 HReturn* instr = new HReturn(graph()->GetConstantUndefined()); |
| 2112 current_block()->FinishExit(instr); | 2158 current_block()->FinishExit(instr); |
| 2113 set_current_block(NULL); | 2159 set_current_block(NULL); |
| 2114 } | 2160 } |
| 2115 } | 2161 } |
| 2116 | 2162 |
| 2117 graph()->OrderBlocks(); | 2163 graph()->OrderBlocks(); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 2135 graph()->InsertRepresentationChanges(); | 2181 graph()->InsertRepresentationChanges(); |
| 2136 graph()->ComputeMinusZeroChecks(); | 2182 graph()->ComputeMinusZeroChecks(); |
| 2137 | 2183 |
| 2138 // Eliminate redundant stack checks on backwards branches. | 2184 // Eliminate redundant stack checks on backwards branches. |
| 2139 HStackCheckEliminator sce(graph()); | 2185 HStackCheckEliminator sce(graph()); |
| 2140 sce.Process(); | 2186 sce.Process(); |
| 2141 | 2187 |
| 2142 // Perform common subexpression elimination and loop-invariant code motion. | 2188 // Perform common subexpression elimination and loop-invariant code motion. |
| 2143 if (FLAG_use_gvn) { | 2189 if (FLAG_use_gvn) { |
| 2144 HPhase phase("Global value numbering", graph()); | 2190 HPhase phase("Global value numbering", graph()); |
| 2145 HGlobalValueNumberer gvn(graph()); | 2191 HGlobalValueNumberer gvn(graph(), info()); |
| 2146 gvn.Analyze(); | 2192 gvn.Analyze(); |
| 2147 } | 2193 } |
| 2148 | 2194 |
| 2149 return graph(); | 2195 return graph(); |
| 2150 } | 2196 } |
| 2151 | 2197 |
| 2152 | 2198 |
| 2153 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) { | 2199 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) { |
| 2154 SubgraphScope scope(this, graph); | 2200 SubgraphScope scope(this, graph); |
| 2155 Visit(stmt); | 2201 Visit(stmt); |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2416 HValue* return_value = NULL; | 2462 HValue* return_value = NULL; |
| 2417 if (context->IsEffect()) { | 2463 if (context->IsEffect()) { |
| 2418 VISIT_FOR_EFFECT(stmt->expression()); | 2464 VISIT_FOR_EFFECT(stmt->expression()); |
| 2419 return_value = graph()->GetConstantUndefined(); | 2465 return_value = graph()->GetConstantUndefined(); |
| 2420 } else { | 2466 } else { |
| 2421 ASSERT(context->IsValue()); | 2467 ASSERT(context->IsValue()); |
| 2422 VISIT_FOR_VALUE(stmt->expression()); | 2468 VISIT_FOR_VALUE(stmt->expression()); |
| 2423 return_value = environment()->Pop(); | 2469 return_value = environment()->Pop(); |
| 2424 } | 2470 } |
| 2425 current_block()->AddLeaveInlined(return_value, | 2471 current_block()->AddLeaveInlined(return_value, |
| 2426 function_return_); | 2472 function_return()); |
| 2427 set_current_block(NULL); | 2473 set_current_block(NULL); |
| 2428 } | 2474 } |
| 2429 } | 2475 } |
| 2430 } | 2476 } |
| 2431 | 2477 |
| 2432 | 2478 |
| 2433 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | 2479 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { |
| 2434 BAILOUT("WithEnterStatement"); | 2480 BAILOUT("WithEnterStatement"); |
| 2435 } | 2481 } |
| 2436 | 2482 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2600 last_false_block->Finish(new HGoto(single_exit_block)); | 2646 last_false_block->Finish(new HGoto(single_exit_block)); |
| 2601 } | 2647 } |
| 2602 | 2648 |
| 2603 if (single_exit_block->HasPredecessor()) { | 2649 if (single_exit_block->HasPredecessor()) { |
| 2604 set_current_block(single_exit_block); | 2650 set_current_block(single_exit_block); |
| 2605 } else { | 2651 } else { |
| 2606 set_current_block(NULL); | 2652 set_current_block(NULL); |
| 2607 } | 2653 } |
| 2608 } | 2654 } |
| 2609 | 2655 |
| 2610 bool HGraph::HasOsrEntryAt(IterationStatement* statement) { | 2656 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { |
| 2611 return statement->OsrEntryId() == info()->osr_ast_id(); | 2657 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2612 } | 2658 } |
| 2613 | 2659 |
| 2614 | 2660 |
| 2615 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { | 2661 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { |
| 2616 if (!graph()->HasOsrEntryAt(statement)) return; | 2662 if (!HasOsrEntryAt(statement)) return; |
| 2617 | 2663 |
| 2618 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2664 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2619 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2665 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 2620 HValue* true_value = graph()->GetConstantTrue(); | 2666 HValue* true_value = graph()->GetConstantTrue(); |
| 2621 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); | 2667 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); |
| 2622 current_block()->Finish(test); | 2668 current_block()->Finish(test); |
| 2623 | 2669 |
| 2624 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2670 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2625 non_osr_entry->Goto(loop_predecessor); | 2671 non_osr_entry->Goto(loop_predecessor); |
| 2626 | 2672 |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2773 } | 2819 } |
| 2774 | 2820 |
| 2775 | 2821 |
| 2776 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | 2822 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 2777 BAILOUT("DebuggerStatement"); | 2823 BAILOUT("DebuggerStatement"); |
| 2778 } | 2824 } |
| 2779 | 2825 |
| 2780 | 2826 |
| 2781 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { | 2827 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 2782 Handle<SharedFunctionInfo> shared_info = | 2828 Handle<SharedFunctionInfo> shared_info = |
| 2783 Compiler::BuildFunctionInfo(expr, graph_->info()->script()); | 2829 Compiler::BuildFunctionInfo(expr, info()->script()); |
| 2784 CHECK_BAILOUT; | 2830 CHECK_BAILOUT; |
| 2785 HFunctionLiteral* instr = | 2831 HFunctionLiteral* instr = |
| 2786 new HFunctionLiteral(shared_info, expr->pretenure()); | 2832 new HFunctionLiteral(shared_info, expr->pretenure()); |
| 2787 ast_context()->ReturnInstruction(instr, expr->id()); | 2833 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2788 } | 2834 } |
| 2789 | 2835 |
| 2790 | 2836 |
| 2791 void HGraphBuilder::VisitSharedFunctionInfoLiteral( | 2837 void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
| 2792 SharedFunctionInfoLiteral* expr) { | 2838 SharedFunctionInfoLiteral* expr) { |
| 2793 BAILOUT("SharedFunctionInfoLiteral"); | 2839 BAILOUT("SharedFunctionInfoLiteral"); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 2815 ast_context()->ReturnValue(Pop()); | 2861 ast_context()->ReturnValue(Pop()); |
| 2816 } | 2862 } |
| 2817 | 2863 |
| 2818 | 2864 |
| 2819 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, | 2865 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
| 2820 LookupResult* lookup, | 2866 LookupResult* lookup, |
| 2821 bool is_store) { | 2867 bool is_store) { |
| 2822 if (var->is_this()) { | 2868 if (var->is_this()) { |
| 2823 BAILOUT("global this reference"); | 2869 BAILOUT("global this reference"); |
| 2824 } | 2870 } |
| 2825 if (!graph()->info()->has_global_object()) { | 2871 if (!info()->has_global_object()) { |
| 2826 BAILOUT("no global object to optimize VariableProxy"); | 2872 BAILOUT("no global object to optimize VariableProxy"); |
| 2827 } | 2873 } |
| 2828 Handle<GlobalObject> global(graph()->info()->global_object()); | 2874 Handle<GlobalObject> global(info()->global_object()); |
| 2829 global->Lookup(*var->name(), lookup); | 2875 global->Lookup(*var->name(), lookup); |
| 2830 if (!lookup->IsProperty()) { | 2876 if (!lookup->IsProperty()) { |
| 2831 BAILOUT("global variable cell not yet introduced"); | 2877 BAILOUT("global variable cell not yet introduced"); |
| 2832 } | 2878 } |
| 2833 if (lookup->type() != NORMAL) { | 2879 if (lookup->type() != NORMAL) { |
| 2834 BAILOUT("global variable has accessors"); | 2880 BAILOUT("global variable has accessors"); |
| 2835 } | 2881 } |
| 2836 if (is_store && lookup->IsReadOnly()) { | 2882 if (is_store && lookup->IsReadOnly()) { |
| 2837 BAILOUT("read-only global variable"); | 2883 BAILOUT("read-only global variable"); |
| 2838 } | 2884 } |
| 2839 if (lookup->holder() != *global) { | 2885 if (lookup->holder() != *global) { |
| 2840 BAILOUT("global property on prototype of global object"); | 2886 BAILOUT("global property on prototype of global object"); |
| 2841 } | 2887 } |
| 2842 } | 2888 } |
| 2843 | 2889 |
| 2844 | 2890 |
| 2845 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { | 2891 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { |
| 2846 ASSERT(var->IsContextSlot()); | 2892 ASSERT(var->IsContextSlot()); |
| 2847 HInstruction* context = new HContext; | 2893 HInstruction* context = new HContext; |
| 2848 AddInstruction(context); | 2894 AddInstruction(context); |
| 2849 int length = graph()->info()->scope()->ContextChainLength(var->scope()); | 2895 int length = info()->scope()->ContextChainLength(var->scope()); |
| 2850 while (length-- > 0) { | 2896 while (length-- > 0) { |
| 2851 context = new HOuterContext(context); | 2897 context = new HOuterContext(context); |
| 2852 AddInstruction(context); | 2898 AddInstruction(context); |
| 2853 } | 2899 } |
| 2854 return context; | 2900 return context; |
| 2855 } | 2901 } |
| 2856 | 2902 |
| 2857 | 2903 |
| 2858 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 2904 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2859 Variable* variable = expr->AsVariable(); | 2905 Variable* variable = expr->AsVariable(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2870 } | 2916 } |
| 2871 HValue* context = BuildContextChainWalk(variable); | 2917 HValue* context = BuildContextChainWalk(variable); |
| 2872 int index = variable->AsSlot()->index(); | 2918 int index = variable->AsSlot()->index(); |
| 2873 HLoadContextSlot* instr = new HLoadContextSlot(context, index); | 2919 HLoadContextSlot* instr = new HLoadContextSlot(context, index); |
| 2874 ast_context()->ReturnInstruction(instr, expr->id()); | 2920 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2875 } else if (variable->is_global()) { | 2921 } else if (variable->is_global()) { |
| 2876 LookupResult lookup; | 2922 LookupResult lookup; |
| 2877 LookupGlobalPropertyCell(variable, &lookup, false); | 2923 LookupGlobalPropertyCell(variable, &lookup, false); |
| 2878 CHECK_BAILOUT; | 2924 CHECK_BAILOUT; |
| 2879 | 2925 |
| 2880 Handle<GlobalObject> global(graph()->info()->global_object()); | 2926 Handle<GlobalObject> global(info()->global_object()); |
| 2881 // TODO(3039103): Handle global property load through an IC call when access | 2927 // TODO(3039103): Handle global property load through an IC call when access |
| 2882 // checks are enabled. | 2928 // checks are enabled. |
| 2883 if (global->IsAccessCheckNeeded()) { | 2929 if (global->IsAccessCheckNeeded()) { |
| 2884 BAILOUT("global object requires access check"); | 2930 BAILOUT("global object requires access check"); |
| 2885 } | 2931 } |
| 2886 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 2932 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 2887 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 2933 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 2888 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); | 2934 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); |
| 2889 ast_context()->ReturnInstruction(instr, expr->id()); | 2935 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2890 } else { | 2936 } else { |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3140 true) // Needs smi and map check. | 3186 true) // Needs smi and map check. |
| 3141 : BuildStoreNamedGeneric(object, name, value); | 3187 : BuildStoreNamedGeneric(object, name, value); |
| 3142 } | 3188 } |
| 3143 | 3189 |
| 3144 | 3190 |
| 3145 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, | 3191 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
| 3146 HValue* object, | 3192 HValue* object, |
| 3147 HValue* value, | 3193 HValue* value, |
| 3148 ZoneMapList* types, | 3194 ZoneMapList* types, |
| 3149 Handle<String> name) { | 3195 Handle<String> name) { |
| 3196 // TODO(ager): We should recognize when the prototype chains for different | |
| 3197 // maps are identical. In that case we can avoid repeatedly generating the | |
| 3198 // same prototype map checks. | |
| 3150 int count = 0; | 3199 int count = 0; |
| 3151 HBasicBlock* join = NULL; | 3200 HBasicBlock* join = NULL; |
| 3152 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | 3201 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
| 3153 Handle<Map> map = types->at(i); | 3202 Handle<Map> map = types->at(i); |
| 3154 LookupResult lookup; | 3203 LookupResult lookup; |
| 3155 if (ComputeStoredField(map, name, &lookup)) { | 3204 if (ComputeStoredField(map, name, &lookup)) { |
| 3156 ++count; | 3205 if (count == 0) { |
| 3157 if (join == NULL) { | |
| 3158 AddInstruction(new HCheckNonSmi(object)); // Only needed once. | 3206 AddInstruction(new HCheckNonSmi(object)); // Only needed once. |
| 3159 join = graph()->CreateBasicBlock(); | 3207 join = graph()->CreateBasicBlock(); |
| 3160 } | 3208 } |
| 3209 ++count; | |
| 3161 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 3210 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3162 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 3211 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3163 HCompareMap* compare = new HCompareMap(object, map, if_true, if_false); | 3212 HCompareMap* compare = new HCompareMap(object, map, if_true, if_false); |
| 3164 current_block()->Finish(compare); | 3213 current_block()->Finish(compare); |
| 3165 | 3214 |
| 3166 set_current_block(if_true); | 3215 set_current_block(if_true); |
| 3167 HInstruction* instr = | 3216 HInstruction* instr = |
| 3168 BuildStoreNamedField(object, name, value, map, &lookup, false); | 3217 BuildStoreNamedField(object, name, value, map, &lookup, false); |
| 3169 instr->set_position(expr->position()); | 3218 instr->set_position(expr->position()); |
| 3170 // Goto will add the HSimulate for the store. | 3219 // Goto will add the HSimulate for the store. |
| 3171 AddInstruction(instr); | 3220 AddInstruction(instr); |
| 3172 if (!ast_context()->IsEffect()) Push(value); | 3221 if (!ast_context()->IsEffect()) Push(value); |
| 3173 current_block()->Goto(join); | 3222 current_block()->Goto(join); |
| 3174 | 3223 |
| 3175 set_current_block(if_false); | 3224 set_current_block(if_false); |
| 3176 } | 3225 } |
| 3177 } | 3226 } |
| 3178 | 3227 |
| 3179 // Finish up. We need a generic IC if there were types we couldn't | 3228 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3180 // resolve statically or if we want to handle maps we've never seen. | 3229 // know about and do not want to handle ones we've never seen. Otherwise |
| 3181 if (count < types->length() || !FLAG_deoptimize_uncommon_cases) { | 3230 // use a generic IC. |
| 3231 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | |
|
fschneider
2011/03/07 11:29:47
Remove extra space.
| |
| 3232 current_block()->FinishExit(new HDeoptimize); | |
| 3233 } else { | |
| 3182 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3234 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3183 instr->set_position(expr->position()); | 3235 instr->set_position(expr->position()); |
| 3184 AddInstruction(instr); | 3236 AddInstruction(instr); |
| 3185 | 3237 |
| 3186 if (join == NULL) { | 3238 if (join != NULL) { |
| 3239 if (!ast_context()->IsEffect()) Push(value); | |
| 3240 current_block()->Goto(join); | |
| 3241 } else { | |
| 3187 // The HSimulate for the store should not see the stored value in | 3242 // The HSimulate for the store should not see the stored value in |
| 3188 // effect contexts (it is not materialized at expr->id() in the | 3243 // effect contexts (it is not materialized at expr->id() in the |
| 3189 // unoptimized code). | 3244 // unoptimized code). |
| 3190 if (instr->HasSideEffects()) { | 3245 if (instr->HasSideEffects()) { |
|
fschneider
2011/03/07 11:29:47
HasSideEffects() is always true for HStoreNamedGen
Kevin Millikin (Chromium)
2011/03/07 11:51:52
But this code shouldn't rely on assuming the type
| |
| 3191 if (ast_context()->IsEffect()) { | 3246 if (ast_context()->IsEffect()) { |
| 3192 AddSimulate(expr->id()); | 3247 AddSimulate(expr->id()); |
| 3193 } else { | 3248 } else { |
| 3194 Push(value); | 3249 Push(value); |
| 3195 AddSimulate(expr->id()); | 3250 AddSimulate(expr->id()); |
| 3196 Drop(1); | 3251 Drop(1); |
| 3197 } | 3252 } |
| 3198 } | 3253 } |
| 3199 ast_context()->ReturnValue(value); | 3254 ast_context()->ReturnValue(value); |
| 3200 } else { | 3255 return; |
| 3201 if (!ast_context()->IsEffect()) Push(value); | |
| 3202 current_block()->Goto(join); | |
| 3203 join->SetJoinId(expr->id()); | |
| 3204 set_current_block(join); | |
| 3205 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | |
| 3206 } | |
| 3207 | |
| 3208 } else { | |
| 3209 current_block()->FinishExit(new HDeoptimize); | |
| 3210 set_current_block(join); | |
| 3211 if (join != NULL) { | |
| 3212 join->SetJoinId(expr->id()); | |
| 3213 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | |
| 3214 } | 3256 } |
| 3215 } | 3257 } |
| 3258 | |
| 3259 ASSERT(join != NULL); | |
| 3260 join->SetJoinId(expr->id()); | |
| 3261 set_current_block(join); | |
| 3262 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | |
| 3216 } | 3263 } |
| 3217 | 3264 |
| 3218 | 3265 |
| 3219 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3266 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3220 Property* prop = expr->target()->AsProperty(); | 3267 Property* prop = expr->target()->AsProperty(); |
| 3221 ASSERT(prop != NULL); | 3268 ASSERT(prop != NULL); |
| 3222 expr->RecordTypeFeedback(oracle()); | 3269 expr->RecordTypeFeedback(oracle()); |
| 3223 VISIT_FOR_VALUE(prop->obj()); | 3270 VISIT_FOR_VALUE(prop->obj()); |
| 3224 | 3271 |
| 3225 HValue* value = NULL; | 3272 HValue* value = NULL; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3286 // owning expression instead of position and ast_id separately. | 3333 // owning expression instead of position and ast_id separately. |
| 3287 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, | 3334 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
| 3288 HValue* value, | 3335 HValue* value, |
| 3289 int position, | 3336 int position, |
| 3290 int ast_id) { | 3337 int ast_id) { |
| 3291 LookupResult lookup; | 3338 LookupResult lookup; |
| 3292 LookupGlobalPropertyCell(var, &lookup, true); | 3339 LookupGlobalPropertyCell(var, &lookup, true); |
| 3293 CHECK_BAILOUT; | 3340 CHECK_BAILOUT; |
| 3294 | 3341 |
| 3295 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3342 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 3296 Handle<GlobalObject> global(graph()->info()->global_object()); | 3343 Handle<GlobalObject> global(info()->global_object()); |
| 3297 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3344 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3298 HInstruction* instr = new HStoreGlobal(value, cell, check_hole); | 3345 HInstruction* instr = new HStoreGlobal(value, cell, check_hole); |
| 3299 instr->set_position(position); | 3346 instr->set_position(position); |
| 3300 AddInstruction(instr); | 3347 AddInstruction(instr); |
| 3301 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3348 if (instr->HasSideEffects()) AddSimulate(ast_id); |
| 3302 } | 3349 } |
| 3303 | 3350 |
| 3304 | 3351 |
| 3305 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3352 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
| 3306 Expression* target = expr->target(); | 3353 Expression* target = expr->target(); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3484 AddSimulate(expr->id()); | 3531 AddSimulate(expr->id()); |
| 3485 current_block()->FinishExit(new HAbnormalExit); | 3532 current_block()->FinishExit(new HAbnormalExit); |
| 3486 set_current_block(NULL); | 3533 set_current_block(NULL); |
| 3487 } | 3534 } |
| 3488 | 3535 |
| 3489 | 3536 |
| 3490 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3537 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
| 3491 HValue* object, | 3538 HValue* object, |
| 3492 ZoneMapList* types, | 3539 ZoneMapList* types, |
| 3493 Handle<String> name) { | 3540 Handle<String> name) { |
| 3494 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); | 3541 // TODO(ager): We should recognize when the prototype chains for different |
| 3495 ZoneMapList maps(number_of_types); | 3542 // maps are identical. In that case we can avoid repeatedly generating the |
| 3496 ZoneList<HSubgraph*> subgraphs(number_of_types); | 3543 // same prototype map checks. |
| 3497 bool needs_generic = (types->length() > kMaxLoadPolymorphism); | 3544 int count = 0; |
| 3498 | 3545 HBasicBlock* join = NULL; |
| 3499 // Build subgraphs for each of the specific maps. | 3546 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 3500 // | |
| 3501 // TODO(ager): We should recognize when the prototype chains for | |
| 3502 // different maps are identical. In that case we can avoid | |
| 3503 // repeatedly generating the same prototype map checks. | |
| 3504 for (int i = 0; i < number_of_types; ++i) { | |
| 3505 Handle<Map> map = types->at(i); | 3547 Handle<Map> map = types->at(i); |
| 3506 LookupResult lookup; | 3548 LookupResult lookup; |
| 3507 map->LookupInDescriptors(NULL, *name, &lookup); | 3549 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3508 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3550 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3509 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3551 if (count == 0) { |
| 3510 SubgraphScope scope(this, subgraph); | 3552 AddInstruction(new HCheckNonSmi(object)); // Only needed once. |
| 3553 join = graph()->CreateBasicBlock(); | |
| 3554 } | |
| 3555 ++count; | |
| 3556 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
| 3557 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
| 3558 HCompareMap* compare = new HCompareMap(object, map, if_true, if_false); | |
| 3559 current_block()->Finish(compare); | |
| 3560 | |
| 3561 set_current_block(if_true); | |
| 3511 HLoadNamedField* instr = | 3562 HLoadNamedField* instr = |
| 3512 BuildLoadNamedField(object, expr, map, &lookup, false); | 3563 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3513 instr->set_position(expr->position()); | 3564 instr->set_position(expr->position()); |
| 3514 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. | 3565 instr->ClearFlag(HValue::kUseGVN); |
| 3515 PushAndAdd(instr); | 3566 AddInstruction(instr); |
| 3516 maps.Add(map); | 3567 if (!ast_context()->IsEffect()) Push(instr); |
| 3517 subgraphs.Add(subgraph); | 3568 current_block()->Goto(join); |
| 3569 | |
| 3570 set_current_block(if_false); | |
| 3571 } | |
|
fschneider
2011/03/07 11:29:47
Remove extra space.
Kevin Millikin (Chromium)
2011/03/07 11:51:52
Thanks.
| |
| 3572 } | |
| 3573 | |
| 3574 // Finish up. Unconditionally deoptimize if we've handled all the maps we | |
| 3575 // know about and do not want to handle ones we've never seen. Otherwise | |
| 3576 // use a generic IC. | |
| 3577 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | |
| 3578 current_block()->FinishExit(new HDeoptimize); | |
| 3579 } else { | |
| 3580 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | |
| 3581 instr->set_position(expr->position()); | |
| 3582 | |
| 3583 if (join != NULL) { | |
| 3584 AddInstruction(instr); | |
| 3585 if (!ast_context()->IsEffect()) Push(instr); | |
| 3586 current_block()->Goto(join); | |
| 3518 } else { | 3587 } else { |
| 3519 needs_generic = true; | 3588 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3589 return; | |
| 3520 } | 3590 } |
| 3521 } | 3591 } |
| 3522 | 3592 |
| 3523 // If none of the properties were named fields we generate a | 3593 ASSERT(join != NULL); |
| 3524 // generic load. | 3594 join->SetJoinId(expr->id()); |
| 3525 if (maps.length() == 0) { | 3595 set_current_block(join); |
| 3526 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3596 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 3527 instr->set_position(expr->position()); | |
| 3528 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 3529 } else { | |
| 3530 // Build subgraph for generic load through IC. | |
| 3531 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | |
| 3532 { SubgraphScope scope(this, default_graph); | |
| 3533 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3534 default_graph->exit_block()->FinishExit(new HDeoptimize()); | |
| 3535 default_graph->set_exit_block(NULL); | |
| 3536 } else { | |
| 3537 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | |
| 3538 instr->set_position(expr->position()); | |
| 3539 PushAndAdd(instr); | |
| 3540 } | |
| 3541 } | |
| 3542 | |
| 3543 HBasicBlock* new_exit_block = | |
| 3544 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); | |
| 3545 set_current_block(new_exit_block); | |
| 3546 // In an effect context, we did not materialized the value in the | |
| 3547 // predecessor environments so there's no need to handle it here. | |
| 3548 if (current_block() != NULL && !ast_context()->IsEffect()) { | |
| 3549 ast_context()->ReturnValue(Pop()); | |
| 3550 } | |
| 3551 } | |
| 3552 } | 3597 } |
| 3553 | 3598 |
| 3554 | 3599 |
| 3555 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3600 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3556 Property* expr, | 3601 Property* expr, |
| 3557 Handle<Map> type, | 3602 Handle<Map> type, |
| 3558 LookupResult* lookup, | 3603 LookupResult* lookup, |
| 3559 bool smi_and_map_check) { | 3604 bool smi_and_map_check) { |
| 3560 if (smi_and_map_check) { | 3605 if (smi_and_map_check) { |
| 3561 AddInstruction(new HCheckNonSmi(object)); | 3606 AddInstruction(new HCheckNonSmi(object)); |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3909 set_current_block(new_exit_block); | 3954 set_current_block(new_exit_block); |
| 3910 // In an effect context, we did not materialized the value in the | 3955 // In an effect context, we did not materialized the value in the |
| 3911 // predecessor environments so there's no need to handle it here. | 3956 // predecessor environments so there's no need to handle it here. |
| 3912 if (new_exit_block != NULL && !ast_context()->IsEffect()) { | 3957 if (new_exit_block != NULL && !ast_context()->IsEffect()) { |
| 3913 ast_context()->ReturnValue(Pop()); | 3958 ast_context()->ReturnValue(Pop()); |
| 3914 } | 3959 } |
| 3915 } | 3960 } |
| 3916 } | 3961 } |
| 3917 | 3962 |
| 3918 | 3963 |
| 3919 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | 3964 void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) { |
| 3920 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); | 3965 if (FLAG_trace_inlining) { |
| 3921 SmartPointer<char> caller = | 3966 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); |
| 3922 graph()->info()->function()->debug_name()->ToCString(); | 3967 SmartPointer<char> caller = |
| 3923 if (result) { | 3968 info()->function()->debug_name()->ToCString(); |
| 3924 PrintF("Inlined %s called from %s.\n", *callee, *caller); | 3969 if (reason == NULL) { |
| 3925 } else { | 3970 PrintF("Inlined %s called from %s.\n", *callee, *caller); |
| 3926 PrintF("Do not inline %s called from %s.\n", *callee, *caller); | 3971 } else { |
| 3972 PrintF("Did not inline %s called from %s (%s).\n", | |
| 3973 *callee, *caller, reason); | |
| 3974 } | |
| 3927 } | 3975 } |
| 3928 } | 3976 } |
| 3929 | 3977 |
| 3930 | 3978 |
| 3931 bool HGraphBuilder::TryInline(Call* expr) { | 3979 bool HGraphBuilder::TryInline(Call* expr) { |
| 3932 if (!FLAG_use_inlining) return false; | 3980 if (!FLAG_use_inlining) return false; |
| 3933 | 3981 |
| 3934 // Precondition: call is monomorphic and we have found a target with the | 3982 // Precondition: call is monomorphic and we have found a target with the |
| 3935 // appropriate arity. | 3983 // appropriate arity. |
| 3936 Handle<JSFunction> target = expr->target(); | 3984 Handle<JSFunction> target = expr->target(); |
| 3937 | 3985 |
| 3938 // Do a quick check on source code length to avoid parsing large | 3986 // Do a quick check on source code length to avoid parsing large |
| 3939 // inlining candidates. | 3987 // inlining candidates. |
| 3940 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { | 3988 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { |
| 3941 if (FLAG_trace_inlining) TraceInline(target, false); | 3989 TraceInline(target, "target text too big"); |
| 3942 return false; | 3990 return false; |
| 3943 } | 3991 } |
| 3944 | 3992 |
| 3945 // Target must be inlineable. | 3993 // Target must be inlineable. |
| 3946 if (!target->IsInlineable()) return false; | 3994 if (!target->IsInlineable()) { |
| 3995 TraceInline(target, "target not inlineable"); | |
| 3996 return false; | |
| 3997 } | |
| 3947 | 3998 |
| 3948 // No context change required. | 3999 // No context change required. |
| 3949 CompilationInfo* outer_info = graph()->info(); | 4000 CompilationInfo* outer_info = info(); |
| 3950 if (target->context() != outer_info->closure()->context() || | 4001 if (target->context() != outer_info->closure()->context() || |
| 3951 outer_info->scope()->contains_with() || | 4002 outer_info->scope()->contains_with() || |
| 3952 outer_info->scope()->num_heap_slots() > 0) { | 4003 outer_info->scope()->num_heap_slots() > 0) { |
| 4004 TraceInline(target, "target requires context change"); | |
| 3953 return false; | 4005 return false; |
| 3954 } | 4006 } |
| 3955 | 4007 |
| 3956 // Don't inline deeper than two calls. | 4008 // Don't inline deeper than two calls. |
| 3957 HEnvironment* env = environment(); | 4009 HEnvironment* env = environment(); |
| 3958 if (env->outer() != NULL && env->outer()->outer() != NULL) return false; | 4010 if (env->outer() != NULL && env->outer()->outer() != NULL) { |
| 4011 TraceInline(target, "inline depth limit reached"); | |
| 4012 return false; | |
| 4013 } | |
| 3959 | 4014 |
| 3960 // Don't inline recursive functions. | 4015 // Don't inline recursive functions. |
| 3961 if (target->shared() == outer_info->closure()->shared()) return false; | 4016 if (target->shared() == outer_info->closure()->shared()) { |
| 4017 TraceInline(target, "target is recursive"); | |
| 4018 return false; | |
| 4019 } | |
| 3962 | 4020 |
| 3963 // We don't want to add more than a certain number of nodes from inlining. | 4021 // We don't want to add more than a certain number of nodes from inlining. |
| 3964 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { | 4022 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { |
| 3965 if (FLAG_trace_inlining) TraceInline(target, false); | 4023 TraceInline(target, "cumulative AST node limit reached"); |
| 3966 return false; | 4024 return false; |
| 3967 } | 4025 } |
| 3968 | 4026 |
| 3969 int count_before = AstNode::Count(); | 4027 int count_before = AstNode::Count(); |
| 3970 | 4028 |
| 3971 // Parse and allocate variables. | 4029 // Parse and allocate variables. |
| 3972 CompilationInfo inner_info(target); | 4030 CompilationInfo target_info(target); |
| 3973 if (!ParserApi::Parse(&inner_info) || | 4031 if (!ParserApi::Parse(&target_info) || |
| 3974 !Scope::Analyze(&inner_info)) { | 4032 !Scope::Analyze(&target_info)) { |
| 3975 if (Top::has_pending_exception()) { | 4033 if (Top::has_pending_exception()) { |
| 4034 // Parse or scope error, never optimize this function. | |
| 3976 SetStackOverflow(); | 4035 SetStackOverflow(); |
| 3977 // Stop trying to optimize and inline this function. | |
| 3978 target->shared()->set_optimization_disabled(true); | 4036 target->shared()->set_optimization_disabled(true); |
| 3979 } | 4037 } |
| 4038 TraceInline(target, "parse failure"); | |
| 3980 return false; | 4039 return false; |
| 3981 } | 4040 } |
| 3982 if (inner_info.scope()->num_heap_slots() > 0) return false; | 4041 |
| 3983 FunctionLiteral* function = inner_info.function(); | 4042 if (target_info.scope()->num_heap_slots() > 0) { |
| 4043 TraceInline(target, "target has context-allocated variables"); | |
| 4044 return false; | |
| 4045 } | |
| 4046 FunctionLiteral* function = target_info.function(); | |
| 3984 | 4047 |
| 3985 // Count the number of AST nodes added by inlining this call. | 4048 // Count the number of AST nodes added by inlining this call. |
| 3986 int nodes_added = AstNode::Count() - count_before; | 4049 int nodes_added = AstNode::Count() - count_before; |
| 3987 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | 4050 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { |
| 3988 if (FLAG_trace_inlining) TraceInline(target, false); | 4051 TraceInline(target, "target AST is too large"); |
| 3989 return false; | 4052 return false; |
| 3990 } | 4053 } |
| 3991 | 4054 |
| 3992 // Check if we can handle all declarations in the inlined functions. | 4055 // Check if we can handle all declarations in the inlined functions. |
| 3993 VisitDeclarations(inner_info.scope()->declarations()); | 4056 VisitDeclarations(target_info.scope()->declarations()); |
| 3994 if (HasStackOverflow()) { | 4057 if (HasStackOverflow()) { |
| 4058 TraceInline(target, "target has non-trivial declaration"); | |
| 3995 ClearStackOverflow(); | 4059 ClearStackOverflow(); |
| 3996 return false; | 4060 return false; |
| 3997 } | 4061 } |
| 3998 | 4062 |
| 3999 // Don't inline functions that uses the arguments object or that | 4063 // Don't inline functions that uses the arguments object or that |
| 4000 // have a mismatching number of parameters. | 4064 // have a mismatching number of parameters. |
| 4001 Handle<SharedFunctionInfo> shared(target->shared()); | 4065 Handle<SharedFunctionInfo> target_shared(target->shared()); |
| 4002 int arity = expr->arguments()->length(); | 4066 int arity = expr->arguments()->length(); |
| 4003 if (function->scope()->arguments() != NULL || | 4067 if (function->scope()->arguments() != NULL || |
| 4004 arity != shared->formal_parameter_count()) { | 4068 arity != target_shared->formal_parameter_count()) { |
| 4069 TraceInline(target, "target requires special argument handling"); | |
| 4005 return false; | 4070 return false; |
| 4006 } | 4071 } |
| 4007 | 4072 |
| 4008 // All statements in the body must be inlineable. | 4073 // All statements in the body must be inlineable. |
| 4009 for (int i = 0, count = function->body()->length(); i < count; ++i) { | 4074 for (int i = 0, count = function->body()->length(); i < count; ++i) { |
| 4010 if (!function->body()->at(i)->IsInlineable()) return false; | 4075 if (!function->body()->at(i)->IsInlineable()) { |
| 4076 TraceInline(target, "target contains unsupported syntax"); | |
| 4077 return false; | |
| 4078 } | |
| 4011 } | 4079 } |
| 4012 | 4080 |
| 4013 // Generate the deoptimization data for the unoptimized version of | 4081 // Generate the deoptimization data for the unoptimized version of |
| 4014 // the target function if we don't already have it. | 4082 // the target function if we don't already have it. |
| 4015 if (!shared->has_deoptimization_support()) { | 4083 if (!target_shared->has_deoptimization_support()) { |
| 4016 // Note that we compile here using the same AST that we will use for | 4084 // Note that we compile here using the same AST that we will use for |
| 4017 // generating the optimized inline code. | 4085 // generating the optimized inline code. |
| 4018 inner_info.EnableDeoptimizationSupport(); | 4086 target_info.EnableDeoptimizationSupport(); |
| 4019 if (!FullCodeGenerator::MakeCode(&inner_info)) return false; | 4087 if (!FullCodeGenerator::MakeCode(&target_info)) { |
| 4020 shared->EnableDeoptimizationSupport(*inner_info.code()); | 4088 TraceInline(target, "could not generate deoptimization info"); |
| 4021 Compiler::RecordFunctionCompilation( | 4089 return false; |
| 4022 Logger::FUNCTION_TAG, &inner_info, shared); | 4090 } |
| 4091 target_shared->EnableDeoptimizationSupport(*target_info.code()); | |
| 4092 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, | |
| 4093 &target_info, | |
| 4094 target_shared); | |
| 4023 } | 4095 } |
| 4024 | 4096 |
| 4097 // ---------------------------------------------------------------- | |
| 4025 // Save the pending call context and type feedback oracle. Set up new ones | 4098 // Save the pending call context and type feedback oracle. Set up new ones |
| 4026 // for the inlined function. | 4099 // for the inlined function. |
| 4027 ASSERT(shared->has_deoptimization_support()); | 4100 ASSERT(target_shared->has_deoptimization_support()); |
| 4028 AstContext* saved_call_context = call_context(); | 4101 TypeFeedbackOracle target_oracle( |
| 4029 HBasicBlock* saved_function_return = function_return(); | 4102 Handle<Code>(target_shared->code()), |
| 4030 TypeFeedbackOracle* saved_oracle = oracle(); | |
| 4031 // On-stack replacement cannot target inlined functions. Since we don't | |
| 4032 // use a separate CompilationInfo structure for the inlined function, we | |
| 4033 // save and restore the AST ID in the original compilation info. | |
| 4034 int saved_osr_ast_id = graph()->info()->osr_ast_id(); | |
| 4035 | |
| 4036 TestContext* test_context = NULL; | |
| 4037 if (ast_context()->IsTest()) { | |
| 4038 // Inlined body is treated as if it occurs in an 'inlined' call context | |
| 4039 // with true and false blocks that will forward to the real ones. | |
| 4040 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
| 4041 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
| 4042 if_true->MarkAsInlineReturnTarget(); | |
| 4043 if_false->MarkAsInlineReturnTarget(); | |
| 4044 // AstContext constructor pushes on the context stack. | |
| 4045 test_context = new TestContext(this, if_true, if_false); | |
| 4046 function_return_ = NULL; | |
| 4047 } else { | |
| 4048 // Inlined body is treated as if it occurs in the original call context. | |
| 4049 function_return_ = graph()->CreateBasicBlock(); | |
| 4050 function_return_->MarkAsInlineReturnTarget(); | |
| 4051 } | |
| 4052 call_context_ = ast_context(); | |
| 4053 TypeFeedbackOracle new_oracle( | |
| 4054 Handle<Code>(shared->code()), | |
| 4055 Handle<Context>(target->context()->global_context())); | 4103 Handle<Context>(target->context()->global_context())); |
| 4056 oracle_ = &new_oracle; | 4104 FunctionState target_state(this, &target_info, &target_oracle); |
| 4057 graph()->info()->SetOsrAstId(AstNode::kNoNumber); | |
| 4058 | 4105 |
| 4059 HSubgraph* body = CreateInlinedSubgraph(env, target, function); | 4106 HSubgraph* body = CreateInlinedSubgraph(env, target, function); |
| 4060 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); | 4107 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); |
| 4061 AddToSubgraph(body, function->body()); | 4108 AddToSubgraph(body, function->body()); |
| 4062 if (HasStackOverflow()) { | 4109 if (HasStackOverflow()) { |
| 4063 // Bail out if the inline function did, as we cannot residualize a call | 4110 // Bail out if the inline function did, as we cannot residualize a call |
| 4064 // instead. | 4111 // instead. |
| 4065 delete test_context; | 4112 TraceInline(target, "inline graph construction failed"); |
| 4066 call_context_ = saved_call_context; | |
| 4067 function_return_ = saved_function_return; | |
| 4068 oracle_ = saved_oracle; | |
| 4069 graph()->info()->SetOsrAstId(saved_osr_ast_id); | |
| 4070 return false; | 4113 return false; |
| 4071 } | 4114 } |
| 4072 | 4115 |
| 4073 // Update inlined nodes count. | 4116 // Update inlined nodes count. |
| 4074 inlined_count_ += nodes_added; | 4117 inlined_count_ += nodes_added; |
| 4075 | 4118 |
| 4076 if (FLAG_trace_inlining) TraceInline(target, true); | 4119 TraceInline(target, NULL); |
| 4077 | 4120 |
| 4078 if (body->exit_block() != NULL) { | 4121 if (body->exit_block() != NULL) { |
| 4079 // Add a return of undefined if control can fall off the body. In a | 4122 // Add a return of undefined if control can fall off the body. In a |
| 4080 // test context, undefined is false. | 4123 // test context, undefined is false. |
| 4081 HValue* return_value = graph()->GetConstantUndefined(); | 4124 HValue* return_value = graph()->GetConstantUndefined(); |
| 4082 if (test_context == NULL) { | 4125 if (inlined_test_context() == NULL) { |
| 4083 ASSERT(function_return_ != NULL); | 4126 ASSERT(function_return() != NULL); |
| 4084 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4127 body->exit_block()->AddLeaveInlined(return_value, function_return()); |
| 4085 } else { | 4128 } else { |
| 4086 // The graph builder assumes control can reach both branches of a | 4129 // The graph builder assumes control can reach both branches of a |
| 4087 // test, so we materialize the undefined value and test it rather than | 4130 // test, so we materialize the undefined value and test it rather than |
| 4088 // simply jumping to the false target. | 4131 // simply jumping to the false target. |
| 4089 // | 4132 // |
| 4090 // TODO(3168478): refactor to avoid this. | 4133 // TODO(3168478): refactor to avoid this. |
| 4091 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4134 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 4092 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4135 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 4093 HTest* test = new HTest(return_value, empty_true, empty_false); | 4136 HTest* test = new HTest(return_value, empty_true, empty_false); |
| 4094 body->exit_block()->Finish(test); | 4137 body->exit_block()->Finish(test); |
| 4095 | 4138 |
| 4096 HValue* const no_return_value = NULL; | 4139 HValue* const no_return_value = NULL; |
| 4097 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); | 4140 empty_true->AddLeaveInlined(no_return_value, |
| 4098 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); | 4141 inlined_test_context()->if_true()); |
| 4142 empty_false->AddLeaveInlined(no_return_value, | |
| 4143 inlined_test_context()->if_false()); | |
| 4099 } | 4144 } |
| 4100 body->set_exit_block(NULL); | 4145 body->set_exit_block(NULL); |
| 4101 } | 4146 } |
| 4102 | 4147 |
| 4103 // Record the environment at the inlined function call. | 4148 // Record the environment at the inlined function call. |
| 4104 AddSimulate(expr->ReturnId()); | 4149 AddSimulate(expr->ReturnId()); |
| 4105 | 4150 |
| 4106 // Jump to the function entry (without re-recording the environment). | 4151 // Jump to the function entry (without re-recording the environment). |
| 4107 current_block()->Finish(new HGoto(body->entry_block())); | 4152 current_block()->Finish(new HGoto(body->entry_block())); |
| 4108 | 4153 |
| 4109 // Fix up the function exits. | 4154 // Fix up the function exits. |
| 4110 if (test_context != NULL) { | 4155 if (inlined_test_context() != NULL) { |
| 4111 HBasicBlock* if_true = test_context->if_true(); | 4156 HBasicBlock* if_true = inlined_test_context()->if_true(); |
| 4112 HBasicBlock* if_false = test_context->if_false(); | 4157 HBasicBlock* if_false = inlined_test_context()->if_false(); |
| 4113 if_true->SetJoinId(expr->id()); | 4158 if_true->SetJoinId(expr->id()); |
| 4114 if_false->SetJoinId(expr->id()); | 4159 if_false->SetJoinId(expr->id()); |
| 4115 ASSERT(ast_context() == test_context); | 4160 ASSERT(ast_context() == inlined_test_context()); |
| 4116 delete test_context; // Destructor pops from expression context stack. | 4161 // Pop the return test context from the expression context stack. |
| 4162 ClearInlinedTestContext(); | |
| 4117 | 4163 |
| 4118 // Forward to the real test context. | 4164 // Forward to the real test context. |
| 4119 HValue* const no_return_value = NULL; | 4165 HValue* const no_return_value = NULL; |
| 4120 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4166 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 4121 if (true_target->IsInlineReturnTarget()) { | 4167 if (true_target->IsInlineReturnTarget()) { |
| 4122 if_true->AddLeaveInlined(no_return_value, true_target); | 4168 if_true->AddLeaveInlined(no_return_value, true_target); |
| 4123 } else { | 4169 } else { |
| 4124 if_true->Goto(true_target); | 4170 if_true->Goto(true_target); |
| 4125 } | 4171 } |
| 4126 | 4172 |
| 4127 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4173 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 4128 if (false_target->IsInlineReturnTarget()) { | 4174 if (false_target->IsInlineReturnTarget()) { |
| 4129 if_false->AddLeaveInlined(no_return_value, false_target); | 4175 if_false->AddLeaveInlined(no_return_value, false_target); |
| 4130 } else { | 4176 } else { |
| 4131 if_false->Goto(false_target); | 4177 if_false->Goto(false_target); |
| 4132 } | 4178 } |
| 4133 | 4179 |
| 4134 // TODO(kmillikin): Come up with a better way to handle this. It is too | 4180 // TODO(kmillikin): Come up with a better way to handle this. It is too |
| 4135 // subtle. NULL here indicates that the enclosing context has no control | 4181 // subtle. NULL here indicates that the enclosing context has no control |
| 4136 // flow to handle. | 4182 // flow to handle. |
| 4137 set_current_block(NULL); | 4183 set_current_block(NULL); |
| 4138 | 4184 |
| 4139 } else { | 4185 } else { |
| 4140 function_return_->SetJoinId(expr->id()); | 4186 function_return()->SetJoinId(expr->id()); |
| 4141 set_current_block(function_return_); | 4187 set_current_block(function_return()); |
| 4142 } | 4188 } |
| 4143 | 4189 |
| 4144 call_context_ = saved_call_context; | |
| 4145 function_return_ = saved_function_return; | |
| 4146 oracle_ = saved_oracle; | |
| 4147 graph()->info()->SetOsrAstId(saved_osr_ast_id); | |
| 4148 | |
| 4149 return true; | 4190 return true; |
| 4150 } | 4191 } |
| 4151 | 4192 |
| 4152 | 4193 |
| 4153 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4194 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4154 ASSERT(target->IsInlineReturnTarget()); | 4195 ASSERT(target->IsInlineReturnTarget()); |
| 4155 AddInstruction(new HLeaveInlined); | 4196 AddInstruction(new HLeaveInlined); |
| 4156 HEnvironment* outer = last_environment()->outer(); | 4197 HEnvironment* outer = last_environment()->outer(); |
| 4157 if (return_value != NULL) outer->Push(return_value); | 4198 if (return_value != NULL) outer->Push(return_value); |
| 4158 UpdateEnvironment(outer); | 4199 UpdateEnvironment(outer); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4246 } | 4287 } |
| 4247 return false; | 4288 return false; |
| 4248 } | 4289 } |
| 4249 | 4290 |
| 4250 | 4291 |
| 4251 bool HGraphBuilder::TryCallApply(Call* expr) { | 4292 bool HGraphBuilder::TryCallApply(Call* expr) { |
| 4252 Expression* callee = expr->expression(); | 4293 Expression* callee = expr->expression(); |
| 4253 Property* prop = callee->AsProperty(); | 4294 Property* prop = callee->AsProperty(); |
| 4254 ASSERT(prop != NULL); | 4295 ASSERT(prop != NULL); |
| 4255 | 4296 |
| 4256 if (graph()->info()->scope()->arguments() == NULL) return false; | 4297 if (info()->scope()->arguments() == NULL) return false; |
| 4257 | 4298 |
| 4258 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4299 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4259 if (!name->IsEqualTo(CStrVector("apply"))) return false; | 4300 if (!name->IsEqualTo(CStrVector("apply"))) return false; |
| 4260 | 4301 |
| 4261 ZoneList<Expression*>* args = expr->arguments(); | 4302 ZoneList<Expression*>* args = expr->arguments(); |
| 4262 if (args->length() != 2) return false; | 4303 if (args->length() != 2) return false; |
| 4263 | 4304 |
| 4264 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 4305 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 4265 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 4306 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 4266 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 4307 HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4402 | 4443 |
| 4403 if (!global_call) { | 4444 if (!global_call) { |
| 4404 ++argument_count; | 4445 ++argument_count; |
| 4405 VISIT_FOR_VALUE(expr->expression()); | 4446 VISIT_FOR_VALUE(expr->expression()); |
| 4406 } | 4447 } |
| 4407 | 4448 |
| 4408 if (global_call) { | 4449 if (global_call) { |
| 4409 // If there is a global property cell for the name at compile time and | 4450 // If there is a global property cell for the name at compile time and |
| 4410 // access check is not enabled we assume that the function will not change | 4451 // access check is not enabled we assume that the function will not change |
| 4411 // and generate optimized code for calling the function. | 4452 // and generate optimized code for calling the function. |
| 4412 CompilationInfo* info = graph()->info(); | 4453 bool known_global_function = info()->has_global_object() && |
| 4413 bool known_global_function = info->has_global_object() && | 4454 !info()->global_object()->IsAccessCheckNeeded() && |
| 4414 !info->global_object()->IsAccessCheckNeeded() && | 4455 expr->ComputeGlobalTarget(Handle<GlobalObject>(info()->global_object() ), |
| 4415 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), | |
| 4416 var->name()); | 4456 var->name()); |
| 4417 if (known_global_function) { | 4457 if (known_global_function) { |
| 4418 // Push the global object instead of the global receiver because | 4458 // Push the global object instead of the global receiver because |
| 4419 // code generated by the full code generator expects it. | 4459 // code generated by the full code generator expects it. |
| 4420 HContext* context = new HContext; | 4460 HContext* context = new HContext; |
| 4421 HGlobalObject* global_object = new HGlobalObject(context); | 4461 HGlobalObject* global_object = new HGlobalObject(context); |
| 4422 AddInstruction(context); | 4462 AddInstruction(context); |
| 4423 PushAndAdd(global_object); | 4463 PushAndAdd(global_object); |
| 4424 VisitExpressions(expr->arguments()); | 4464 VisitExpressions(expr->arguments()); |
| 4425 CHECK_BAILOUT; | 4465 CHECK_BAILOUT; |
| (...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5035 return; | 5075 return; |
| 5036 } | 5076 } |
| 5037 | 5077 |
| 5038 VISIT_FOR_VALUE(expr->left()); | 5078 VISIT_FOR_VALUE(expr->left()); |
| 5039 VISIT_FOR_VALUE(expr->right()); | 5079 VISIT_FOR_VALUE(expr->right()); |
| 5040 | 5080 |
| 5041 HValue* right = Pop(); | 5081 HValue* right = Pop(); |
| 5042 HValue* left = Pop(); | 5082 HValue* left = Pop(); |
| 5043 Token::Value op = expr->op(); | 5083 Token::Value op = expr->op(); |
| 5044 | 5084 |
| 5045 TypeInfo info = oracle()->CompareType(expr); | 5085 TypeInfo type_info = oracle()->CompareType(expr); |
| 5046 HInstruction* instr = NULL; | 5086 HInstruction* instr = NULL; |
| 5047 if (op == Token::INSTANCEOF) { | 5087 if (op == Token::INSTANCEOF) { |
| 5048 // Check to see if the rhs of the instanceof is a global function not | 5088 // Check to see if the rhs of the instanceof is a global function not |
| 5049 // residing in new space. If it is we assume that the function will stay the | 5089 // residing in new space. If it is we assume that the function will stay the |
| 5050 // same. | 5090 // same. |
| 5051 Handle<JSFunction> target = Handle<JSFunction>::null(); | 5091 Handle<JSFunction> target = Handle<JSFunction>::null(); |
| 5052 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); | 5092 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); |
| 5053 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); | 5093 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); |
| 5054 CompilationInfo* info = graph()->info(); | |
| 5055 if (global_function && | 5094 if (global_function && |
| 5056 info->has_global_object() && | 5095 info()->has_global_object() && |
| 5057 !info->global_object()->IsAccessCheckNeeded()) { | 5096 !info()->global_object()->IsAccessCheckNeeded()) { |
| 5058 Handle<String> name = var->name(); | 5097 Handle<String> name = var->name(); |
| 5059 Handle<GlobalObject> global(info->global_object()); | 5098 Handle<GlobalObject> global(info()->global_object()); |
| 5060 LookupResult lookup; | 5099 LookupResult lookup; |
| 5061 global->Lookup(*name, &lookup); | 5100 global->Lookup(*name, &lookup); |
| 5062 if (lookup.IsProperty() && | 5101 if (lookup.IsProperty() && |
| 5063 lookup.type() == NORMAL && | 5102 lookup.type() == NORMAL && |
| 5064 lookup.GetValue()->IsJSFunction()) { | 5103 lookup.GetValue()->IsJSFunction()) { |
| 5065 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); | 5104 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
| 5066 // If the function is in new space we assume it's more likely to | 5105 // If the function is in new space we assume it's more likely to |
| 5067 // change and thus prefer the general IC code. | 5106 // change and thus prefer the general IC code. |
| 5068 if (!Heap::InNewSpace(*candidate)) { | 5107 if (!Heap::InNewSpace(*candidate)) { |
| 5069 target = candidate; | 5108 target = candidate; |
| 5070 } | 5109 } |
| 5071 } | 5110 } |
| 5072 } | 5111 } |
| 5073 | 5112 |
| 5074 // If the target is not null we have found a known global function that is | 5113 // If the target is not null we have found a known global function that is |
| 5075 // assumed to stay the same for this instanceof. | 5114 // assumed to stay the same for this instanceof. |
| 5076 if (target.is_null()) { | 5115 if (target.is_null()) { |
| 5077 HContext* context = new HContext; | 5116 HContext* context = new HContext; |
| 5078 AddInstruction(context); | 5117 AddInstruction(context); |
| 5079 instr = new HInstanceOf(context, left, right); | 5118 instr = new HInstanceOf(context, left, right); |
| 5080 } else { | 5119 } else { |
| 5081 AddInstruction(new HCheckFunction(right, target)); | 5120 AddInstruction(new HCheckFunction(right, target)); |
| 5082 instr = new HInstanceOfKnownGlobal(left, target); | 5121 instr = new HInstanceOfKnownGlobal(left, target); |
| 5083 } | 5122 } |
| 5084 } else if (op == Token::IN) { | 5123 } else if (op == Token::IN) { |
| 5085 BAILOUT("Unsupported comparison: in"); | 5124 BAILOUT("Unsupported comparison: in"); |
| 5086 } else if (info.IsNonPrimitive()) { | 5125 } else if (type_info.IsNonPrimitive()) { |
| 5087 switch (op) { | 5126 switch (op) { |
| 5088 case Token::EQ: | 5127 case Token::EQ: |
| 5089 case Token::EQ_STRICT: { | 5128 case Token::EQ_STRICT: { |
| 5090 AddInstruction(new HCheckNonSmi(left)); | 5129 AddInstruction(new HCheckNonSmi(left)); |
| 5091 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); | 5130 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); |
| 5092 AddInstruction(new HCheckNonSmi(right)); | 5131 AddInstruction(new HCheckNonSmi(right)); |
| 5093 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); | 5132 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); |
| 5094 instr = new HCompareJSObjectEq(left, right); | 5133 instr = new HCompareJSObjectEq(left, right); |
| 5095 break; | 5134 break; |
| 5096 } | 5135 } |
| 5097 default: | 5136 default: |
| 5098 BAILOUT("Unsupported non-primitive compare"); | 5137 BAILOUT("Unsupported non-primitive compare"); |
| 5099 break; | 5138 break; |
| 5100 } | 5139 } |
| 5101 } else { | 5140 } else { |
| 5102 HCompare* compare = new HCompare(left, right, op); | 5141 HCompare* compare = new HCompare(left, right, op); |
| 5103 Representation r = ToRepresentation(info); | 5142 Representation r = ToRepresentation(type_info); |
| 5104 compare->SetInputRepresentation(r); | 5143 compare->SetInputRepresentation(r); |
| 5105 instr = compare; | 5144 instr = compare; |
| 5106 } | 5145 } |
| 5107 instr->set_position(expr->position()); | 5146 instr->set_position(expr->position()); |
| 5108 ast_context()->ReturnInstruction(instr, expr->id()); | 5147 ast_context()->ReturnInstruction(instr, expr->id()); |
| 5109 } | 5148 } |
| 5110 | 5149 |
| 5111 | 5150 |
| 5112 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { | 5151 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { |
| 5113 VISIT_FOR_VALUE(expr->expression()); | 5152 VISIT_FOR_VALUE(expr->expression()); |
| (...skipping 892 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6006 } | 6045 } |
| 6007 } | 6046 } |
| 6008 | 6047 |
| 6009 #ifdef DEBUG | 6048 #ifdef DEBUG |
| 6010 if (graph_ != NULL) graph_->Verify(); | 6049 if (graph_ != NULL) graph_->Verify(); |
| 6011 if (allocator_ != NULL) allocator_->Verify(); | 6050 if (allocator_ != NULL) allocator_->Verify(); |
| 6012 #endif | 6051 #endif |
| 6013 } | 6052 } |
| 6014 | 6053 |
| 6015 } } // namespace v8::internal | 6054 } } // namespace v8::internal |
| OLD | NEW |