| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 end_(NULL), | 57 end_(NULL), |
| 58 loop_information_(NULL), | 58 loop_information_(NULL), |
| 59 predecessors_(2), | 59 predecessors_(2), |
| 60 dominator_(NULL), | 60 dominator_(NULL), |
| 61 dominated_blocks_(4), | 61 dominated_blocks_(4), |
| 62 last_environment_(NULL), | 62 last_environment_(NULL), |
| 63 argument_count_(-1), | 63 argument_count_(-1), |
| 64 first_instruction_index_(-1), | 64 first_instruction_index_(-1), |
| 65 last_instruction_index_(-1), | 65 last_instruction_index_(-1), |
| 66 deleted_phis_(4), | 66 deleted_phis_(4), |
| 67 is_inline_return_target_(false), | 67 is_inline_return_target_(false) { |
| 68 inverted_(false), | |
| 69 deopt_predecessor_(NULL) { | |
| 70 } | 68 } |
| 71 | 69 |
| 72 | 70 |
| 73 void HBasicBlock::AttachLoopInformation() { | 71 void HBasicBlock::AttachLoopInformation() { |
| 74 ASSERT(!IsLoopHeader()); | 72 ASSERT(!IsLoopHeader()); |
| 75 loop_information_ = new HLoopInformation(this); | 73 loop_information_ = new HLoopInformation(this); |
| 76 } | 74 } |
| 77 | 75 |
| 78 | 76 |
| 79 void HBasicBlock::DetachLoopInformation() { | 77 void HBasicBlock::DetachLoopInformation() { |
| (...skipping 944 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1024 value->id(), | 1022 value->id(), |
| 1025 Token::Name(op), | 1023 Token::Name(op), |
| 1026 other->id()); | 1024 other->id()); |
| 1027 | 1025 |
| 1028 if (op == Token::EQ || op == Token::EQ_STRICT) { | 1026 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 1029 // The same range has to apply for value. | 1027 // The same range has to apply for value. |
| 1030 new_range = range->Copy(); | 1028 new_range = range->Copy(); |
| 1031 } else if (op == Token::LT || op == Token::LTE) { | 1029 } else if (op == Token::LT || op == Token::LTE) { |
| 1032 new_range = range->CopyClearLower(); | 1030 new_range = range->CopyClearLower(); |
| 1033 if (op == Token::LT) { | 1031 if (op == Token::LT) { |
| 1034 new_range->Add(-1); | 1032 new_range->AddConstant(-1); |
| 1035 } | 1033 } |
| 1036 } else if (op == Token::GT || op == Token::GTE) { | 1034 } else if (op == Token::GT || op == Token::GTE) { |
| 1037 new_range = range->CopyClearUpper(); | 1035 new_range = range->CopyClearUpper(); |
| 1038 if (op == Token::GT) { | 1036 if (op == Token::GT) { |
| 1039 new_range->Add(1); | 1037 new_range->AddConstant(1); |
| 1040 } | 1038 } |
| 1041 } | 1039 } |
| 1042 | 1040 |
| 1043 if (new_range != NULL && !new_range->IsMostGeneric()) { | 1041 if (new_range != NULL && !new_range->IsMostGeneric()) { |
| 1044 AddRange(value, new_range); | 1042 AddRange(value, new_range); |
| 1045 } | 1043 } |
| 1046 } | 1044 } |
| 1047 | 1045 |
| 1048 | 1046 |
| 1049 void HRangeAnalysis::InferPhiRange(HPhi* phi) { | 1047 void HRangeAnalysis::InferPhiRange(HPhi* phi) { |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1285 | 1283 |
| 1286 | 1284 |
| 1287 void HStackCheckEliminator::Process() { | 1285 void HStackCheckEliminator::Process() { |
| 1288 // For each loop block walk the dominator tree from the backwards branch to | 1286 // For each loop block walk the dominator tree from the backwards branch to |
| 1289 // the loop header. If a call instruction is encountered the backwards branch | 1287 // the loop header. If a call instruction is encountered the backwards branch |
| 1290 // is dominated by a call and the stack check in the backwards branch can be | 1288 // is dominated by a call and the stack check in the backwards branch can be |
| 1291 // removed. | 1289 // removed. |
| 1292 for (int i = 0; i < graph_->blocks()->length(); i++) { | 1290 for (int i = 0; i < graph_->blocks()->length(); i++) { |
| 1293 HBasicBlock* block = graph_->blocks()->at(i); | 1291 HBasicBlock* block = graph_->blocks()->at(i); |
| 1294 if (block->IsLoopHeader()) { | 1292 if (block->IsLoopHeader()) { |
| 1295 HBasicBlock* backedge = block->loop_information()->GetLastBackEdge(); | 1293 HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge(); |
| 1296 HBasicBlock* dominator = backedge; | 1294 HBasicBlock* dominator = back_edge; |
| 1297 bool backedge_dominated_by_call = false; | 1295 bool back_edge_dominated_by_call = false; |
| 1298 while (dominator != block && !backedge_dominated_by_call) { | 1296 while (dominator != block && !back_edge_dominated_by_call) { |
| 1299 HInstruction* instr = dominator->first(); | 1297 HInstruction* instr = dominator->first(); |
| 1300 while (instr != NULL && !backedge_dominated_by_call) { | 1298 while (instr != NULL && !back_edge_dominated_by_call) { |
| 1301 if (instr->IsCall()) { | 1299 if (instr->IsCall()) { |
| 1302 RemoveStackCheck(backedge); | 1300 RemoveStackCheck(back_edge); |
| 1303 backedge_dominated_by_call = true; | 1301 back_edge_dominated_by_call = true; |
| 1304 } | 1302 } |
| 1305 instr = instr->next(); | 1303 instr = instr->next(); |
| 1306 } | 1304 } |
| 1307 dominator = dominator->dominator(); | 1305 dominator = dominator->dominator(); |
| 1308 } | 1306 } |
| 1309 } | 1307 } |
| 1310 } | 1308 } |
| 1311 } | 1309 } |
| 1312 | 1310 |
| 1313 | 1311 |
| (...skipping 732 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2046 if (instr->HasSideEffects()) { | 2044 if (instr->HasSideEffects()) { |
| 2047 builder->Push(instr); | 2045 builder->Push(instr); |
| 2048 builder->AddSimulate(ast_id); | 2046 builder->AddSimulate(ast_id); |
| 2049 builder->Pop(); | 2047 builder->Pop(); |
| 2050 } | 2048 } |
| 2051 BuildBranch(instr); | 2049 BuildBranch(instr); |
| 2052 } | 2050 } |
| 2053 | 2051 |
| 2054 | 2052 |
| 2055 void TestContext::BuildBranch(HValue* value) { | 2053 void TestContext::BuildBranch(HValue* value) { |
| 2054 // We expect the graph to be in edge-split form: there is no edge that |
| 2055 // connects a branch node to a join node. We conservatively ensure that |
| 2056 // property by always adding an empty block on the outgoing edges of this |
| 2057 // branch. |
| 2056 HGraphBuilder* builder = owner(); | 2058 HGraphBuilder* builder = owner(); |
| 2057 HBasicBlock* materialize_true = builder->graph()->CreateBasicBlock(); | 2059 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2058 HBasicBlock* materialize_false = builder->graph()->CreateBasicBlock(); | 2060 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2059 HBranch* branch = new HBranch(materialize_true, materialize_false, value); | 2061 HBranch* branch = new HBranch(empty_true, empty_false, value); |
| 2060 builder->CurrentBlock()->Finish(branch); | 2062 builder->CurrentBlock()->Finish(branch); |
| 2061 | 2063 |
| 2062 HBasicBlock* true_block = if_true(); | 2064 HValue* const no_return_value = NULL; |
| 2063 HValue* true_value = invert_true() | 2065 HBasicBlock* true_target = if_true(); |
| 2064 ? builder->graph()->GetConstantFalse() | 2066 if (true_target->IsInlineReturnTarget()) { |
| 2065 : builder->graph()->GetConstantTrue(); | 2067 empty_true->AddLeaveInlined(no_return_value, true_target); |
| 2066 materialize_true->set_inverted(invert_true()); | |
| 2067 true_block->set_deopt_predecessor(materialize_true); | |
| 2068 | |
| 2069 if (true_block->IsInlineReturnTarget()) { | |
| 2070 materialize_true->AddLeaveInlined(true_value, true_block); | |
| 2071 } else { | 2068 } else { |
| 2072 materialize_true->last_environment()->Push(true_value); | 2069 empty_true->Goto(true_target); |
| 2073 materialize_true->Goto(true_block); | |
| 2074 } | 2070 } |
| 2075 | 2071 |
| 2076 HBasicBlock* false_block = if_false(); | 2072 HBasicBlock* false_target = if_false(); |
| 2077 HValue* false_value = invert_false() | 2073 if (false_target->IsInlineReturnTarget()) { |
| 2078 ? builder->graph()->GetConstantTrue() | 2074 empty_false->AddLeaveInlined(no_return_value, false_target); |
| 2079 : builder->graph()->GetConstantFalse(); | |
| 2080 materialize_false->set_inverted(invert_false()); | |
| 2081 false_block->set_deopt_predecessor(materialize_false); | |
| 2082 | |
| 2083 if (false_block->IsInlineReturnTarget()) { | |
| 2084 materialize_false->AddLeaveInlined(false_value, false_block); | |
| 2085 } else { | 2075 } else { |
| 2086 materialize_false->last_environment()->Push(false_value); | 2076 empty_false->Goto(false_target); |
| 2087 materialize_false->Goto(false_block); | |
| 2088 } | 2077 } |
| 2089 builder->subgraph()->set_exit_block(NULL); | 2078 builder->subgraph()->set_exit_block(NULL); |
| 2090 } | 2079 } |
| 2091 | 2080 |
| 2092 | 2081 |
| 2093 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2082 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 2094 #define BAILOUT(reason) \ | 2083 #define BAILOUT(reason) \ |
| 2095 do { \ | 2084 do { \ |
| 2096 Bailout(reason); \ | 2085 Bailout(reason); \ |
| 2097 return; \ | 2086 return; \ |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2111 } while (false) | 2100 } while (false) |
| 2112 | 2101 |
| 2113 | 2102 |
| 2114 #define VISIT_FOR_VALUE(expr) \ | 2103 #define VISIT_FOR_VALUE(expr) \ |
| 2115 do { \ | 2104 do { \ |
| 2116 VisitForValue(expr); \ | 2105 VisitForValue(expr); \ |
| 2117 if (HasStackOverflow()) return; \ | 2106 if (HasStackOverflow()) return; \ |
| 2118 } while (false) | 2107 } while (false) |
| 2119 | 2108 |
| 2120 | 2109 |
| 2110 #define VISIT_FOR_CONTROL(expr, true_block, false_block) \ |
| 2111 do { \ |
| 2112 VisitForControl(expr, true_block, false_block); \ |
| 2113 if (HasStackOverflow()) return; \ |
| 2114 } while (false) |
| 2115 |
| 2116 |
| 2121 // 'thing' could be an expression, statement, or list of statements. | 2117 // 'thing' could be an expression, statement, or list of statements. |
| 2122 #define ADD_TO_SUBGRAPH(graph, thing) \ | 2118 #define ADD_TO_SUBGRAPH(graph, thing) \ |
| 2123 do { \ | 2119 do { \ |
| 2124 AddToSubgraph(graph, thing); \ | 2120 AddToSubgraph(graph, thing); \ |
| 2125 if (HasStackOverflow()) return; \ | 2121 if (HasStackOverflow()) return; \ |
| 2126 } while (false) | 2122 } while (false) |
| 2127 | 2123 |
| 2128 | 2124 |
| 2129 class HGraphBuilder::SubgraphScope BASE_EMBEDDED { | 2125 class HGraphBuilder::SubgraphScope BASE_EMBEDDED { |
| 2130 public: | 2126 public: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2163 Visit(expr); | 2159 Visit(expr); |
| 2164 } | 2160 } |
| 2165 | 2161 |
| 2166 | 2162 |
| 2167 void HGraphBuilder::VisitForValue(Expression* expr) { | 2163 void HGraphBuilder::VisitForValue(Expression* expr) { |
| 2168 ValueContext for_value(this); | 2164 ValueContext for_value(this); |
| 2169 Visit(expr); | 2165 Visit(expr); |
| 2170 } | 2166 } |
| 2171 | 2167 |
| 2172 | 2168 |
| 2169 void HGraphBuilder::VisitForControl(Expression* expr, |
| 2170 HBasicBlock* true_block, |
| 2171 HBasicBlock* false_block) { |
| 2172 TestContext for_test(this, true_block, false_block); |
| 2173 Visit(expr); |
| 2174 } |
| 2175 |
| 2176 |
| 2173 HValue* HGraphBuilder::VisitArgument(Expression* expr) { | 2177 HValue* HGraphBuilder::VisitArgument(Expression* expr) { |
| 2174 VisitForValue(expr); | 2178 VisitForValue(expr); |
| 2175 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; | 2179 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; |
| 2176 return environment()->Top(); | 2180 return environment()->Top(); |
| 2177 } | 2181 } |
| 2178 | 2182 |
| 2179 | 2183 |
| 2180 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { | 2184 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { |
| 2181 for (int i = 0; i < arguments->length(); i++) { | 2185 for (int i = 0; i < arguments->length(); i++) { |
| 2182 VisitArgument(arguments->at(i)); | 2186 VisitArgument(arguments->at(i)); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2252 Visit(stmt); | 2256 Visit(stmt); |
| 2253 } | 2257 } |
| 2254 | 2258 |
| 2255 | 2259 |
| 2256 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { | 2260 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { |
| 2257 SubgraphScope scope(this, graph); | 2261 SubgraphScope scope(this, graph); |
| 2258 VisitForValue(expr); | 2262 VisitForValue(expr); |
| 2259 } | 2263 } |
| 2260 | 2264 |
| 2261 | 2265 |
| 2262 void HGraphBuilder::VisitCondition(Expression* expr, | |
| 2263 HBasicBlock* true_block, | |
| 2264 HBasicBlock* false_block, | |
| 2265 bool invert_true, | |
| 2266 bool invert_false) { | |
| 2267 VisitForControl(expr, true_block, false_block, invert_true, invert_false); | |
| 2268 CHECK_BAILOUT; | |
| 2269 #ifdef DEBUG | |
| 2270 HValue* value = true_block->predecessors()->at(0)->last_environment()->Top(); | |
| 2271 true_block->set_cond(HConstant::cast(value)->handle()); | |
| 2272 | |
| 2273 value = false_block->predecessors()->at(0)->last_environment()->Top(); | |
| 2274 false_block->set_cond(HConstant::cast(value)->handle()); | |
| 2275 #endif | |
| 2276 | |
| 2277 true_block->SetJoinId(expr->id()); | |
| 2278 false_block->SetJoinId(expr->id()); | |
| 2279 true_block->last_environment()->Pop(); | |
| 2280 false_block->last_environment()->Pop(); | |
| 2281 } | |
| 2282 | |
| 2283 | |
| 2284 void HGraphBuilder::AddConditionToSubgraph(HSubgraph* subgraph, | |
| 2285 Expression* expr, | |
| 2286 HSubgraph* true_graph, | |
| 2287 HSubgraph* false_graph) { | |
| 2288 SubgraphScope scope(this, subgraph); | |
| 2289 VisitCondition(expr, | |
| 2290 true_graph->entry_block(), | |
| 2291 false_graph->entry_block(), | |
| 2292 false, | |
| 2293 false); | |
| 2294 } | |
| 2295 | |
| 2296 | |
| 2297 void HGraphBuilder::VisitForControl(Expression* expr, | |
| 2298 HBasicBlock* true_block, | |
| 2299 HBasicBlock* false_block, | |
| 2300 bool invert_true, | |
| 2301 bool invert_false) { | |
| 2302 TestContext for_test(this, true_block, false_block, | |
| 2303 invert_true, invert_false); | |
| 2304 Visit(expr); | |
| 2305 } | |
| 2306 | |
| 2307 | |
| 2308 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, | 2266 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, |
| 2309 ZoneList<Statement*>* stmts) { | 2267 ZoneList<Statement*>* stmts) { |
| 2310 SubgraphScope scope(this, graph); | 2268 SubgraphScope scope(this, graph); |
| 2311 VisitStatements(stmts); | 2269 VisitStatements(stmts); |
| 2312 } | 2270 } |
| 2313 | 2271 |
| 2314 | 2272 |
| 2315 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { | 2273 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
| 2316 ASSERT(current_subgraph_->HasExit()); | 2274 ASSERT(current_subgraph_->HasExit()); |
| 2317 current_subgraph_->exit_block()->AddInstruction(instr); | 2275 current_subgraph_->exit_block()->AddInstruction(instr); |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2477 VisitForEffect(stmt->expression()); | 2435 VisitForEffect(stmt->expression()); |
| 2478 } | 2436 } |
| 2479 | 2437 |
| 2480 | 2438 |
| 2481 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { | 2439 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { |
| 2482 } | 2440 } |
| 2483 | 2441 |
| 2484 | 2442 |
| 2485 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { | 2443 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { |
| 2486 if (stmt->condition()->ToBooleanIsTrue()) { | 2444 if (stmt->condition()->ToBooleanIsTrue()) { |
| 2445 AddSimulate(stmt->ThenId()); |
| 2487 Visit(stmt->then_statement()); | 2446 Visit(stmt->then_statement()); |
| 2488 } else if (stmt->condition()->ToBooleanIsFalse()) { | 2447 } else if (stmt->condition()->ToBooleanIsFalse()) { |
| 2448 AddSimulate(stmt->ElseId()); |
| 2489 Visit(stmt->else_statement()); | 2449 Visit(stmt->else_statement()); |
| 2490 } else { | 2450 } else { |
| 2491 HSubgraph* then_graph = CreateEmptySubgraph(); | 2451 HSubgraph* then_graph = CreateEmptySubgraph(); |
| 2492 HSubgraph* else_graph = CreateEmptySubgraph(); | 2452 HSubgraph* else_graph = CreateEmptySubgraph(); |
| 2493 VisitCondition(stmt->condition(), | 2453 VISIT_FOR_CONTROL(stmt->condition(), |
| 2494 then_graph->entry_block(), | 2454 then_graph->entry_block(), |
| 2495 else_graph->entry_block(), | 2455 else_graph->entry_block()); |
| 2496 false, false); | 2456 |
| 2497 if (HasStackOverflow()) return; | 2457 then_graph->entry_block()->SetJoinId(stmt->ThenId()); |
| 2498 ADD_TO_SUBGRAPH(then_graph, stmt->then_statement()); | 2458 ADD_TO_SUBGRAPH(then_graph, stmt->then_statement()); |
| 2459 |
| 2460 else_graph->entry_block()->SetJoinId(stmt->ElseId()); |
| 2499 ADD_TO_SUBGRAPH(else_graph, stmt->else_statement()); | 2461 ADD_TO_SUBGRAPH(else_graph, stmt->else_statement()); |
| 2462 |
| 2500 current_subgraph_->AppendJoin(then_graph, else_graph, stmt); | 2463 current_subgraph_->AppendJoin(then_graph, else_graph, stmt); |
| 2501 } | 2464 } |
| 2502 } | 2465 } |
| 2503 | 2466 |
| 2504 | 2467 |
| 2505 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { | 2468 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
| 2506 current_subgraph_->FinishBreakContinue(stmt->target(), true); | 2469 current_subgraph_->FinishBreakContinue(stmt->target(), true); |
| 2507 } | 2470 } |
| 2508 | 2471 |
| 2509 | 2472 |
| 2510 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { | 2473 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { |
| 2511 current_subgraph_->FinishBreakContinue(stmt->target(), false); | 2474 current_subgraph_->FinishBreakContinue(stmt->target(), false); |
| 2512 } | 2475 } |
| 2513 | 2476 |
| 2514 | 2477 |
| 2515 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 2478 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
| 2516 AstContext* context = call_context(); | 2479 AstContext* context = call_context(); |
| 2517 if (context == NULL) { | 2480 if (context == NULL) { |
| 2518 // Not an inlined return, so an actual one. | 2481 // Not an inlined return, so an actual one. |
| 2519 VISIT_FOR_VALUE(stmt->expression()); | 2482 VISIT_FOR_VALUE(stmt->expression()); |
| 2520 HValue* result = environment()->Pop(); | 2483 HValue* result = environment()->Pop(); |
| 2521 subgraph()->FinishExit(new HReturn(result)); | 2484 subgraph()->FinishExit(new HReturn(result)); |
| 2522 } else { | 2485 } else { |
| 2523 // Return from an inlined function, visit the subexpression in the | 2486 // Return from an inlined function, visit the subexpression in the |
| 2524 // expression context of the call. | 2487 // expression context of the call. |
| 2525 if (context->IsTest()) { | 2488 if (context->IsTest()) { |
| 2526 TestContext* test = TestContext::cast(context); | 2489 TestContext* test = TestContext::cast(context); |
| 2527 VisitForControl(stmt->expression(), | 2490 VisitForControl(stmt->expression(), |
| 2528 test->if_true(), | 2491 test->if_true(), |
| 2529 test->if_false(), | 2492 test->if_false()); |
| 2530 false, | |
| 2531 false); | |
| 2532 } else { | 2493 } else { |
| 2533 HValue* return_value = NULL; | 2494 HValue* return_value = NULL; |
| 2534 if (context->IsEffect()) { | 2495 if (context->IsEffect()) { |
| 2535 VISIT_FOR_EFFECT(stmt->expression()); | 2496 VISIT_FOR_EFFECT(stmt->expression()); |
| 2536 return_value = graph()->GetConstantUndefined(); | 2497 return_value = graph()->GetConstantUndefined(); |
| 2537 } else { | 2498 } else { |
| 2538 ASSERT(context->IsValue()); | 2499 ASSERT(context->IsValue()); |
| 2539 VISIT_FOR_VALUE(stmt->expression()); | 2500 VISIT_FOR_VALUE(stmt->expression()); |
| 2540 return_value = environment()->Pop(); | 2501 return_value = environment()->Pop(); |
| 2541 } | 2502 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2567 clause_value, | 2528 clause_value, |
| 2568 Token::EQ_STRICT); | 2529 Token::EQ_STRICT); |
| 2569 compare->SetInputRepresentation(Representation::Integer32()); | 2530 compare->SetInputRepresentation(Representation::Integer32()); |
| 2570 subgraph->exit_block()->AddInstruction(compare); | 2531 subgraph->exit_block()->AddInstruction(compare); |
| 2571 return compare; | 2532 return compare; |
| 2572 } | 2533 } |
| 2573 | 2534 |
| 2574 | 2535 |
| 2575 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2536 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 2576 VISIT_FOR_VALUE(stmt->tag()); | 2537 VISIT_FOR_VALUE(stmt->tag()); |
| 2538 // TODO(3168478): simulate added for tag should be enough. |
| 2539 AddSimulate(stmt->EntryId()); |
| 2577 HValue* switch_value = Pop(); | 2540 HValue* switch_value = Pop(); |
| 2578 | 2541 |
| 2579 ZoneList<CaseClause*>* clauses = stmt->cases(); | 2542 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 2580 int num_clauses = clauses->length(); | 2543 int num_clauses = clauses->length(); |
| 2581 if (num_clauses == 0) return; | 2544 if (num_clauses == 0) return; |
| 2582 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); | 2545 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); |
| 2583 | 2546 |
| 2547 int num_smi_clauses = num_clauses; |
| 2584 for (int i = 0; i < num_clauses; i++) { | 2548 for (int i = 0; i < num_clauses; i++) { |
| 2585 CaseClause* clause = clauses->at(i); | 2549 CaseClause* clause = clauses->at(i); |
| 2586 if (clause->is_default()) continue; | 2550 if (clause->is_default()) continue; |
| 2587 clause->RecordTypeFeedback(oracle()); | 2551 clause->RecordTypeFeedback(oracle()); |
| 2588 if (!clause->IsSmiCompare()) BAILOUT("SwitchStatement: non-smi compare"); | 2552 if (!clause->IsSmiCompare()) { |
| 2553 if (i == 0) BAILOUT("SwitchStatement: no smi compares"); |
| 2554 // We will deoptimize if the first non-smi compare is reached. |
| 2555 num_smi_clauses = i; |
| 2556 break; |
| 2557 } |
| 2589 if (!clause->label()->IsSmiLiteral()) { | 2558 if (!clause->label()->IsSmiLiteral()) { |
| 2590 BAILOUT("SwitchStatement: non-literal switch label"); | 2559 BAILOUT("SwitchStatement: non-literal switch label"); |
| 2591 } | 2560 } |
| 2592 } | 2561 } |
| 2593 | 2562 |
| 2594 // The single exit block of the whole switch statement. | 2563 // The single exit block of the whole switch statement. |
| 2595 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); | 2564 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); |
| 2596 | 2565 |
| 2597 // Build a series of empty subgraphs for the comparisons. | 2566 // Build a series of empty subgraphs for the comparisons. |
| 2598 // The default clause does not have a comparison subgraph. | 2567 // The default clause does not have a comparison subgraph. |
| 2599 ZoneList<HSubgraph*> compare_graphs(num_clauses); | 2568 ZoneList<HSubgraph*> compare_graphs(num_smi_clauses); |
| 2600 for (int i = 0; i < num_clauses; i++) { | 2569 for (int i = 0; i < num_smi_clauses; i++) { |
| 2601 HSubgraph* subgraph = !clauses->at(i)->is_default() | 2570 if (clauses->at(i)->is_default()) { |
| 2602 ? CreateEmptySubgraph() | 2571 compare_graphs.Add(NULL); |
| 2603 : NULL; | 2572 } else { |
| 2604 compare_graphs.Add(subgraph); | 2573 compare_graphs.Add(CreateEmptySubgraph()); |
| 2574 } |
| 2605 } | 2575 } |
| 2606 | 2576 |
| 2607 HSubgraph* prev_graph = current_subgraph_; | 2577 HSubgraph* prev_graph = current_subgraph_; |
| 2608 HCompare* prev_compare_inst = NULL; | 2578 HCompare* prev_compare_inst = NULL; |
| 2609 for (int i = 0; i < num_clauses; i++) { | 2579 for (int i = 0; i < num_smi_clauses; i++) { |
| 2610 CaseClause* clause = clauses->at(i); | 2580 CaseClause* clause = clauses->at(i); |
| 2611 if (clause->is_default()) continue; | 2581 if (clause->is_default()) continue; |
| 2612 | 2582 |
| 2613 // Finish the previous graph by connecting it to the current. | 2583 // Finish the previous graph by connecting it to the current. |
| 2614 HSubgraph* subgraph = compare_graphs.at(i); | 2584 HSubgraph* subgraph = compare_graphs.at(i); |
| 2615 if (prev_compare_inst == NULL) { | 2585 if (prev_compare_inst == NULL) { |
| 2616 ASSERT(prev_graph == current_subgraph_); | 2586 ASSERT(prev_graph == current_subgraph_); |
| 2617 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | 2587 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); |
| 2618 } else { | 2588 } else { |
| 2619 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2589 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2620 prev_graph->exit_block()->Finish(new HBranch(empty, | 2590 prev_graph->exit_block()->Finish(new HBranch(empty, |
| 2621 subgraph->entry_block(), | 2591 subgraph->entry_block(), |
| 2622 prev_compare_inst)); | 2592 prev_compare_inst)); |
| 2623 } | 2593 } |
| 2624 | 2594 |
| 2625 // Build instructions for current subgraph. | 2595 // Build instructions for current subgraph. |
| 2596 ASSERT(clause->IsSmiCompare()); |
| 2626 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | 2597 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); |
| 2627 if (HasStackOverflow()) return; | 2598 if (HasStackOverflow()) return; |
| 2628 | 2599 |
| 2629 prev_graph = subgraph; | 2600 prev_graph = subgraph; |
| 2630 } | 2601 } |
| 2631 | 2602 |
| 2632 // Finish last comparison if there was at least one comparison. | 2603 // Finish last comparison if there was at least one comparison. |
| 2633 // last_false_block is the (empty) false-block of the last comparison. If | 2604 // last_false_block is the (empty) false-block of the last comparison. If |
| 2634 // there are no comparisons at all (a single default clause), it is just | 2605 // there are no comparisons at all (a single default clause), it is just |
| 2635 // the last block of the current subgraph. | 2606 // the last block of the current subgraph. |
| 2636 HBasicBlock* last_false_block = current_subgraph_->exit_block(); | 2607 HBasicBlock* last_false_block = current_subgraph_->exit_block(); |
| 2637 if (prev_graph != current_subgraph_) { | 2608 if (prev_graph != current_subgraph_) { |
| 2638 last_false_block = graph()->CreateBasicBlock(); | 2609 last_false_block = graph()->CreateBasicBlock(); |
| 2639 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2610 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2640 prev_graph->exit_block()->Finish(new HBranch(empty, | 2611 prev_graph->exit_block()->Finish(new HBranch(empty, |
| 2641 last_false_block, | 2612 last_false_block, |
| 2642 prev_compare_inst)); | 2613 prev_compare_inst)); |
| 2643 } | 2614 } |
| 2644 | 2615 |
| 2616 // If we have a non-smi compare clause, we deoptimize after trying |
| 2617 // all the previous compares. |
| 2618 if (num_smi_clauses < num_clauses) { |
| 2619 last_false_block->Finish(new HDeoptimize); |
| 2620 } |
| 2621 |
| 2645 // Build statement blocks, connect them to their comparison block and | 2622 // Build statement blocks, connect them to their comparison block and |
| 2646 // to the previous statement block, if there is a fall-through. | 2623 // to the previous statement block, if there is a fall-through. |
| 2647 HSubgraph* previous_subgraph = NULL; | 2624 HSubgraph* previous_subgraph = NULL; |
| 2648 for (int i = 0; i < num_clauses; i++) { | 2625 for (int i = 0; i < num_clauses; i++) { |
| 2649 CaseClause* clause = clauses->at(i); | 2626 CaseClause* clause = clauses->at(i); |
| 2650 HSubgraph* subgraph = CreateEmptySubgraph(); | 2627 // Subgraph for the statements of the clause is only created when |
| 2628 // it's reachable either from the corresponding compare or as a |
| 2629 // fall-through from previous statements. |
| 2630 HSubgraph* subgraph = NULL; |
| 2651 | 2631 |
| 2652 if (clause->is_default()) { | 2632 if (i < num_smi_clauses) { |
| 2653 // Default clause: Connect it to the last false block. | 2633 if (clause->is_default()) { |
| 2654 last_false_block->Finish(new HGoto(subgraph->entry_block())); | 2634 if (!last_false_block->IsFinished()) { |
| 2655 } else { | 2635 // Default clause: Connect it to the last false block. |
| 2656 // Connect with the corresponding comparison. | 2636 subgraph = CreateEmptySubgraph(); |
| 2657 HBasicBlock* empty = | 2637 last_false_block->Finish(new HGoto(subgraph->entry_block())); |
| 2658 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); | 2638 } |
| 2659 empty->Finish(new HGoto(subgraph->entry_block())); | 2639 } else { |
| 2640 ASSERT(clause->IsSmiCompare()); |
| 2641 // Connect with the corresponding comparison. |
| 2642 subgraph = CreateEmptySubgraph(); |
| 2643 HBasicBlock* empty = |
| 2644 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); |
| 2645 empty->Finish(new HGoto(subgraph->entry_block())); |
| 2646 } |
| 2660 } | 2647 } |
| 2661 | 2648 |
| 2662 // Check for fall-through from previous statement block. | 2649 // Check for fall-through from previous statement block. |
| 2663 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { | 2650 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { |
| 2651 if (subgraph == NULL) subgraph = CreateEmptySubgraph(); |
| 2664 previous_subgraph->exit_block()-> | 2652 previous_subgraph->exit_block()-> |
| 2665 Finish(new HGoto(subgraph->entry_block())); | 2653 Finish(new HGoto(subgraph->entry_block())); |
| 2666 } | 2654 } |
| 2667 | 2655 |
| 2668 ADD_TO_SUBGRAPH(subgraph, clause->statements()); | 2656 if (subgraph != NULL) { |
| 2669 HBasicBlock* break_block = subgraph->BundleBreak(stmt); | 2657 ADD_TO_SUBGRAPH(subgraph, clause->statements()); |
| 2670 if (break_block != NULL) { | 2658 HBasicBlock* break_block = subgraph->BundleBreak(stmt); |
| 2671 break_block->Finish(new HGoto(single_exit_block)); | 2659 if (break_block != NULL) { |
| 2660 break_block->Finish(new HGoto(single_exit_block)); |
| 2661 } |
| 2672 } | 2662 } |
| 2673 | 2663 |
| 2674 previous_subgraph = subgraph; | 2664 previous_subgraph = subgraph; |
| 2675 } | 2665 } |
| 2676 | 2666 |
| 2677 // If the last statement block has a fall-through, connect it to the | 2667 // If the last statement block has a fall-through, connect it to the |
| 2678 // single exit block. | 2668 // single exit block. |
| 2679 if (previous_subgraph->HasExit()) { | 2669 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { |
| 2680 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); | 2670 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); |
| 2681 } | 2671 } |
| 2682 | 2672 |
| 2683 // If there is no default clause finish the last comparison's false target. | 2673 // If there is no default clause finish the last comparison's false target. |
| 2684 if (!last_false_block->IsFinished()) { | 2674 if (!last_false_block->IsFinished()) { |
| 2685 last_false_block->Finish(new HGoto(single_exit_block)); | 2675 last_false_block->Finish(new HGoto(single_exit_block)); |
| 2686 } | 2676 } |
| 2687 | 2677 |
| 2688 if (single_exit_block->HasPredecessor()) { | 2678 if (single_exit_block->HasPredecessor()) { |
| 2689 current_subgraph_->set_exit_block(single_exit_block); | 2679 current_subgraph_->set_exit_block(single_exit_block); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2735 | 2725 |
| 2736 HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment()); | 2726 HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment()); |
| 2737 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2727 ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
| 2738 body_graph->ResolveContinue(stmt); | 2728 body_graph->ResolveContinue(stmt); |
| 2739 | 2729 |
| 2740 if (!body_graph->HasExit() || stmt->cond()->ToBooleanIsTrue()) { | 2730 if (!body_graph->HasExit() || stmt->cond()->ToBooleanIsTrue()) { |
| 2741 current_subgraph_->AppendEndless(body_graph, stmt); | 2731 current_subgraph_->AppendEndless(body_graph, stmt); |
| 2742 } else { | 2732 } else { |
| 2743 HSubgraph* go_back = CreateEmptySubgraph(); | 2733 HSubgraph* go_back = CreateEmptySubgraph(); |
| 2744 HSubgraph* exit = CreateEmptySubgraph(); | 2734 HSubgraph* exit = CreateEmptySubgraph(); |
| 2745 AddConditionToSubgraph(body_graph, stmt->cond(), go_back, exit); | 2735 { |
| 2746 if (HasStackOverflow()) return; | 2736 SubgraphScope scope(this, body_graph); |
| 2737 VISIT_FOR_CONTROL(stmt->cond(), |
| 2738 go_back->entry_block(), |
| 2739 exit->entry_block()); |
| 2740 go_back->entry_block()->SetJoinId(stmt->BackEdgeId()); |
| 2741 exit->entry_block()->SetJoinId(stmt->ExitId()); |
| 2742 } |
| 2747 current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit); | 2743 current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit); |
| 2748 } | 2744 } |
| 2749 } | 2745 } |
| 2750 | 2746 |
| 2751 | 2747 |
| 2752 bool HGraphBuilder::ShouldPeel(HSubgraph* cond, HSubgraph* body) { | 2748 bool HGraphBuilder::ShouldPeel(HSubgraph* cond, HSubgraph* body) { |
| 2753 return FLAG_use_peeling; | 2749 return FLAG_use_peeling; |
| 2754 } | 2750 } |
| 2755 | 2751 |
| 2756 | 2752 |
| 2757 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { | 2753 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { |
| 2758 ASSERT(subgraph()->HasExit()); | 2754 ASSERT(subgraph()->HasExit()); |
| 2759 subgraph()->PreProcessOsrEntry(stmt); | 2755 subgraph()->PreProcessOsrEntry(stmt); |
| 2760 | 2756 |
| 2761 HSubgraph* cond_graph = NULL; | 2757 HSubgraph* cond_graph = NULL; |
| 2762 HSubgraph* body_graph = NULL; | 2758 HSubgraph* body_graph = NULL; |
| 2763 HSubgraph* exit_graph = NULL; | 2759 HSubgraph* exit_graph = NULL; |
| 2764 | 2760 |
| 2765 // If the condition is constant true, do not generate a condition subgraph. | 2761 // If the condition is constant true, do not generate a condition subgraph. |
| 2766 if (stmt->cond()->ToBooleanIsTrue()) { | 2762 if (stmt->cond()->ToBooleanIsTrue()) { |
| 2767 body_graph = CreateLoopHeaderSubgraph(environment()); | 2763 body_graph = CreateLoopHeaderSubgraph(environment()); |
| 2768 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2764 ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
| 2769 } else { | 2765 } else { |
| 2770 cond_graph = CreateLoopHeaderSubgraph(environment()); | 2766 cond_graph = CreateLoopHeaderSubgraph(environment()); |
| 2771 body_graph = CreateEmptySubgraph(); | 2767 body_graph = CreateEmptySubgraph(); |
| 2772 exit_graph = CreateEmptySubgraph(); | 2768 exit_graph = CreateEmptySubgraph(); |
| 2773 AddConditionToSubgraph(cond_graph, stmt->cond(), body_graph, exit_graph); | 2769 { |
| 2774 if (HasStackOverflow()) return; | 2770 SubgraphScope scope(this, cond_graph); |
| 2771 VISIT_FOR_CONTROL(stmt->cond(), |
| 2772 body_graph->entry_block(), |
| 2773 exit_graph->entry_block()); |
| 2774 body_graph->entry_block()->SetJoinId(stmt->BodyId()); |
| 2775 exit_graph->entry_block()->SetJoinId(stmt->ExitId()); |
| 2776 } |
| 2775 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2777 ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
| 2776 } | 2778 } |
| 2777 | 2779 |
| 2778 body_graph->ResolveContinue(stmt); | 2780 body_graph->ResolveContinue(stmt); |
| 2779 | 2781 |
| 2780 if (cond_graph != NULL) { | 2782 if (cond_graph != NULL) { |
| 2781 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph); | 2783 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph); |
| 2782 } else { | 2784 } else { |
| 2783 // TODO(fschneider): Implement peeling for endless loops as well. | 2785 // TODO(fschneider): Implement peeling for endless loops as well. |
| 2784 current_subgraph_->AppendEndless(body_graph, stmt); | 2786 current_subgraph_->AppendEndless(body_graph, stmt); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2814 ASSERT(subgraph()->HasExit()); | 2816 ASSERT(subgraph()->HasExit()); |
| 2815 subgraph()->PreProcessOsrEntry(stmt); | 2817 subgraph()->PreProcessOsrEntry(stmt); |
| 2816 | 2818 |
| 2817 HSubgraph* cond_graph = NULL; | 2819 HSubgraph* cond_graph = NULL; |
| 2818 HSubgraph* body_graph = NULL; | 2820 HSubgraph* body_graph = NULL; |
| 2819 HSubgraph* exit_graph = NULL; | 2821 HSubgraph* exit_graph = NULL; |
| 2820 if (stmt->cond() != NULL) { | 2822 if (stmt->cond() != NULL) { |
| 2821 cond_graph = CreateLoopHeaderSubgraph(environment()); | 2823 cond_graph = CreateLoopHeaderSubgraph(environment()); |
| 2822 body_graph = CreateEmptySubgraph(); | 2824 body_graph = CreateEmptySubgraph(); |
| 2823 exit_graph = CreateEmptySubgraph(); | 2825 exit_graph = CreateEmptySubgraph(); |
| 2824 AddConditionToSubgraph(cond_graph, stmt->cond(), body_graph, exit_graph); | 2826 { |
| 2825 if (HasStackOverflow()) return; | 2827 SubgraphScope scope(this, cond_graph); |
| 2826 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2828 VISIT_FOR_CONTROL(stmt->cond(), |
| 2829 body_graph->entry_block(), |
| 2830 exit_graph->entry_block()); |
| 2831 body_graph->entry_block()->SetJoinId(stmt->BodyId()); |
| 2832 exit_graph->entry_block()->SetJoinId(stmt->ExitId()); |
| 2833 } |
| 2827 } else { | 2834 } else { |
| 2828 body_graph = CreateLoopHeaderSubgraph(environment()); | 2835 body_graph = CreateLoopHeaderSubgraph(environment()); |
| 2829 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | |
| 2830 } | 2836 } |
| 2837 ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
| 2831 | 2838 |
| 2832 HSubgraph* next_graph = NULL; | 2839 HSubgraph* next_graph = NULL; |
| 2833 body_graph->ResolveContinue(stmt); | 2840 body_graph->ResolveContinue(stmt); |
| 2834 | 2841 |
| 2835 if (stmt->next() != NULL && body_graph->HasExit()) { | 2842 if (stmt->next() != NULL && body_graph->HasExit()) { |
| 2836 next_graph = CreateGotoSubgraph(body_graph->environment()); | 2843 next_graph = CreateGotoSubgraph(body_graph->environment()); |
| 2837 ADD_TO_SUBGRAPH(next_graph, stmt->next()); | 2844 ADD_TO_SUBGRAPH(next_graph, stmt->next()); |
| 2838 body_graph->Append(next_graph, NULL); | 2845 body_graph->Append(next_graph, NULL); |
| 2839 next_graph->entry_block()->SetJoinId(stmt->ContinueId()); | 2846 next_graph->entry_block()->SetJoinId(stmt->ContinueId()); |
| 2840 } | 2847 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2879 | 2886 |
| 2880 void HGraphBuilder::VisitSharedFunctionInfoLiteral( | 2887 void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
| 2881 SharedFunctionInfoLiteral* expr) { | 2888 SharedFunctionInfoLiteral* expr) { |
| 2882 BAILOUT("SharedFunctionInfoLiteral"); | 2889 BAILOUT("SharedFunctionInfoLiteral"); |
| 2883 } | 2890 } |
| 2884 | 2891 |
| 2885 | 2892 |
| 2886 void HGraphBuilder::VisitConditional(Conditional* expr) { | 2893 void HGraphBuilder::VisitConditional(Conditional* expr) { |
| 2887 HSubgraph* then_graph = CreateEmptySubgraph(); | 2894 HSubgraph* then_graph = CreateEmptySubgraph(); |
| 2888 HSubgraph* else_graph = CreateEmptySubgraph(); | 2895 HSubgraph* else_graph = CreateEmptySubgraph(); |
| 2889 VisitCondition(expr->condition(), | 2896 VISIT_FOR_CONTROL(expr->condition(), |
| 2890 then_graph->entry_block(), | 2897 then_graph->entry_block(), |
| 2891 else_graph->entry_block(), | 2898 else_graph->entry_block()); |
| 2892 false, false); | 2899 |
| 2893 if (HasStackOverflow()) return; | 2900 then_graph->entry_block()->SetJoinId(expr->ThenId()); |
| 2894 ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); | 2901 ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); |
| 2902 |
| 2903 else_graph->entry_block()->SetJoinId(expr->ElseId()); |
| 2895 ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); | 2904 ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); |
| 2905 |
| 2896 current_subgraph_->AppendJoin(then_graph, else_graph, expr); | 2906 current_subgraph_->AppendJoin(then_graph, else_graph, expr); |
| 2897 ast_context()->ReturnValue(Pop()); | 2907 ast_context()->ReturnValue(Pop()); |
| 2898 } | 2908 } |
| 2899 | 2909 |
| 2900 | 2910 |
| 2901 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, | 2911 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
| 2902 LookupResult* lookup, | 2912 LookupResult* lookup, |
| 2903 bool is_store) { | 2913 bool is_store) { |
| 2904 if (var->is_this()) { | 2914 if (var->is_this()) { |
| 2905 BAILOUT("global this reference"); | 2915 BAILOUT("global this reference"); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3016 ZoneList<Expression*>* subexprs = expr->values(); | 3026 ZoneList<Expression*>* subexprs = expr->values(); |
| 3017 int length = subexprs->length(); | 3027 int length = subexprs->length(); |
| 3018 | 3028 |
| 3019 HArrayLiteral* literal = new HArrayLiteral(expr->constant_elements(), | 3029 HArrayLiteral* literal = new HArrayLiteral(expr->constant_elements(), |
| 3020 length, | 3030 length, |
| 3021 expr->literal_index(), | 3031 expr->literal_index(), |
| 3022 expr->depth()); | 3032 expr->depth()); |
| 3023 // The array is expected in the bailout environment during computation | 3033 // The array is expected in the bailout environment during computation |
| 3024 // of the property values and is the value of the entire expression. | 3034 // of the property values and is the value of the entire expression. |
| 3025 PushAndAdd(literal); | 3035 PushAndAdd(literal); |
| 3026 HValue* elements = AddInstruction(new HLoadElements(literal)); | 3036 |
| 3037 HLoadElements* elements = NULL; |
| 3027 | 3038 |
| 3028 for (int i = 0; i < length; i++) { | 3039 for (int i = 0; i < length; i++) { |
| 3029 Expression* subexpr = subexprs->at(i); | 3040 Expression* subexpr = subexprs->at(i); |
| 3030 // If the subexpression is a literal or a simple materialized literal it | 3041 // If the subexpression is a literal or a simple materialized literal it |
| 3031 // is already set in the cloned array. | 3042 // is already set in the cloned array. |
| 3032 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 3043 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
| 3033 | 3044 |
| 3034 VISIT_FOR_VALUE(subexpr); | 3045 VISIT_FOR_VALUE(subexpr); |
| 3035 HValue* value = Pop(); | 3046 HValue* value = Pop(); |
| 3036 if (!Smi::IsValid(i)) BAILOUT("Non-smi key in array literal"); | 3047 if (!Smi::IsValid(i)) BAILOUT("Non-smi key in array literal"); |
| 3048 |
| 3049 // Load the elements array before the first store. |
| 3050 if (elements == NULL) { |
| 3051 elements = new HLoadElements(literal); |
| 3052 AddInstruction(elements); |
| 3053 } |
| 3054 |
| 3037 HValue* key = AddInstruction(new HConstant(Handle<Object>(Smi::FromInt(i)), | 3055 HValue* key = AddInstruction(new HConstant(Handle<Object>(Smi::FromInt(i)), |
| 3038 Representation::Integer32())); | 3056 Representation::Integer32())); |
| 3039 AddInstruction(new HStoreKeyedFastElement(elements, key, value)); | 3057 AddInstruction(new HStoreKeyedFastElement(elements, key, value)); |
| 3040 AddSimulate(expr->GetIdForElement(i)); | 3058 AddSimulate(expr->GetIdForElement(i)); |
| 3041 } | 3059 } |
| 3042 ast_context()->ReturnValue(Pop()); | 3060 ast_context()->ReturnValue(Pop()); |
| 3043 } | 3061 } |
| 3044 | 3062 |
| 3045 | 3063 |
| 3046 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 3064 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3140 // from the end of the fixed part of the object. | 3158 // from the end of the fixed part of the object. |
| 3141 offset += type->instance_size(); | 3159 offset += type->instance_size(); |
| 3142 } else { | 3160 } else { |
| 3143 offset += FixedArray::kHeaderSize; | 3161 offset += FixedArray::kHeaderSize; |
| 3144 } | 3162 } |
| 3145 HStoreNamedField* instr = | 3163 HStoreNamedField* instr = |
| 3146 new HStoreNamedField(object, name, value, is_in_object, offset); | 3164 new HStoreNamedField(object, name, value, is_in_object, offset); |
| 3147 if (lookup->type() == MAP_TRANSITION) { | 3165 if (lookup->type() == MAP_TRANSITION) { |
| 3148 Handle<Map> transition(lookup->GetTransitionMapFromMap(*type)); | 3166 Handle<Map> transition(lookup->GetTransitionMapFromMap(*type)); |
| 3149 instr->set_transition(transition); | 3167 instr->set_transition(transition); |
| 3168 // TODO(fschneider): Record the new map type of the object in the IR to |
| 3169 // enable elimination of redundant checks after the transition store. |
| 3170 instr->SetFlag(HValue::kChangesMaps); |
| 3150 } | 3171 } |
| 3151 return instr; | 3172 return instr; |
| 3152 } | 3173 } |
| 3153 | 3174 |
| 3154 | 3175 |
| 3155 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, | 3176 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, |
| 3156 Handle<String> name, | 3177 Handle<String> name, |
| 3157 HValue* value) { | 3178 HValue* value) { |
| 3158 return new HStoreNamedGeneric(object, name, value); | 3179 return new HStoreNamedGeneric(object, name, value); |
| 3159 } | 3180 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3232 } else { | 3253 } else { |
| 3233 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3254 HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
| 3234 Push(value); | 3255 Push(value); |
| 3235 instr->set_position(expr->position()); | 3256 instr->set_position(expr->position()); |
| 3236 AddInstruction(instr); | 3257 AddInstruction(instr); |
| 3237 } | 3258 } |
| 3238 subgraphs.Add(subgraph); | 3259 subgraphs.Add(subgraph); |
| 3239 } | 3260 } |
| 3240 | 3261 |
| 3241 HBasicBlock* new_exit_block = | 3262 HBasicBlock* new_exit_block = |
| 3242 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | 3263 BuildTypeSwitch(&maps, &subgraphs, object, expr->AssignmentId()); |
| 3243 subgraph()->set_exit_block(new_exit_block); | 3264 subgraph()->set_exit_block(new_exit_block); |
| 3244 } | 3265 } |
| 3245 | 3266 |
| 3246 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | 3267 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
| 3247 } | 3268 } |
| 3248 | 3269 |
| 3249 | 3270 |
| 3250 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3271 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3251 Property* prop = expr->target()->AsProperty(); | 3272 Property* prop = expr->target()->AsProperty(); |
| 3252 ASSERT(prop != NULL); | 3273 ASSERT(prop != NULL); |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3504 // different maps are identical. In that case we can avoid | 3525 // different maps are identical. In that case we can avoid |
| 3505 // repeatedly generating the same prototype map checks. | 3526 // repeatedly generating the same prototype map checks. |
| 3506 for (int i = 0; i < number_of_types; ++i) { | 3527 for (int i = 0; i < number_of_types; ++i) { |
| 3507 Handle<Map> map = types->at(i); | 3528 Handle<Map> map = types->at(i); |
| 3508 LookupResult lookup; | 3529 LookupResult lookup; |
| 3509 map->LookupInDescriptors(NULL, *name, &lookup); | 3530 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3510 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3531 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3511 maps.Add(map); | 3532 maps.Add(map); |
| 3512 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3533 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3513 SubgraphScope scope(this, subgraph); | 3534 SubgraphScope scope(this, subgraph); |
| 3514 HInstruction* instr = | 3535 HLoadNamedField* instr = |
| 3515 BuildLoadNamedField(object, expr, map, &lookup, false); | 3536 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3516 instr->set_position(expr->position()); | 3537 instr->set_position(expr->position()); |
| 3538 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. |
| 3517 PushAndAdd(instr); | 3539 PushAndAdd(instr); |
| 3518 subgraphs.Add(subgraph); | 3540 subgraphs.Add(subgraph); |
| 3519 } else { | 3541 } else { |
| 3520 needs_generic = true; | 3542 needs_generic = true; |
| 3521 } | 3543 } |
| 3522 } | 3544 } |
| 3523 | 3545 |
| 3524 // If none of the properties were named fields we generate a | 3546 // If none of the properties were named fields we generate a |
| 3525 // generic load. | 3547 // generic load. |
| 3526 if (maps.length() == 0) { | 3548 if (maps.length() == 0) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3545 | 3567 |
| 3546 HBasicBlock* new_exit_block = | 3568 HBasicBlock* new_exit_block = |
| 3547 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | 3569 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); |
| 3548 subgraph()->set_exit_block(new_exit_block); | 3570 subgraph()->set_exit_block(new_exit_block); |
| 3549 } | 3571 } |
| 3550 | 3572 |
| 3551 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); | 3573 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
| 3552 } | 3574 } |
| 3553 | 3575 |
| 3554 | 3576 |
| 3555 HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3577 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3556 Property* expr, | 3578 Property* expr, |
| 3557 Handle<Map> type, | 3579 Handle<Map> type, |
| 3558 LookupResult* lookup, | 3580 LookupResult* lookup, |
| 3559 bool smi_and_map_check) { | 3581 bool smi_and_map_check) { |
| 3560 if (smi_and_map_check) { | 3582 if (smi_and_map_check) { |
| 3561 AddInstruction(new HCheckNonSmi(object)); | 3583 AddInstruction(new HCheckNonSmi(object)); |
| 3562 AddInstruction(new HCheckMap(object, type)); | 3584 AddInstruction(new HCheckMap(object, type)); |
| 3563 } | 3585 } |
| 3564 | 3586 |
| 3565 int index = lookup->GetLocalFieldIndexFromMap(*type); | 3587 int index = lookup->GetLocalFieldIndexFromMap(*type); |
| 3566 if (index < 0) { | 3588 if (index < 0) { |
| 3567 // Negative property indices are in-object properties, indexed | 3589 // Negative property indices are in-object properties, indexed |
| 3568 // from the end of the fixed part of the object. | 3590 // from the end of the fixed part of the object. |
| 3569 int offset = (index * kPointerSize) + type->instance_size(); | 3591 int offset = (index * kPointerSize) + type->instance_size(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3589 Handle<Map> map, | 3611 Handle<Map> map, |
| 3590 Handle<String> name) { | 3612 Handle<String> name) { |
| 3591 LookupResult lookup; | 3613 LookupResult lookup; |
| 3592 map->LookupInDescriptors(NULL, *name, &lookup); | 3614 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3593 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3615 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3594 return BuildLoadNamedField(obj, | 3616 return BuildLoadNamedField(obj, |
| 3595 expr, | 3617 expr, |
| 3596 map, | 3618 map, |
| 3597 &lookup, | 3619 &lookup, |
| 3598 true); | 3620 true); |
| 3621 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { |
| 3622 AddInstruction(new HCheckNonSmi(obj)); |
| 3623 AddInstruction(new HCheckMap(obj, map)); |
| 3624 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); |
| 3625 return new HConstant(function, Representation::Tagged()); |
| 3599 } else { | 3626 } else { |
| 3600 return BuildLoadNamedGeneric(obj, expr); | 3627 return BuildLoadNamedGeneric(obj, expr); |
| 3601 } | 3628 } |
| 3602 } | 3629 } |
| 3603 | 3630 |
| 3604 | 3631 |
| 3605 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 3632 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 3606 HValue* key) { | 3633 HValue* key) { |
| 3607 return new HLoadKeyedGeneric(object, key); | 3634 return new HLoadKeyedGeneric(object, key); |
| 3608 } | 3635 } |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3935 | 3962 |
| 3936 TestContext* test_context = NULL; | 3963 TestContext* test_context = NULL; |
| 3937 if (ast_context()->IsTest()) { | 3964 if (ast_context()->IsTest()) { |
| 3938 // Inlined body is treated as if it occurs in an 'inlined' call context | 3965 // Inlined body is treated as if it occurs in an 'inlined' call context |
| 3939 // with true and false blocks that will forward to the real ones. | 3966 // with true and false blocks that will forward to the real ones. |
| 3940 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 3967 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3941 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 3968 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3942 if_true->MarkAsInlineReturnTarget(); | 3969 if_true->MarkAsInlineReturnTarget(); |
| 3943 if_false->MarkAsInlineReturnTarget(); | 3970 if_false->MarkAsInlineReturnTarget(); |
| 3944 // AstContext constructor pushes on the context stack. | 3971 // AstContext constructor pushes on the context stack. |
| 3945 bool invert_true = TestContext::cast(ast_context())->invert_true(); | 3972 test_context = new TestContext(this, if_true, if_false); |
| 3946 bool invert_false = TestContext::cast(ast_context())->invert_false(); | |
| 3947 test_context = new TestContext(this, if_true, if_false, | |
| 3948 invert_true, invert_false); | |
| 3949 function_return_ = NULL; | 3973 function_return_ = NULL; |
| 3950 } else { | 3974 } else { |
| 3951 // Inlined body is treated as if it occurs in the original call context. | 3975 // Inlined body is treated as if it occurs in the original call context. |
| 3952 function_return_ = graph()->CreateBasicBlock(); | 3976 function_return_ = graph()->CreateBasicBlock(); |
| 3953 function_return_->MarkAsInlineReturnTarget(); | 3977 function_return_->MarkAsInlineReturnTarget(); |
| 3954 } | 3978 } |
| 3955 call_context_ = ast_context(); | 3979 call_context_ = ast_context(); |
| 3956 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code())); | 3980 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code())); |
| 3957 oracle_ = &new_oracle; | 3981 oracle_ = &new_oracle; |
| 3958 graph()->info()->SetOsrAstId(AstNode::kNoNumber); | 3982 graph()->info()->SetOsrAstId(AstNode::kNoNumber); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3982 HValue* return_value = graph()->GetConstantUndefined(); | 4006 HValue* return_value = graph()->GetConstantUndefined(); |
| 3983 if (test_context == NULL) { | 4007 if (test_context == NULL) { |
| 3984 ASSERT(function_return_ != NULL); | 4008 ASSERT(function_return_ != NULL); |
| 3985 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4009 body->exit_block()->AddLeaveInlined(return_value, function_return_); |
| 3986 } else { | 4010 } else { |
| 3987 // The graph builder assumes control can reach both branches of a | 4011 // The graph builder assumes control can reach both branches of a |
| 3988 // test, so we materialize the undefined value and test it rather than | 4012 // test, so we materialize the undefined value and test it rather than |
| 3989 // simply jumping to the false target. | 4013 // simply jumping to the false target. |
| 3990 // | 4014 // |
| 3991 // TODO(3168478): refactor to avoid this. | 4015 // TODO(3168478): refactor to avoid this. |
| 3992 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); | 4016 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 3993 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); | 4017 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 3994 HBranch* branch = | 4018 HBranch* branch = |
| 3995 new HBranch(materialize_true, materialize_false, return_value); | 4019 new HBranch(empty_true, empty_false, return_value); |
| 3996 body->exit_block()->Finish(branch); | 4020 body->exit_block()->Finish(branch); |
| 3997 | 4021 |
| 3998 materialize_true->AddLeaveInlined(graph()->GetConstantTrue(), | 4022 HValue* const no_return_value = NULL; |
| 3999 test_context->if_true()); | 4023 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); |
| 4000 materialize_false->AddLeaveInlined(graph()->GetConstantFalse(), | 4024 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); |
| 4001 test_context->if_false()); | |
| 4002 } | 4025 } |
| 4003 body->set_exit_block(NULL); | 4026 body->set_exit_block(NULL); |
| 4004 } | 4027 } |
| 4005 | 4028 |
| 4006 // Record the environment at the inlined function call. | 4029 // Record the environment at the inlined function call. |
| 4007 AddSimulate(expr->ReturnId()); | 4030 AddSimulate(expr->ReturnId()); |
| 4008 | 4031 |
| 4009 // Jump to the function entry (without re-recording the environment). | 4032 // Jump to the function entry (without re-recording the environment). |
| 4010 subgraph()->exit_block()->Finish(new HGoto(body->entry_block())); | 4033 subgraph()->exit_block()->Finish(new HGoto(body->entry_block())); |
| 4011 | 4034 |
| 4012 // Fix up the function exits. | 4035 // Fix up the function exits. |
| 4013 if (test_context != NULL) { | 4036 if (test_context != NULL) { |
| 4014 HBasicBlock* if_true = test_context->if_true(); | 4037 HBasicBlock* if_true = test_context->if_true(); |
| 4015 HBasicBlock* if_false = test_context->if_false(); | 4038 HBasicBlock* if_false = test_context->if_false(); |
| 4016 if_true->SetJoinId(expr->id()); | 4039 if_true->SetJoinId(expr->id()); |
| 4017 if_false->SetJoinId(expr->id()); | 4040 if_false->SetJoinId(expr->id()); |
| 4018 ASSERT(ast_context() == test_context); | 4041 ASSERT(ast_context() == test_context); |
| 4019 delete test_context; // Destructor pops from expression context stack. | 4042 delete test_context; // Destructor pops from expression context stack. |
| 4043 |
| 4020 // Forward to the real test context. | 4044 // Forward to the real test context. |
| 4021 | 4045 HValue* const no_return_value = NULL; |
| 4022 // Discard the lingering branch value (which may be true or false, | |
| 4023 // depending on whether the final condition was negated) and jump to the | |
| 4024 // true target with a true branch value. | |
| 4025 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4046 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 4026 bool invert_true = TestContext::cast(ast_context())->invert_true(); | |
| 4027 HValue* true_value = invert_true | |
| 4028 ? graph()->GetConstantFalse() | |
| 4029 : graph()->GetConstantTrue(); | |
| 4030 if_true->last_environment()->Pop(); | |
| 4031 if (true_target->IsInlineReturnTarget()) { | 4047 if (true_target->IsInlineReturnTarget()) { |
| 4032 if_true->AddLeaveInlined(true_value, true_target); | 4048 if_true->AddLeaveInlined(no_return_value, true_target); |
| 4033 } else { | 4049 } else { |
| 4034 if_true->last_environment()->Push(true_value); | |
| 4035 if_true->Goto(true_target); | 4050 if_true->Goto(true_target); |
| 4036 } | 4051 } |
| 4037 | 4052 |
| 4038 // Do the same for the false target. | |
| 4039 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4053 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 4040 bool invert_false = TestContext::cast(ast_context())->invert_false(); | |
| 4041 HValue* false_value = invert_false | |
| 4042 ? graph()->GetConstantTrue() | |
| 4043 : graph()->GetConstantFalse(); | |
| 4044 if_false->last_environment()->Pop(); | |
| 4045 if (false_target->IsInlineReturnTarget()) { | 4054 if (false_target->IsInlineReturnTarget()) { |
| 4046 if_false->AddLeaveInlined(false_value, false_target); | 4055 if_false->AddLeaveInlined(no_return_value, false_target); |
| 4047 } else { | 4056 } else { |
| 4048 if_false->last_environment()->Push(false_value); | |
| 4049 if_false->Goto(false_target); | 4057 if_false->Goto(false_target); |
| 4050 } | 4058 } |
| 4051 | 4059 |
| 4052 // TODO(kmillikin): Come up with a better way to handle this. It is too | 4060 // TODO(kmillikin): Come up with a better way to handle this. It is too |
| 4053 // subtle. NULL here indicates that the enclosing context has no control | 4061 // subtle. NULL here indicates that the enclosing context has no control |
| 4054 // flow to handle. | 4062 // flow to handle. |
| 4055 subgraph()->set_exit_block(NULL); | 4063 subgraph()->set_exit_block(NULL); |
| 4056 | 4064 |
| 4057 } else { | 4065 } else { |
| 4058 function_return_->SetJoinId(expr->id()); | 4066 function_return_->SetJoinId(expr->id()); |
| 4059 subgraph()->set_exit_block(function_return_); | 4067 subgraph()->set_exit_block(function_return_); |
| 4060 } | 4068 } |
| 4061 | 4069 |
| 4062 call_context_ = saved_call_context; | 4070 call_context_ = saved_call_context; |
| 4063 function_return_ = saved_function_return; | 4071 function_return_ = saved_function_return; |
| 4064 oracle_ = saved_oracle; | 4072 oracle_ = saved_oracle; |
| 4065 graph()->info()->SetOsrAstId(saved_osr_ast_id); | 4073 graph()->info()->SetOsrAstId(saved_osr_ast_id); |
| 4066 | 4074 |
| 4067 return true; | 4075 return true; |
| 4068 } | 4076 } |
| 4069 | 4077 |
| 4070 | 4078 |
| 4071 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4079 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4072 ASSERT(target->IsInlineReturnTarget()); | 4080 ASSERT(target->IsInlineReturnTarget()); |
| 4073 AddInstruction(new HLeaveInlined); | 4081 AddInstruction(new HLeaveInlined); |
| 4074 HEnvironment* outer = last_environment()->outer(); | 4082 HEnvironment* outer = last_environment()->outer(); |
| 4075 outer->Push(return_value); | 4083 if (return_value != NULL) outer->Push(return_value); |
| 4076 UpdateEnvironment(outer); | 4084 UpdateEnvironment(outer); |
| 4077 Goto(target); | 4085 Goto(target); |
| 4078 } | 4086 } |
| 4079 | 4087 |
| 4080 | 4088 |
| 4081 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4089 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| 4082 // Try to inline calls like Math.* as operations in the calling function. | 4090 // Try to inline calls like Math.* as operations in the calling function. |
| 4083 MathFunctionId id = expr->target()->shared()->math_function_id(); | 4091 if (!expr->target()->shared()->IsBuiltinMathFunction()) return false; |
| 4092 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 4084 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4093 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4085 switch (id) { | 4094 switch (id) { |
| 4086 case kMathRound: | 4095 case kMathRound: |
| 4087 case kMathFloor: | 4096 case kMathFloor: |
| 4088 case kMathAbs: | 4097 case kMathAbs: |
| 4089 case kMathSqrt: | 4098 case kMathSqrt: |
| 4099 case kMathLog: |
| 4100 case kMathSin: |
| 4101 case kMathCos: |
| 4090 if (argument_count == 2) { | 4102 if (argument_count == 2) { |
| 4091 HValue* argument = Pop(); | 4103 HValue* argument = Pop(); |
| 4092 Drop(1); // Receiver. | 4104 Drop(1); // Receiver. |
| 4093 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4105 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4094 op->set_position(expr->position()); | 4106 op->set_position(expr->position()); |
| 4095 ast_context()->ReturnInstruction(op, expr->id()); | 4107 ast_context()->ReturnInstruction(op, expr->id()); |
| 4096 return true; | 4108 return true; |
| 4097 } | 4109 } |
| 4098 break; | 4110 break; |
| 4099 case kMathPow: | 4111 case kMathPow: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4135 ast_context()->ReturnInstruction(result, expr->id()); | 4147 ast_context()->ReturnInstruction(result, expr->id()); |
| 4136 return true; | 4148 return true; |
| 4137 } | 4149 } |
| 4138 | 4150 |
| 4139 result = new HPower(left, right); | 4151 result = new HPower(left, right); |
| 4140 ast_context()->ReturnInstruction(result, expr->id()); | 4152 ast_context()->ReturnInstruction(result, expr->id()); |
| 4141 return true; | 4153 return true; |
| 4142 } | 4154 } |
| 4143 break; | 4155 break; |
| 4144 default: | 4156 default: |
| 4145 // Either not a special math function or not yet supported for inlining. | 4157 // Not yet supported for inlining. |
| 4146 break; | 4158 break; |
| 4147 } | 4159 } |
| 4148 return false; | 4160 return false; |
| 4149 } | 4161 } |
| 4150 | 4162 |
| 4151 | 4163 |
| 4152 bool HGraphBuilder::TryCallApply(Call* expr) { | 4164 bool HGraphBuilder::TryCallApply(Call* expr) { |
| 4153 Expression* callee = expr->expression(); | 4165 Expression* callee = expr->expression(); |
| 4154 Property* prop = callee->AsProperty(); | 4166 Property* prop = callee->AsProperty(); |
| 4155 ASSERT(prop != NULL); | 4167 ASSERT(prop != NULL); |
| 4156 | 4168 |
| 4157 if (graph()->info()->scope()->arguments() == NULL) return false; | 4169 if (graph()->info()->scope()->arguments() == NULL) return false; |
| 4158 | 4170 |
| 4159 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4171 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4160 if (!name->IsEqualTo(CStrVector("apply"))) return false; | 4172 if (!name->IsEqualTo(CStrVector("apply"))) return false; |
| 4161 | 4173 |
| 4162 ZoneList<Expression*>* args = expr->arguments(); | 4174 ZoneList<Expression*>* args = expr->arguments(); |
| 4163 if (args->length() != 2) return false; | 4175 if (args->length() != 2) return false; |
| 4164 | 4176 |
| 4165 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 4177 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 4166 if (arg_two == NULL) return false; | 4178 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 4167 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 4179 HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
| 4168 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 4180 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 4169 | 4181 |
| 4170 if (!expr->IsMonomorphic()) return false; | 4182 if (!expr->IsMonomorphic()) return false; |
| 4171 | 4183 |
| 4172 // Found pattern f.apply(receiver, arguments). | 4184 // Found pattern f.apply(receiver, arguments). |
| 4173 VisitForValue(prop->obj()); | 4185 VisitForValue(prop->obj()); |
| 4174 if (HasStackOverflow()) return false; | 4186 if (HasStackOverflow()) return false; |
| 4175 HValue* function = Pop(); | 4187 HValue* function = Pop(); |
| 4176 VisitForValue(args->at(0)); | 4188 VisitForValue(args->at(0)); |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4449 } else if (var->is_global()) { | 4461 } else if (var->is_global()) { |
| 4450 BAILOUT("delete with global variable"); | 4462 BAILOUT("delete with global variable"); |
| 4451 } else { | 4463 } else { |
| 4452 BAILOUT("delete with non-global variable"); | 4464 BAILOUT("delete with non-global variable"); |
| 4453 } | 4465 } |
| 4454 } else if (op == Token::NOT) { | 4466 } else if (op == Token::NOT) { |
| 4455 if (ast_context()->IsTest()) { | 4467 if (ast_context()->IsTest()) { |
| 4456 TestContext* context = TestContext::cast(ast_context()); | 4468 TestContext* context = TestContext::cast(ast_context()); |
| 4457 VisitForControl(expr->expression(), | 4469 VisitForControl(expr->expression(), |
| 4458 context->if_false(), | 4470 context->if_false(), |
| 4459 context->if_true(), | 4471 context->if_true()); |
| 4460 !context->invert_false(), | |
| 4461 !context->invert_true()); | |
| 4462 } else { | 4472 } else { |
| 4463 HSubgraph* true_graph = CreateEmptySubgraph(); | 4473 HSubgraph* true_graph = CreateEmptySubgraph(); |
| 4464 HSubgraph* false_graph = CreateEmptySubgraph(); | 4474 HSubgraph* false_graph = CreateEmptySubgraph(); |
| 4465 VisitCondition(expr->expression(), | 4475 VISIT_FOR_CONTROL(expr->expression(), |
| 4466 false_graph->entry_block(), | 4476 false_graph->entry_block(), |
| 4467 true_graph->entry_block(), | 4477 true_graph->entry_block()); |
| 4468 true, true); | 4478 true_graph->entry_block()->SetJoinId(expr->expression()->id()); |
| 4469 if (HasStackOverflow()) return; | |
| 4470 true_graph->environment()->Push(graph_->GetConstantTrue()); | 4479 true_graph->environment()->Push(graph_->GetConstantTrue()); |
| 4480 |
| 4481 false_graph->entry_block()->SetJoinId(expr->expression()->id()); |
| 4471 false_graph->environment()->Push(graph_->GetConstantFalse()); | 4482 false_graph->environment()->Push(graph_->GetConstantFalse()); |
| 4483 |
| 4472 current_subgraph_->AppendJoin(true_graph, false_graph, expr); | 4484 current_subgraph_->AppendJoin(true_graph, false_graph, expr); |
| 4473 ast_context()->ReturnValue(Pop()); | 4485 ast_context()->ReturnValue(Pop()); |
| 4474 } | 4486 } |
| 4475 } else if (op == Token::BIT_NOT || op == Token::SUB) { | 4487 } else if (op == Token::BIT_NOT || op == Token::SUB) { |
| 4476 VISIT_FOR_VALUE(expr->expression()); | 4488 VISIT_FOR_VALUE(expr->expression()); |
| 4477 HValue* value = Pop(); | 4489 HValue* value = Pop(); |
| 4478 HInstruction* instr = NULL; | 4490 HInstruction* instr = NULL; |
| 4479 switch (op) { | 4491 switch (op) { |
| 4480 case Token::BIT_NOT: | 4492 case Token::BIT_NOT: |
| 4481 instr = new HBitNot(value); | 4493 instr = new HBitNot(value); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4524 ASSERT(var == NULL || prop == NULL); | 4536 ASSERT(var == NULL || prop == NULL); |
| 4525 bool inc = expr->op() == Token::INC; | 4537 bool inc = expr->op() == Token::INC; |
| 4526 | 4538 |
| 4527 if (var != NULL) { | 4539 if (var != NULL) { |
| 4528 if (!var->is_global() && !var->IsStackAllocated()) { | 4540 if (!var->is_global() && !var->IsStackAllocated()) { |
| 4529 BAILOUT("non-stack/non-global variable in count operation"); | 4541 BAILOUT("non-stack/non-global variable in count operation"); |
| 4530 } | 4542 } |
| 4531 | 4543 |
| 4532 VISIT_FOR_VALUE(target); | 4544 VISIT_FOR_VALUE(target); |
| 4533 | 4545 |
| 4534 HValue* value = Pop(); | 4546 // Match the full code generator stack by simulating an extra stack |
| 4535 HInstruction* instr = BuildIncrement(value, inc); | 4547 // element for postfix operations in a non-effect context. |
| 4536 AddInstruction(instr); | 4548 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
| 4537 | 4549 HValue* before = has_extra ? Top() : Pop(); |
| 4538 if (expr->is_prefix()) { | 4550 HInstruction* after = BuildIncrement(before, inc); |
| 4539 Push(instr); | 4551 AddInstruction(after); |
| 4540 } else { | 4552 Push(after); |
| 4541 Push(value); | |
| 4542 } | |
| 4543 | 4553 |
| 4544 if (var->is_global()) { | 4554 if (var->is_global()) { |
| 4545 HandleGlobalVariableAssignment(var, | 4555 HandleGlobalVariableAssignment(var, |
| 4546 instr, | 4556 after, |
| 4547 expr->position(), | 4557 expr->position(), |
| 4548 expr->AssignmentId()); | 4558 expr->AssignmentId()); |
| 4549 } else { | 4559 } else { |
| 4550 ASSERT(var->IsStackAllocated()); | 4560 ASSERT(var->IsStackAllocated()); |
| 4551 Bind(var, instr); | 4561 Bind(var, after); |
| 4552 } | 4562 } |
| 4553 ast_context()->ReturnValue(Pop()); | 4563 Drop(has_extra ? 2 : 1); |
| 4564 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4554 | 4565 |
| 4555 } else if (prop != NULL) { | 4566 } else if (prop != NULL) { |
| 4556 prop->RecordTypeFeedback(oracle()); | 4567 prop->RecordTypeFeedback(oracle()); |
| 4557 | 4568 |
| 4558 if (prop->key()->IsPropertyName()) { | 4569 if (prop->key()->IsPropertyName()) { |
| 4559 // Named property. | 4570 // Named property. |
| 4560 | 4571 |
| 4561 // Match the full code generator stack by simulating an extra stack | 4572 // Match the full code generator stack by simulating an extra stack |
| 4562 // element for postfix operations in a value context. | 4573 // element for postfix operations in a non-effect context. |
| 4563 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); | 4574 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
| 4564 if (has_extra) Push(graph_->GetConstantUndefined()); | 4575 if (has_extra) Push(graph_->GetConstantUndefined()); |
| 4565 | 4576 |
| 4566 VISIT_FOR_VALUE(prop->obj()); | 4577 VISIT_FOR_VALUE(prop->obj()); |
| 4567 HValue* obj = Top(); | 4578 HValue* obj = Top(); |
| 4568 | 4579 |
| 4569 HInstruction* load = NULL; | 4580 HInstruction* load = NULL; |
| 4570 if (prop->IsMonomorphic()) { | 4581 if (prop->IsMonomorphic()) { |
| 4571 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4582 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4572 Handle<Map> map = prop->GetReceiverTypes()->first(); | 4583 Handle<Map> map = prop->GetReceiverTypes()->first(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 4593 if (has_extra) environment()->SetExpressionStackAt(1, before); | 4604 if (has_extra) environment()->SetExpressionStackAt(1, before); |
| 4594 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 4605 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4595 Drop(has_extra ? 2 : 1); | 4606 Drop(has_extra ? 2 : 1); |
| 4596 | 4607 |
| 4597 ast_context()->ReturnValue(expr->is_postfix() ? before : after); | 4608 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4598 | 4609 |
| 4599 } else { | 4610 } else { |
| 4600 // Keyed property. | 4611 // Keyed property. |
| 4601 | 4612 |
| 4602 // Match the full code generator stack by simulate an extra stack element | 4613 // Match the full code generator stack by simulate an extra stack element |
| 4603 // for postfix operations in a value context. | 4614 // for postfix operations in a non-effect context. |
| 4604 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); | 4615 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
| 4605 if (has_extra) Push(graph_->GetConstantUndefined()); | 4616 if (has_extra) Push(graph_->GetConstantUndefined()); |
| 4606 | 4617 |
| 4607 VISIT_FOR_VALUE(prop->obj()); | 4618 VISIT_FOR_VALUE(prop->obj()); |
| 4608 VISIT_FOR_VALUE(prop->key()); | 4619 VISIT_FOR_VALUE(prop->key()); |
| 4609 HValue* obj = environment()->ExpressionStackAt(1); | 4620 HValue* obj = environment()->ExpressionStackAt(1); |
| 4610 HValue* key = environment()->ExpressionStackAt(0); | 4621 HValue* key = environment()->ExpressionStackAt(0); |
| 4611 | 4622 |
| 4612 bool is_fast_elements = prop->IsMonomorphic() && | 4623 bool is_fast_elements = prop->IsMonomorphic() && |
| 4613 prop->GetMonomorphicReceiverType()->has_fast_elements(); | 4624 prop->GetMonomorphicReceiverType()->has_fast_elements(); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4726 // expression. | 4737 // expression. |
| 4727 Visit(expr->right()); | 4738 Visit(expr->right()); |
| 4728 | 4739 |
| 4729 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { | 4740 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { |
| 4730 bool is_logical_and = (expr->op() == Token::AND); | 4741 bool is_logical_and = (expr->op() == Token::AND); |
| 4731 if (ast_context()->IsTest()) { | 4742 if (ast_context()->IsTest()) { |
| 4732 TestContext* context = TestContext::cast(ast_context()); | 4743 TestContext* context = TestContext::cast(ast_context()); |
| 4733 // Translate left subexpression. | 4744 // Translate left subexpression. |
| 4734 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 4745 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 4735 if (is_logical_and) { | 4746 if (is_logical_and) { |
| 4736 VisitForControl(expr->left(), eval_right, context->if_false(), | 4747 VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false()); |
| 4737 false, context->invert_false()); | |
| 4738 } else { | 4748 } else { |
| 4739 VisitForControl(expr->left(), context->if_true(), eval_right, | 4749 VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right); |
| 4740 context->invert_true(), false); | |
| 4741 } | 4750 } |
| 4742 if (HasStackOverflow()) return; | 4751 eval_right->SetJoinId(expr->RightId()); |
| 4743 eval_right->SetJoinId(expr->left()->id()); | |
| 4744 | 4752 |
| 4745 // Translate right subexpression by visiting it in the same AST | 4753 // Translate right subexpression by visiting it in the same AST |
| 4746 // context as the entire expression. | 4754 // context as the entire expression. |
| 4747 eval_right->last_environment()->Pop(); | |
| 4748 subgraph()->set_exit_block(eval_right); | 4755 subgraph()->set_exit_block(eval_right); |
| 4749 Visit(expr->right()); | 4756 Visit(expr->right()); |
| 4750 | 4757 |
| 4751 } else { | 4758 } else { |
| 4752 VISIT_FOR_VALUE(expr->left()); | 4759 VISIT_FOR_VALUE(expr->left()); |
| 4753 ASSERT(current_subgraph_->HasExit()); | 4760 ASSERT(current_subgraph_->HasExit()); |
| 4754 | 4761 |
| 4755 HValue* left = Top(); | 4762 HValue* left = Top(); |
| 4756 HEnvironment* environment_copy = environment()->Copy(); | 4763 HEnvironment* environment_copy = environment()->Copy(); |
| 4757 environment_copy->Pop(); | 4764 environment_copy->Pop(); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4942 | 4949 |
| 4943 | 4950 |
| 4944 void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { | 4951 void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { |
| 4945 ASSERT(argument_count == 1); | 4952 ASSERT(argument_count == 1); |
| 4946 HValue* value = Pop(); | 4953 HValue* value = Pop(); |
| 4947 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); | 4954 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); |
| 4948 ast_context()->ReturnInstruction(result, ast_id); | 4955 ast_context()->ReturnInstruction(result, ast_id); |
| 4949 } | 4956 } |
| 4950 | 4957 |
| 4951 | 4958 |
| 4959 void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { |
| 4960 ASSERT(argument_count == 1); |
| 4961 |
| 4962 HValue* value = Pop(); |
| 4963 HIsObject* test = new HIsObject(value); |
| 4964 ast_context()->ReturnInstruction(test, ast_id); |
| 4965 } |
| 4966 |
| 4967 |
| 4952 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, | 4968 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, |
| 4953 int ast_id) { | 4969 int ast_id) { |
| 4954 BAILOUT("inlined runtime function: IsNonNegativeSmi"); | 4970 BAILOUT("inlined runtime function: IsNonNegativeSmi"); |
| 4955 } | 4971 } |
| 4956 | 4972 |
| 4957 | 4973 |
| 4958 void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { | |
| 4959 BAILOUT("inlined runtime function: IsObject"); | |
| 4960 } | |
| 4961 | |
| 4962 | |
| 4963 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, | 4974 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, |
| 4964 int ast_id) { | 4975 int ast_id) { |
| 4965 BAILOUT("inlined runtime function: IsUndetectableObject"); | 4976 BAILOUT("inlined runtime function: IsUndetectableObject"); |
| 4966 } | 4977 } |
| 4967 | 4978 |
| 4968 | 4979 |
| 4969 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 4980 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 4970 int argument_count, | 4981 int argument_count, |
| 4971 int ast_id) { | 4982 int ast_id) { |
| 4972 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 4983 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| (...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5666 } | 5677 } |
| 5667 | 5678 |
| 5668 #ifdef DEBUG | 5679 #ifdef DEBUG |
| 5669 if (graph_ != NULL) graph_->Verify(); | 5680 if (graph_ != NULL) graph_->Verify(); |
| 5670 if (chunk_ != NULL) chunk_->Verify(); | 5681 if (chunk_ != NULL) chunk_->Verify(); |
| 5671 if (allocator_ != NULL) allocator_->Verify(); | 5682 if (allocator_ != NULL) allocator_->Verify(); |
| 5672 #endif | 5683 #endif |
| 5673 } | 5684 } |
| 5674 | 5685 |
| 5675 } } // namespace v8::internal | 5686 } } // namespace v8::internal |
| OLD | NEW |