| 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 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 if (end->FirstSuccessor() != NULL) { | 144 if (end->FirstSuccessor() != NULL) { |
| 145 end->FirstSuccessor()->RegisterPredecessor(this); | 145 end->FirstSuccessor()->RegisterPredecessor(this); |
| 146 if (end->SecondSuccessor() != NULL) { | 146 if (end->SecondSuccessor() != NULL) { |
| 147 end->SecondSuccessor()->RegisterPredecessor(this); | 147 end->SecondSuccessor()->RegisterPredecessor(this); |
| 148 } | 148 } |
| 149 } | 149 } |
| 150 } | 150 } |
| 151 | 151 |
| 152 | 152 |
| 153 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) { | 153 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) { |
| 154 if (block->IsInlineReturnTarget()) { |
| 155 AddInstruction(new HLeaveInlined); |
| 156 last_environment_ = last_environment()->outer(); |
| 157 } |
| 154 AddSimulate(AstNode::kNoNumber); | 158 AddSimulate(AstNode::kNoNumber); |
| 155 HGoto* instr = new HGoto(block); | 159 HGoto* instr = new HGoto(block); |
| 156 instr->set_include_stack_check(include_stack_check); | 160 instr->set_include_stack_check(include_stack_check); |
| 157 Finish(instr); | 161 Finish(instr); |
| 158 } | 162 } |
| 159 | 163 |
| 160 | 164 |
| 165 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 166 ASSERT(target->IsInlineReturnTarget()); |
| 167 ASSERT(return_value != NULL); |
| 168 AddInstruction(new HLeaveInlined); |
| 169 last_environment_ = last_environment()->outer(); |
| 170 last_environment()->Push(return_value); |
| 171 AddSimulate(AstNode::kNoNumber); |
| 172 HGoto* instr = new HGoto(target); |
| 173 Finish(instr); |
| 174 } |
| 175 |
| 176 |
| 161 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { | 177 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { |
| 162 ASSERT(!HasEnvironment()); | 178 ASSERT(!HasEnvironment()); |
| 163 ASSERT(first() == NULL); | 179 ASSERT(first() == NULL); |
| 164 UpdateEnvironment(env); | 180 UpdateEnvironment(env); |
| 165 } | 181 } |
| 166 | 182 |
| 167 | 183 |
| 168 void HBasicBlock::SetJoinId(int id) { | 184 void HBasicBlock::SetJoinId(int id) { |
| 169 int length = predecessors_.length(); | 185 int length = predecessors_.length(); |
| 170 ASSERT(length > 0); | 186 ASSERT(length > 0); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 UNREACHABLE(); | 296 UNREACHABLE(); |
| 281 return -1; | 297 return -1; |
| 282 } | 298 } |
| 283 | 299 |
| 284 | 300 |
| 285 #ifdef DEBUG | 301 #ifdef DEBUG |
| 286 void HBasicBlock::Verify() { | 302 void HBasicBlock::Verify() { |
| 287 // Check that every block is finished. | 303 // Check that every block is finished. |
| 288 ASSERT(IsFinished()); | 304 ASSERT(IsFinished()); |
| 289 ASSERT(block_id() >= 0); | 305 ASSERT(block_id() >= 0); |
| 306 |
| 307 // Check that the incoming edges are in edge split form. |
| 308 if (predecessors_.length() > 1) { |
| 309 for (int i = 0; i < predecessors_.length(); ++i) { |
| 310 ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL); |
| 311 } |
| 312 } |
| 290 } | 313 } |
| 291 #endif | 314 #endif |
| 292 | 315 |
| 293 | 316 |
| 294 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { | 317 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { |
| 295 this->back_edges_.Add(block); | 318 this->back_edges_.Add(block); |
| 296 AddBlock(block); | 319 AddBlock(block); |
| 297 } | 320 } |
| 298 | 321 |
| 299 | 322 |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 | 553 |
| 531 void HBasicBlock::FinishExit(HControlInstruction* instruction) { | 554 void HBasicBlock::FinishExit(HControlInstruction* instruction) { |
| 532 Finish(instruction); | 555 Finish(instruction); |
| 533 ClearEnvironment(); | 556 ClearEnvironment(); |
| 534 } | 557 } |
| 535 | 558 |
| 536 | 559 |
| 537 HGraph::HGraph(CompilationInfo* info) | 560 HGraph::HGraph(CompilationInfo* info) |
| 538 : HSubgraph(this), | 561 : HSubgraph(this), |
| 539 next_block_id_(0), | 562 next_block_id_(0), |
| 540 info_(info), | |
| 541 blocks_(8), | 563 blocks_(8), |
| 542 values_(16), | 564 values_(16), |
| 543 phi_list_(NULL) { | 565 phi_list_(NULL) { |
| 544 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); | 566 start_environment_ = new HEnvironment(NULL, info->scope(), info->closure()); |
| 545 start_environment_->set_ast_id(info->function()->id()); | 567 start_environment_->set_ast_id(info->function()->id()); |
| 546 } | 568 } |
| 547 | 569 |
| 548 | 570 |
| 549 bool HGraph::AllowCodeMotion() const { | 571 Handle<Code> HGraph::Compile(CompilationInfo* info) { |
| 550 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; | |
| 551 } | |
| 552 | |
| 553 | |
| 554 Handle<Code> HGraph::Compile() { | |
| 555 int values = GetMaximumValueID(); | 572 int values = GetMaximumValueID(); |
| 556 if (values > LAllocator::max_initial_value_ids()) { | 573 if (values > LAllocator::max_initial_value_ids()) { |
| 557 if (FLAG_trace_bailout) PrintF("Function is too big\n"); | 574 if (FLAG_trace_bailout) PrintF("Function is too big\n"); |
| 558 return Handle<Code>::null(); | 575 return Handle<Code>::null(); |
| 559 } | 576 } |
| 560 | 577 |
| 561 LAllocator allocator(values, this); | 578 LAllocator allocator(values, this); |
| 562 LChunkBuilder builder(this, &allocator); | 579 LChunkBuilder builder(info, this, &allocator); |
| 563 LChunk* chunk = builder.Build(); | 580 LChunk* chunk = builder.Build(); |
| 564 if (chunk == NULL) return Handle<Code>::null(); | 581 if (chunk == NULL) return Handle<Code>::null(); |
| 565 | 582 |
| 566 if (!FLAG_alloc_lithium) return Handle<Code>::null(); | 583 if (!FLAG_alloc_lithium) return Handle<Code>::null(); |
| 567 | 584 |
| 568 allocator.Allocate(chunk); | 585 allocator.Allocate(chunk); |
| 569 | 586 |
| 570 if (!FLAG_use_lithium) return Handle<Code>::null(); | 587 if (!FLAG_use_lithium) return Handle<Code>::null(); |
| 571 | 588 |
| 572 MacroAssembler assembler(NULL, 0); | 589 MacroAssembler assembler(NULL, 0); |
| 573 LCodeGen generator(chunk, &assembler, info()); | 590 LCodeGen generator(chunk, &assembler, info); |
| 574 | 591 |
| 575 if (FLAG_eliminate_empty_blocks) { | 592 if (FLAG_eliminate_empty_blocks) { |
| 576 chunk->MarkEmptyBlocks(); | 593 chunk->MarkEmptyBlocks(); |
| 577 } | 594 } |
| 578 | 595 |
| 579 if (generator.GenerateCode()) { | 596 if (generator.GenerateCode()) { |
| 580 if (FLAG_trace_codegen) { | 597 if (FLAG_trace_codegen) { |
| 581 PrintF("Crankshaft Compiler - "); | 598 PrintF("Crankshaft Compiler - "); |
| 582 } | 599 } |
| 583 CodeGenerator::MakeCodePrologue(info()); | 600 CodeGenerator::MakeCodePrologue(info); |
| 584 Code::Flags flags = | 601 Code::Flags flags = |
| 585 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP); | 602 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP); |
| 586 Handle<Code> code = | 603 Handle<Code> code = |
| 587 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info()); | 604 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info); |
| 588 generator.FinishCode(code); | 605 generator.FinishCode(code); |
| 589 CodeGenerator::PrintCode(code, info()); | 606 CodeGenerator::PrintCode(code, info); |
| 590 return code; | 607 return code; |
| 591 } | 608 } |
| 592 return Handle<Code>::null(); | 609 return Handle<Code>::null(); |
| 593 } | 610 } |
| 594 | 611 |
| 595 | 612 |
| 596 HBasicBlock* HGraph::CreateBasicBlock() { | 613 HBasicBlock* HGraph::CreateBasicBlock() { |
| 597 HBasicBlock* result = new HBasicBlock(this); | 614 HBasicBlock* result = new HBasicBlock(this); |
| 598 blocks_.Add(result); | 615 blocks_.Add(result); |
| 599 return result; | 616 return result; |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 861 InferControlFlowRange(inverted_op, compare->right(), compare->left()); | 878 InferControlFlowRange(inverted_op, compare->right(), compare->left()); |
| 862 } | 879 } |
| 863 } | 880 } |
| 864 | 881 |
| 865 | 882 |
| 866 // We know that value [op] other. Use this information to update the range on | 883 // We know that value [op] other. Use this information to update the range on |
| 867 // value. | 884 // value. |
| 868 void HRangeAnalysis::InferControlFlowRange(Token::Value op, | 885 void HRangeAnalysis::InferControlFlowRange(Token::Value op, |
| 869 HValue* value, | 886 HValue* value, |
| 870 HValue* other) { | 887 HValue* other) { |
| 871 Range* range = other->range(); | 888 Range temp_range; |
| 872 if (range == NULL) range = new Range(); | 889 Range* range = other->range() != NULL ? other->range() : &temp_range; |
| 873 Range* new_range = NULL; | 890 Range* new_range = NULL; |
| 874 | 891 |
| 875 TraceRange("Control flow range infer %d %s %d\n", | 892 TraceRange("Control flow range infer %d %s %d\n", |
| 876 value->id(), | 893 value->id(), |
| 877 Token::Name(op), | 894 Token::Name(op), |
| 878 other->id()); | 895 other->id()); |
| 879 | 896 |
| 880 if (op == Token::EQ || op == Token::EQ_STRICT) { | 897 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 881 // The same range has to apply for value. | 898 // The same range has to apply for value. |
| 882 new_range = range->Copy(); | 899 new_range = range->Copy(); |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1170 HGoto::cast(instr)->set_include_stack_check(false); | 1187 HGoto::cast(instr)->set_include_stack_check(false); |
| 1171 return; | 1188 return; |
| 1172 } | 1189 } |
| 1173 instr = instr->next(); | 1190 instr = instr->next(); |
| 1174 } | 1191 } |
| 1175 } | 1192 } |
| 1176 | 1193 |
| 1177 | 1194 |
| 1178 class HGlobalValueNumberer BASE_EMBEDDED { | 1195 class HGlobalValueNumberer BASE_EMBEDDED { |
| 1179 public: | 1196 public: |
| 1180 explicit HGlobalValueNumberer(HGraph* graph) | 1197 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) |
| 1181 : graph_(graph), | 1198 : graph_(graph), |
| 1199 info_(info), |
| 1182 block_side_effects_(graph_->blocks()->length()), | 1200 block_side_effects_(graph_->blocks()->length()), |
| 1183 loop_side_effects_(graph_->blocks()->length()) { | 1201 loop_side_effects_(graph_->blocks()->length()) { |
| 1184 ASSERT(HEAP->allow_allocation(false)); | 1202 ASSERT(HEAP->allow_allocation(false)); |
| 1185 block_side_effects_.AddBlock(0, graph_->blocks()->length()); | 1203 block_side_effects_.AddBlock(0, graph_->blocks()->length()); |
| 1186 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); | 1204 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); |
| 1187 } | 1205 } |
| 1188 ~HGlobalValueNumberer() { | 1206 ~HGlobalValueNumberer() { |
| 1189 ASSERT(!HEAP->allow_allocation(true)); | 1207 ASSERT(!HEAP->allow_allocation(true)); |
| 1190 } | 1208 } |
| 1191 | 1209 |
| 1192 void Analyze(); | 1210 void Analyze(); |
| 1193 | 1211 |
| 1194 private: | 1212 private: |
| 1195 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); | 1213 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); |
| 1196 void ComputeBlockSideEffects(); | 1214 void ComputeBlockSideEffects(); |
| 1197 void LoopInvariantCodeMotion(); | 1215 void LoopInvariantCodeMotion(); |
| 1198 void ProcessLoopBlock(HBasicBlock* block, | 1216 void ProcessLoopBlock(HBasicBlock* block, |
| 1199 HBasicBlock* before_loop, | 1217 HBasicBlock* before_loop, |
| 1200 int loop_kills); | 1218 int loop_kills); |
| 1219 bool AllowCodeMotion(); |
| 1201 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); | 1220 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); |
| 1202 | 1221 |
| 1222 HGraph* graph() { return graph_; } |
| 1223 CompilationInfo* info() { return info_; } |
| 1224 |
| 1203 HGraph* graph_; | 1225 HGraph* graph_; |
| 1226 CompilationInfo* info_; |
| 1204 | 1227 |
| 1205 // A map of block IDs to their side effects. | 1228 // A map of block IDs to their side effects. |
| 1206 ZoneList<int> block_side_effects_; | 1229 ZoneList<int> block_side_effects_; |
| 1207 | 1230 |
| 1208 // A map of loop header block IDs to their loop's side effects. | 1231 // A map of loop header block IDs to their loop's side effects. |
| 1209 ZoneList<int> loop_side_effects_; | 1232 ZoneList<int> loop_side_effects_; |
| 1210 }; | 1233 }; |
| 1211 | 1234 |
| 1212 | 1235 |
| 1213 void HGlobalValueNumberer::Analyze() { | 1236 void HGlobalValueNumberer::Analyze() { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 // Move the instruction out of the loop. | 1317 // Move the instruction out of the loop. |
| 1295 instr->Unlink(); | 1318 instr->Unlink(); |
| 1296 instr->InsertBefore(pre_header->end()); | 1319 instr->InsertBefore(pre_header->end()); |
| 1297 } | 1320 } |
| 1298 } | 1321 } |
| 1299 instr = next; | 1322 instr = next; |
| 1300 } | 1323 } |
| 1301 } | 1324 } |
| 1302 | 1325 |
| 1303 | 1326 |
| 1327 bool HGlobalValueNumberer::AllowCodeMotion() { |
| 1328 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; |
| 1329 } |
| 1330 |
| 1331 |
| 1304 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, | 1332 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, |
| 1305 HBasicBlock* loop_header) { | 1333 HBasicBlock* loop_header) { |
| 1306 // If we've disabled code motion, don't move any instructions. | 1334 // If we've disabled code motion, don't move any instructions. |
| 1307 if (!graph_->AllowCodeMotion()) return false; | 1335 if (!AllowCodeMotion()) return false; |
| 1308 | 1336 |
| 1309 // If --aggressive-loop-invariant-motion, move everything except change | 1337 // If --aggressive-loop-invariant-motion, move everything except change |
| 1310 // instructions. | 1338 // instructions. |
| 1311 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { | 1339 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { |
| 1312 return true; | 1340 return true; |
| 1313 } | 1341 } |
| 1314 | 1342 |
| 1315 // Otherwise only move instructions that postdominate the loop header | 1343 // Otherwise only move instructions that postdominate the loop header |
| 1316 // (i.e. are always executed inside the loop). This is to avoid | 1344 // (i.e. are always executed inside the loop). This is to avoid |
| 1317 // unnecessary deoptimizations assuming the loop is executed at least | 1345 // unnecessary deoptimizations assuming the loop is executed at least |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1842 ASSERT(visited.IsEmpty()); | 1870 ASSERT(visited.IsEmpty()); |
| 1843 PropagateMinusZeroChecks(change->value(), &visited); | 1871 PropagateMinusZeroChecks(change->value(), &visited); |
| 1844 visited.Clear(); | 1872 visited.Clear(); |
| 1845 } | 1873 } |
| 1846 } | 1874 } |
| 1847 } | 1875 } |
| 1848 } | 1876 } |
| 1849 } | 1877 } |
| 1850 | 1878 |
| 1851 | 1879 |
| 1880 // Implementation of utility class to encapsulate the translation state for |
| 1881 // a (possibly inlined) function. |
| 1882 FunctionState::FunctionState(HGraphBuilder* owner, |
| 1883 CompilationInfo* info, |
| 1884 TypeFeedbackOracle* oracle) |
| 1885 : owner_(owner), |
| 1886 compilation_info_(info), |
| 1887 oracle_(oracle), |
| 1888 call_context_(NULL), |
| 1889 function_return_(NULL), |
| 1890 test_context_(NULL), |
| 1891 outer_(owner->function_state()) { |
| 1892 if (outer_ != NULL) { |
| 1893 // State for an inline function. |
| 1894 if (owner->ast_context()->IsTest()) { |
| 1895 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
| 1896 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
| 1897 if_true->MarkAsInlineReturnTarget(); |
| 1898 if_false->MarkAsInlineReturnTarget(); |
| 1899 // The AstContext constructor pushed on the context stack. This newed |
| 1900 // instance is the reason that AstContext can't be BASE_EMBEDDED. |
| 1901 test_context_ = new TestContext(owner, if_true, if_false); |
| 1902 } else { |
| 1903 function_return_ = owner->graph()->CreateBasicBlock(); |
| 1904 function_return()->MarkAsInlineReturnTarget(); |
| 1905 } |
| 1906 // Set this after possibly allocating a new TestContext above. |
| 1907 call_context_ = owner->ast_context(); |
| 1908 } |
| 1909 |
| 1910 // Push on the state stack. |
| 1911 owner->set_function_state(this); |
| 1912 } |
| 1913 |
| 1914 |
| 1915 FunctionState::~FunctionState() { |
| 1916 delete test_context_; |
| 1917 owner_->set_function_state(outer_); |
| 1918 } |
| 1919 |
| 1920 |
| 1852 // Implementation of utility classes to represent an expression's context in | 1921 // Implementation of utility classes to represent an expression's context in |
| 1853 // the AST. | 1922 // the AST. |
| 1854 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 1923 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
| 1855 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { | 1924 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { |
| 1856 owner->set_ast_context(this); // Push. | 1925 owner->set_ast_context(this); // Push. |
| 1857 #ifdef DEBUG | 1926 #ifdef DEBUG |
| 1858 original_length_ = owner->environment()->length(); | 1927 original_length_ = owner->environment()->length(); |
| 1859 #endif | 1928 #endif |
| 1860 } | 1929 } |
| 1861 | 1930 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1927 // We expect the graph to be in edge-split form: there is no edge that | 1996 // We expect the graph to be in edge-split form: there is no edge that |
| 1928 // connects a branch node to a join node. We conservatively ensure that | 1997 // connects a branch node to a join node. We conservatively ensure that |
| 1929 // property by always adding an empty block on the outgoing edges of this | 1998 // property by always adding an empty block on the outgoing edges of this |
| 1930 // branch. | 1999 // branch. |
| 1931 HGraphBuilder* builder = owner(); | 2000 HGraphBuilder* builder = owner(); |
| 1932 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2001 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 1933 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2002 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 1934 HTest* test = new HTest(value, empty_true, empty_false); | 2003 HTest* test = new HTest(value, empty_true, empty_false); |
| 1935 builder->current_block()->Finish(test); | 2004 builder->current_block()->Finish(test); |
| 1936 | 2005 |
| 1937 HValue* const no_return_value = NULL; | 2006 empty_true->Goto(if_true(), false); |
| 1938 HBasicBlock* true_target = if_true(); | 2007 empty_false->Goto(if_false(), false); |
| 1939 if (true_target->IsInlineReturnTarget()) { | |
| 1940 empty_true->AddLeaveInlined(no_return_value, true_target); | |
| 1941 } else { | |
| 1942 empty_true->Goto(true_target); | |
| 1943 } | |
| 1944 | |
| 1945 HBasicBlock* false_target = if_false(); | |
| 1946 if (false_target->IsInlineReturnTarget()) { | |
| 1947 empty_false->AddLeaveInlined(no_return_value, false_target); | |
| 1948 } else { | |
| 1949 empty_false->Goto(false_target); | |
| 1950 } | |
| 1951 builder->set_current_block(NULL); | 2008 builder->set_current_block(NULL); |
| 1952 } | 2009 } |
| 1953 | 2010 |
| 1954 | 2011 |
| 1955 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2012 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 1956 #define BAILOUT(reason) \ | 2013 #define BAILOUT(reason) \ |
| 1957 do { \ | 2014 do { \ |
| 1958 Bailout(reason); \ | 2015 Bailout(reason); \ |
| 1959 return; \ | 2016 return; \ |
| 1960 } while (false) | 2017 } while (false) |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2012 | 2069 |
| 2013 private: | 2070 private: |
| 2014 HGraphBuilder* builder_; | 2071 HGraphBuilder* builder_; |
| 2015 HSubgraph* old_subgraph_; | 2072 HSubgraph* old_subgraph_; |
| 2016 HSubgraph* subgraph_; | 2073 HSubgraph* subgraph_; |
| 2017 }; | 2074 }; |
| 2018 | 2075 |
| 2019 | 2076 |
| 2020 void HGraphBuilder::Bailout(const char* reason) { | 2077 void HGraphBuilder::Bailout(const char* reason) { |
| 2021 if (FLAG_trace_bailout) { | 2078 if (FLAG_trace_bailout) { |
| 2022 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); | 2079 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); |
| 2023 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *debug_name, reason); | 2080 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason); |
| 2024 } | 2081 } |
| 2025 SetStackOverflow(); | 2082 SetStackOverflow(); |
| 2026 } | 2083 } |
| 2027 | 2084 |
| 2028 | 2085 |
| 2029 void HGraphBuilder::VisitForEffect(Expression* expr) { | 2086 void HGraphBuilder::VisitForEffect(Expression* expr) { |
| 2030 EffectContext for_effect(this); | 2087 EffectContext for_effect(this); |
| 2031 Visit(expr); | 2088 Visit(expr); |
| 2032 } | 2089 } |
| 2033 | 2090 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2060 } | 2117 } |
| 2061 | 2118 |
| 2062 | 2119 |
| 2063 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { | 2120 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { |
| 2064 for (int i = 0; i < exprs->length(); ++i) { | 2121 for (int i = 0; i < exprs->length(); ++i) { |
| 2065 VISIT_FOR_VALUE(exprs->at(i)); | 2122 VISIT_FOR_VALUE(exprs->at(i)); |
| 2066 } | 2123 } |
| 2067 } | 2124 } |
| 2068 | 2125 |
| 2069 | 2126 |
| 2070 HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { | 2127 HGraph* HGraphBuilder::CreateGraph() { |
| 2071 ASSERT(subgraph() == NULL); | 2128 ASSERT(subgraph() == NULL); |
| 2072 graph_ = new HGraph(info); | 2129 graph_ = new HGraph(info()); |
| 2073 | 2130 |
| 2074 { | 2131 { |
| 2075 HPhase phase("Block building"); | 2132 HPhase phase("Block building"); |
| 2076 graph()->Initialize(CreateBasicBlock(graph()->start_environment())); | 2133 graph()->Initialize(CreateBasicBlock(graph()->start_environment())); |
| 2077 current_subgraph_ = graph(); | 2134 current_subgraph_ = graph(); |
| 2078 | 2135 |
| 2079 Scope* scope = info->scope(); | 2136 Scope* scope = info()->scope(); |
| 2080 if (scope->HasIllegalRedeclaration()) { | 2137 if (scope->HasIllegalRedeclaration()) { |
| 2081 Bailout("function with illegal redeclaration"); | 2138 Bailout("function with illegal redeclaration"); |
| 2082 return NULL; | 2139 return NULL; |
| 2083 } | 2140 } |
| 2084 SetupScope(scope); | 2141 SetupScope(scope); |
| 2085 VisitDeclarations(scope->declarations()); | 2142 VisitDeclarations(scope->declarations()); |
| 2086 AddInstruction(new HStackCheck()); | 2143 AddInstruction(new HStackCheck()); |
| 2087 | 2144 |
| 2088 // Add an edge to the body entry. This is warty: the graph's start | 2145 // Add an edge to the body entry. This is warty: the graph's start |
| 2089 // environment will be used by the Lithium translation as the initial | 2146 // environment will be used by the Lithium translation as the initial |
| 2090 // environment on graph entry, but it has now been mutated by the | 2147 // environment on graph entry, but it has now been mutated by the |
| 2091 // Hydrogen translation of the instructions in the start block. This | 2148 // Hydrogen translation of the instructions in the start block. This |
| 2092 // environment uses values which have not been defined yet. These | 2149 // environment uses values which have not been defined yet. These |
| 2093 // Hydrogen instructions will then be replayed by the Lithium | 2150 // Hydrogen instructions will then be replayed by the Lithium |
| 2094 // translation, so they cannot have an environment effect. The edge to | 2151 // translation, so they cannot have an environment effect. The edge to |
| 2095 // the body's entry block (along with some special logic for the start | 2152 // the body's entry block (along with some special logic for the start |
| 2096 // block in HInstruction::InsertAfter) seals the start block from | 2153 // block in HInstruction::InsertAfter) seals the start block from |
| 2097 // getting unwanted instructions inserted. | 2154 // getting unwanted instructions inserted. |
| 2098 // | 2155 // |
| 2099 // TODO(kmillikin): Fix this. Stop mutating the initial environment. | 2156 // TODO(kmillikin): Fix this. Stop mutating the initial environment. |
| 2100 // Make the Hydrogen instructions in the initial block into Hydrogen | 2157 // Make the Hydrogen instructions in the initial block into Hydrogen |
| 2101 // values (but not instructions), present in the initial environment and | 2158 // values (but not instructions), present in the initial environment and |
| 2102 // not replayed by the Lithium translation. | 2159 // not replayed by the Lithium translation. |
| 2103 HEnvironment* initial_env = environment()->CopyWithoutHistory(); | 2160 HEnvironment* initial_env = environment()->CopyWithoutHistory(); |
| 2104 HBasicBlock* body_entry = CreateBasicBlock(initial_env); | 2161 HBasicBlock* body_entry = CreateBasicBlock(initial_env); |
| 2105 current_block()->Goto(body_entry); | 2162 current_block()->Goto(body_entry); |
| 2106 body_entry->SetJoinId(info->function()->id()); | 2163 body_entry->SetJoinId(info()->function()->id()); |
| 2107 set_current_block(body_entry); | 2164 set_current_block(body_entry); |
| 2108 VisitStatements(info->function()->body()); | 2165 VisitStatements(info()->function()->body()); |
| 2109 if (HasStackOverflow()) return NULL; | 2166 if (HasStackOverflow()) return NULL; |
| 2110 | 2167 |
| 2111 if (current_block() != NULL) { | 2168 if (current_block() != NULL) { |
| 2112 HReturn* instr = new HReturn(graph()->GetConstantUndefined()); | 2169 HReturn* instr = new HReturn(graph()->GetConstantUndefined()); |
| 2113 current_block()->FinishExit(instr); | 2170 current_block()->FinishExit(instr); |
| 2114 set_current_block(NULL); | 2171 set_current_block(NULL); |
| 2115 } | 2172 } |
| 2116 } | 2173 } |
| 2117 | 2174 |
| 2118 graph()->OrderBlocks(); | 2175 graph()->OrderBlocks(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2136 graph()->InsertRepresentationChanges(); | 2193 graph()->InsertRepresentationChanges(); |
| 2137 graph()->ComputeMinusZeroChecks(); | 2194 graph()->ComputeMinusZeroChecks(); |
| 2138 | 2195 |
| 2139 // Eliminate redundant stack checks on backwards branches. | 2196 // Eliminate redundant stack checks on backwards branches. |
| 2140 HStackCheckEliminator sce(graph()); | 2197 HStackCheckEliminator sce(graph()); |
| 2141 sce.Process(); | 2198 sce.Process(); |
| 2142 | 2199 |
| 2143 // Perform common subexpression elimination and loop-invariant code motion. | 2200 // Perform common subexpression elimination and loop-invariant code motion. |
| 2144 if (FLAG_use_gvn) { | 2201 if (FLAG_use_gvn) { |
| 2145 HPhase phase("Global value numbering", graph()); | 2202 HPhase phase("Global value numbering", graph()); |
| 2146 HGlobalValueNumberer gvn(graph()); | 2203 HGlobalValueNumberer gvn(graph(), info()); |
| 2147 gvn.Analyze(); | 2204 gvn.Analyze(); |
| 2148 } | 2205 } |
| 2149 | 2206 |
| 2150 return graph(); | 2207 return graph(); |
| 2151 } | 2208 } |
| 2152 | 2209 |
| 2153 | 2210 |
| 2154 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) { | 2211 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Statement* stmt) { |
| 2155 SubgraphScope scope(this, graph); | 2212 SubgraphScope scope(this, graph); |
| 2156 Visit(stmt); | 2213 Visit(stmt); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2229 | 2286 |
| 2230 // Set the initial values of stack-allocated locals. | 2287 // Set the initial values of stack-allocated locals. |
| 2231 for (int i = count; i < environment()->length(); ++i) { | 2288 for (int i = count; i < environment()->length(); ++i) { |
| 2232 environment()->Bind(i, undefined_constant); | 2289 environment()->Bind(i, undefined_constant); |
| 2233 } | 2290 } |
| 2234 | 2291 |
| 2235 // Handle the arguments and arguments shadow variables specially (they do | 2292 // Handle the arguments and arguments shadow variables specially (they do |
| 2236 // not have declarations). | 2293 // not have declarations). |
| 2237 if (scope->arguments() != NULL) { | 2294 if (scope->arguments() != NULL) { |
| 2238 if (!scope->arguments()->IsStackAllocated() || | 2295 if (!scope->arguments()->IsStackAllocated() || |
| 2239 !scope->arguments_shadow()->IsStackAllocated()) { | 2296 (scope->arguments_shadow() != NULL && |
| 2297 !scope->arguments_shadow()->IsStackAllocated())) { |
| 2240 BAILOUT("context-allocated arguments"); | 2298 BAILOUT("context-allocated arguments"); |
| 2241 } | 2299 } |
| 2242 HArgumentsObject* object = new HArgumentsObject; | 2300 HArgumentsObject* object = new HArgumentsObject; |
| 2243 AddInstruction(object); | 2301 AddInstruction(object); |
| 2244 graph()->SetArgumentsObject(object); | 2302 graph()->SetArgumentsObject(object); |
| 2245 environment()->Bind(scope->arguments(), object); | 2303 environment()->Bind(scope->arguments(), object); |
| 2246 environment()->Bind(scope->arguments_shadow(), object); | 2304 if (scope->arguments_shadow() != NULL) { |
| 2305 environment()->Bind(scope->arguments_shadow(), object); |
| 2306 } |
| 2247 } | 2307 } |
| 2248 } | 2308 } |
| 2249 | 2309 |
| 2250 | 2310 |
| 2251 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { | 2311 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { |
| 2252 for (int i = 0; i < statements->length(); i++) { | 2312 for (int i = 0; i < statements->length(); i++) { |
| 2253 Visit(statements->at(i)); | 2313 Visit(statements->at(i)); |
| 2254 if (HasStackOverflow() || current_block() == NULL) break; | 2314 if (HasStackOverflow() || current_block() == NULL) break; |
| 2255 } | 2315 } |
| 2256 } | 2316 } |
| 2257 | 2317 |
| 2258 | 2318 |
| 2259 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { | 2319 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| 2260 HBasicBlock* b = graph()->CreateBasicBlock(); | 2320 HBasicBlock* b = graph()->CreateBasicBlock(); |
| 2261 b->SetInitialEnvironment(env); | 2321 b->SetInitialEnvironment(env); |
| 2262 return b; | 2322 return b; |
| 2263 } | 2323 } |
| 2264 | 2324 |
| 2265 | 2325 |
| 2266 HSubgraph* HGraphBuilder::CreateInlinedSubgraph(HEnvironment* outer, | |
| 2267 Handle<JSFunction> target, | |
| 2268 FunctionLiteral* function) { | |
| 2269 HConstant* undefined = graph()->GetConstantUndefined(); | |
| 2270 HEnvironment* inner = | |
| 2271 outer->CopyForInlining(target, function, true, undefined); | |
| 2272 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2273 subgraph->Initialize(CreateBasicBlock(inner)); | |
| 2274 return subgraph; | |
| 2275 } | |
| 2276 | |
| 2277 | |
| 2278 HSubgraph* HGraphBuilder::CreateEmptySubgraph() { | 2326 HSubgraph* HGraphBuilder::CreateEmptySubgraph() { |
| 2279 HSubgraph* subgraph = new HSubgraph(graph()); | 2327 HSubgraph* subgraph = new HSubgraph(graph()); |
| 2280 subgraph->Initialize(graph()->CreateBasicBlock()); | 2328 subgraph->Initialize(graph()->CreateBasicBlock()); |
| 2281 return subgraph; | 2329 return subgraph; |
| 2282 } | 2330 } |
| 2283 | 2331 |
| 2284 | 2332 |
| 2285 HSubgraph* HGraphBuilder::CreateBranchSubgraph(HEnvironment* env) { | |
| 2286 HSubgraph* subgraph = new HSubgraph(graph()); | |
| 2287 HEnvironment* new_env = env->Copy(); | |
| 2288 subgraph->Initialize(CreateBasicBlock(new_env)); | |
| 2289 return subgraph; | |
| 2290 } | |
| 2291 | |
| 2292 | |
| 2293 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { | 2333 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
| 2294 HBasicBlock* header = graph()->CreateBasicBlock(); | 2334 HBasicBlock* header = graph()->CreateBasicBlock(); |
| 2295 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); | 2335 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| 2296 header->SetInitialEnvironment(entry_env); | 2336 header->SetInitialEnvironment(entry_env); |
| 2297 header->AttachLoopInformation(); | 2337 header->AttachLoopInformation(); |
| 2298 return header; | 2338 return header; |
| 2299 } | 2339 } |
| 2300 | 2340 |
| 2301 | 2341 |
| 2302 void HGraphBuilder::VisitBlock(Block* stmt) { | 2342 void HGraphBuilder::VisitBlock(Block* stmt) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2406 current_block()->FinishExit(new HReturn(result)); | 2446 current_block()->FinishExit(new HReturn(result)); |
| 2407 set_current_block(NULL); | 2447 set_current_block(NULL); |
| 2408 } else { | 2448 } else { |
| 2409 // Return from an inlined function, visit the subexpression in the | 2449 // Return from an inlined function, visit the subexpression in the |
| 2410 // expression context of the call. | 2450 // expression context of the call. |
| 2411 if (context->IsTest()) { | 2451 if (context->IsTest()) { |
| 2412 TestContext* test = TestContext::cast(context); | 2452 TestContext* test = TestContext::cast(context); |
| 2413 VisitForControl(stmt->expression(), | 2453 VisitForControl(stmt->expression(), |
| 2414 test->if_true(), | 2454 test->if_true(), |
| 2415 test->if_false()); | 2455 test->if_false()); |
| 2456 } else if (context->IsEffect()) { |
| 2457 VISIT_FOR_EFFECT(stmt->expression()); |
| 2458 current_block()->Goto(function_return(), false); |
| 2416 } else { | 2459 } else { |
| 2417 HValue* return_value = NULL; | 2460 ASSERT(context->IsValue()); |
| 2418 if (context->IsEffect()) { | 2461 VISIT_FOR_VALUE(stmt->expression()); |
| 2419 VISIT_FOR_EFFECT(stmt->expression()); | 2462 HValue* return_value = environment()->Pop(); |
| 2420 return_value = graph()->GetConstantUndefined(); | 2463 current_block()->AddLeaveInlined(return_value, function_return()); |
| 2421 } else { | |
| 2422 ASSERT(context->IsValue()); | |
| 2423 VISIT_FOR_VALUE(stmt->expression()); | |
| 2424 return_value = environment()->Pop(); | |
| 2425 } | |
| 2426 current_block()->AddLeaveInlined(return_value, | |
| 2427 function_return_); | |
| 2428 set_current_block(NULL); | |
| 2429 } | 2464 } |
| 2465 set_current_block(NULL); |
| 2430 } | 2466 } |
| 2431 } | 2467 } |
| 2432 | 2468 |
| 2433 | 2469 |
| 2434 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { | 2470 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { |
| 2435 BAILOUT("WithEnterStatement"); | 2471 BAILOUT("WithEnterStatement"); |
| 2436 } | 2472 } |
| 2437 | 2473 |
| 2438 | 2474 |
| 2439 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { | 2475 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2601 last_false_block->Finish(new HGoto(single_exit_block)); | 2637 last_false_block->Finish(new HGoto(single_exit_block)); |
| 2602 } | 2638 } |
| 2603 | 2639 |
| 2604 if (single_exit_block->HasPredecessor()) { | 2640 if (single_exit_block->HasPredecessor()) { |
| 2605 set_current_block(single_exit_block); | 2641 set_current_block(single_exit_block); |
| 2606 } else { | 2642 } else { |
| 2607 set_current_block(NULL); | 2643 set_current_block(NULL); |
| 2608 } | 2644 } |
| 2609 } | 2645 } |
| 2610 | 2646 |
| 2611 bool HGraph::HasOsrEntryAt(IterationStatement* statement) { | 2647 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { |
| 2612 return statement->OsrEntryId() == info()->osr_ast_id(); | 2648 return statement->OsrEntryId() == info()->osr_ast_id(); |
| 2613 } | 2649 } |
| 2614 | 2650 |
| 2615 | 2651 |
| 2616 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { | 2652 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { |
| 2617 if (!graph()->HasOsrEntryAt(statement)) return; | 2653 if (!HasOsrEntryAt(statement)) return; |
| 2618 | 2654 |
| 2619 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); | 2655 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); |
| 2620 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); | 2656 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); |
| 2621 HValue* true_value = graph()->GetConstantTrue(); | 2657 HValue* true_value = graph()->GetConstantTrue(); |
| 2622 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); | 2658 HTest* test = new HTest(true_value, non_osr_entry, osr_entry); |
| 2623 current_block()->Finish(test); | 2659 current_block()->Finish(test); |
| 2624 | 2660 |
| 2625 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); | 2661 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); |
| 2626 non_osr_entry->Goto(loop_predecessor); | 2662 non_osr_entry->Goto(loop_predecessor); |
| 2627 | 2663 |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2774 } | 2810 } |
| 2775 | 2811 |
| 2776 | 2812 |
| 2777 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | 2813 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 2778 BAILOUT("DebuggerStatement"); | 2814 BAILOUT("DebuggerStatement"); |
| 2779 } | 2815 } |
| 2780 | 2816 |
| 2781 | 2817 |
| 2782 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { | 2818 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 2783 Handle<SharedFunctionInfo> shared_info = | 2819 Handle<SharedFunctionInfo> shared_info = |
| 2784 Compiler::BuildFunctionInfo(expr, graph_->info()->script()); | 2820 Compiler::BuildFunctionInfo(expr, info()->script()); |
| 2785 CHECK_BAILOUT; | 2821 CHECK_BAILOUT; |
| 2786 HFunctionLiteral* instr = | 2822 HFunctionLiteral* instr = |
| 2787 new HFunctionLiteral(shared_info, expr->pretenure()); | 2823 new HFunctionLiteral(shared_info, expr->pretenure()); |
| 2788 ast_context()->ReturnInstruction(instr, expr->id()); | 2824 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2789 } | 2825 } |
| 2790 | 2826 |
| 2791 | 2827 |
| 2792 void HGraphBuilder::VisitSharedFunctionInfoLiteral( | 2828 void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
| 2793 SharedFunctionInfoLiteral* expr) { | 2829 SharedFunctionInfoLiteral* expr) { |
| 2794 BAILOUT("SharedFunctionInfoLiteral"); | 2830 BAILOUT("SharedFunctionInfoLiteral"); |
| 2795 } | 2831 } |
| 2796 | 2832 |
| 2797 | 2833 |
| 2798 void HGraphBuilder::VisitConditional(Conditional* expr) { | 2834 void HGraphBuilder::VisitConditional(Conditional* expr) { |
| 2799 HBasicBlock* cond_true = graph()->CreateBasicBlock(); | 2835 HBasicBlock* cond_true = graph()->CreateBasicBlock(); |
| 2800 HBasicBlock* cond_false = graph()->CreateBasicBlock(); | 2836 HBasicBlock* cond_false = graph()->CreateBasicBlock(); |
| 2801 VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false); | 2837 VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false); |
| 2802 cond_true->SetJoinId(expr->ThenId()); | 2838 cond_true->SetJoinId(expr->ThenId()); |
| 2803 cond_false->SetJoinId(expr->ElseId()); | 2839 cond_false->SetJoinId(expr->ElseId()); |
| 2804 | 2840 |
| 2805 // TOOD(kmillikin): Visit the subexpressions in the same AST context as | 2841 // Visit the true and false subexpressions in the same AST context as the |
| 2806 // the whole expression. | 2842 // whole expression. |
| 2807 set_current_block(cond_true); | 2843 set_current_block(cond_true); |
| 2808 VISIT_FOR_VALUE(expr->then_expression()); | 2844 Visit(expr->then_expression()); |
| 2845 CHECK_BAILOUT; |
| 2809 HBasicBlock* other = current_block(); | 2846 HBasicBlock* other = current_block(); |
| 2810 | 2847 |
| 2811 set_current_block(cond_false); | 2848 set_current_block(cond_false); |
| 2812 VISIT_FOR_VALUE(expr->else_expression()); | 2849 Visit(expr->else_expression()); |
| 2850 CHECK_BAILOUT; |
| 2813 | 2851 |
| 2814 HBasicBlock* join = CreateJoin(other, current_block(), expr->id()); | 2852 if (!ast_context()->IsTest()) { |
| 2815 set_current_block(join); | 2853 HBasicBlock* join = CreateJoin(other, current_block(), expr->id()); |
| 2816 ast_context()->ReturnValue(Pop()); | 2854 set_current_block(join); |
| 2855 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 2856 } |
| 2817 } | 2857 } |
| 2818 | 2858 |
| 2819 | 2859 |
| 2820 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, | 2860 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
| 2821 LookupResult* lookup, | 2861 LookupResult* lookup, |
| 2822 bool is_store) { | 2862 bool is_store) { |
| 2823 if (var->is_this()) { | 2863 if (var->is_this()) { |
| 2824 BAILOUT("global this reference"); | 2864 BAILOUT("global this reference"); |
| 2825 } | 2865 } |
| 2826 if (!graph()->info()->has_global_object()) { | 2866 if (!info()->has_global_object()) { |
| 2827 BAILOUT("no global object to optimize VariableProxy"); | 2867 BAILOUT("no global object to optimize VariableProxy"); |
| 2828 } | 2868 } |
| 2829 Handle<GlobalObject> global(graph()->info()->global_object()); | 2869 Handle<GlobalObject> global(info()->global_object()); |
| 2830 global->Lookup(*var->name(), lookup); | 2870 global->Lookup(*var->name(), lookup); |
| 2831 if (!lookup->IsProperty()) { | 2871 if (!lookup->IsProperty()) { |
| 2832 BAILOUT("global variable cell not yet introduced"); | 2872 BAILOUT("global variable cell not yet introduced"); |
| 2833 } | 2873 } |
| 2834 if (lookup->type() != NORMAL) { | 2874 if (lookup->type() != NORMAL) { |
| 2835 BAILOUT("global variable has accessors"); | 2875 BAILOUT("global variable has accessors"); |
| 2836 } | 2876 } |
| 2837 if (is_store && lookup->IsReadOnly()) { | 2877 if (is_store && lookup->IsReadOnly()) { |
| 2838 BAILOUT("read-only global variable"); | 2878 BAILOUT("read-only global variable"); |
| 2839 } | 2879 } |
| 2840 if (lookup->holder() != *global) { | 2880 if (lookup->holder() != *global) { |
| 2841 BAILOUT("global property on prototype of global object"); | 2881 BAILOUT("global property on prototype of global object"); |
| 2842 } | 2882 } |
| 2843 } | 2883 } |
| 2844 | 2884 |
| 2845 | 2885 |
| 2846 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { | 2886 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { |
| 2847 ASSERT(var->IsContextSlot()); | 2887 ASSERT(var->IsContextSlot()); |
| 2848 HInstruction* context = new HContext; | 2888 HInstruction* context = new HContext; |
| 2849 AddInstruction(context); | 2889 AddInstruction(context); |
| 2850 int length = graph()->info()->scope()->ContextChainLength(var->scope()); | 2890 int length = info()->scope()->ContextChainLength(var->scope()); |
| 2851 while (length-- > 0) { | 2891 while (length-- > 0) { |
| 2852 context = new HOuterContext(context); | 2892 context = new HOuterContext(context); |
| 2853 AddInstruction(context); | 2893 AddInstruction(context); |
| 2854 } | 2894 } |
| 2855 return context; | 2895 return context; |
| 2856 } | 2896 } |
| 2857 | 2897 |
| 2858 | 2898 |
| 2859 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 2899 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2860 Variable* variable = expr->AsVariable(); | 2900 Variable* variable = expr->AsVariable(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2871 } | 2911 } |
| 2872 HValue* context = BuildContextChainWalk(variable); | 2912 HValue* context = BuildContextChainWalk(variable); |
| 2873 int index = variable->AsSlot()->index(); | 2913 int index = variable->AsSlot()->index(); |
| 2874 HLoadContextSlot* instr = new HLoadContextSlot(context, index); | 2914 HLoadContextSlot* instr = new HLoadContextSlot(context, index); |
| 2875 ast_context()->ReturnInstruction(instr, expr->id()); | 2915 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2876 } else if (variable->is_global()) { | 2916 } else if (variable->is_global()) { |
| 2877 LookupResult lookup; | 2917 LookupResult lookup; |
| 2878 LookupGlobalPropertyCell(variable, &lookup, false); | 2918 LookupGlobalPropertyCell(variable, &lookup, false); |
| 2879 CHECK_BAILOUT; | 2919 CHECK_BAILOUT; |
| 2880 | 2920 |
| 2881 Handle<GlobalObject> global(graph()->info()->global_object()); | 2921 Handle<GlobalObject> global(info()->global_object()); |
| 2882 // TODO(3039103): Handle global property load through an IC call when access | 2922 // TODO(3039103): Handle global property load through an IC call when access |
| 2883 // checks are enabled. | 2923 // checks are enabled. |
| 2884 if (global->IsAccessCheckNeeded()) { | 2924 if (global->IsAccessCheckNeeded()) { |
| 2885 BAILOUT("global object requires access check"); | 2925 BAILOUT("global object requires access check"); |
| 2886 } | 2926 } |
| 2887 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 2927 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 2888 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 2928 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 2889 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); | 2929 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); |
| 2890 ast_context()->ReturnInstruction(instr, expr->id()); | 2930 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2891 } else { | 2931 } else { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2997 } | 3037 } |
| 2998 ast_context()->ReturnValue(Pop()); | 3038 ast_context()->ReturnValue(Pop()); |
| 2999 } | 3039 } |
| 3000 | 3040 |
| 3001 | 3041 |
| 3002 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 3042 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 3003 BAILOUT("CatchExtensionObject"); | 3043 BAILOUT("CatchExtensionObject"); |
| 3004 } | 3044 } |
| 3005 | 3045 |
| 3006 | 3046 |
| 3007 HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver, | |
| 3008 ZoneMapList* maps, | |
| 3009 ZoneList<HSubgraph*>* body_graphs, | |
| 3010 HSubgraph* default_graph, | |
| 3011 int join_id) { | |
| 3012 ASSERT(maps->length() == body_graphs->length()); | |
| 3013 HBasicBlock* join_block = graph()->CreateBasicBlock(); | |
| 3014 AddInstruction(new HCheckNonSmi(receiver)); | |
| 3015 | |
| 3016 for (int i = 0; i < maps->length(); ++i) { | |
| 3017 // Build the branches, connect all the target subgraphs to the join | |
| 3018 // block. Use the default as a target of the last branch. | |
| 3019 HSubgraph* if_true = body_graphs->at(i); | |
| 3020 HSubgraph* if_false = (i == maps->length() - 1) | |
| 3021 ? default_graph | |
| 3022 : CreateBranchSubgraph(environment()); | |
| 3023 HCompareMap* compare = | |
| 3024 new HCompareMap(receiver, | |
| 3025 maps->at(i), | |
| 3026 if_true->entry_block(), | |
| 3027 if_false->entry_block()); | |
| 3028 current_block()->Finish(compare); | |
| 3029 | |
| 3030 if (if_true->exit_block() != NULL) { | |
| 3031 // In an effect context the value of the type switch is not needed. | |
| 3032 // There is no need to merge it at the join block only to discard it. | |
| 3033 if (ast_context()->IsEffect()) { | |
| 3034 if_true->exit_block()->last_environment()->Drop(1); | |
| 3035 } | |
| 3036 if_true->exit_block()->Goto(join_block); | |
| 3037 } | |
| 3038 | |
| 3039 set_current_block(if_false->exit_block()); | |
| 3040 } | |
| 3041 | |
| 3042 // Connect the default if necessary. | |
| 3043 if (current_block() != NULL) { | |
| 3044 if (ast_context()->IsEffect()) { | |
| 3045 environment()->Drop(1); | |
| 3046 } | |
| 3047 current_block()->Goto(join_block); | |
| 3048 } | |
| 3049 | |
| 3050 if (join_block->predecessors()->is_empty()) return NULL; | |
| 3051 join_block->SetJoinId(join_id); | |
| 3052 return join_block; | |
| 3053 } | |
| 3054 | |
| 3055 | |
| 3056 // Sets the lookup result and returns true if the store can be inlined. | 3047 // Sets the lookup result and returns true if the store can be inlined. |
| 3057 static bool ComputeStoredField(Handle<Map> type, | 3048 static bool ComputeStoredField(Handle<Map> type, |
| 3058 Handle<String> name, | 3049 Handle<String> name, |
| 3059 LookupResult* lookup) { | 3050 LookupResult* lookup) { |
| 3060 type->LookupInDescriptors(NULL, *name, lookup); | 3051 type->LookupInDescriptors(NULL, *name, lookup); |
| 3061 if (!lookup->IsPropertyOrTransition()) return false; | 3052 if (!lookup->IsPropertyOrTransition()) return false; |
| 3062 if (lookup->type() == FIELD) return true; | 3053 if (lookup->type() == FIELD) return true; |
| 3063 return (lookup->type() == MAP_TRANSITION) && | 3054 return (lookup->type() == MAP_TRANSITION) && |
| 3064 (type->unused_property_fields() > 0); | 3055 (type->unused_property_fields() > 0); |
| 3065 } | 3056 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3141 true) // Needs smi and map check. | 3132 true) // Needs smi and map check. |
| 3142 : BuildStoreNamedGeneric(object, name, value); | 3133 : BuildStoreNamedGeneric(object, name, value); |
| 3143 } | 3134 } |
| 3144 | 3135 |
| 3145 | 3136 |
| 3146 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, | 3137 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
| 3147 HValue* object, | 3138 HValue* object, |
| 3148 HValue* value, | 3139 HValue* value, |
| 3149 ZoneMapList* types, | 3140 ZoneMapList* types, |
| 3150 Handle<String> name) { | 3141 Handle<String> name) { |
| 3151 int number_of_types = Min(types->length(), kMaxStorePolymorphism); | 3142 // TODO(ager): We should recognize when the prototype chains for different |
| 3152 ZoneMapList maps(number_of_types); | 3143 // maps are identical. In that case we can avoid repeatedly generating the |
| 3153 ZoneList<HSubgraph*> subgraphs(number_of_types); | 3144 // same prototype map checks. |
| 3154 bool needs_generic = (types->length() > kMaxStorePolymorphism); | 3145 int count = 0; |
| 3155 | 3146 HBasicBlock* join = NULL; |
| 3156 // Build subgraphs for each of the specific maps. | 3147 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
| 3157 // | |
| 3158 // TODO(ager): We should recognize when the prototype chains for | |
| 3159 // different maps are identical. In that case we can avoid | |
| 3160 // repeatedly generating the same prototype map checks. | |
| 3161 for (int i = 0; i < number_of_types; ++i) { | |
| 3162 Handle<Map> map = types->at(i); | 3148 Handle<Map> map = types->at(i); |
| 3163 LookupResult lookup; | 3149 LookupResult lookup; |
| 3164 if (ComputeStoredField(map, name, &lookup)) { | 3150 if (ComputeStoredField(map, name, &lookup)) { |
| 3165 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3151 if (count == 0) { |
| 3166 SubgraphScope scope(this, subgraph); | 3152 AddInstruction(new HCheckNonSmi(object)); // Only needed once. |
| 3153 join = graph()->CreateBasicBlock(); |
| 3154 } |
| 3155 ++count; |
| 3156 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3157 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3158 HCompareMap* compare = new HCompareMap(object, map, if_true, if_false); |
| 3159 current_block()->Finish(compare); |
| 3160 |
| 3161 set_current_block(if_true); |
| 3167 HInstruction* instr = | 3162 HInstruction* instr = |
| 3168 BuildStoreNamedField(object, name, value, map, &lookup, false); | 3163 BuildStoreNamedField(object, name, value, map, &lookup, false); |
| 3169 Push(value); | |
| 3170 instr->set_position(expr->position()); | 3164 instr->set_position(expr->position()); |
| 3165 // Goto will add the HSimulate for the store. |
| 3171 AddInstruction(instr); | 3166 AddInstruction(instr); |
| 3172 maps.Add(map); | 3167 if (!ast_context()->IsEffect()) Push(value); |
| 3173 subgraphs.Add(subgraph); | 3168 current_block()->Goto(join); |
| 3174 } else { | 3169 |
| 3175 needs_generic = true; | 3170 set_current_block(if_false); |
| 3176 } | 3171 } |
| 3177 } | 3172 } |
| 3178 | 3173 |
| 3179 // If none of the properties were named fields we generate a | 3174 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3180 // generic store. | 3175 // know about and do not want to handle ones we've never seen. Otherwise |
| 3181 if (maps.length() == 0) { | 3176 // use a generic IC. |
| 3177 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3178 current_block()->FinishExit(new HDeoptimize); |
| 3179 } else { |
| 3182 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3180 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| 3183 Push(value); | |
| 3184 instr->set_position(expr->position()); | 3181 instr->set_position(expr->position()); |
| 3185 AddInstruction(instr); | 3182 AddInstruction(instr); |
| 3186 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3183 |
| 3187 ast_context()->ReturnValue(Pop()); | 3184 if (join != NULL) { |
| 3188 } else { | 3185 if (!ast_context()->IsEffect()) Push(value); |
| 3189 // Build subgraph for generic store through IC. | 3186 current_block()->Goto(join); |
| 3190 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | 3187 } else { |
| 3191 { SubgraphScope scope(this, default_graph); | 3188 // The HSimulate for the store should not see the stored value in |
| 3192 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3189 // effect contexts (it is not materialized at expr->id() in the |
| 3193 default_graph->exit_block()->FinishExit(new HDeoptimize()); | 3190 // unoptimized code). |
| 3194 default_graph->set_exit_block(NULL); | 3191 if (instr->HasSideEffects()) { |
| 3195 } else { | 3192 if (ast_context()->IsEffect()) { |
| 3196 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3193 AddSimulate(expr->id()); |
| 3197 Push(value); | 3194 } else { |
| 3198 instr->set_position(expr->position()); | 3195 Push(value); |
| 3199 AddInstruction(instr); | 3196 AddSimulate(expr->id()); |
| 3197 Drop(1); |
| 3198 } |
| 3200 } | 3199 } |
| 3201 } | 3200 ast_context()->ReturnValue(value); |
| 3202 | 3201 return; |
| 3203 HBasicBlock* new_exit_block = | |
| 3204 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); | |
| 3205 set_current_block(new_exit_block); | |
| 3206 // In an effect context, we did not materialized the value in the | |
| 3207 // predecessor environments so there's no need to handle it here. | |
| 3208 if (current_block() != NULL && !ast_context()->IsEffect()) { | |
| 3209 ast_context()->ReturnValue(Pop()); | |
| 3210 } | 3202 } |
| 3211 } | 3203 } |
| 3204 |
| 3205 ASSERT(join != NULL); |
| 3206 join->SetJoinId(expr->id()); |
| 3207 set_current_block(join); |
| 3208 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 3212 } | 3209 } |
| 3213 | 3210 |
| 3214 | 3211 |
| 3215 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3212 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3216 Property* prop = expr->target()->AsProperty(); | 3213 Property* prop = expr->target()->AsProperty(); |
| 3217 ASSERT(prop != NULL); | 3214 ASSERT(prop != NULL); |
| 3218 expr->RecordTypeFeedback(oracle()); | 3215 expr->RecordTypeFeedback(oracle()); |
| 3219 VISIT_FOR_VALUE(prop->obj()); | 3216 VISIT_FOR_VALUE(prop->obj()); |
| 3220 | 3217 |
| 3221 HValue* value = NULL; | 3218 HValue* value = NULL; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3282 // owning expression instead of position and ast_id separately. | 3279 // owning expression instead of position and ast_id separately. |
| 3283 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, | 3280 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
| 3284 HValue* value, | 3281 HValue* value, |
| 3285 int position, | 3282 int position, |
| 3286 int ast_id) { | 3283 int ast_id) { |
| 3287 LookupResult lookup; | 3284 LookupResult lookup; |
| 3288 LookupGlobalPropertyCell(var, &lookup, true); | 3285 LookupGlobalPropertyCell(var, &lookup, true); |
| 3289 CHECK_BAILOUT; | 3286 CHECK_BAILOUT; |
| 3290 | 3287 |
| 3291 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | 3288 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 3292 Handle<GlobalObject> global(graph()->info()->global_object()); | 3289 Handle<GlobalObject> global(info()->global_object()); |
| 3293 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3290 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3294 HInstruction* instr = new HStoreGlobal(value, cell, check_hole); | 3291 HInstruction* instr = new HStoreGlobal(value, cell, check_hole); |
| 3295 instr->set_position(position); | 3292 instr->set_position(position); |
| 3296 AddInstruction(instr); | 3293 AddInstruction(instr); |
| 3297 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3294 if (instr->HasSideEffects()) AddSimulate(ast_id); |
| 3298 } | 3295 } |
| 3299 | 3296 |
| 3300 | 3297 |
| 3301 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3298 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
| 3302 Expression* target = expr->target(); | 3299 Expression* target = expr->target(); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3480 AddSimulate(expr->id()); | 3477 AddSimulate(expr->id()); |
| 3481 current_block()->FinishExit(new HAbnormalExit); | 3478 current_block()->FinishExit(new HAbnormalExit); |
| 3482 set_current_block(NULL); | 3479 set_current_block(NULL); |
| 3483 } | 3480 } |
| 3484 | 3481 |
| 3485 | 3482 |
| 3486 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3483 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
| 3487 HValue* object, | 3484 HValue* object, |
| 3488 ZoneMapList* types, | 3485 ZoneMapList* types, |
| 3489 Handle<String> name) { | 3486 Handle<String> name) { |
| 3490 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); | 3487 // TODO(ager): We should recognize when the prototype chains for different |
| 3491 ZoneMapList maps(number_of_types); | 3488 // maps are identical. In that case we can avoid repeatedly generating the |
| 3492 ZoneList<HSubgraph*> subgraphs(number_of_types); | 3489 // same prototype map checks. |
| 3493 bool needs_generic = (types->length() > kMaxLoadPolymorphism); | 3490 int count = 0; |
| 3494 | 3491 HBasicBlock* join = NULL; |
| 3495 // Build subgraphs for each of the specific maps. | 3492 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 3496 // | |
| 3497 // TODO(ager): We should recognize when the prototype chains for | |
| 3498 // different maps are identical. In that case we can avoid | |
| 3499 // repeatedly generating the same prototype map checks. | |
| 3500 for (int i = 0; i < number_of_types; ++i) { | |
| 3501 Handle<Map> map = types->at(i); | 3493 Handle<Map> map = types->at(i); |
| 3502 LookupResult lookup; | 3494 LookupResult lookup; |
| 3503 map->LookupInDescriptors(NULL, *name, &lookup); | 3495 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3504 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3496 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3505 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3497 if (count == 0) { |
| 3506 SubgraphScope scope(this, subgraph); | 3498 AddInstruction(new HCheckNonSmi(object)); // Only needed once. |
| 3499 join = graph()->CreateBasicBlock(); |
| 3500 } |
| 3501 ++count; |
| 3502 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3503 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3504 HCompareMap* compare = new HCompareMap(object, map, if_true, if_false); |
| 3505 current_block()->Finish(compare); |
| 3506 |
| 3507 set_current_block(if_true); |
| 3507 HLoadNamedField* instr = | 3508 HLoadNamedField* instr = |
| 3508 BuildLoadNamedField(object, expr, map, &lookup, false); | 3509 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3509 instr->set_position(expr->position()); | 3510 instr->set_position(expr->position()); |
| 3510 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. | 3511 instr->ClearFlag(HValue::kUseGVN); |
| 3511 PushAndAdd(instr); | 3512 AddInstruction(instr); |
| 3512 maps.Add(map); | 3513 if (!ast_context()->IsEffect()) Push(instr); |
| 3513 subgraphs.Add(subgraph); | 3514 current_block()->Goto(join); |
| 3514 } else { | 3515 |
| 3515 needs_generic = true; | 3516 set_current_block(if_false); |
| 3516 } | 3517 } |
| 3517 } | 3518 } |
| 3518 | 3519 |
| 3519 // If none of the properties were named fields we generate a | 3520 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3520 // generic load. | 3521 // know about and do not want to handle ones we've never seen. Otherwise |
| 3521 if (maps.length() == 0) { | 3522 // use a generic IC. |
| 3523 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3524 current_block()->FinishExit(new HDeoptimize); |
| 3525 } else { |
| 3522 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3526 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3523 instr->set_position(expr->position()); | 3527 instr->set_position(expr->position()); |
| 3524 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 3525 } else { | |
| 3526 // Build subgraph for generic load through IC. | |
| 3527 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | |
| 3528 { SubgraphScope scope(this, default_graph); | |
| 3529 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3530 default_graph->exit_block()->FinishExit(new HDeoptimize()); | |
| 3531 default_graph->set_exit_block(NULL); | |
| 3532 } else { | |
| 3533 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | |
| 3534 instr->set_position(expr->position()); | |
| 3535 PushAndAdd(instr); | |
| 3536 } | |
| 3537 } | |
| 3538 | 3528 |
| 3539 HBasicBlock* new_exit_block = | 3529 if (join != NULL) { |
| 3540 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); | 3530 AddInstruction(instr); |
| 3541 set_current_block(new_exit_block); | 3531 if (!ast_context()->IsEffect()) Push(instr); |
| 3542 // In an effect context, we did not materialized the value in the | 3532 current_block()->Goto(join); |
| 3543 // predecessor environments so there's no need to handle it here. | 3533 } else { |
| 3544 if (current_block() != NULL && !ast_context()->IsEffect()) { | 3534 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3545 ast_context()->ReturnValue(Pop()); | 3535 return; |
| 3546 } | 3536 } |
| 3547 } | 3537 } |
| 3538 |
| 3539 ASSERT(join != NULL); |
| 3540 join->SetJoinId(expr->id()); |
| 3541 set_current_block(join); |
| 3542 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 3548 } | 3543 } |
| 3549 | 3544 |
| 3550 | 3545 |
| 3551 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3546 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3552 Property* expr, | 3547 Property* expr, |
| 3553 Handle<Map> type, | 3548 Handle<Map> type, |
| 3554 LookupResult* lookup, | 3549 LookupResult* lookup, |
| 3555 bool smi_and_map_check) { | 3550 bool smi_and_map_check) { |
| 3556 if (smi_and_map_check) { | 3551 if (smi_and_map_check) { |
| 3557 AddInstruction(new HCheckNonSmi(object)); | 3552 AddInstruction(new HCheckNonSmi(object)); |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3829 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), | 3824 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), |
| 3830 expr->holder())); | 3825 expr->holder())); |
| 3831 } | 3826 } |
| 3832 } | 3827 } |
| 3833 | 3828 |
| 3834 | 3829 |
| 3835 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 3830 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
| 3836 HValue* receiver, | 3831 HValue* receiver, |
| 3837 ZoneMapList* types, | 3832 ZoneMapList* types, |
| 3838 Handle<String> name) { | 3833 Handle<String> name) { |
| 3839 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | |
| 3840 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | |
| 3841 ZoneMapList maps(number_of_types); | |
| 3842 ZoneList<HSubgraph*> subgraphs(number_of_types); | |
| 3843 bool needs_generic = (types->length() > kMaxCallPolymorphism); | |
| 3844 | |
| 3845 // Build subgraphs for each of the specific maps. | |
| 3846 // | |
| 3847 // TODO(ager): We should recognize when the prototype chains for different | 3834 // TODO(ager): We should recognize when the prototype chains for different |
| 3848 // maps are identical. In that case we can avoid repeatedly generating the | 3835 // maps are identical. In that case we can avoid repeatedly generating the |
| 3849 // same prototype map checks. | 3836 // same prototype map checks. |
| 3850 for (int i = 0; i < number_of_types; ++i) { | 3837 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 3838 int count = 0; |
| 3839 HBasicBlock* join = NULL; |
| 3840 for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) { |
| 3851 Handle<Map> map = types->at(i); | 3841 Handle<Map> map = types->at(i); |
| 3852 if (expr->ComputeTarget(map, name)) { | 3842 if (expr->ComputeTarget(map, name)) { |
| 3853 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3843 if (count == 0) { |
| 3854 SubgraphScope scope(this, subgraph); | 3844 AddInstruction(new HCheckNonSmi(receiver)); // Only needed once. |
| 3845 join = graph()->CreateBasicBlock(); |
| 3846 } |
| 3847 ++count; |
| 3848 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3849 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3850 HCompareMap* compare = new HCompareMap(receiver, map, if_true, if_false); |
| 3851 current_block()->Finish(compare); |
| 3852 |
| 3853 set_current_block(if_true); |
| 3855 AddCheckConstantFunction(expr, receiver, map, false); | 3854 AddCheckConstantFunction(expr, receiver, map, false); |
| 3856 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 3855 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 3857 PrintF("Trying to inline the polymorphic call to %s\n", | 3856 PrintF("Trying to inline the polymorphic call to %s\n", |
| 3858 *name->ToCString()); | 3857 *name->ToCString()); |
| 3859 } | 3858 } |
| 3860 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { | 3859 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { |
| 3861 // Check for bailout, as trying to inline might fail due to bailout | 3860 // Check for bailout, as trying to inline might fail due to bailout |
| 3862 // during hydrogen processing. | 3861 // during hydrogen processing. |
| 3863 CHECK_BAILOUT; | 3862 CHECK_BAILOUT; |
| 3864 HCallConstantFunction* call = | 3863 HCallConstantFunction* call = |
| 3865 new HCallConstantFunction(expr->target(), argument_count); | 3864 new HCallConstantFunction(expr->target(), argument_count); |
| 3866 call->set_position(expr->position()); | 3865 call->set_position(expr->position()); |
| 3867 PreProcessCall(call); | 3866 PreProcessCall(call); |
| 3868 PushAndAdd(call); | 3867 AddInstruction(call); |
| 3868 if (!ast_context()->IsEffect()) Push(call); |
| 3869 } | 3869 } |
| 3870 maps.Add(map); | 3870 |
| 3871 subgraphs.Add(subgraph); | 3871 if (current_block() != NULL) current_block()->Goto(join); |
| 3872 } else { | 3872 set_current_block(if_false); |
| 3873 needs_generic = true; | |
| 3874 } | 3873 } |
| 3875 } | 3874 } |
| 3876 | 3875 |
| 3877 // If we couldn't compute the target for any of the maps just perform an | 3876 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 3878 // IC call. | 3877 // know about and do not want to handle ones we've never seen. Otherwise |
| 3879 if (maps.length() == 0) { | 3878 // use a generic IC. |
| 3879 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 3880 current_block()->FinishExit(new HDeoptimize); |
| 3881 } else { |
| 3880 HContext* context = new HContext; | 3882 HContext* context = new HContext; |
| 3881 AddInstruction(context); | 3883 AddInstruction(context); |
| 3882 HCallNamed* call = new HCallNamed(context, name, argument_count); | 3884 HCallNamed* call = new HCallNamed(context, name, argument_count); |
| 3883 call->set_position(expr->position()); | 3885 call->set_position(expr->position()); |
| 3884 PreProcessCall(call); | 3886 PreProcessCall(call); |
| 3885 ast_context()->ReturnInstruction(call, expr->id()); | 3887 |
| 3886 } else { | 3888 if (join != NULL) { |
| 3887 // Build subgraph for generic call through IC. | 3889 AddInstruction(call); |
| 3888 HSubgraph* default_graph = CreateBranchSubgraph(environment()); | 3890 if (!ast_context()->IsEffect()) Push(call); |
| 3889 { SubgraphScope scope(this, default_graph); | 3891 current_block()->Goto(join); |
| 3890 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3892 } else { |
| 3891 default_graph->exit_block()->FinishExit(new HDeoptimize()); | 3893 ast_context()->ReturnInstruction(call, expr->id()); |
| 3892 default_graph->set_exit_block(NULL); | 3894 return; |
| 3893 } else { | |
| 3894 HContext* context = new HContext; | |
| 3895 AddInstruction(context); | |
| 3896 HCallNamed* call = new HCallNamed(context, name, argument_count); | |
| 3897 call->set_position(expr->position()); | |
| 3898 PreProcessCall(call); | |
| 3899 PushAndAdd(call); | |
| 3900 } | |
| 3901 } | 3895 } |
| 3896 } |
| 3902 | 3897 |
| 3903 HBasicBlock* new_exit_block = | 3898 // We assume that control flow is always live after an expression. So |
| 3904 BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id()); | 3899 // even without predecessors to the join block, we set it as the exit |
| 3905 set_current_block(new_exit_block); | 3900 // block and continue by adding instructions there. |
| 3906 // In an effect context, we did not materialized the value in the | 3901 ASSERT(join != NULL); |
| 3907 // predecessor environments so there's no need to handle it here. | 3902 set_current_block(join); |
| 3908 if (new_exit_block != NULL && !ast_context()->IsEffect()) { | 3903 if (join->HasPredecessor()) { |
| 3909 ast_context()->ReturnValue(Pop()); | 3904 join->SetJoinId(expr->id()); |
| 3905 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 3906 } |
| 3907 } |
| 3908 |
| 3909 |
| 3910 void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) { |
| 3911 if (FLAG_trace_inlining) { |
| 3912 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); |
| 3913 SmartPointer<char> caller = |
| 3914 info()->function()->debug_name()->ToCString(); |
| 3915 if (reason == NULL) { |
| 3916 PrintF("Inlined %s called from %s.\n", *callee, *caller); |
| 3917 } else { |
| 3918 PrintF("Did not inline %s called from %s (%s).\n", |
| 3919 *callee, *caller, reason); |
| 3910 } | 3920 } |
| 3911 } | 3921 } |
| 3912 } | 3922 } |
| 3913 | 3923 |
| 3914 | |
| 3915 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | |
| 3916 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); | |
| 3917 SmartPointer<char> caller = | |
| 3918 graph()->info()->function()->debug_name()->ToCString(); | |
| 3919 if (result) { | |
| 3920 PrintF("Inlined %s called from %s.\n", *callee, *caller); | |
| 3921 } else { | |
| 3922 PrintF("Do not inline %s called from %s.\n", *callee, *caller); | |
| 3923 } | |
| 3924 } | |
| 3925 | |
| 3926 | 3924 |
| 3927 bool HGraphBuilder::TryInline(Call* expr) { | 3925 bool HGraphBuilder::TryInline(Call* expr) { |
| 3928 if (!FLAG_use_inlining) return false; | 3926 if (!FLAG_use_inlining) return false; |
| 3929 | 3927 |
| 3930 // Precondition: call is monomorphic and we have found a target with the | 3928 // Precondition: call is monomorphic and we have found a target with the |
| 3931 // appropriate arity. | 3929 // appropriate arity. |
| 3932 Handle<JSFunction> target = expr->target(); | 3930 Handle<JSFunction> target = expr->target(); |
| 3933 | 3931 |
| 3934 // Do a quick check on source code length to avoid parsing large | 3932 // Do a quick check on source code length to avoid parsing large |
| 3935 // inlining candidates. | 3933 // inlining candidates. |
| 3936 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { | 3934 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { |
| 3937 if (FLAG_trace_inlining) TraceInline(target, false); | 3935 TraceInline(target, "target text too big"); |
| 3938 return false; | 3936 return false; |
| 3939 } | 3937 } |
| 3940 | 3938 |
| 3941 // Target must be inlineable. | 3939 // Target must be inlineable. |
| 3942 if (!target->IsInlineable()) return false; | 3940 if (!target->IsInlineable()) { |
| 3941 TraceInline(target, "target not inlineable"); |
| 3942 return false; |
| 3943 } |
| 3943 | 3944 |
| 3944 // No context change required. | 3945 // No context change required. |
| 3945 CompilationInfo* outer_info = graph()->info(); | 3946 CompilationInfo* outer_info = info(); |
| 3946 if (target->context() != outer_info->closure()->context() || | 3947 if (target->context() != outer_info->closure()->context() || |
| 3947 outer_info->scope()->contains_with() || | 3948 outer_info->scope()->contains_with() || |
| 3948 outer_info->scope()->num_heap_slots() > 0) { | 3949 outer_info->scope()->num_heap_slots() > 0) { |
| 3950 TraceInline(target, "target requires context change"); |
| 3949 return false; | 3951 return false; |
| 3950 } | 3952 } |
| 3951 | 3953 |
| 3952 // Don't inline deeper than two calls. | 3954 // Don't inline deeper than two calls. |
| 3953 HEnvironment* env = environment(); | 3955 HEnvironment* env = environment(); |
| 3954 if (env->outer() != NULL && env->outer()->outer() != NULL) return false; | 3956 if (env->outer() != NULL && env->outer()->outer() != NULL) { |
| 3957 TraceInline(target, "inline depth limit reached"); |
| 3958 return false; |
| 3959 } |
| 3955 | 3960 |
| 3956 // Don't inline recursive functions. | 3961 // Don't inline recursive functions. |
| 3957 if (target->shared() == outer_info->closure()->shared()) return false; | 3962 if (target->shared() == outer_info->closure()->shared()) { |
| 3963 TraceInline(target, "target is recursive"); |
| 3964 return false; |
| 3965 } |
| 3958 | 3966 |
| 3959 // We don't want to add more than a certain number of nodes from inlining. | 3967 // We don't want to add more than a certain number of nodes from inlining. |
| 3960 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { | 3968 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { |
| 3961 if (FLAG_trace_inlining) TraceInline(target, false); | 3969 TraceInline(target, "cumulative AST node limit reached"); |
| 3962 return false; | 3970 return false; |
| 3963 } | 3971 } |
| 3964 | 3972 |
| 3965 int count_before = AstNode::Count(); | 3973 int count_before = AstNode::Count(); |
| 3966 | 3974 |
| 3967 // Parse and allocate variables. | 3975 // Parse and allocate variables. |
| 3968 CompilationInfo inner_info(target); | 3976 CompilationInfo target_info(target); |
| 3969 if (!ParserApi::Parse(&inner_info) || | 3977 if (!ParserApi::Parse(&target_info) || |
| 3970 !Scope::Analyze(&inner_info)) { | 3978 !Scope::Analyze(&target_info)) { |
| 3971 if (inner_info.isolate()->has_pending_exception()) { | 3979 if (target_info.isolate()->has_pending_exception()) { |
| 3980 // Parse or scope error, never optimize this function. |
| 3972 SetStackOverflow(); | 3981 SetStackOverflow(); |
| 3973 // Stop trying to optimize and inline this function. | |
| 3974 target->shared()->set_optimization_disabled(true); | 3982 target->shared()->set_optimization_disabled(true); |
| 3975 } | 3983 } |
| 3984 TraceInline(target, "parse failure"); |
| 3976 return false; | 3985 return false; |
| 3977 } | 3986 } |
| 3978 if (inner_info.scope()->num_heap_slots() > 0) return false; | 3987 |
| 3979 FunctionLiteral* function = inner_info.function(); | 3988 if (target_info.scope()->num_heap_slots() > 0) { |
| 3989 TraceInline(target, "target has context-allocated variables"); |
| 3990 return false; |
| 3991 } |
| 3992 FunctionLiteral* function = target_info.function(); |
| 3980 | 3993 |
| 3981 // Count the number of AST nodes added by inlining this call. | 3994 // Count the number of AST nodes added by inlining this call. |
| 3982 int nodes_added = AstNode::Count() - count_before; | 3995 int nodes_added = AstNode::Count() - count_before; |
| 3983 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | 3996 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { |
| 3984 if (FLAG_trace_inlining) TraceInline(target, false); | 3997 TraceInline(target, "target AST is too large"); |
| 3985 return false; | 3998 return false; |
| 3986 } | 3999 } |
| 3987 | 4000 |
| 3988 // Check if we can handle all declarations in the inlined functions. | 4001 // Check if we can handle all declarations in the inlined functions. |
| 3989 VisitDeclarations(inner_info.scope()->declarations()); | 4002 VisitDeclarations(target_info.scope()->declarations()); |
| 3990 if (HasStackOverflow()) { | 4003 if (HasStackOverflow()) { |
| 4004 TraceInline(target, "target has non-trivial declaration"); |
| 3991 ClearStackOverflow(); | 4005 ClearStackOverflow(); |
| 3992 return false; | 4006 return false; |
| 3993 } | 4007 } |
| 3994 | 4008 |
| 3995 // Don't inline functions that uses the arguments object or that | 4009 // Don't inline functions that uses the arguments object or that |
| 3996 // have a mismatching number of parameters. | 4010 // have a mismatching number of parameters. |
| 3997 Handle<SharedFunctionInfo> shared(target->shared()); | 4011 Handle<SharedFunctionInfo> target_shared(target->shared()); |
| 3998 int arity = expr->arguments()->length(); | 4012 int arity = expr->arguments()->length(); |
| 3999 if (function->scope()->arguments() != NULL || | 4013 if (function->scope()->arguments() != NULL || |
| 4000 arity != shared->formal_parameter_count()) { | 4014 arity != target_shared->formal_parameter_count()) { |
| 4015 TraceInline(target, "target requires special argument handling"); |
| 4001 return false; | 4016 return false; |
| 4002 } | 4017 } |
| 4003 | 4018 |
| 4004 // All statements in the body must be inlineable. | 4019 // All statements in the body must be inlineable. |
| 4005 for (int i = 0, count = function->body()->length(); i < count; ++i) { | 4020 for (int i = 0, count = function->body()->length(); i < count; ++i) { |
| 4006 if (!function->body()->at(i)->IsInlineable()) return false; | 4021 if (!function->body()->at(i)->IsInlineable()) { |
| 4022 TraceInline(target, "target contains unsupported syntax"); |
| 4023 return false; |
| 4024 } |
| 4007 } | 4025 } |
| 4008 | 4026 |
| 4009 // Generate the deoptimization data for the unoptimized version of | 4027 // Generate the deoptimization data for the unoptimized version of |
| 4010 // the target function if we don't already have it. | 4028 // the target function if we don't already have it. |
| 4011 if (!shared->has_deoptimization_support()) { | 4029 if (!target_shared->has_deoptimization_support()) { |
| 4012 // Note that we compile here using the same AST that we will use for | 4030 // Note that we compile here using the same AST that we will use for |
| 4013 // generating the optimized inline code. | 4031 // generating the optimized inline code. |
| 4014 inner_info.EnableDeoptimizationSupport(); | 4032 target_info.EnableDeoptimizationSupport(); |
| 4015 if (!FullCodeGenerator::MakeCode(&inner_info)) return false; | 4033 if (!FullCodeGenerator::MakeCode(&target_info)) { |
| 4016 shared->EnableDeoptimizationSupport(*inner_info.code()); | 4034 TraceInline(target, "could not generate deoptimization info"); |
| 4017 Compiler::RecordFunctionCompilation( | 4035 return false; |
| 4018 Logger::FUNCTION_TAG, &inner_info, shared); | 4036 } |
| 4037 target_shared->EnableDeoptimizationSupport(*target_info.code()); |
| 4038 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, |
| 4039 &target_info, |
| 4040 target_shared); |
| 4019 } | 4041 } |
| 4020 | 4042 |
| 4043 // ---------------------------------------------------------------- |
| 4021 // Save the pending call context and type feedback oracle. Set up new ones | 4044 // Save the pending call context and type feedback oracle. Set up new ones |
| 4022 // for the inlined function. | 4045 // for the inlined function. |
| 4023 ASSERT(shared->has_deoptimization_support()); | 4046 ASSERT(target_shared->has_deoptimization_support()); |
| 4024 AstContext* saved_call_context = call_context(); | 4047 TypeFeedbackOracle target_oracle( |
| 4025 HBasicBlock* saved_function_return = function_return(); | 4048 Handle<Code>(target_shared->code()), |
| 4026 TypeFeedbackOracle* saved_oracle = oracle(); | 4049 Handle<Context>(target->context()->global_context())); |
| 4027 // On-stack replacement cannot target inlined functions. Since we don't | 4050 FunctionState target_state(this, &target_info, &target_oracle); |
| 4028 // use a separate CompilationInfo structure for the inlined function, we | |
| 4029 // save and restore the AST ID in the original compilation info. | |
| 4030 int saved_osr_ast_id = graph()->info()->osr_ast_id(); | |
| 4031 | 4051 |
| 4032 TestContext* test_context = NULL; | 4052 HConstant* undefined = graph()->GetConstantUndefined(); |
| 4033 if (ast_context()->IsTest()) { | 4053 HEnvironment* inner_env = |
| 4034 // Inlined body is treated as if it occurs in an 'inlined' call context | 4054 environment()->CopyForInlining(target, function, true, undefined); |
| 4035 // with true and false blocks that will forward to the real ones. | 4055 HBasicBlock* body_entry = CreateBasicBlock(inner_env); |
| 4036 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4056 current_block()->Goto(body_entry); |
| 4037 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
| 4038 if_true->MarkAsInlineReturnTarget(); | |
| 4039 if_false->MarkAsInlineReturnTarget(); | |
| 4040 // AstContext constructor pushes on the context stack. | |
| 4041 test_context = new TestContext(this, if_true, if_false); | |
| 4042 function_return_ = NULL; | |
| 4043 } else { | |
| 4044 // Inlined body is treated as if it occurs in the original call context. | |
| 4045 function_return_ = graph()->CreateBasicBlock(); | |
| 4046 function_return_->MarkAsInlineReturnTarget(); | |
| 4047 } | |
| 4048 call_context_ = ast_context(); | |
| 4049 TypeFeedbackOracle new_oracle( | |
| 4050 Handle<Code>(shared->code()), | |
| 4051 Handle<Context>(target->context()->global_context())); | |
| 4052 oracle_ = &new_oracle; | |
| 4053 graph()->info()->SetOsrAstId(AstNode::kNoNumber); | |
| 4054 | 4057 |
| 4055 HSubgraph* body = CreateInlinedSubgraph(env, target, function); | 4058 body_entry->SetJoinId(expr->ReturnId()); |
| 4056 body->exit_block()->AddInstruction(new HEnterInlined(target, function)); | 4059 set_current_block(body_entry); |
| 4057 AddToSubgraph(body, function->body()); | 4060 AddInstruction(new HEnterInlined(target, function)); |
| 4061 VisitStatements(function->body()); |
| 4058 if (HasStackOverflow()) { | 4062 if (HasStackOverflow()) { |
| 4059 // Bail out if the inline function did, as we cannot residualize a call | 4063 // Bail out if the inline function did, as we cannot residualize a call |
| 4060 // instead. | 4064 // instead. |
| 4061 delete test_context; | 4065 TraceInline(target, "inline graph construction failed"); |
| 4062 call_context_ = saved_call_context; | |
| 4063 function_return_ = saved_function_return; | |
| 4064 oracle_ = saved_oracle; | |
| 4065 graph()->info()->SetOsrAstId(saved_osr_ast_id); | |
| 4066 return false; | 4066 return false; |
| 4067 } | 4067 } |
| 4068 | 4068 |
| 4069 // Update inlined nodes count. | 4069 // Update inlined nodes count. |
| 4070 inlined_count_ += nodes_added; | 4070 inlined_count_ += nodes_added; |
| 4071 | 4071 |
| 4072 if (FLAG_trace_inlining) TraceInline(target, true); | 4072 TraceInline(target, NULL); |
| 4073 | 4073 |
| 4074 if (body->exit_block() != NULL) { | 4074 if (current_block() != NULL) { |
| 4075 // Add a return of undefined if control can fall off the body. In a | 4075 // Add a return of undefined if control can fall off the body. In a |
| 4076 // test context, undefined is false. | 4076 // test context, undefined is false. |
| 4077 HValue* return_value = graph()->GetConstantUndefined(); | 4077 if (inlined_test_context() == NULL) { |
| 4078 if (test_context == NULL) { | 4078 ASSERT(function_return() != NULL); |
| 4079 ASSERT(function_return_ != NULL); | 4079 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
| 4080 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4080 if (call_context()->IsEffect()) { |
| 4081 current_block()->Goto(function_return(), false); |
| 4082 } else { |
| 4083 current_block()->AddLeaveInlined(undefined, function_return()); |
| 4084 } |
| 4081 } else { | 4085 } else { |
| 4082 // The graph builder assumes control can reach both branches of a | 4086 // The graph builder assumes control can reach both branches of a |
| 4083 // test, so we materialize the undefined value and test it rather than | 4087 // test, so we materialize the undefined value and test it rather than |
| 4084 // simply jumping to the false target. | 4088 // simply jumping to the false target. |
| 4085 // | 4089 // |
| 4086 // TODO(3168478): refactor to avoid this. | 4090 // TODO(3168478): refactor to avoid this. |
| 4087 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4091 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 4088 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4092 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 4089 HTest* test = new HTest(return_value, empty_true, empty_false); | 4093 HTest* test = new HTest(undefined, empty_true, empty_false); |
| 4090 body->exit_block()->Finish(test); | 4094 current_block()->Finish(test); |
| 4091 | 4095 |
| 4092 HValue* const no_return_value = NULL; | 4096 empty_true->Goto(inlined_test_context()->if_true(), false); |
| 4093 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); | 4097 empty_false->Goto(inlined_test_context()->if_false(), false); |
| 4094 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); | |
| 4095 } | 4098 } |
| 4096 body->set_exit_block(NULL); | |
| 4097 } | 4099 } |
| 4098 | 4100 |
| 4099 // Record the environment at the inlined function call. | |
| 4100 AddSimulate(expr->ReturnId()); | |
| 4101 | |
| 4102 // Jump to the function entry (without re-recording the environment). | |
| 4103 current_block()->Finish(new HGoto(body->entry_block())); | |
| 4104 | |
| 4105 // Fix up the function exits. | 4101 // Fix up the function exits. |
| 4106 if (test_context != NULL) { | 4102 if (inlined_test_context() != NULL) { |
| 4107 HBasicBlock* if_true = test_context->if_true(); | 4103 HBasicBlock* if_true = inlined_test_context()->if_true(); |
| 4108 HBasicBlock* if_false = test_context->if_false(); | 4104 HBasicBlock* if_false = inlined_test_context()->if_false(); |
| 4109 if_true->SetJoinId(expr->id()); | 4105 if_true->SetJoinId(expr->id()); |
| 4110 if_false->SetJoinId(expr->id()); | 4106 if_false->SetJoinId(expr->id()); |
| 4111 ASSERT(ast_context() == test_context); | 4107 ASSERT(ast_context() == inlined_test_context()); |
| 4112 delete test_context; // Destructor pops from expression context stack. | 4108 // Pop the return test context from the expression context stack. |
| 4109 ClearInlinedTestContext(); |
| 4113 | 4110 |
| 4114 // Forward to the real test context. | 4111 // Forward to the real test context. |
| 4115 HValue* const no_return_value = NULL; | |
| 4116 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4112 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 4117 if (true_target->IsInlineReturnTarget()) { | |
| 4118 if_true->AddLeaveInlined(no_return_value, true_target); | |
| 4119 } else { | |
| 4120 if_true->Goto(true_target); | |
| 4121 } | |
| 4122 | |
| 4123 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4113 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 4124 if (false_target->IsInlineReturnTarget()) { | 4114 if_true->Goto(true_target, false); |
| 4125 if_false->AddLeaveInlined(no_return_value, false_target); | 4115 if_false->Goto(false_target, false); |
| 4126 } else { | |
| 4127 if_false->Goto(false_target); | |
| 4128 } | |
| 4129 | 4116 |
| 4130 // TODO(kmillikin): Come up with a better way to handle this. It is too | 4117 // TODO(kmillikin): Come up with a better way to handle this. It is too |
| 4131 // subtle. NULL here indicates that the enclosing context has no control | 4118 // subtle. NULL here indicates that the enclosing context has no control |
| 4132 // flow to handle. | 4119 // flow to handle. |
| 4133 set_current_block(NULL); | 4120 set_current_block(NULL); |
| 4134 | 4121 |
| 4135 } else { | 4122 } else { |
| 4136 function_return_->SetJoinId(expr->id()); | 4123 function_return()->SetJoinId(expr->id()); |
| 4137 set_current_block(function_return_); | 4124 set_current_block(function_return()); |
| 4138 } | 4125 } |
| 4139 | 4126 |
| 4140 call_context_ = saved_call_context; | |
| 4141 function_return_ = saved_function_return; | |
| 4142 oracle_ = saved_oracle; | |
| 4143 graph()->info()->SetOsrAstId(saved_osr_ast_id); | |
| 4144 | |
| 4145 return true; | 4127 return true; |
| 4146 } | 4128 } |
| 4147 | 4129 |
| 4148 | 4130 |
| 4149 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | |
| 4150 ASSERT(target->IsInlineReturnTarget()); | |
| 4151 AddInstruction(new HLeaveInlined); | |
| 4152 HEnvironment* outer = last_environment()->outer(); | |
| 4153 if (return_value != NULL) outer->Push(return_value); | |
| 4154 UpdateEnvironment(outer); | |
| 4155 Goto(target); | |
| 4156 } | |
| 4157 | |
| 4158 | |
| 4159 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, | 4131 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
| 4160 HValue* receiver, | 4132 HValue* receiver, |
| 4161 Handle<Map> receiver_map, | 4133 Handle<Map> receiver_map, |
| 4162 CheckType check_type) { | 4134 CheckType check_type) { |
| 4163 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | 4135 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
| 4164 // Try to inline calls like Math.* as operations in the calling function. | 4136 // Try to inline calls like Math.* as operations in the calling function. |
| 4165 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 4137 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 4166 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 4138 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4167 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4139 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4168 switch (id) { | 4140 switch (id) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4242 } | 4214 } |
| 4243 return false; | 4215 return false; |
| 4244 } | 4216 } |
| 4245 | 4217 |
| 4246 | 4218 |
| 4247 bool HGraphBuilder::TryCallApply(Call* expr) { | 4219 bool HGraphBuilder::TryCallApply(Call* expr) { |
| 4248 Expression* callee = expr->expression(); | 4220 Expression* callee = expr->expression(); |
| 4249 Property* prop = callee->AsProperty(); | 4221 Property* prop = callee->AsProperty(); |
| 4250 ASSERT(prop != NULL); | 4222 ASSERT(prop != NULL); |
| 4251 | 4223 |
| 4252 if (graph()->info()->scope()->arguments() == NULL) return false; | 4224 if (info()->scope()->arguments() == NULL) return false; |
| 4253 | 4225 |
| 4254 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4226 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4255 if (!name->IsEqualTo(CStrVector("apply"))) return false; | 4227 if (!name->IsEqualTo(CStrVector("apply"))) return false; |
| 4256 | 4228 |
| 4257 ZoneList<Expression*>* args = expr->arguments(); | 4229 ZoneList<Expression*>* args = expr->arguments(); |
| 4258 if (args->length() != 2) return false; | 4230 if (args->length() != 2) return false; |
| 4259 | 4231 |
| 4260 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 4232 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 4261 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 4233 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 4262 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 4234 HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4355 // When the target has a custom call IC generator, use the IC, | 4327 // When the target has a custom call IC generator, use the IC, |
| 4356 // because it is likely to generate better code. Also use the | 4328 // because it is likely to generate better code. Also use the |
| 4357 // IC when a primitive receiver check is required. | 4329 // IC when a primitive receiver check is required. |
| 4358 HContext* context = new HContext; | 4330 HContext* context = new HContext; |
| 4359 AddInstruction(context); | 4331 AddInstruction(context); |
| 4360 call = PreProcessCall(new HCallNamed(context, name, argument_count)); | 4332 call = PreProcessCall(new HCallNamed(context, name, argument_count)); |
| 4361 } else { | 4333 } else { |
| 4362 AddCheckConstantFunction(expr, receiver, receiver_map, true); | 4334 AddCheckConstantFunction(expr, receiver, receiver_map, true); |
| 4363 | 4335 |
| 4364 if (TryInline(expr)) { | 4336 if (TryInline(expr)) { |
| 4365 if (current_block() != NULL) { | |
| 4366 HValue* return_value = Pop(); | |
| 4367 // If we inlined a function in a test context then we need to emit | |
| 4368 // a simulate here to shadow the ones at the end of the | |
| 4369 // predecessor blocks. Those environments contain the return | |
| 4370 // value on top and do not correspond to any actual state of the | |
| 4371 // unoptimized code. | |
| 4372 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4373 ast_context()->ReturnValue(return_value); | |
| 4374 } | |
| 4375 return; | 4337 return; |
| 4376 } else { | 4338 } else { |
| 4377 // Check for bailout, as the TryInline call in the if condition above | 4339 // Check for bailout, as the TryInline call in the if condition above |
| 4378 // might return false due to bailout during hydrogen processing. | 4340 // might return false due to bailout during hydrogen processing. |
| 4379 CHECK_BAILOUT; | 4341 CHECK_BAILOUT; |
| 4380 call = PreProcessCall(new HCallConstantFunction(expr->target(), | 4342 call = PreProcessCall(new HCallConstantFunction(expr->target(), |
| 4381 argument_count)); | 4343 argument_count)); |
| 4382 } | 4344 } |
| 4383 } | 4345 } |
| 4384 } else if (types != NULL && types->length() > 1) { | 4346 } else if (types != NULL && types->length() > 1) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4395 } else { | 4357 } else { |
| 4396 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4358 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4397 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); | 4359 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); |
| 4398 | 4360 |
| 4399 if (!global_call) { | 4361 if (!global_call) { |
| 4400 ++argument_count; | 4362 ++argument_count; |
| 4401 VISIT_FOR_VALUE(expr->expression()); | 4363 VISIT_FOR_VALUE(expr->expression()); |
| 4402 } | 4364 } |
| 4403 | 4365 |
| 4404 if (global_call) { | 4366 if (global_call) { |
| 4367 bool known_global_function = false; |
| 4405 // If there is a global property cell for the name at compile time and | 4368 // If there is a global property cell for the name at compile time and |
| 4406 // access check is not enabled we assume that the function will not change | 4369 // access check is not enabled we assume that the function will not change |
| 4407 // and generate optimized code for calling the function. | 4370 // and generate optimized code for calling the function. |
| 4408 CompilationInfo* info = graph()->info(); | 4371 if (info()->has_global_object() && |
| 4409 bool known_global_function = info->has_global_object() && | 4372 !info()->global_object()->IsAccessCheckNeeded()) { |
| 4410 !info->global_object()->IsAccessCheckNeeded() && | 4373 Handle<GlobalObject> global(info()->global_object()); |
| 4411 expr->ComputeGlobalTarget(Handle<GlobalObject>(info->global_object()), | 4374 known_global_function = expr->ComputeGlobalTarget(global, var->name()); |
| 4412 var->name()); | 4375 } |
| 4413 if (known_global_function) { | 4376 if (known_global_function) { |
| 4414 // Push the global object instead of the global receiver because | 4377 // Push the global object instead of the global receiver because |
| 4415 // code generated by the full code generator expects it. | 4378 // code generated by the full code generator expects it. |
| 4416 HContext* context = new HContext; | 4379 HContext* context = new HContext; |
| 4417 HGlobalObject* global_object = new HGlobalObject(context); | 4380 HGlobalObject* global_object = new HGlobalObject(context); |
| 4418 AddInstruction(context); | 4381 AddInstruction(context); |
| 4419 PushAndAdd(global_object); | 4382 PushAndAdd(global_object); |
| 4420 VisitExpressions(expr->arguments()); | 4383 VisitExpressions(expr->arguments()); |
| 4421 CHECK_BAILOUT; | 4384 CHECK_BAILOUT; |
| 4422 | 4385 |
| 4423 VISIT_FOR_VALUE(expr->expression()); | 4386 VISIT_FOR_VALUE(expr->expression()); |
| 4424 HValue* function = Pop(); | 4387 HValue* function = Pop(); |
| 4425 AddInstruction(new HCheckFunction(function, expr->target())); | 4388 AddInstruction(new HCheckFunction(function, expr->target())); |
| 4426 | 4389 |
| 4427 // Replace the global object with the global receiver. | 4390 // Replace the global object with the global receiver. |
| 4428 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); | 4391 HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); |
| 4429 // Index of the receiver from the top of the expression stack. | 4392 // Index of the receiver from the top of the expression stack. |
| 4430 const int receiver_index = argument_count - 1; | 4393 const int receiver_index = argument_count - 1; |
| 4431 AddInstruction(global_receiver); | 4394 AddInstruction(global_receiver); |
| 4432 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4395 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 4433 IsGlobalObject()); | 4396 IsGlobalObject()); |
| 4434 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4397 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 4435 | 4398 |
| 4436 if (TryInline(expr)) { | 4399 if (TryInline(expr)) { |
| 4437 if (current_block() != NULL) { | |
| 4438 HValue* return_value = Pop(); | |
| 4439 // If we inlined a function in a test context then we need to | |
| 4440 // emit a simulate here to shadow the ones at the end of the | |
| 4441 // predecessor blocks. Those environments contain the return | |
| 4442 // value on top and do not correspond to any actual state of the | |
| 4443 // unoptimized code. | |
| 4444 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4445 ast_context()->ReturnValue(return_value); | |
| 4446 } | |
| 4447 return; | 4400 return; |
| 4448 } | 4401 } |
| 4449 // Check for bailout, as trying to inline might fail due to bailout | 4402 // Check for bailout, as trying to inline might fail due to bailout |
| 4450 // during hydrogen processing. | 4403 // during hydrogen processing. |
| 4451 CHECK_BAILOUT; | 4404 CHECK_BAILOUT; |
| 4452 | 4405 |
| 4453 call = PreProcessCall(new HCallKnownGlobal(expr->target(), | 4406 call = PreProcessCall(new HCallKnownGlobal(expr->target(), |
| 4454 argument_count)); | 4407 argument_count)); |
| 4455 } else { | 4408 } else { |
| 4456 HContext* context = new HContext; | 4409 HContext* context = new HContext; |
| (...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5031 return; | 4984 return; |
| 5032 } | 4985 } |
| 5033 | 4986 |
| 5034 VISIT_FOR_VALUE(expr->left()); | 4987 VISIT_FOR_VALUE(expr->left()); |
| 5035 VISIT_FOR_VALUE(expr->right()); | 4988 VISIT_FOR_VALUE(expr->right()); |
| 5036 | 4989 |
| 5037 HValue* right = Pop(); | 4990 HValue* right = Pop(); |
| 5038 HValue* left = Pop(); | 4991 HValue* left = Pop(); |
| 5039 Token::Value op = expr->op(); | 4992 Token::Value op = expr->op(); |
| 5040 | 4993 |
| 5041 TypeInfo info = oracle()->CompareType(expr); | 4994 TypeInfo type_info = oracle()->CompareType(expr); |
| 5042 HInstruction* instr = NULL; | 4995 HInstruction* instr = NULL; |
| 5043 if (op == Token::INSTANCEOF) { | 4996 if (op == Token::INSTANCEOF) { |
| 5044 // Check to see if the rhs of the instanceof is a global function not | 4997 // Check to see if the rhs of the instanceof is a global function not |
| 5045 // residing in new space. If it is we assume that the function will stay the | 4998 // residing in new space. If it is we assume that the function will stay the |
| 5046 // same. | 4999 // same. |
| 5047 Handle<JSFunction> target = Handle<JSFunction>::null(); | 5000 Handle<JSFunction> target = Handle<JSFunction>::null(); |
| 5048 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); | 5001 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); |
| 5049 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); | 5002 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); |
| 5050 CompilationInfo* info = graph()->info(); | |
| 5051 if (global_function && | 5003 if (global_function && |
| 5052 info->has_global_object() && | 5004 info()->has_global_object() && |
| 5053 !info->global_object()->IsAccessCheckNeeded()) { | 5005 !info()->global_object()->IsAccessCheckNeeded()) { |
| 5054 Handle<String> name = var->name(); | 5006 Handle<String> name = var->name(); |
| 5055 Handle<GlobalObject> global(info->global_object()); | 5007 Handle<GlobalObject> global(info()->global_object()); |
| 5056 LookupResult lookup; | 5008 LookupResult lookup; |
| 5057 global->Lookup(*name, &lookup); | 5009 global->Lookup(*name, &lookup); |
| 5058 if (lookup.IsProperty() && | 5010 if (lookup.IsProperty() && |
| 5059 lookup.type() == NORMAL && | 5011 lookup.type() == NORMAL && |
| 5060 lookup.GetValue()->IsJSFunction()) { | 5012 lookup.GetValue()->IsJSFunction()) { |
| 5061 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); | 5013 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
| 5062 // If the function is in new space we assume it's more likely to | 5014 // If the function is in new space we assume it's more likely to |
| 5063 // change and thus prefer the general IC code. | 5015 // change and thus prefer the general IC code. |
| 5064 if (!info->isolate()->heap()->InNewSpace(*candidate)) { | 5016 if (!Isolate::Current()->heap()->InNewSpace(*candidate)) { |
| 5065 target = candidate; | 5017 target = candidate; |
| 5066 } | 5018 } |
| 5067 } | 5019 } |
| 5068 } | 5020 } |
| 5069 | 5021 |
| 5070 // If the target is not null we have found a known global function that is | 5022 // If the target is not null we have found a known global function that is |
| 5071 // assumed to stay the same for this instanceof. | 5023 // assumed to stay the same for this instanceof. |
| 5072 if (target.is_null()) { | 5024 if (target.is_null()) { |
| 5073 HContext* context = new HContext; | 5025 HContext* context = new HContext; |
| 5074 AddInstruction(context); | 5026 AddInstruction(context); |
| 5075 instr = new HInstanceOf(context, left, right); | 5027 instr = new HInstanceOf(context, left, right); |
| 5076 } else { | 5028 } else { |
| 5077 AddInstruction(new HCheckFunction(right, target)); | 5029 AddInstruction(new HCheckFunction(right, target)); |
| 5078 instr = new HInstanceOfKnownGlobal(left, target); | 5030 instr = new HInstanceOfKnownGlobal(left, target); |
| 5079 } | 5031 } |
| 5080 } else if (op == Token::IN) { | 5032 } else if (op == Token::IN) { |
| 5081 BAILOUT("Unsupported comparison: in"); | 5033 BAILOUT("Unsupported comparison: in"); |
| 5082 } else if (info.IsNonPrimitive()) { | 5034 } else if (type_info.IsNonPrimitive()) { |
| 5083 switch (op) { | 5035 switch (op) { |
| 5084 case Token::EQ: | 5036 case Token::EQ: |
| 5085 case Token::EQ_STRICT: { | 5037 case Token::EQ_STRICT: { |
| 5086 AddInstruction(new HCheckNonSmi(left)); | 5038 AddInstruction(new HCheckNonSmi(left)); |
| 5087 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); | 5039 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); |
| 5088 AddInstruction(new HCheckNonSmi(right)); | 5040 AddInstruction(new HCheckNonSmi(right)); |
| 5089 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); | 5041 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); |
| 5090 instr = new HCompareJSObjectEq(left, right); | 5042 instr = new HCompareJSObjectEq(left, right); |
| 5091 break; | 5043 break; |
| 5092 } | 5044 } |
| 5093 default: | 5045 default: |
| 5094 BAILOUT("Unsupported non-primitive compare"); | 5046 BAILOUT("Unsupported non-primitive compare"); |
| 5095 break; | 5047 break; |
| 5096 } | 5048 } |
| 5097 } else { | 5049 } else { |
| 5098 HCompare* compare = new HCompare(left, right, op); | 5050 HCompare* compare = new HCompare(left, right, op); |
| 5099 Representation r = ToRepresentation(info); | 5051 Representation r = ToRepresentation(type_info); |
| 5100 compare->SetInputRepresentation(r); | 5052 compare->SetInputRepresentation(r); |
| 5101 instr = compare; | 5053 instr = compare; |
| 5102 } | 5054 } |
| 5103 instr->set_position(expr->position()); | 5055 instr->set_position(expr->position()); |
| 5104 ast_context()->ReturnInstruction(instr, expr->id()); | 5056 ast_context()->ReturnInstruction(instr, expr->id()); |
| 5105 } | 5057 } |
| 5106 | 5058 |
| 5107 | 5059 |
| 5108 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { | 5060 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { |
| 5109 VISIT_FOR_VALUE(expr->expression()); | 5061 VISIT_FOR_VALUE(expr->expression()); |
| (...skipping 892 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6002 } | 5954 } |
| 6003 } | 5955 } |
| 6004 | 5956 |
| 6005 #ifdef DEBUG | 5957 #ifdef DEBUG |
| 6006 if (graph_ != NULL) graph_->Verify(); | 5958 if (graph_ != NULL) graph_->Verify(); |
| 6007 if (allocator_ != NULL) allocator_->Verify(); | 5959 if (allocator_ != NULL) allocator_->Verify(); |
| 6008 #endif | 5960 #endif |
| 6009 } | 5961 } |
| 6010 | 5962 |
| 6011 } } // namespace v8::internal | 5963 } } // namespace v8::internal |
| OLD | NEW |