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 |