| 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 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1976 } | 1974 } |
| 1977 } | 1975 } |
| 1978 } | 1976 } |
| 1979 | 1977 |
| 1980 | 1978 |
| 1981 // Implementation of utility classes to represent an expression's context in | 1979 // Implementation of utility classes to represent an expression's context in |
| 1982 // the AST. | 1980 // the AST. |
| 1983 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 1981 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
| 1984 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { | 1982 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { |
| 1985 owner->set_ast_context(this); // Push. | 1983 owner->set_ast_context(this); // Push. |
| 1984 #ifdef DEBUG |
| 1985 original_count_ = owner->environment()->total_count(); |
| 1986 #endif |
| 1986 } | 1987 } |
| 1987 | 1988 |
| 1988 | 1989 |
| 1989 AstContext::~AstContext() { | 1990 AstContext::~AstContext() { |
| 1990 owner_->set_ast_context(outer_); // Pop. | 1991 owner_->set_ast_context(outer_); // Pop. |
| 1991 } | 1992 } |
| 1992 | 1993 |
| 1993 | 1994 |
| 1995 EffectContext::~EffectContext() { |
| 1996 ASSERT(owner()->HasStackOverflow() || |
| 1997 !owner()->subgraph()->HasExit() || |
| 1998 owner()->environment()->total_count() == original_count_); |
| 1999 } |
| 2000 |
| 2001 |
| 2002 ValueContext::~ValueContext() { |
| 2003 ASSERT(owner()->HasStackOverflow() || |
| 2004 !owner()->subgraph()->HasExit() || |
| 2005 owner()->environment()->total_count() == original_count_ + 1); |
| 2006 } |
| 2007 |
| 2008 |
| 2009 void EffectContext::ReturnValue(HValue* value) { |
| 2010 // The value is simply ignored. |
| 2011 } |
| 2012 |
| 2013 |
| 2014 void ValueContext::ReturnValue(HValue* value) { |
| 2015 // The value is tracked in the bailout environment, and communicated |
| 2016 // through the environment as the result of the expression. |
| 2017 owner()->Push(value); |
| 2018 } |
| 2019 |
| 2020 |
| 2021 void TestContext::ReturnValue(HValue* value) { |
| 2022 BuildBranch(value); |
| 2023 } |
| 2024 |
| 2025 |
| 2026 void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
| 2027 owner()->AddInstruction(instr); |
| 2028 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); |
| 2029 } |
| 2030 |
| 2031 |
| 2032 void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
| 2033 owner()->AddInstruction(instr); |
| 2034 owner()->Push(instr); |
| 2035 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); |
| 2036 } |
| 2037 |
| 2038 |
| 2039 void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) { |
| 2040 HGraphBuilder* builder = owner(); |
| 2041 builder->AddInstruction(instr); |
| 2042 // We expect a simulate after every expression with side effects, though |
| 2043 // this one isn't actually needed (and wouldn't work if it were targeted). |
| 2044 if (instr->HasSideEffects()) { |
| 2045 builder->Push(instr); |
| 2046 builder->AddSimulate(ast_id); |
| 2047 builder->Pop(); |
| 2048 } |
| 2049 BuildBranch(instr); |
| 2050 } |
| 2051 |
| 2052 |
| 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. |
| 2058 HGraphBuilder* builder = owner(); |
| 2059 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
| 2060 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
| 2061 HBranch* branch = new HBranch(empty_true, empty_false, value); |
| 2062 builder->CurrentBlock()->Finish(branch); |
| 2063 |
| 2064 HValue* const no_return_value = NULL; |
| 2065 HBasicBlock* true_target = if_true(); |
| 2066 if (true_target->IsInlineReturnTarget()) { |
| 2067 empty_true->AddLeaveInlined(no_return_value, true_target); |
| 2068 } else { |
| 2069 empty_true->Goto(true_target); |
| 2070 } |
| 2071 |
| 2072 HBasicBlock* false_target = if_false(); |
| 2073 if (false_target->IsInlineReturnTarget()) { |
| 2074 empty_false->AddLeaveInlined(no_return_value, false_target); |
| 2075 } else { |
| 2076 empty_false->Goto(false_target); |
| 2077 } |
| 2078 builder->subgraph()->set_exit_block(NULL); |
| 2079 } |
| 2080 |
| 1994 | 2081 |
| 1995 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2082 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 1996 #define BAILOUT(reason) \ | 2083 #define BAILOUT(reason) \ |
| 1997 do { \ | 2084 do { \ |
| 1998 Bailout(reason); \ | 2085 Bailout(reason); \ |
| 1999 return; \ | 2086 return; \ |
| 2000 } while (false) | 2087 } while (false) |
| 2001 | 2088 |
| 2002 | 2089 |
| 2003 #define CHECK_BAILOUT \ | 2090 #define CHECK_BAILOUT \ |
| 2004 do { \ | 2091 do { \ |
| 2005 if (HasStackOverflow()) return; \ | 2092 if (HasStackOverflow()) return; \ |
| 2006 } while (false) | 2093 } while (false) |
| 2007 | 2094 |
| 2008 | 2095 |
| 2009 #define VISIT_FOR_EFFECT(expr) \ | 2096 #define VISIT_FOR_EFFECT(expr) \ |
| 2010 do { \ | 2097 do { \ |
| 2011 VisitForEffect(expr); \ | 2098 VisitForEffect(expr); \ |
| 2012 if (HasStackOverflow()) return; \ | 2099 if (HasStackOverflow()) return; \ |
| 2013 } while (false) | 2100 } while (false) |
| 2014 | 2101 |
| 2015 | 2102 |
| 2016 #define VISIT_FOR_VALUE(expr) \ | 2103 #define VISIT_FOR_VALUE(expr) \ |
| 2017 do { \ | 2104 do { \ |
| 2018 VisitForValue(expr); \ | 2105 VisitForValue(expr); \ |
| 2019 if (HasStackOverflow()) return; \ | 2106 if (HasStackOverflow()) return; \ |
| 2020 } while (false) | 2107 } while (false) |
| 2021 | 2108 |
| 2022 | 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 |
| 2023 // 'thing' could be an expression, statement, or list of statements. | 2117 // 'thing' could be an expression, statement, or list of statements. |
| 2024 #define ADD_TO_SUBGRAPH(graph, thing) \ | 2118 #define ADD_TO_SUBGRAPH(graph, thing) \ |
| 2025 do { \ | 2119 do { \ |
| 2026 AddToSubgraph(graph, thing); \ | 2120 AddToSubgraph(graph, thing); \ |
| 2027 if (HasStackOverflow()) return; \ | 2121 if (HasStackOverflow()) return; \ |
| 2028 } while (false) | 2122 } while (false) |
| 2029 | 2123 |
| 2030 | 2124 |
| 2031 class HGraphBuilder::SubgraphScope BASE_EMBEDDED { | 2125 class HGraphBuilder::SubgraphScope BASE_EMBEDDED { |
| 2032 public: | 2126 public: |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2054 void HGraphBuilder::Bailout(const char* reason) { | 2148 void HGraphBuilder::Bailout(const char* reason) { |
| 2055 if (FLAG_trace_bailout) { | 2149 if (FLAG_trace_bailout) { |
| 2056 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); | 2150 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); |
| 2057 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *debug_name, reason); | 2151 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *debug_name, reason); |
| 2058 } | 2152 } |
| 2059 SetStackOverflow(); | 2153 SetStackOverflow(); |
| 2060 } | 2154 } |
| 2061 | 2155 |
| 2062 | 2156 |
| 2063 void HGraphBuilder::VisitForEffect(Expression* expr) { | 2157 void HGraphBuilder::VisitForEffect(Expression* expr) { |
| 2064 #ifdef DEBUG | 2158 EffectContext for_effect(this); |
| 2065 int original_count = environment()->total_count(); | 2159 Visit(expr); |
| 2066 #endif | |
| 2067 BinaryOperation* binary_op = expr->AsBinaryOperation(); | |
| 2068 | |
| 2069 // We use special casing for expression types not handled properly by our | |
| 2070 // usual trick of pretending they're in a value context and cleaning up | |
| 2071 // later. | |
| 2072 if (binary_op != NULL && binary_op->op() == Token::COMMA) { | |
| 2073 VISIT_FOR_EFFECT(binary_op->left()); | |
| 2074 VISIT_FOR_EFFECT(binary_op->right()); | |
| 2075 } else { | |
| 2076 { EffectContext for_effect(this); | |
| 2077 Visit(expr); | |
| 2078 } | |
| 2079 if (HasStackOverflow() || !subgraph()->HasExit()) return; | |
| 2080 // Discard return value. | |
| 2081 Pop(); | |
| 2082 // TODO(kasperl): Try to improve the way we compute the last added | |
| 2083 // instruction. The NULL check makes me uncomfortable. | |
| 2084 HValue* last = subgraph()->exit_block()->GetLastInstruction(); | |
| 2085 // We need to ensure we emit a simulate after inlined functions in an | |
| 2086 // effect context, to avoid having a bailout target the fictional | |
| 2087 // environment with the return value on top. | |
| 2088 if ((last != NULL && last->HasSideEffects()) || | |
| 2089 subgraph()->exit_block()->IsInlineReturnTarget()) { | |
| 2090 AddSimulate(expr->id()); | |
| 2091 } | |
| 2092 } | |
| 2093 | |
| 2094 ASSERT(environment()->total_count() == original_count); | |
| 2095 } | 2160 } |
| 2096 | 2161 |
| 2097 | 2162 |
| 2098 void HGraphBuilder::VisitForValue(Expression* expr) { | 2163 void HGraphBuilder::VisitForValue(Expression* expr) { |
| 2099 #ifdef DEBUG | 2164 ValueContext for_value(this); |
| 2100 int original_height = environment()->values()->length(); | 2165 Visit(expr); |
| 2101 #endif | |
| 2102 { ValueContext for_value(this); | |
| 2103 Visit(expr); | |
| 2104 } | |
| 2105 if (HasStackOverflow() || !subgraph()->HasExit()) return; | |
| 2106 // TODO(kasperl): Try to improve the way we compute the last added | |
| 2107 // instruction. The NULL check makes me uncomfortable. | |
| 2108 HValue* last = subgraph()->exit_block()->GetLastInstruction(); | |
| 2109 if (last != NULL && last->HasSideEffects()) { | |
| 2110 AddSimulate(expr->id()); | |
| 2111 } | |
| 2112 ASSERT(environment()->values()->length() == original_height + 1); | |
| 2113 } | 2166 } |
| 2114 | 2167 |
| 2115 | 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 |
| 2116 HValue* HGraphBuilder::VisitArgument(Expression* expr) { | 2177 HValue* HGraphBuilder::VisitArgument(Expression* expr) { |
| 2117 VisitForValue(expr); | 2178 VisitForValue(expr); |
| 2118 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; | 2179 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; |
| 2119 return environment()->Top(); | 2180 return environment()->Top(); |
| 2120 } | 2181 } |
| 2121 | 2182 |
| 2122 | 2183 |
| 2123 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { | 2184 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { |
| 2124 for (int i = 0; i < arguments->length(); i++) { | 2185 for (int i = 0; i < arguments->length(); i++) { |
| 2125 VisitArgument(arguments->at(i)); | 2186 VisitArgument(arguments->at(i)); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2195 Visit(stmt); | 2256 Visit(stmt); |
| 2196 } | 2257 } |
| 2197 | 2258 |
| 2198 | 2259 |
| 2199 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { | 2260 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, Expression* expr) { |
| 2200 SubgraphScope scope(this, graph); | 2261 SubgraphScope scope(this, graph); |
| 2201 VisitForValue(expr); | 2262 VisitForValue(expr); |
| 2202 } | 2263 } |
| 2203 | 2264 |
| 2204 | 2265 |
| 2205 void HGraphBuilder::VisitCondition(Expression* expr, | |
| 2206 HBasicBlock* true_block, | |
| 2207 HBasicBlock* false_block, | |
| 2208 bool invert_true, | |
| 2209 bool invert_false) { | |
| 2210 VisitForControl(expr, true_block, false_block, invert_true, invert_false); | |
| 2211 CHECK_BAILOUT; | |
| 2212 #ifdef DEBUG | |
| 2213 HValue* value = true_block->predecessors()->at(0)->last_environment()->Top(); | |
| 2214 true_block->set_cond(HConstant::cast(value)->handle()); | |
| 2215 | |
| 2216 value = false_block->predecessors()->at(0)->last_environment()->Top(); | |
| 2217 false_block->set_cond(HConstant::cast(value)->handle()); | |
| 2218 #endif | |
| 2219 | |
| 2220 true_block->SetJoinId(expr->id()); | |
| 2221 false_block->SetJoinId(expr->id()); | |
| 2222 true_block->last_environment()->Pop(); | |
| 2223 false_block->last_environment()->Pop(); | |
| 2224 } | |
| 2225 | |
| 2226 | |
| 2227 void HGraphBuilder::AddConditionToSubgraph(HSubgraph* subgraph, | |
| 2228 Expression* expr, | |
| 2229 HSubgraph* true_graph, | |
| 2230 HSubgraph* false_graph) { | |
| 2231 SubgraphScope scope(this, subgraph); | |
| 2232 VisitCondition(expr, | |
| 2233 true_graph->entry_block(), | |
| 2234 false_graph->entry_block(), | |
| 2235 false, | |
| 2236 false); | |
| 2237 } | |
| 2238 | |
| 2239 | |
| 2240 void HGraphBuilder::VisitForControl(Expression* expr, | |
| 2241 HBasicBlock* true_block, | |
| 2242 HBasicBlock* false_block, | |
| 2243 bool invert_true, | |
| 2244 bool invert_false) { | |
| 2245 TestContext for_test(this, true_block, false_block, | |
| 2246 invert_true, invert_false); | |
| 2247 BinaryOperation* binary_op = expr->AsBinaryOperation(); | |
| 2248 UnaryOperation* unary_op = expr->AsUnaryOperation(); | |
| 2249 | |
| 2250 if (unary_op != NULL && unary_op->op() == Token::NOT) { | |
| 2251 VisitForControl(unary_op->expression(), | |
| 2252 false_block, | |
| 2253 true_block, | |
| 2254 !invert_false, | |
| 2255 !invert_true); | |
| 2256 } else if (binary_op != NULL && binary_op->op() == Token::AND) { | |
| 2257 // Translate left subexpression. | |
| 2258 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | |
| 2259 VisitForControl(binary_op->left(), | |
| 2260 eval_right, | |
| 2261 false_block, | |
| 2262 false, | |
| 2263 invert_false); | |
| 2264 if (HasStackOverflow()) return; | |
| 2265 eval_right->SetJoinId(binary_op->left()->id()); | |
| 2266 | |
| 2267 // Translate right subexpression. | |
| 2268 eval_right->last_environment()->Pop(); | |
| 2269 subgraph()->set_exit_block(eval_right); | |
| 2270 VisitForControl(binary_op->right(), | |
| 2271 true_block, | |
| 2272 false_block, | |
| 2273 invert_true, | |
| 2274 invert_false); | |
| 2275 } else if (binary_op != NULL && binary_op->op() == Token::OR) { | |
| 2276 // Translate left subexpression. | |
| 2277 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | |
| 2278 VisitForControl(binary_op->left(), | |
| 2279 true_block, | |
| 2280 eval_right, | |
| 2281 invert_true, | |
| 2282 false); | |
| 2283 if (HasStackOverflow()) return; | |
| 2284 eval_right->SetJoinId(binary_op->left()->id()); | |
| 2285 | |
| 2286 // Translate right subexpression | |
| 2287 eval_right->last_environment()->Pop(); | |
| 2288 subgraph()->set_exit_block(eval_right); | |
| 2289 VisitForControl(binary_op->right(), | |
| 2290 true_block, | |
| 2291 false_block, | |
| 2292 invert_true, | |
| 2293 invert_false); | |
| 2294 } else { | |
| 2295 #ifdef DEBUG | |
| 2296 int original_length = environment()->values()->length(); | |
| 2297 #endif | |
| 2298 // TODO(kmillikin): Refactor to avoid. This code is duplicated from | |
| 2299 // VisitForValue, except without pushing a value context on the | |
| 2300 // expression context stack. | |
| 2301 Visit(expr); | |
| 2302 if (HasStackOverflow() || !subgraph()->HasExit()) return; | |
| 2303 HValue* last = subgraph()->exit_block()->GetLastInstruction(); | |
| 2304 if (last != NULL && last->HasSideEffects()) { | |
| 2305 AddSimulate(expr->id()); | |
| 2306 } | |
| 2307 ASSERT(environment()->values()->length() == original_length + 1); | |
| 2308 HValue* value = Pop(); | |
| 2309 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); | |
| 2310 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); | |
| 2311 CurrentBlock()->Finish(new HBranch(materialize_true, | |
| 2312 materialize_false, | |
| 2313 value)); | |
| 2314 HValue* true_value = invert_true | |
| 2315 ? graph()->GetConstantFalse() | |
| 2316 : graph()->GetConstantTrue(); | |
| 2317 materialize_true->set_inverted(invert_true); | |
| 2318 true_block->set_deopt_predecessor(materialize_true); | |
| 2319 | |
| 2320 if (true_block->IsInlineReturnTarget()) { | |
| 2321 materialize_true->AddLeaveInlined(true_value, true_block); | |
| 2322 } else { | |
| 2323 materialize_true->last_environment()->Push(true_value); | |
| 2324 materialize_true->Goto(true_block); | |
| 2325 } | |
| 2326 HValue* false_value = invert_false | |
| 2327 ? graph()->GetConstantTrue() | |
| 2328 : graph()->GetConstantFalse(); | |
| 2329 materialize_false->set_inverted(invert_false); | |
| 2330 false_block->set_deopt_predecessor(materialize_false); | |
| 2331 | |
| 2332 if (false_block->IsInlineReturnTarget()) { | |
| 2333 materialize_false->AddLeaveInlined(false_value, false_block); | |
| 2334 } else { | |
| 2335 materialize_false->last_environment()->Push(false_value); | |
| 2336 materialize_false->Goto(false_block); | |
| 2337 } | |
| 2338 subgraph()->set_exit_block(NULL); | |
| 2339 } | |
| 2340 } | |
| 2341 | |
| 2342 | |
| 2343 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, | 2266 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, |
| 2344 ZoneList<Statement*>* stmts) { | 2267 ZoneList<Statement*>* stmts) { |
| 2345 SubgraphScope scope(this, graph); | 2268 SubgraphScope scope(this, graph); |
| 2346 VisitStatements(stmts); | 2269 VisitStatements(stmts); |
| 2347 } | 2270 } |
| 2348 | 2271 |
| 2349 | 2272 |
| 2350 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { | 2273 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
| 2351 ASSERT(current_subgraph_->HasExit()); | 2274 ASSERT(current_subgraph_->HasExit()); |
| 2352 current_subgraph_->exit_block()->AddInstruction(instr); | 2275 current_subgraph_->exit_block()->AddInstruction(instr); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2365 current_subgraph_->exit_block()->AddPhi(instr); | 2288 current_subgraph_->exit_block()->AddPhi(instr); |
| 2366 } | 2289 } |
| 2367 | 2290 |
| 2368 | 2291 |
| 2369 void HGraphBuilder::PushAndAdd(HInstruction* instr) { | 2292 void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
| 2370 Push(instr); | 2293 Push(instr); |
| 2371 AddInstruction(instr); | 2294 AddInstruction(instr); |
| 2372 } | 2295 } |
| 2373 | 2296 |
| 2374 | 2297 |
| 2375 void HGraphBuilder::PushAndAdd(HInstruction* instr, int position) { | |
| 2376 instr->set_position(position); | |
| 2377 PushAndAdd(instr); | |
| 2378 } | |
| 2379 | |
| 2380 | |
| 2381 void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { | 2298 void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { |
| 2382 const int kMaxStubArguments = 4; | 2299 const int kMaxStubArguments = 4; |
| 2383 ASSERT_GE(kMaxStubArguments, argument_count); | 2300 ASSERT_GE(kMaxStubArguments, argument_count); |
| 2384 // Push the arguments on the stack. | 2301 // Push the arguments on the stack. |
| 2385 HValue* arguments[kMaxStubArguments]; | 2302 HValue* arguments[kMaxStubArguments]; |
| 2386 for (int i = argument_count - 1; i >= 0; i--) { | 2303 for (int i = argument_count - 1; i >= 0; i--) { |
| 2387 arguments[i] = Pop(); | 2304 arguments[i] = Pop(); |
| 2388 } | 2305 } |
| 2389 for (int i = 0; i < argument_count; i++) { | 2306 for (int i = 0; i < argument_count; i++) { |
| 2390 AddInstruction(new HPushArgument(arguments[i])); | 2307 AddInstruction(new HPushArgument(arguments[i])); |
| 2391 } | 2308 } |
| 2392 } | 2309 } |
| 2393 | 2310 |
| 2394 | 2311 |
| 2395 void HGraphBuilder::ProcessCall(HCall* call, int source_position) { | 2312 void HGraphBuilder::ProcessCall(HCall* call) { |
| 2396 for (int i = call->argument_count() - 1; i >= 0; --i) { | 2313 for (int i = call->argument_count() - 1; i >= 0; --i) { |
| 2397 HValue* value = Pop(); | 2314 HValue* value = Pop(); |
| 2398 HPushArgument* push = new HPushArgument(value); | 2315 HPushArgument* push = new HPushArgument(value); |
| 2399 call->SetArgumentAt(i, push); | 2316 call->SetArgumentAt(i, push); |
| 2400 } | 2317 } |
| 2401 | 2318 |
| 2402 for (int i = 0; i < call->argument_count(); ++i) { | 2319 for (int i = 0; i < call->argument_count(); ++i) { |
| 2403 AddInstruction(call->PushArgumentAt(i)); | 2320 AddInstruction(call->PushArgumentAt(i)); |
| 2404 } | 2321 } |
| 2405 | |
| 2406 PushAndAdd(call, source_position); | |
| 2407 } | 2322 } |
| 2408 | 2323 |
| 2409 | 2324 |
| 2410 void HGraphBuilder::SetupScope(Scope* scope) { | 2325 void HGraphBuilder::SetupScope(Scope* scope) { |
| 2411 // We don't yet handle the function name for named function expressions. | 2326 // We don't yet handle the function name for named function expressions. |
| 2412 if (scope->function() != NULL) BAILOUT("named function expression"); | 2327 if (scope->function() != NULL) BAILOUT("named function expression"); |
| 2413 | 2328 |
| 2414 // We can't handle heap-allocated locals. | 2329 // We can't handle heap-allocated locals. |
| 2415 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); | 2330 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); |
| 2416 | 2331 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2520 VisitForEffect(stmt->expression()); | 2435 VisitForEffect(stmt->expression()); |
| 2521 } | 2436 } |
| 2522 | 2437 |
| 2523 | 2438 |
| 2524 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { | 2439 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { |
| 2525 } | 2440 } |
| 2526 | 2441 |
| 2527 | 2442 |
| 2528 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { | 2443 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { |
| 2529 if (stmt->condition()->ToBooleanIsTrue()) { | 2444 if (stmt->condition()->ToBooleanIsTrue()) { |
| 2445 AddSimulate(stmt->ThenId()); |
| 2530 Visit(stmt->then_statement()); | 2446 Visit(stmt->then_statement()); |
| 2531 } else if (stmt->condition()->ToBooleanIsFalse()) { | 2447 } else if (stmt->condition()->ToBooleanIsFalse()) { |
| 2448 AddSimulate(stmt->ElseId()); |
| 2532 Visit(stmt->else_statement()); | 2449 Visit(stmt->else_statement()); |
| 2533 } else { | 2450 } else { |
| 2534 HSubgraph* then_graph = CreateEmptySubgraph(); | 2451 HSubgraph* then_graph = CreateEmptySubgraph(); |
| 2535 HSubgraph* else_graph = CreateEmptySubgraph(); | 2452 HSubgraph* else_graph = CreateEmptySubgraph(); |
| 2536 VisitCondition(stmt->condition(), | 2453 VISIT_FOR_CONTROL(stmt->condition(), |
| 2537 then_graph->entry_block(), | 2454 then_graph->entry_block(), |
| 2538 else_graph->entry_block(), | 2455 else_graph->entry_block()); |
| 2539 false, false); | 2456 |
| 2540 if (HasStackOverflow()) return; | 2457 then_graph->entry_block()->SetJoinId(stmt->ThenId()); |
| 2541 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()); |
| 2542 ADD_TO_SUBGRAPH(else_graph, stmt->else_statement()); | 2461 ADD_TO_SUBGRAPH(else_graph, stmt->else_statement()); |
| 2462 |
| 2543 current_subgraph_->AppendJoin(then_graph, else_graph, stmt); | 2463 current_subgraph_->AppendJoin(then_graph, else_graph, stmt); |
| 2544 } | 2464 } |
| 2545 } | 2465 } |
| 2546 | 2466 |
| 2547 | 2467 |
| 2548 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { | 2468 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
| 2549 current_subgraph_->FinishBreakContinue(stmt->target(), true); | 2469 current_subgraph_->FinishBreakContinue(stmt->target(), true); |
| 2550 } | 2470 } |
| 2551 | 2471 |
| 2552 | 2472 |
| 2553 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { | 2473 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { |
| 2554 current_subgraph_->FinishBreakContinue(stmt->target(), false); | 2474 current_subgraph_->FinishBreakContinue(stmt->target(), false); |
| 2555 } | 2475 } |
| 2556 | 2476 |
| 2557 | 2477 |
| 2558 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 2478 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
| 2559 AstContext* context = call_context(); | 2479 AstContext* context = call_context(); |
| 2560 if (context == NULL) { | 2480 if (context == NULL) { |
| 2561 // Not an inlined return, so an actual one. | 2481 // Not an inlined return, so an actual one. |
| 2562 VISIT_FOR_VALUE(stmt->expression()); | 2482 VISIT_FOR_VALUE(stmt->expression()); |
| 2563 HValue* result = environment()->Pop(); | 2483 HValue* result = environment()->Pop(); |
| 2564 subgraph()->FinishExit(new HReturn(result)); | 2484 subgraph()->FinishExit(new HReturn(result)); |
| 2565 } else { | 2485 } else { |
| 2566 // Return from an inlined function, visit the subexpression in the | 2486 // Return from an inlined function, visit the subexpression in the |
| 2567 // expression context of the call. | 2487 // expression context of the call. |
| 2568 if (context->IsTest()) { | 2488 if (context->IsTest()) { |
| 2569 TestContext* test = TestContext::cast(context); | 2489 TestContext* test = TestContext::cast(context); |
| 2570 VisitForControl(stmt->expression(), | 2490 VisitForControl(stmt->expression(), |
| 2571 test->if_true(), | 2491 test->if_true(), |
| 2572 test->if_false(), | 2492 test->if_false()); |
| 2573 false, | |
| 2574 false); | |
| 2575 } else { | 2493 } else { |
| 2576 HValue* return_value = NULL; | 2494 HValue* return_value = NULL; |
| 2577 if (context->IsEffect()) { | 2495 if (context->IsEffect()) { |
| 2578 VISIT_FOR_EFFECT(stmt->expression()); | 2496 VISIT_FOR_EFFECT(stmt->expression()); |
| 2579 return_value = graph()->GetConstantUndefined(); | 2497 return_value = graph()->GetConstantUndefined(); |
| 2580 } else { | 2498 } else { |
| 2581 ASSERT(context->IsValue()); | 2499 ASSERT(context->IsValue()); |
| 2582 VISIT_FOR_VALUE(stmt->expression()); | 2500 VISIT_FOR_VALUE(stmt->expression()); |
| 2583 return_value = environment()->Pop(); | 2501 return_value = environment()->Pop(); |
| 2584 } | 2502 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2610 clause_value, | 2528 clause_value, |
| 2611 Token::EQ_STRICT); | 2529 Token::EQ_STRICT); |
| 2612 compare->SetInputRepresentation(Representation::Integer32()); | 2530 compare->SetInputRepresentation(Representation::Integer32()); |
| 2613 subgraph->exit_block()->AddInstruction(compare); | 2531 subgraph->exit_block()->AddInstruction(compare); |
| 2614 return compare; | 2532 return compare; |
| 2615 } | 2533 } |
| 2616 | 2534 |
| 2617 | 2535 |
| 2618 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 2536 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 2619 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()); |
| 2620 HValue* switch_value = Pop(); | 2540 HValue* switch_value = Pop(); |
| 2621 | 2541 |
| 2622 ZoneList<CaseClause*>* clauses = stmt->cases(); | 2542 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 2623 int num_clauses = clauses->length(); | 2543 int num_clauses = clauses->length(); |
| 2624 if (num_clauses == 0) return; | 2544 if (num_clauses == 0) return; |
| 2625 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); | 2545 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses"); |
| 2626 | 2546 |
| 2547 int num_smi_clauses = num_clauses; |
| 2627 for (int i = 0; i < num_clauses; i++) { | 2548 for (int i = 0; i < num_clauses; i++) { |
| 2628 CaseClause* clause = clauses->at(i); | 2549 CaseClause* clause = clauses->at(i); |
| 2629 if (clause->is_default()) continue; | 2550 if (clause->is_default()) continue; |
| 2630 clause->RecordTypeFeedback(oracle()); | 2551 clause->RecordTypeFeedback(oracle()); |
| 2631 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 } |
| 2632 if (!clause->label()->IsSmiLiteral()) { | 2558 if (!clause->label()->IsSmiLiteral()) { |
| 2633 BAILOUT("SwitchStatement: non-literal switch label"); | 2559 BAILOUT("SwitchStatement: non-literal switch label"); |
| 2634 } | 2560 } |
| 2635 } | 2561 } |
| 2636 | 2562 |
| 2637 // The single exit block of the whole switch statement. | 2563 // The single exit block of the whole switch statement. |
| 2638 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); | 2564 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); |
| 2639 | 2565 |
| 2640 // Build a series of empty subgraphs for the comparisons. | 2566 // Build a series of empty subgraphs for the comparisons. |
| 2641 // The default clause does not have a comparison subgraph. | 2567 // The default clause does not have a comparison subgraph. |
| 2642 ZoneList<HSubgraph*> compare_graphs(num_clauses); | 2568 ZoneList<HSubgraph*> compare_graphs(num_smi_clauses); |
| 2643 for (int i = 0; i < num_clauses; i++) { | 2569 for (int i = 0; i < num_smi_clauses; i++) { |
| 2644 HSubgraph* subgraph = !clauses->at(i)->is_default() | 2570 if (clauses->at(i)->is_default()) { |
| 2645 ? CreateEmptySubgraph() | 2571 compare_graphs.Add(NULL); |
| 2646 : NULL; | 2572 } else { |
| 2647 compare_graphs.Add(subgraph); | 2573 compare_graphs.Add(CreateEmptySubgraph()); |
| 2574 } |
| 2648 } | 2575 } |
| 2649 | 2576 |
| 2650 HSubgraph* prev_graph = current_subgraph_; | 2577 HSubgraph* prev_graph = current_subgraph_; |
| 2651 HCompare* prev_compare_inst = NULL; | 2578 HCompare* prev_compare_inst = NULL; |
| 2652 for (int i = 0; i < num_clauses; i++) { | 2579 for (int i = 0; i < num_smi_clauses; i++) { |
| 2653 CaseClause* clause = clauses->at(i); | 2580 CaseClause* clause = clauses->at(i); |
| 2654 if (clause->is_default()) continue; | 2581 if (clause->is_default()) continue; |
| 2655 | 2582 |
| 2656 // Finish the previous graph by connecting it to the current. | 2583 // Finish the previous graph by connecting it to the current. |
| 2657 HSubgraph* subgraph = compare_graphs.at(i); | 2584 HSubgraph* subgraph = compare_graphs.at(i); |
| 2658 if (prev_compare_inst == NULL) { | 2585 if (prev_compare_inst == NULL) { |
| 2659 ASSERT(prev_graph == current_subgraph_); | 2586 ASSERT(prev_graph == current_subgraph_); |
| 2660 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); | 2587 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block())); |
| 2661 } else { | 2588 } else { |
| 2662 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2589 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2663 prev_graph->exit_block()->Finish(new HBranch(empty, | 2590 prev_graph->exit_block()->Finish(new HBranch(empty, |
| 2664 subgraph->entry_block(), | 2591 subgraph->entry_block(), |
| 2665 prev_compare_inst)); | 2592 prev_compare_inst)); |
| 2666 } | 2593 } |
| 2667 | 2594 |
| 2668 // Build instructions for current subgraph. | 2595 // Build instructions for current subgraph. |
| 2596 ASSERT(clause->IsSmiCompare()); |
| 2669 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); | 2597 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause); |
| 2670 if (HasStackOverflow()) return; | 2598 if (HasStackOverflow()) return; |
| 2671 | 2599 |
| 2672 prev_graph = subgraph; | 2600 prev_graph = subgraph; |
| 2673 } | 2601 } |
| 2674 | 2602 |
| 2675 // Finish last comparison if there was at least one comparison. | 2603 // Finish last comparison if there was at least one comparison. |
| 2676 // 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 |
| 2677 // 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 |
| 2678 // the last block of the current subgraph. | 2606 // the last block of the current subgraph. |
| 2679 HBasicBlock* last_false_block = current_subgraph_->exit_block(); | 2607 HBasicBlock* last_false_block = current_subgraph_->exit_block(); |
| 2680 if (prev_graph != current_subgraph_) { | 2608 if (prev_graph != current_subgraph_) { |
| 2681 last_false_block = graph()->CreateBasicBlock(); | 2609 last_false_block = graph()->CreateBasicBlock(); |
| 2682 HBasicBlock* empty = graph()->CreateBasicBlock(); | 2610 HBasicBlock* empty = graph()->CreateBasicBlock(); |
| 2683 prev_graph->exit_block()->Finish(new HBranch(empty, | 2611 prev_graph->exit_block()->Finish(new HBranch(empty, |
| 2684 last_false_block, | 2612 last_false_block, |
| 2685 prev_compare_inst)); | 2613 prev_compare_inst)); |
| 2686 } | 2614 } |
| 2687 | 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 |
| 2688 // Build statement blocks, connect them to their comparison block and | 2622 // Build statement blocks, connect them to their comparison block and |
| 2689 // to the previous statement block, if there is a fall-through. | 2623 // to the previous statement block, if there is a fall-through. |
| 2690 HSubgraph* previous_subgraph = NULL; | 2624 HSubgraph* previous_subgraph = NULL; |
| 2691 for (int i = 0; i < num_clauses; i++) { | 2625 for (int i = 0; i < num_clauses; i++) { |
| 2692 CaseClause* clause = clauses->at(i); | 2626 CaseClause* clause = clauses->at(i); |
| 2693 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; |
| 2694 | 2631 |
| 2695 if (clause->is_default()) { | 2632 if (i < num_smi_clauses) { |
| 2696 // Default clause: Connect it to the last false block. | 2633 if (clause->is_default()) { |
| 2697 last_false_block->Finish(new HGoto(subgraph->entry_block())); | 2634 if (!last_false_block->IsFinished()) { |
| 2698 } else { | 2635 // Default clause: Connect it to the last false block. |
| 2699 // Connect with the corresponding comparison. | 2636 subgraph = CreateEmptySubgraph(); |
| 2700 HBasicBlock* empty = | 2637 last_false_block->Finish(new HGoto(subgraph->entry_block())); |
| 2701 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor(); | 2638 } |
| 2702 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 } |
| 2703 } | 2647 } |
| 2704 | 2648 |
| 2705 // Check for fall-through from previous statement block. | 2649 // Check for fall-through from previous statement block. |
| 2706 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { | 2650 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { |
| 2651 if (subgraph == NULL) subgraph = CreateEmptySubgraph(); |
| 2707 previous_subgraph->exit_block()-> | 2652 previous_subgraph->exit_block()-> |
| 2708 Finish(new HGoto(subgraph->entry_block())); | 2653 Finish(new HGoto(subgraph->entry_block())); |
| 2709 } | 2654 } |
| 2710 | 2655 |
| 2711 ADD_TO_SUBGRAPH(subgraph, clause->statements()); | 2656 if (subgraph != NULL) { |
| 2712 HBasicBlock* break_block = subgraph->BundleBreak(stmt); | 2657 ADD_TO_SUBGRAPH(subgraph, clause->statements()); |
| 2713 if (break_block != NULL) { | 2658 HBasicBlock* break_block = subgraph->BundleBreak(stmt); |
| 2714 break_block->Finish(new HGoto(single_exit_block)); | 2659 if (break_block != NULL) { |
| 2660 break_block->Finish(new HGoto(single_exit_block)); |
| 2661 } |
| 2715 } | 2662 } |
| 2716 | 2663 |
| 2717 previous_subgraph = subgraph; | 2664 previous_subgraph = subgraph; |
| 2718 } | 2665 } |
| 2719 | 2666 |
| 2720 // 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 |
| 2721 // single exit block. | 2668 // single exit block. |
| 2722 if (previous_subgraph->HasExit()) { | 2669 if (previous_subgraph != NULL && previous_subgraph->HasExit()) { |
| 2723 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); | 2670 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block)); |
| 2724 } | 2671 } |
| 2725 | 2672 |
| 2726 // 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. |
| 2727 if (!last_false_block->IsFinished()) { | 2674 if (!last_false_block->IsFinished()) { |
| 2728 last_false_block->Finish(new HGoto(single_exit_block)); | 2675 last_false_block->Finish(new HGoto(single_exit_block)); |
| 2729 } | 2676 } |
| 2730 | 2677 |
| 2731 if (single_exit_block->HasPredecessor()) { | 2678 if (single_exit_block->HasPredecessor()) { |
| 2732 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... |
| 2778 | 2725 |
| 2779 HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment()); | 2726 HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment()); |
| 2780 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2727 ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
| 2781 body_graph->ResolveContinue(stmt); | 2728 body_graph->ResolveContinue(stmt); |
| 2782 | 2729 |
| 2783 if (!body_graph->HasExit() || stmt->cond()->ToBooleanIsTrue()) { | 2730 if (!body_graph->HasExit() || stmt->cond()->ToBooleanIsTrue()) { |
| 2784 current_subgraph_->AppendEndless(body_graph, stmt); | 2731 current_subgraph_->AppendEndless(body_graph, stmt); |
| 2785 } else { | 2732 } else { |
| 2786 HSubgraph* go_back = CreateEmptySubgraph(); | 2733 HSubgraph* go_back = CreateEmptySubgraph(); |
| 2787 HSubgraph* exit = CreateEmptySubgraph(); | 2734 HSubgraph* exit = CreateEmptySubgraph(); |
| 2788 AddConditionToSubgraph(body_graph, stmt->cond(), go_back, exit); | 2735 { |
| 2789 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 } |
| 2790 current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit); | 2743 current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit); |
| 2791 } | 2744 } |
| 2792 } | 2745 } |
| 2793 | 2746 |
| 2794 | 2747 |
| 2795 bool HGraphBuilder::ShouldPeel(HSubgraph* cond, HSubgraph* body) { | 2748 bool HGraphBuilder::ShouldPeel(HSubgraph* cond, HSubgraph* body) { |
| 2796 return FLAG_use_peeling; | 2749 return FLAG_use_peeling; |
| 2797 } | 2750 } |
| 2798 | 2751 |
| 2799 | 2752 |
| 2800 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { | 2753 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { |
| 2801 ASSERT(subgraph()->HasExit()); | 2754 ASSERT(subgraph()->HasExit()); |
| 2802 subgraph()->PreProcessOsrEntry(stmt); | 2755 subgraph()->PreProcessOsrEntry(stmt); |
| 2803 | 2756 |
| 2804 HSubgraph* cond_graph = NULL; | 2757 HSubgraph* cond_graph = NULL; |
| 2805 HSubgraph* body_graph = NULL; | 2758 HSubgraph* body_graph = NULL; |
| 2806 HSubgraph* exit_graph = NULL; | 2759 HSubgraph* exit_graph = NULL; |
| 2807 | 2760 |
| 2808 // 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. |
| 2809 if (stmt->cond()->ToBooleanIsTrue()) { | 2762 if (stmt->cond()->ToBooleanIsTrue()) { |
| 2810 body_graph = CreateLoopHeaderSubgraph(environment()); | 2763 body_graph = CreateLoopHeaderSubgraph(environment()); |
| 2811 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2764 ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
| 2812 } else { | 2765 } else { |
| 2813 cond_graph = CreateLoopHeaderSubgraph(environment()); | 2766 cond_graph = CreateLoopHeaderSubgraph(environment()); |
| 2814 body_graph = CreateEmptySubgraph(); | 2767 body_graph = CreateEmptySubgraph(); |
| 2815 exit_graph = CreateEmptySubgraph(); | 2768 exit_graph = CreateEmptySubgraph(); |
| 2816 AddConditionToSubgraph(cond_graph, stmt->cond(), body_graph, exit_graph); | 2769 { |
| 2817 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 } |
| 2818 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | 2777 ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
| 2819 } | 2778 } |
| 2820 | 2779 |
| 2821 body_graph->ResolveContinue(stmt); | 2780 body_graph->ResolveContinue(stmt); |
| 2822 | 2781 |
| 2823 if (cond_graph != NULL) { | 2782 if (cond_graph != NULL) { |
| 2824 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph); | 2783 AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph); |
| 2825 } else { | 2784 } else { |
| 2826 // TODO(fschneider): Implement peeling for endless loops as well. | 2785 // TODO(fschneider): Implement peeling for endless loops as well. |
| 2827 current_subgraph_->AppendEndless(body_graph, stmt); | 2786 current_subgraph_->AppendEndless(body_graph, stmt); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2857 ASSERT(subgraph()->HasExit()); | 2816 ASSERT(subgraph()->HasExit()); |
| 2858 subgraph()->PreProcessOsrEntry(stmt); | 2817 subgraph()->PreProcessOsrEntry(stmt); |
| 2859 | 2818 |
| 2860 HSubgraph* cond_graph = NULL; | 2819 HSubgraph* cond_graph = NULL; |
| 2861 HSubgraph* body_graph = NULL; | 2820 HSubgraph* body_graph = NULL; |
| 2862 HSubgraph* exit_graph = NULL; | 2821 HSubgraph* exit_graph = NULL; |
| 2863 if (stmt->cond() != NULL) { | 2822 if (stmt->cond() != NULL) { |
| 2864 cond_graph = CreateLoopHeaderSubgraph(environment()); | 2823 cond_graph = CreateLoopHeaderSubgraph(environment()); |
| 2865 body_graph = CreateEmptySubgraph(); | 2824 body_graph = CreateEmptySubgraph(); |
| 2866 exit_graph = CreateEmptySubgraph(); | 2825 exit_graph = CreateEmptySubgraph(); |
| 2867 AddConditionToSubgraph(cond_graph, stmt->cond(), body_graph, exit_graph); | 2826 { |
| 2868 if (HasStackOverflow()) return; | 2827 SubgraphScope scope(this, cond_graph); |
| 2869 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 } |
| 2870 } else { | 2834 } else { |
| 2871 body_graph = CreateLoopHeaderSubgraph(environment()); | 2835 body_graph = CreateLoopHeaderSubgraph(environment()); |
| 2872 ADD_TO_SUBGRAPH(body_graph, stmt->body()); | |
| 2873 } | 2836 } |
| 2837 ADD_TO_SUBGRAPH(body_graph, stmt->body()); |
| 2874 | 2838 |
| 2875 HSubgraph* next_graph = NULL; | 2839 HSubgraph* next_graph = NULL; |
| 2876 body_graph->ResolveContinue(stmt); | 2840 body_graph->ResolveContinue(stmt); |
| 2877 | 2841 |
| 2878 if (stmt->next() != NULL && body_graph->HasExit()) { | 2842 if (stmt->next() != NULL && body_graph->HasExit()) { |
| 2879 next_graph = CreateGotoSubgraph(body_graph->environment()); | 2843 next_graph = CreateGotoSubgraph(body_graph->environment()); |
| 2880 ADD_TO_SUBGRAPH(next_graph, stmt->next()); | 2844 ADD_TO_SUBGRAPH(next_graph, stmt->next()); |
| 2881 body_graph->Append(next_graph, NULL); | 2845 body_graph->Append(next_graph, NULL); |
| 2882 next_graph->entry_block()->SetJoinId(stmt->ContinueId()); | 2846 next_graph->entry_block()->SetJoinId(stmt->ContinueId()); |
| 2883 } | 2847 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2907 | 2871 |
| 2908 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | 2872 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 2909 BAILOUT("DebuggerStatement"); | 2873 BAILOUT("DebuggerStatement"); |
| 2910 } | 2874 } |
| 2911 | 2875 |
| 2912 | 2876 |
| 2913 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { | 2877 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 2914 Handle<SharedFunctionInfo> shared_info = | 2878 Handle<SharedFunctionInfo> shared_info = |
| 2915 Compiler::BuildFunctionInfo(expr, graph_->info()->script()); | 2879 Compiler::BuildFunctionInfo(expr, graph_->info()->script()); |
| 2916 CHECK_BAILOUT; | 2880 CHECK_BAILOUT; |
| 2917 PushAndAdd(new HFunctionLiteral(shared_info, expr->pretenure())); | 2881 HFunctionLiteral* instr = |
| 2882 new HFunctionLiteral(shared_info, expr->pretenure()); |
| 2883 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2918 } | 2884 } |
| 2919 | 2885 |
| 2920 | 2886 |
| 2921 void HGraphBuilder::VisitSharedFunctionInfoLiteral( | 2887 void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
| 2922 SharedFunctionInfoLiteral* expr) { | 2888 SharedFunctionInfoLiteral* expr) { |
| 2923 BAILOUT("SharedFunctionInfoLiteral"); | 2889 BAILOUT("SharedFunctionInfoLiteral"); |
| 2924 } | 2890 } |
| 2925 | 2891 |
| 2926 | 2892 |
| 2927 void HGraphBuilder::VisitConditional(Conditional* expr) { | 2893 void HGraphBuilder::VisitConditional(Conditional* expr) { |
| 2928 HSubgraph* then_graph = CreateEmptySubgraph(); | 2894 HSubgraph* then_graph = CreateEmptySubgraph(); |
| 2929 HSubgraph* else_graph = CreateEmptySubgraph(); | 2895 HSubgraph* else_graph = CreateEmptySubgraph(); |
| 2930 VisitCondition(expr->condition(), | 2896 VISIT_FOR_CONTROL(expr->condition(), |
| 2931 then_graph->entry_block(), | 2897 then_graph->entry_block(), |
| 2932 else_graph->entry_block(), | 2898 else_graph->entry_block()); |
| 2933 false, false); | 2899 |
| 2934 if (HasStackOverflow()) return; | 2900 then_graph->entry_block()->SetJoinId(expr->ThenId()); |
| 2935 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()); |
| 2936 ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); | 2904 ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); |
| 2905 |
| 2937 current_subgraph_->AppendJoin(then_graph, else_graph, expr); | 2906 current_subgraph_->AppendJoin(then_graph, else_graph, expr); |
| 2907 ast_context()->ReturnValue(Pop()); |
| 2938 } | 2908 } |
| 2939 | 2909 |
| 2940 | 2910 |
| 2941 void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr, | 2911 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
| 2942 LookupResult* lookup, | 2912 LookupResult* lookup, |
| 2943 bool is_store) { | 2913 bool is_store) { |
| 2944 if (expr->is_this()) { | 2914 if (var->is_this()) { |
| 2945 BAILOUT("global this reference"); | 2915 BAILOUT("global this reference"); |
| 2946 } | 2916 } |
| 2947 if (!graph()->info()->has_global_object()) { | 2917 if (!graph()->info()->has_global_object()) { |
| 2948 BAILOUT("no global object to optimize VariableProxy"); | 2918 BAILOUT("no global object to optimize VariableProxy"); |
| 2949 } | 2919 } |
| 2950 Handle<GlobalObject> global(graph()->info()->global_object()); | 2920 Handle<GlobalObject> global(graph()->info()->global_object()); |
| 2951 global->Lookup(*expr->name(), lookup); | 2921 global->Lookup(*var->name(), lookup); |
| 2952 if (!lookup->IsProperty()) { | 2922 if (!lookup->IsProperty()) { |
| 2953 BAILOUT("global variable cell not yet introduced"); | 2923 BAILOUT("global variable cell not yet introduced"); |
| 2954 } | 2924 } |
| 2955 if (lookup->type() != NORMAL) { | 2925 if (lookup->type() != NORMAL) { |
| 2956 BAILOUT("global variable has accessors"); | 2926 BAILOUT("global variable has accessors"); |
| 2957 } | 2927 } |
| 2958 if (is_store && lookup->IsReadOnly()) { | 2928 if (is_store && lookup->IsReadOnly()) { |
| 2959 BAILOUT("read-only global variable"); | 2929 BAILOUT("read-only global variable"); |
| 2960 } | 2930 } |
| 2961 } | 2931 } |
| 2962 | 2932 |
| 2963 | 2933 |
| 2964 void HGraphBuilder::HandleGlobalVariableLoad(VariableProxy* expr) { | |
| 2965 LookupResult lookup; | |
| 2966 LookupGlobalPropertyCell(expr, &lookup, false); | |
| 2967 CHECK_BAILOUT; | |
| 2968 | |
| 2969 Handle<GlobalObject> global(graph()->info()->global_object()); | |
| 2970 // TODO(3039103): Handle global property load through an IC call when access | |
| 2971 // checks are enabled. | |
| 2972 if (global->IsAccessCheckNeeded()) { | |
| 2973 BAILOUT("global object requires access check"); | |
| 2974 } | |
| 2975 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | |
| 2976 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | |
| 2977 PushAndAdd(new HLoadGlobal(cell, check_hole)); | |
| 2978 } | |
| 2979 | |
| 2980 | |
| 2981 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 2934 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2982 Variable* variable = expr->AsVariable(); | 2935 Variable* variable = expr->AsVariable(); |
| 2983 if (variable == NULL) { | 2936 if (variable == NULL) { |
| 2984 BAILOUT("reference to rewritten variable"); | 2937 BAILOUT("reference to rewritten variable"); |
| 2985 } else if (variable->IsStackAllocated()) { | 2938 } else if (variable->IsStackAllocated()) { |
| 2986 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { | 2939 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { |
| 2987 BAILOUT("unsupported context for arguments object"); | 2940 BAILOUT("unsupported context for arguments object"); |
| 2988 } | 2941 } |
| 2989 Push(environment()->Lookup(variable)); | 2942 ast_context()->ReturnValue(environment()->Lookup(variable)); |
| 2990 } else if (variable->is_global()) { | 2943 } else if (variable->is_global()) { |
| 2991 HandleGlobalVariableLoad(expr); | 2944 LookupResult lookup; |
| 2945 LookupGlobalPropertyCell(variable, &lookup, false); |
| 2946 CHECK_BAILOUT; |
| 2947 |
| 2948 Handle<GlobalObject> global(graph()->info()->global_object()); |
| 2949 // TODO(3039103): Handle global property load through an IC call when access |
| 2950 // checks are enabled. |
| 2951 if (global->IsAccessCheckNeeded()) { |
| 2952 BAILOUT("global object requires access check"); |
| 2953 } |
| 2954 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 2955 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); |
| 2956 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); |
| 2957 ast_context()->ReturnInstruction(instr, expr->id()); |
| 2992 } else { | 2958 } else { |
| 2993 BAILOUT("reference to non-stack-allocated/non-global variable"); | 2959 BAILOUT("reference to non-stack-allocated/non-global variable"); |
| 2994 } | 2960 } |
| 2995 } | 2961 } |
| 2996 | 2962 |
| 2997 | 2963 |
| 2998 void HGraphBuilder::VisitLiteral(Literal* expr) { | 2964 void HGraphBuilder::VisitLiteral(Literal* expr) { |
| 2999 PushAndAdd(new HConstant(expr->handle(), Representation::Tagged())); | 2965 HConstant* instr = new HConstant(expr->handle(), Representation::Tagged()); |
| 2966 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3000 } | 2967 } |
| 3001 | 2968 |
| 3002 | 2969 |
| 3003 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { | 2970 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 3004 PushAndAdd(new HRegExpLiteral(expr->pattern(), | 2971 HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(), |
| 3005 expr->flags(), | 2972 expr->flags(), |
| 3006 expr->literal_index())); | 2973 expr->literal_index()); |
| 2974 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3007 } | 2975 } |
| 3008 | 2976 |
| 3009 | 2977 |
| 3010 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | 2978 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 3011 HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(), | 2979 HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(), |
| 3012 expr->fast_elements(), | 2980 expr->fast_elements(), |
| 3013 expr->literal_index(), | 2981 expr->literal_index(), |
| 3014 expr->depth())); | 2982 expr->depth())); |
| 2983 // The object is expected in the bailout environment during computation |
| 2984 // of the property values and is the value of the entire expression. |
| 3015 PushAndAdd(literal); | 2985 PushAndAdd(literal); |
| 3016 | 2986 |
| 3017 expr->CalculateEmitStore(); | 2987 expr->CalculateEmitStore(); |
| 3018 | 2988 |
| 3019 for (int i = 0; i < expr->properties()->length(); i++) { | 2989 for (int i = 0; i < expr->properties()->length(); i++) { |
| 3020 ObjectLiteral::Property* property = expr->properties()->at(i); | 2990 ObjectLiteral::Property* property = expr->properties()->at(i); |
| 3021 if (property->IsCompileTimeValue()) continue; | 2991 if (property->IsCompileTimeValue()) continue; |
| 3022 | 2992 |
| 3023 Literal* key = property->key(); | 2993 Literal* key = property->key(); |
| 3024 Expression* value = property->value(); | 2994 Expression* value = property->value(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3041 break; | 3011 break; |
| 3042 } | 3012 } |
| 3043 // Fall through. | 3013 // Fall through. |
| 3044 case ObjectLiteral::Property::PROTOTYPE: | 3014 case ObjectLiteral::Property::PROTOTYPE: |
| 3045 case ObjectLiteral::Property::SETTER: | 3015 case ObjectLiteral::Property::SETTER: |
| 3046 case ObjectLiteral::Property::GETTER: | 3016 case ObjectLiteral::Property::GETTER: |
| 3047 BAILOUT("Object literal with complex property"); | 3017 BAILOUT("Object literal with complex property"); |
| 3048 default: UNREACHABLE(); | 3018 default: UNREACHABLE(); |
| 3049 } | 3019 } |
| 3050 } | 3020 } |
| 3021 ast_context()->ReturnValue(Pop()); |
| 3051 } | 3022 } |
| 3052 | 3023 |
| 3053 | 3024 |
| 3054 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { | 3025 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
| 3055 ZoneList<Expression*>* subexprs = expr->values(); | 3026 ZoneList<Expression*>* subexprs = expr->values(); |
| 3056 int length = subexprs->length(); | 3027 int length = subexprs->length(); |
| 3057 | 3028 |
| 3058 HArrayLiteral* literal = new HArrayLiteral(expr->constant_elements(), | 3029 HArrayLiteral* literal = new HArrayLiteral(expr->constant_elements(), |
| 3059 length, | 3030 length, |
| 3060 expr->literal_index(), | 3031 expr->literal_index(), |
| 3061 expr->depth()); | 3032 expr->depth()); |
| 3033 // The array is expected in the bailout environment during computation |
| 3034 // of the property values and is the value of the entire expression. |
| 3062 PushAndAdd(literal); | 3035 PushAndAdd(literal); |
| 3063 HValue* elements = AddInstruction(new HLoadElements(literal)); | 3036 |
| 3037 HLoadElements* elements = NULL; |
| 3064 | 3038 |
| 3065 for (int i = 0; i < length; i++) { | 3039 for (int i = 0; i < length; i++) { |
| 3066 Expression* subexpr = subexprs->at(i); | 3040 Expression* subexpr = subexprs->at(i); |
| 3067 // 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 |
| 3068 // is already set in the cloned array. | 3042 // is already set in the cloned array. |
| 3069 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 3043 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
| 3070 | 3044 |
| 3071 VISIT_FOR_VALUE(subexpr); | 3045 VISIT_FOR_VALUE(subexpr); |
| 3072 HValue* value = Pop(); | 3046 HValue* value = Pop(); |
| 3073 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 |
| 3074 HValue* key = AddInstruction(new HConstant(Handle<Object>(Smi::FromInt(i)), | 3055 HValue* key = AddInstruction(new HConstant(Handle<Object>(Smi::FromInt(i)), |
| 3075 Representation::Integer32())); | 3056 Representation::Integer32())); |
| 3076 AddInstruction(new HStoreKeyedFastElement(elements, key, value)); | 3057 AddInstruction(new HStoreKeyedFastElement(elements, key, value)); |
| 3077 AddSimulate(expr->GetIdForElement(i)); | 3058 AddSimulate(expr->GetIdForElement(i)); |
| 3078 } | 3059 } |
| 3060 ast_context()->ReturnValue(Pop()); |
| 3079 } | 3061 } |
| 3080 | 3062 |
| 3081 | 3063 |
| 3082 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 3064 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 3083 BAILOUT("CatchExtensionObject"); | 3065 BAILOUT("CatchExtensionObject"); |
| 3084 } | 3066 } |
| 3085 | 3067 |
| 3086 | 3068 |
| 3087 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, | 3069 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, |
| 3088 ZoneList<HSubgraph*>* subgraphs, | 3070 ZoneList<HSubgraph*>* subgraphs, |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3176 // from the end of the fixed part of the object. | 3158 // from the end of the fixed part of the object. |
| 3177 offset += type->instance_size(); | 3159 offset += type->instance_size(); |
| 3178 } else { | 3160 } else { |
| 3179 offset += FixedArray::kHeaderSize; | 3161 offset += FixedArray::kHeaderSize; |
| 3180 } | 3162 } |
| 3181 HStoreNamedField* instr = | 3163 HStoreNamedField* instr = |
| 3182 new HStoreNamedField(object, name, value, is_in_object, offset); | 3164 new HStoreNamedField(object, name, value, is_in_object, offset); |
| 3183 if (lookup->type() == MAP_TRANSITION) { | 3165 if (lookup->type() == MAP_TRANSITION) { |
| 3184 Handle<Map> transition(lookup->GetTransitionMapFromMap(*type)); | 3166 Handle<Map> transition(lookup->GetTransitionMapFromMap(*type)); |
| 3185 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); |
| 3186 } | 3171 } |
| 3187 return instr; | 3172 return instr; |
| 3188 } | 3173 } |
| 3189 | 3174 |
| 3190 | 3175 |
| 3191 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, | 3176 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, |
| 3192 Handle<String> name, | 3177 Handle<String> name, |
| 3193 HValue* value) { | 3178 HValue* value) { |
| 3194 return new HStoreNamedGeneric(object, name, value); | 3179 return new HStoreNamedGeneric(object, name, value); |
| 3195 } | 3180 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3250 } | 3235 } |
| 3251 } | 3236 } |
| 3252 | 3237 |
| 3253 // If none of the properties were named fields we generate a | 3238 // If none of the properties were named fields we generate a |
| 3254 // generic store. | 3239 // generic store. |
| 3255 if (maps.length() == 0) { | 3240 if (maps.length() == 0) { |
| 3256 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3241 HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
| 3257 Push(value); | 3242 Push(value); |
| 3258 instr->set_position(expr->position()); | 3243 instr->set_position(expr->position()); |
| 3259 AddInstruction(instr); | 3244 AddInstruction(instr); |
| 3260 return; | 3245 if (instr->HasSideEffects()) AddSimulate(expr->id()); |
| 3246 } else { |
| 3247 // Build subgraph for generic store through IC. |
| 3248 { |
| 3249 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3250 SubgraphScope scope(this, subgraph); |
| 3251 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3252 subgraph->FinishExit(new HDeoptimize()); |
| 3253 } else { |
| 3254 HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
| 3255 Push(value); |
| 3256 instr->set_position(expr->position()); |
| 3257 AddInstruction(instr); |
| 3258 } |
| 3259 subgraphs.Add(subgraph); |
| 3260 } |
| 3261 |
| 3262 HBasicBlock* new_exit_block = |
| 3263 BuildTypeSwitch(&maps, &subgraphs, object, expr->AssignmentId()); |
| 3264 subgraph()->set_exit_block(new_exit_block); |
| 3261 } | 3265 } |
| 3262 | 3266 |
| 3263 // Build subgraph for generic store through IC. | 3267 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
| 3264 { | |
| 3265 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | |
| 3266 SubgraphScope scope(this, subgraph); | |
| 3267 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3268 subgraph->FinishExit(new HDeoptimize()); | |
| 3269 } else { | |
| 3270 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | |
| 3271 Push(value); | |
| 3272 instr->set_position(expr->position()); | |
| 3273 AddInstruction(instr); | |
| 3274 } | |
| 3275 subgraphs.Add(subgraph); | |
| 3276 } | |
| 3277 | |
| 3278 HBasicBlock* new_exit_block = | |
| 3279 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | |
| 3280 current_subgraph_->set_exit_block(new_exit_block); | |
| 3281 } | 3268 } |
| 3282 | 3269 |
| 3283 | 3270 |
| 3284 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3271 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3285 Property* prop = expr->target()->AsProperty(); | 3272 Property* prop = expr->target()->AsProperty(); |
| 3286 ASSERT(prop != NULL); | 3273 ASSERT(prop != NULL); |
| 3287 expr->RecordTypeFeedback(oracle()); | 3274 expr->RecordTypeFeedback(oracle()); |
| 3288 VISIT_FOR_VALUE(prop->obj()); | 3275 VISIT_FOR_VALUE(prop->obj()); |
| 3289 | 3276 |
| 3290 HValue* value = NULL; | 3277 HValue* value = NULL; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3326 expr->GetMonomorphicReceiverType()->has_fast_elements(); | 3313 expr->GetMonomorphicReceiverType()->has_fast_elements(); |
| 3327 | 3314 |
| 3328 instr = is_fast_elements | 3315 instr = is_fast_elements |
| 3329 ? BuildStoreKeyedFastElement(object, key, value, expr) | 3316 ? BuildStoreKeyedFastElement(object, key, value, expr) |
| 3330 : BuildStoreKeyedGeneric(object, key, value); | 3317 : BuildStoreKeyedGeneric(object, key, value); |
| 3331 } | 3318 } |
| 3332 | 3319 |
| 3333 Push(value); | 3320 Push(value); |
| 3334 instr->set_position(expr->position()); | 3321 instr->set_position(expr->position()); |
| 3335 AddInstruction(instr); | 3322 AddInstruction(instr); |
| 3323 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3324 ast_context()->ReturnValue(Pop()); |
| 3336 } | 3325 } |
| 3337 | 3326 |
| 3338 | 3327 |
| 3339 void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy, | 3328 // Because not every expression has a position and there is not common |
| 3329 // superclass of Assignment and CountOperation, we cannot just pass the |
| 3330 // owning expression instead of position and ast_id separately. |
| 3331 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
| 3340 HValue* value, | 3332 HValue* value, |
| 3341 int position) { | 3333 int position, |
| 3334 int ast_id) { |
| 3342 LookupResult lookup; | 3335 LookupResult lookup; |
| 3343 LookupGlobalPropertyCell(proxy, &lookup, true); | 3336 LookupGlobalPropertyCell(var, &lookup, true); |
| 3344 CHECK_BAILOUT; | 3337 CHECK_BAILOUT; |
| 3345 | 3338 |
| 3346 Handle<GlobalObject> global(graph()->info()->global_object()); | 3339 Handle<GlobalObject> global(graph()->info()->global_object()); |
| 3347 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3340 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3348 HInstruction* instr = new HStoreGlobal(value, cell); | 3341 HInstruction* instr = new HStoreGlobal(value, cell); |
| 3349 instr->set_position(position); | 3342 instr->set_position(position); |
| 3350 AddInstruction(instr); | 3343 AddInstruction(instr); |
| 3344 if (instr->HasSideEffects()) AddSimulate(ast_id); |
| 3351 } | 3345 } |
| 3352 | 3346 |
| 3353 | 3347 |
| 3354 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3348 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
| 3355 Expression* target = expr->target(); | 3349 Expression* target = expr->target(); |
| 3356 VariableProxy* proxy = target->AsVariableProxy(); | 3350 VariableProxy* proxy = target->AsVariableProxy(); |
| 3357 Variable* var = proxy->AsVariable(); | 3351 Variable* var = proxy->AsVariable(); |
| 3358 Property* prop = target->AsProperty(); | 3352 Property* prop = target->AsProperty(); |
| 3359 ASSERT(var == NULL || prop == NULL); | 3353 ASSERT(var == NULL || prop == NULL); |
| 3360 | 3354 |
| 3361 // We have a second position recorded in the FullCodeGenerator to have | 3355 // We have a second position recorded in the FullCodeGenerator to have |
| 3362 // type feedback for the binary operation. | 3356 // type feedback for the binary operation. |
| 3363 BinaryOperation* operation = expr->binary_operation(); | 3357 BinaryOperation* operation = expr->binary_operation(); |
| 3364 operation->RecordTypeFeedback(oracle()); | 3358 operation->RecordTypeFeedback(oracle()); |
| 3365 | 3359 |
| 3366 if (var != NULL) { | 3360 if (var != NULL) { |
| 3367 if (!var->is_global() && !var->IsStackAllocated()) { | 3361 if (!var->is_global() && !var->IsStackAllocated()) { |
| 3368 BAILOUT("non-stack/non-global in compound assignment"); | 3362 BAILOUT("non-stack/non-global in compound assignment"); |
| 3369 } | 3363 } |
| 3370 | 3364 |
| 3371 VISIT_FOR_VALUE(operation); | 3365 VISIT_FOR_VALUE(operation); |
| 3372 | 3366 |
| 3373 if (var->is_global()) { | 3367 if (var->is_global()) { |
| 3374 HandleGlobalVariableAssignment(proxy, Top(), expr->position()); | 3368 HandleGlobalVariableAssignment(var, |
| 3369 Top(), |
| 3370 expr->position(), |
| 3371 expr->AssignmentId()); |
| 3375 } else { | 3372 } else { |
| 3376 Bind(var, Top()); | 3373 Bind(var, Top()); |
| 3377 } | 3374 } |
| 3375 ast_context()->ReturnValue(Pop()); |
| 3376 |
| 3378 } else if (prop != NULL) { | 3377 } else if (prop != NULL) { |
| 3379 prop->RecordTypeFeedback(oracle()); | 3378 prop->RecordTypeFeedback(oracle()); |
| 3380 | 3379 |
| 3381 if (prop->key()->IsPropertyName()) { | 3380 if (prop->key()->IsPropertyName()) { |
| 3382 // Named property. | 3381 // Named property. |
| 3383 VISIT_FOR_VALUE(prop->obj()); | 3382 VISIT_FOR_VALUE(prop->obj()); |
| 3384 HValue* obj = Top(); | 3383 HValue* obj = Top(); |
| 3385 | 3384 |
| 3386 HInstruction* load = NULL; | 3385 HInstruction* load = NULL; |
| 3387 if (prop->IsMonomorphic()) { | 3386 if (prop->IsMonomorphic()) { |
| 3388 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 3387 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 3389 Handle<Map> map = prop->GetReceiverTypes()->first(); | 3388 Handle<Map> map = prop->GetReceiverTypes()->first(); |
| 3390 load = BuildLoadNamed(obj, prop, map, name); | 3389 load = BuildLoadNamed(obj, prop, map, name); |
| 3391 } else { | 3390 } else { |
| 3392 load = BuildLoadNamedGeneric(obj, prop); | 3391 load = BuildLoadNamedGeneric(obj, prop); |
| 3393 } | 3392 } |
| 3394 PushAndAdd(load); | 3393 PushAndAdd(load); |
| 3395 if (load->HasSideEffects()) { | 3394 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); |
| 3396 AddSimulate(expr->compound_bailout_id()); | |
| 3397 } | |
| 3398 | 3395 |
| 3399 VISIT_FOR_VALUE(expr->value()); | 3396 VISIT_FOR_VALUE(expr->value()); |
| 3400 HValue* right = Pop(); | 3397 HValue* right = Pop(); |
| 3401 HValue* left = Pop(); | 3398 HValue* left = Pop(); |
| 3402 | 3399 |
| 3403 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 3400 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
| 3404 PushAndAdd(instr); | 3401 PushAndAdd(instr); |
| 3405 if (instr->HasSideEffects()) AddSimulate(operation->id()); | 3402 if (instr->HasSideEffects()) AddSimulate(operation->id()); |
| 3406 | 3403 |
| 3407 HInstruction* store = BuildStoreNamed(obj, instr, prop); | 3404 HInstruction* store = BuildStoreNamed(obj, instr, prop); |
| 3408 AddInstruction(store); | 3405 AddInstruction(store); |
| 3409 | 3406 // Drop the simulated receiver and value. Return the value. |
| 3410 // Drop the simulated receiver and value and put back the value. | |
| 3411 Drop(2); | 3407 Drop(2); |
| 3412 Push(instr); | 3408 Push(instr); |
| 3409 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3410 ast_context()->ReturnValue(Pop()); |
| 3413 | 3411 |
| 3414 } else { | 3412 } else { |
| 3415 // Keyed property. | 3413 // Keyed property. |
| 3416 VISIT_FOR_VALUE(prop->obj()); | 3414 VISIT_FOR_VALUE(prop->obj()); |
| 3417 VISIT_FOR_VALUE(prop->key()); | 3415 VISIT_FOR_VALUE(prop->key()); |
| 3418 HValue* obj = environment()->ExpressionStackAt(1); | 3416 HValue* obj = environment()->ExpressionStackAt(1); |
| 3419 HValue* key = environment()->ExpressionStackAt(0); | 3417 HValue* key = environment()->ExpressionStackAt(0); |
| 3420 | 3418 |
| 3421 bool is_fast_elements = prop->IsMonomorphic() && | 3419 bool is_fast_elements = prop->IsMonomorphic() && |
| 3422 prop->GetMonomorphicReceiverType()->has_fast_elements(); | 3420 prop->GetMonomorphicReceiverType()->has_fast_elements(); |
| 3423 | 3421 |
| 3424 HInstruction* load = is_fast_elements | 3422 HInstruction* load = is_fast_elements |
| 3425 ? BuildLoadKeyedFastElement(obj, key, prop) | 3423 ? BuildLoadKeyedFastElement(obj, key, prop) |
| 3426 : BuildLoadKeyedGeneric(obj, key); | 3424 : BuildLoadKeyedGeneric(obj, key); |
| 3427 PushAndAdd(load); | 3425 PushAndAdd(load); |
| 3428 if (load->HasSideEffects()) { | 3426 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); |
| 3429 AddSimulate(expr->compound_bailout_id()); | |
| 3430 } | |
| 3431 | 3427 |
| 3432 VISIT_FOR_VALUE(expr->value()); | 3428 VISIT_FOR_VALUE(expr->value()); |
| 3433 HValue* right = Pop(); | 3429 HValue* right = Pop(); |
| 3434 HValue* left = Pop(); | 3430 HValue* left = Pop(); |
| 3435 | 3431 |
| 3436 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 3432 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
| 3437 PushAndAdd(instr); | 3433 PushAndAdd(instr); |
| 3438 if (instr->HasSideEffects()) AddSimulate(operation->id()); | 3434 if (instr->HasSideEffects()) AddSimulate(operation->id()); |
| 3439 | 3435 |
| 3440 HInstruction* store = is_fast_elements | 3436 HInstruction* store = is_fast_elements |
| 3441 ? BuildStoreKeyedFastElement(obj, key, instr, prop) | 3437 ? BuildStoreKeyedFastElement(obj, key, instr, prop) |
| 3442 : BuildStoreKeyedGeneric(obj, key, instr); | 3438 : BuildStoreKeyedGeneric(obj, key, instr); |
| 3443 AddInstruction(store); | 3439 AddInstruction(store); |
| 3444 | 3440 // Drop the simulated receiver, key, and value. Return the value. |
| 3445 // Drop the simulated receiver, key and value and put back the value. | |
| 3446 Drop(3); | 3441 Drop(3); |
| 3447 Push(instr); | 3442 Push(instr); |
| 3443 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 3444 ast_context()->ReturnValue(Pop()); |
| 3448 } | 3445 } |
| 3446 |
| 3449 } else { | 3447 } else { |
| 3450 BAILOUT("invalid lhs in compound assignment"); | 3448 BAILOUT("invalid lhs in compound assignment"); |
| 3451 } | 3449 } |
| 3452 } | 3450 } |
| 3453 | 3451 |
| 3454 | 3452 |
| 3455 void HGraphBuilder::VisitAssignment(Assignment* expr) { | 3453 void HGraphBuilder::VisitAssignment(Assignment* expr) { |
| 3456 VariableProxy* proxy = expr->target()->AsVariableProxy(); | 3454 VariableProxy* proxy = expr->target()->AsVariableProxy(); |
| 3457 Variable* var = proxy->AsVariable(); | 3455 Variable* var = proxy->AsVariable(); |
| 3458 Property* prop = expr->target()->AsProperty(); | 3456 Property* prop = expr->target()->AsProperty(); |
| 3459 ASSERT(var == NULL || prop == NULL); | 3457 ASSERT(var == NULL || prop == NULL); |
| 3460 | 3458 |
| 3461 if (expr->is_compound()) { | 3459 if (expr->is_compound()) { |
| 3462 HandleCompoundAssignment(expr); | 3460 HandleCompoundAssignment(expr); |
| 3463 return; | 3461 return; |
| 3464 } | 3462 } |
| 3465 | 3463 |
| 3466 if (var != NULL) { | 3464 if (var != NULL) { |
| 3467 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); | 3465 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); |
| 3466 |
| 3467 // Handle the assignment. |
| 3468 if (var->is_global()) { | 3468 if (var->is_global()) { |
| 3469 VISIT_FOR_VALUE(expr->value()); | 3469 VISIT_FOR_VALUE(expr->value()); |
| 3470 HandleGlobalVariableAssignment(proxy, Top(), expr->position()); | 3470 HandleGlobalVariableAssignment(var, |
| 3471 Top(), |
| 3472 expr->position(), |
| 3473 expr->AssignmentId()); |
| 3471 } else { | 3474 } else { |
| 3472 // We allow reference to the arguments object only in assignemtns | 3475 // We allow reference to the arguments object only in assignemtns |
| 3473 // to local variables to make sure that the arguments object does | 3476 // to local variables to make sure that the arguments object does |
| 3474 // not escape and is not modified. | 3477 // not escape and is not modified. |
| 3475 VariableProxy* rhs = expr->value()->AsVariableProxy(); | 3478 VariableProxy* rhs = expr->value()->AsVariableProxy(); |
| 3476 if (rhs != NULL && | 3479 if (rhs != NULL && |
| 3477 rhs->var()->IsStackAllocated() && | 3480 rhs->var()->IsStackAllocated() && |
| 3478 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { | 3481 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { |
| 3479 Push(environment()->Lookup(rhs->var())); | 3482 Push(environment()->Lookup(rhs->var())); |
| 3480 } else { | 3483 } else { |
| 3481 VISIT_FOR_VALUE(expr->value()); | 3484 VISIT_FOR_VALUE(expr->value()); |
| 3482 } | 3485 } |
| 3483 | |
| 3484 Bind(proxy->var(), Top()); | 3486 Bind(proxy->var(), Top()); |
| 3485 } | 3487 } |
| 3488 // Return the value. |
| 3489 ast_context()->ReturnValue(Pop()); |
| 3490 |
| 3486 } else if (prop != NULL) { | 3491 } else if (prop != NULL) { |
| 3487 HandlePropertyAssignment(expr); | 3492 HandlePropertyAssignment(expr); |
| 3488 } else { | 3493 } else { |
| 3489 BAILOUT("unsupported invalid lhs"); | 3494 BAILOUT("unsupported invalid lhs"); |
| 3490 } | 3495 } |
| 3491 } | 3496 } |
| 3492 | 3497 |
| 3493 | 3498 |
| 3494 void HGraphBuilder::VisitThrow(Throw* expr) { | 3499 void HGraphBuilder::VisitThrow(Throw* expr) { |
| 3500 // We don't optimize functions with invalid left-hand sides in |
| 3501 // assignments, count operations, or for-in. Consequently throw can |
| 3502 // currently only occur in an effect context. |
| 3503 ASSERT(ast_context()->IsEffect()); |
| 3495 VISIT_FOR_VALUE(expr->exception()); | 3504 VISIT_FOR_VALUE(expr->exception()); |
| 3496 | 3505 |
| 3497 HValue* value = environment()->Pop(); | 3506 HValue* value = environment()->Pop(); |
| 3498 HControlInstruction* instr = new HThrow(value); | 3507 HControlInstruction* instr = new HThrow(value); |
| 3499 instr->set_position(expr->position()); | 3508 instr->set_position(expr->position()); |
| 3500 current_subgraph_->FinishExit(instr); | 3509 current_subgraph_->FinishExit(instr); |
| 3501 } | 3510 } |
| 3502 | 3511 |
| 3503 | 3512 |
| 3504 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3513 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3516 // different maps are identical. In that case we can avoid | 3525 // different maps are identical. In that case we can avoid |
| 3517 // repeatedly generating the same prototype map checks. | 3526 // repeatedly generating the same prototype map checks. |
| 3518 for (int i = 0; i < number_of_types; ++i) { | 3527 for (int i = 0; i < number_of_types; ++i) { |
| 3519 Handle<Map> map = types->at(i); | 3528 Handle<Map> map = types->at(i); |
| 3520 LookupResult lookup; | 3529 LookupResult lookup; |
| 3521 map->LookupInDescriptors(NULL, *name, &lookup); | 3530 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3522 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3531 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3523 maps.Add(map); | 3532 maps.Add(map); |
| 3524 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3533 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3525 SubgraphScope scope(this, subgraph); | 3534 SubgraphScope scope(this, subgraph); |
| 3526 HInstruction* instr = | 3535 HLoadNamedField* instr = |
| 3527 BuildLoadNamedField(object, expr, map, &lookup, false); | 3536 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3528 PushAndAdd(instr, expr->position()); | 3537 instr->set_position(expr->position()); |
| 3538 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. |
| 3539 PushAndAdd(instr); |
| 3529 subgraphs.Add(subgraph); | 3540 subgraphs.Add(subgraph); |
| 3530 } else { | 3541 } else { |
| 3531 needs_generic = true; | 3542 needs_generic = true; |
| 3532 } | 3543 } |
| 3533 } | 3544 } |
| 3534 | 3545 |
| 3535 // If none of the properties were named fields we generate a | 3546 // If none of the properties were named fields we generate a |
| 3536 // generic load. | 3547 // generic load. |
| 3537 if (maps.length() == 0) { | 3548 if (maps.length() == 0) { |
| 3538 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3549 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3539 PushAndAdd(instr, expr->position()); | 3550 instr->set_position(expr->position()); |
| 3540 return; | 3551 PushAndAdd(instr); |
| 3552 if (instr->HasSideEffects()) AddSimulate(expr->id()); |
| 3553 } else { |
| 3554 // Build subgraph for generic load through IC. |
| 3555 { |
| 3556 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3557 SubgraphScope scope(this, subgraph); |
| 3558 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3559 subgraph->FinishExit(new HDeoptimize()); |
| 3560 } else { |
| 3561 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3562 instr->set_position(expr->position()); |
| 3563 PushAndAdd(instr); |
| 3564 } |
| 3565 subgraphs.Add(subgraph); |
| 3566 } |
| 3567 |
| 3568 HBasicBlock* new_exit_block = |
| 3569 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); |
| 3570 subgraph()->set_exit_block(new_exit_block); |
| 3541 } | 3571 } |
| 3542 | 3572 |
| 3543 // Build subgraph for generic load through IC. | 3573 if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); |
| 3544 { | |
| 3545 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | |
| 3546 SubgraphScope scope(this, subgraph); | |
| 3547 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3548 subgraph->FinishExit(new HDeoptimize()); | |
| 3549 } else { | |
| 3550 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | |
| 3551 PushAndAdd(instr, expr->position()); | |
| 3552 } | |
| 3553 subgraphs.Add(subgraph); | |
| 3554 } | |
| 3555 | |
| 3556 HBasicBlock* new_exit_block = | |
| 3557 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | |
| 3558 current_subgraph_->set_exit_block(new_exit_block); | |
| 3559 } | 3574 } |
| 3560 | 3575 |
| 3561 | 3576 |
| 3562 HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3577 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3563 Property* expr, | 3578 Property* expr, |
| 3564 Handle<Map> type, | 3579 Handle<Map> type, |
| 3565 LookupResult* lookup, | 3580 LookupResult* lookup, |
| 3566 bool smi_and_map_check) { | 3581 bool smi_and_map_check) { |
| 3567 if (smi_and_map_check) { | 3582 if (smi_and_map_check) { |
| 3568 AddInstruction(new HCheckNonSmi(object)); | 3583 AddInstruction(new HCheckNonSmi(object)); |
| 3569 AddInstruction(new HCheckMap(object, type)); | 3584 AddInstruction(new HCheckMap(object, type)); |
| 3570 } | 3585 } |
| 3571 | 3586 |
| 3572 int index = lookup->GetLocalFieldIndexFromMap(*type); | 3587 int index = lookup->GetLocalFieldIndexFromMap(*type); |
| 3573 if (index < 0) { | 3588 if (index < 0) { |
| 3574 // Negative property indices are in-object properties, indexed | 3589 // Negative property indices are in-object properties, indexed |
| 3575 // from the end of the fixed part of the object. | 3590 // from the end of the fixed part of the object. |
| 3576 int offset = (index * kPointerSize) + type->instance_size(); | 3591 int offset = (index * kPointerSize) + type->instance_size(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3596 Handle<Map> map, | 3611 Handle<Map> map, |
| 3597 Handle<String> name) { | 3612 Handle<String> name) { |
| 3598 LookupResult lookup; | 3613 LookupResult lookup; |
| 3599 map->LookupInDescriptors(NULL, *name, &lookup); | 3614 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3600 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3615 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3601 return BuildLoadNamedField(obj, | 3616 return BuildLoadNamedField(obj, |
| 3602 expr, | 3617 expr, |
| 3603 map, | 3618 map, |
| 3604 &lookup, | 3619 &lookup, |
| 3605 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()); |
| 3606 } else { | 3626 } else { |
| 3607 return BuildLoadNamedGeneric(obj, expr); | 3627 return BuildLoadNamedGeneric(obj, expr); |
| 3608 } | 3628 } |
| 3609 } | 3629 } |
| 3610 | 3630 |
| 3611 | 3631 |
| 3612 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 3632 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 3613 HValue* key) { | 3633 HValue* key) { |
| 3614 return new HLoadKeyedGeneric(object, key); | 3634 return new HLoadKeyedGeneric(object, key); |
| 3615 } | 3635 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3661 | 3681 |
| 3662 | 3682 |
| 3663 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 3683 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
| 3664 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 3684 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
| 3665 if (proxy == NULL) return false; | 3685 if (proxy == NULL) return false; |
| 3666 if (!proxy->var()->IsStackAllocated()) return false; | 3686 if (!proxy->var()->IsStackAllocated()) return false; |
| 3667 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 3687 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
| 3668 return false; | 3688 return false; |
| 3669 } | 3689 } |
| 3670 | 3690 |
| 3691 HInstruction* result = NULL; |
| 3671 if (expr->key()->IsPropertyName()) { | 3692 if (expr->key()->IsPropertyName()) { |
| 3672 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 3693 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3673 if (!name->IsEqualTo(CStrVector("length"))) return false; | 3694 if (!name->IsEqualTo(CStrVector("length"))) return false; |
| 3674 HInstruction* elements = AddInstruction(new HArgumentsElements); | 3695 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 3675 PushAndAdd(new HArgumentsLength(elements)); | 3696 result = new HArgumentsLength(elements); |
| 3676 } else { | 3697 } else { |
| 3677 VisitForValue(expr->key()); | 3698 VisitForValue(expr->key()); |
| 3678 if (HasStackOverflow()) return false; | 3699 if (HasStackOverflow()) return false; |
| 3679 HValue* key = Pop(); | 3700 HValue* key = Pop(); |
| 3680 HInstruction* elements = AddInstruction(new HArgumentsElements); | 3701 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 3681 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 3702 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 3682 AddInstruction(new HBoundsCheck(key, length)); | 3703 AddInstruction(new HBoundsCheck(key, length)); |
| 3683 PushAndAdd(new HAccessArgumentsAt(elements, length, key)); | 3704 result = new HAccessArgumentsAt(elements, length, key); |
| 3684 } | 3705 } |
| 3706 ast_context()->ReturnInstruction(result, expr->id()); |
| 3685 return true; | 3707 return true; |
| 3686 } | 3708 } |
| 3687 | 3709 |
| 3688 | 3710 |
| 3689 void HGraphBuilder::VisitProperty(Property* expr) { | 3711 void HGraphBuilder::VisitProperty(Property* expr) { |
| 3690 expr->RecordTypeFeedback(oracle()); | 3712 expr->RecordTypeFeedback(oracle()); |
| 3691 | 3713 |
| 3692 if (TryArgumentsAccess(expr)) return; | 3714 if (TryArgumentsAccess(expr)) return; |
| 3693 CHECK_BAILOUT; | 3715 CHECK_BAILOUT; |
| 3694 | 3716 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3721 HValue* key = Pop(); | 3743 HValue* key = Pop(); |
| 3722 HValue* obj = Pop(); | 3744 HValue* obj = Pop(); |
| 3723 | 3745 |
| 3724 bool is_fast_elements = expr->IsMonomorphic() && | 3746 bool is_fast_elements = expr->IsMonomorphic() && |
| 3725 expr->GetMonomorphicReceiverType()->has_fast_elements(); | 3747 expr->GetMonomorphicReceiverType()->has_fast_elements(); |
| 3726 | 3748 |
| 3727 instr = is_fast_elements | 3749 instr = is_fast_elements |
| 3728 ? BuildLoadKeyedFastElement(obj, key, expr) | 3750 ? BuildLoadKeyedFastElement(obj, key, expr) |
| 3729 : BuildLoadKeyedGeneric(obj, key); | 3751 : BuildLoadKeyedGeneric(obj, key); |
| 3730 } | 3752 } |
| 3731 PushAndAdd(instr, expr->position()); | 3753 instr->set_position(expr->position()); |
| 3754 ast_context()->ReturnInstruction(instr, expr->id()); |
| 3732 } | 3755 } |
| 3733 | 3756 |
| 3734 | 3757 |
| 3735 void HGraphBuilder::AddCheckConstantFunction(Call* expr, | 3758 void HGraphBuilder::AddCheckConstantFunction(Call* expr, |
| 3736 HValue* receiver, | 3759 HValue* receiver, |
| 3737 Handle<Map> receiver_map, | 3760 Handle<Map> receiver_map, |
| 3738 bool smi_and_map_check) { | 3761 bool smi_and_map_check) { |
| 3739 // Constant functions have the nice property that the map will change if they | 3762 // Constant functions have the nice property that the map will change if they |
| 3740 // are overwritten. Therefore it is enough to check the map of the holder and | 3763 // are overwritten. Therefore it is enough to check the map of the holder and |
| 3741 // its prototypes. | 3764 // its prototypes. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3756 ZoneMapList* types, | 3779 ZoneMapList* types, |
| 3757 Handle<String> name) { | 3780 Handle<String> name) { |
| 3758 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 3781 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 3759 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | 3782 int number_of_types = Min(types->length(), kMaxCallPolymorphism); |
| 3760 ZoneMapList maps(number_of_types); | 3783 ZoneMapList maps(number_of_types); |
| 3761 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3784 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); |
| 3762 bool needs_generic = (types->length() > kMaxCallPolymorphism); | 3785 bool needs_generic = (types->length() > kMaxCallPolymorphism); |
| 3763 | 3786 |
| 3764 // Build subgraphs for each of the specific maps. | 3787 // Build subgraphs for each of the specific maps. |
| 3765 // | 3788 // |
| 3766 // TODO(ager): We should recognize when the prototype chains for | 3789 // TODO(ager): We should recognize when the prototype chains for different |
| 3767 // different maps are identical. In that case we can avoid | 3790 // maps are identical. In that case we can avoid repeatedly generating the |
| 3768 // repeatedly generating the same prototype map checks. | 3791 // same prototype map checks. |
| 3769 for (int i = 0; i < number_of_types; ++i) { | 3792 for (int i = 0; i < number_of_types; ++i) { |
| 3770 Handle<Map> map = types->at(i); | 3793 Handle<Map> map = types->at(i); |
| 3771 if (expr->ComputeTarget(map, name)) { | 3794 if (expr->ComputeTarget(map, name)) { |
| 3772 maps.Add(map); | 3795 maps.Add(map); |
| 3773 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3796 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3774 SubgraphScope scope(this, subgraph); | 3797 SubgraphScope scope(this, subgraph); |
| 3775 AddCheckConstantFunction(expr, receiver, map, false); | 3798 AddCheckConstantFunction(expr, receiver, map, false); |
| 3776 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 3799 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 3777 PrintF("Trying to inline the polymorphic call to %s\n", | 3800 PrintF("Trying to inline the polymorphic call to %s\n", |
| 3778 *name->ToCString()); | 3801 *name->ToCString()); |
| 3779 } | 3802 } |
| 3780 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { | 3803 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { |
| 3781 // Check for bailout, as trying to inline might fail due to bailout | 3804 // Check for bailout, as trying to inline might fail due to bailout |
| 3782 // during hydrogen processing. | 3805 // during hydrogen processing. |
| 3783 CHECK_BAILOUT; | 3806 CHECK_BAILOUT; |
| 3784 HCall* call = new HCallConstantFunction(expr->target(), argument_count); | 3807 HCall* call = new HCallConstantFunction(expr->target(), argument_count); |
| 3785 ProcessCall(call, expr->position()); | 3808 call->set_position(expr->position()); |
| 3809 ProcessCall(call); |
| 3810 PushAndAdd(call); |
| 3786 } | 3811 } |
| 3787 subgraphs.Add(subgraph); | 3812 subgraphs.Add(subgraph); |
| 3788 } else { | 3813 } else { |
| 3789 needs_generic = true; | 3814 needs_generic = true; |
| 3790 } | 3815 } |
| 3791 } | 3816 } |
| 3792 | 3817 |
| 3793 // If we couldn't compute the target for any of the maps just | 3818 // If we couldn't compute the target for any of the maps just perform an |
| 3794 // perform an IC call. | 3819 // IC call. |
| 3795 if (maps.length() == 0) { | 3820 if (maps.length() == 0) { |
| 3796 HCall* call = new HCallNamed(name, argument_count); | 3821 HCall* call = new HCallNamed(name, argument_count); |
| 3797 ProcessCall(call, expr->position()); | 3822 call->set_position(expr->position()); |
| 3798 return; | 3823 ProcessCall(call); |
| 3824 ast_context()->ReturnInstruction(call, expr->id()); |
| 3825 } else { |
| 3826 // Build subgraph for generic call through IC. |
| 3827 { |
| 3828 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3829 SubgraphScope scope(this, subgraph); |
| 3830 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| 3831 subgraph->FinishExit(new HDeoptimize()); |
| 3832 } else { |
| 3833 HCall* call = new HCallNamed(name, argument_count); |
| 3834 call->set_position(expr->position()); |
| 3835 ProcessCall(call); |
| 3836 PushAndAdd(call); |
| 3837 } |
| 3838 subgraphs.Add(subgraph); |
| 3839 } |
| 3840 |
| 3841 HBasicBlock* new_exit_block = |
| 3842 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); |
| 3843 subgraph()->set_exit_block(new_exit_block); |
| 3844 if (new_exit_block != NULL) ast_context()->ReturnValue(Pop()); |
| 3799 } | 3845 } |
| 3800 | |
| 3801 // Build subgraph for generic call through IC. | |
| 3802 { | |
| 3803 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | |
| 3804 SubgraphScope scope(this, subgraph); | |
| 3805 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3806 subgraph->FinishExit(new HDeoptimize()); | |
| 3807 } else { | |
| 3808 HCall* call = new HCallNamed(name, argument_count); | |
| 3809 ProcessCall(call, expr->position()); | |
| 3810 } | |
| 3811 subgraphs.Add(subgraph); | |
| 3812 } | |
| 3813 | |
| 3814 HBasicBlock* new_exit_block = | |
| 3815 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); | |
| 3816 current_subgraph_->set_exit_block(new_exit_block); | |
| 3817 } | 3846 } |
| 3818 | 3847 |
| 3819 | 3848 |
| 3820 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | 3849 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { |
| 3821 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); | 3850 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); |
| 3822 SmartPointer<char> caller = | 3851 SmartPointer<char> caller = |
| 3823 graph()->info()->function()->debug_name()->ToCString(); | 3852 graph()->info()->function()->debug_name()->ToCString(); |
| 3824 if (result) { | 3853 if (result) { |
| 3825 PrintF("Inlined %s called from %s.\n", *callee, *caller); | 3854 PrintF("Inlined %s called from %s.\n", *callee, *caller); |
| 3826 } else { | 3855 } else { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3933 | 3962 |
| 3934 TestContext* test_context = NULL; | 3963 TestContext* test_context = NULL; |
| 3935 if (ast_context()->IsTest()) { | 3964 if (ast_context()->IsTest()) { |
| 3936 // 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 |
| 3937 // 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. |
| 3938 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 3967 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 3939 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 3968 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 3940 if_true->MarkAsInlineReturnTarget(); | 3969 if_true->MarkAsInlineReturnTarget(); |
| 3941 if_false->MarkAsInlineReturnTarget(); | 3970 if_false->MarkAsInlineReturnTarget(); |
| 3942 // AstContext constructor pushes on the context stack. | 3971 // AstContext constructor pushes on the context stack. |
| 3943 bool invert_true = TestContext::cast(ast_context())->invert_true(); | 3972 test_context = new TestContext(this, if_true, if_false); |
| 3944 bool invert_false = TestContext::cast(ast_context())->invert_false(); | |
| 3945 test_context = new TestContext(this, if_true, if_false, | |
| 3946 invert_true, invert_false); | |
| 3947 function_return_ = NULL; | 3973 function_return_ = NULL; |
| 3948 } else { | 3974 } else { |
| 3949 // 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. |
| 3950 function_return_ = graph()->CreateBasicBlock(); | 3976 function_return_ = graph()->CreateBasicBlock(); |
| 3951 function_return_->MarkAsInlineReturnTarget(); | 3977 function_return_->MarkAsInlineReturnTarget(); |
| 3952 } | 3978 } |
| 3953 call_context_ = ast_context(); | 3979 call_context_ = ast_context(); |
| 3954 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code())); | 3980 TypeFeedbackOracle new_oracle(Handle<Code>(shared->code())); |
| 3955 oracle_ = &new_oracle; | 3981 oracle_ = &new_oracle; |
| 3956 graph()->info()->SetOsrAstId(AstNode::kNoNumber); | 3982 graph()->info()->SetOsrAstId(AstNode::kNoNumber); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 3980 HValue* return_value = graph()->GetConstantUndefined(); | 4006 HValue* return_value = graph()->GetConstantUndefined(); |
| 3981 if (test_context == NULL) { | 4007 if (test_context == NULL) { |
| 3982 ASSERT(function_return_ != NULL); | 4008 ASSERT(function_return_ != NULL); |
| 3983 body->exit_block()->AddLeaveInlined(return_value, function_return_); | 4009 body->exit_block()->AddLeaveInlined(return_value, function_return_); |
| 3984 } else { | 4010 } else { |
| 3985 // The graph builder assumes control can reach both branches of a | 4011 // The graph builder assumes control can reach both branches of a |
| 3986 // 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 |
| 3987 // simply jumping to the false target. | 4013 // simply jumping to the false target. |
| 3988 // | 4014 // |
| 3989 // TODO(3168478): refactor to avoid this. | 4015 // TODO(3168478): refactor to avoid this. |
| 3990 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); | 4016 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
| 3991 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); | 4017 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
| 3992 HBranch* branch = | 4018 HBranch* branch = |
| 3993 new HBranch(materialize_true, materialize_false, return_value); | 4019 new HBranch(empty_true, empty_false, return_value); |
| 3994 body->exit_block()->Finish(branch); | 4020 body->exit_block()->Finish(branch); |
| 3995 | 4021 |
| 3996 materialize_true->AddLeaveInlined(graph()->GetConstantTrue(), | 4022 HValue* const no_return_value = NULL; |
| 3997 test_context->if_true()); | 4023 empty_true->AddLeaveInlined(no_return_value, test_context->if_true()); |
| 3998 materialize_false->AddLeaveInlined(graph()->GetConstantFalse(), | 4024 empty_false->AddLeaveInlined(no_return_value, test_context->if_false()); |
| 3999 test_context->if_false()); | |
| 4000 } | 4025 } |
| 4001 body->set_exit_block(NULL); | 4026 body->set_exit_block(NULL); |
| 4002 } | 4027 } |
| 4003 | 4028 |
| 4004 // Record the environment at the inlined function call. | 4029 // Record the environment at the inlined function call. |
| 4005 AddSimulate(expr->ReturnId()); | 4030 AddSimulate(expr->ReturnId()); |
| 4006 | 4031 |
| 4007 // Jump to the function entry (without re-recording the environment). | 4032 // Jump to the function entry (without re-recording the environment). |
| 4008 subgraph()->exit_block()->Finish(new HGoto(body->entry_block())); | 4033 subgraph()->exit_block()->Finish(new HGoto(body->entry_block())); |
| 4009 | 4034 |
| 4010 // Fix up the function exits. | 4035 // Fix up the function exits. |
| 4011 if (test_context != NULL) { | 4036 if (test_context != NULL) { |
| 4012 HBasicBlock* if_true = test_context->if_true(); | 4037 HBasicBlock* if_true = test_context->if_true(); |
| 4013 HBasicBlock* if_false = test_context->if_false(); | 4038 HBasicBlock* if_false = test_context->if_false(); |
| 4014 if_true->SetJoinId(expr->id()); | 4039 if_true->SetJoinId(expr->id()); |
| 4015 if_false->SetJoinId(expr->id()); | 4040 if_false->SetJoinId(expr->id()); |
| 4016 ASSERT(ast_context() == test_context); | 4041 ASSERT(ast_context() == test_context); |
| 4017 delete test_context; // Destructor pops from expression context stack. | 4042 delete test_context; // Destructor pops from expression context stack. |
| 4043 |
| 4018 // Forward to the real test context. | 4044 // Forward to the real test context. |
| 4019 | 4045 HValue* const no_return_value = NULL; |
| 4020 // Discard the lingering branch value (which may be true or false, | |
| 4021 // depending on whether the final condition was negated) and jump to the | |
| 4022 // true target with a true branch value. | |
| 4023 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4046 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
| 4024 bool invert_true = TestContext::cast(ast_context())->invert_true(); | |
| 4025 HValue* true_value = invert_true | |
| 4026 ? graph()->GetConstantFalse() | |
| 4027 : graph()->GetConstantTrue(); | |
| 4028 if_true->last_environment()->Pop(); | |
| 4029 if (true_target->IsInlineReturnTarget()) { | 4047 if (true_target->IsInlineReturnTarget()) { |
| 4030 if_true->AddLeaveInlined(true_value, true_target); | 4048 if_true->AddLeaveInlined(no_return_value, true_target); |
| 4031 } else { | 4049 } else { |
| 4032 if_true->last_environment()->Push(true_value); | |
| 4033 if_true->Goto(true_target); | 4050 if_true->Goto(true_target); |
| 4034 } | 4051 } |
| 4035 | 4052 |
| 4036 // Do the same for the false target. | |
| 4037 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4053 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
| 4038 bool invert_false = TestContext::cast(ast_context())->invert_false(); | |
| 4039 HValue* false_value = invert_false | |
| 4040 ? graph()->GetConstantTrue() | |
| 4041 : graph()->GetConstantFalse(); | |
| 4042 if_false->last_environment()->Pop(); | |
| 4043 if (false_target->IsInlineReturnTarget()) { | 4054 if (false_target->IsInlineReturnTarget()) { |
| 4044 if_false->AddLeaveInlined(false_value, false_target); | 4055 if_false->AddLeaveInlined(no_return_value, false_target); |
| 4045 } else { | 4056 } else { |
| 4046 if_false->last_environment()->Push(false_value); | |
| 4047 if_false->Goto(false_target); | 4057 if_false->Goto(false_target); |
| 4048 } | 4058 } |
| 4049 | 4059 |
| 4050 // 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 |
| 4051 // subtle. NULL here indicates that the enclosing context has no control | 4061 // subtle. NULL here indicates that the enclosing context has no control |
| 4052 // flow to handle. | 4062 // flow to handle. |
| 4053 subgraph()->set_exit_block(NULL); | 4063 subgraph()->set_exit_block(NULL); |
| 4054 | 4064 |
| 4055 } else { | 4065 } else { |
| 4056 function_return_->SetJoinId(expr->id()); | 4066 function_return_->SetJoinId(expr->id()); |
| 4057 subgraph()->set_exit_block(function_return_); | 4067 subgraph()->set_exit_block(function_return_); |
| 4058 } | 4068 } |
| 4059 | 4069 |
| 4060 call_context_ = saved_call_context; | 4070 call_context_ = saved_call_context; |
| 4061 function_return_ = saved_function_return; | 4071 function_return_ = saved_function_return; |
| 4062 oracle_ = saved_oracle; | 4072 oracle_ = saved_oracle; |
| 4063 graph()->info()->SetOsrAstId(saved_osr_ast_id); | 4073 graph()->info()->SetOsrAstId(saved_osr_ast_id); |
| 4074 |
| 4064 return true; | 4075 return true; |
| 4065 } | 4076 } |
| 4066 | 4077 |
| 4067 | 4078 |
| 4068 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4079 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4069 ASSERT(target->IsInlineReturnTarget()); | 4080 ASSERT(target->IsInlineReturnTarget()); |
| 4070 AddInstruction(new HLeaveInlined); | 4081 AddInstruction(new HLeaveInlined); |
| 4071 HEnvironment* outer = last_environment()->outer(); | 4082 HEnvironment* outer = last_environment()->outer(); |
| 4072 outer->Push(return_value); | 4083 if (return_value != NULL) outer->Push(return_value); |
| 4073 UpdateEnvironment(outer); | 4084 UpdateEnvironment(outer); |
| 4074 Goto(target); | 4085 Goto(target); |
| 4075 } | 4086 } |
| 4076 | 4087 |
| 4077 | 4088 |
| 4078 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4089 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| 4079 // 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. |
| 4080 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(); |
| 4081 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4093 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4082 switch (id) { | 4094 switch (id) { |
| 4083 case kMathRound: | 4095 case kMathRound: |
| 4084 case kMathFloor: | 4096 case kMathFloor: |
| 4085 case kMathAbs: | 4097 case kMathAbs: |
| 4086 case kMathSqrt: | 4098 case kMathSqrt: |
| 4099 case kMathLog: |
| 4100 case kMathSin: |
| 4101 case kMathCos: |
| 4087 if (argument_count == 2) { | 4102 if (argument_count == 2) { |
| 4088 HValue* argument = Pop(); | 4103 HValue* argument = Pop(); |
| 4089 // Pop receiver. | 4104 Drop(1); // Receiver. |
| 4090 Pop(); | |
| 4091 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4105 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4092 PushAndAdd(op, expr->position()); | 4106 op->set_position(expr->position()); |
| 4107 ast_context()->ReturnInstruction(op, expr->id()); |
| 4108 return true; |
| 4109 } |
| 4110 break; |
| 4111 case kMathPow: |
| 4112 if (argument_count == 3) { |
| 4113 HValue* right = Pop(); |
| 4114 HValue* left = Pop(); |
| 4115 Pop(); // Pop receiver. |
| 4116 HInstruction* result = NULL; |
| 4117 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4118 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4119 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4120 if (exponent == 0.5) { |
| 4121 result = new HUnaryMathOperation(left, kMathPowHalf); |
| 4122 ast_context()->ReturnInstruction(result, expr->id()); |
| 4123 return true; |
| 4124 } else if (exponent == -0.5) { |
| 4125 HConstant* double_one = |
| 4126 new HConstant(Handle<Object>(Smi::FromInt(1)), |
| 4127 Representation::Double()); |
| 4128 AddInstruction(double_one); |
| 4129 HUnaryMathOperation* square_root = |
| 4130 new HUnaryMathOperation(left, kMathPowHalf); |
| 4131 AddInstruction(square_root); |
| 4132 // MathPowHalf doesn't have side effects so there's no need for |
| 4133 // an environment simulation here. |
| 4134 ASSERT(!square_root->HasSideEffects()); |
| 4135 result = new HDiv(double_one, square_root); |
| 4136 ast_context()->ReturnInstruction(result, expr->id()); |
| 4137 return true; |
| 4138 } else if (exponent == 2.0) { |
| 4139 result = new HMul(left, left); |
| 4140 ast_context()->ReturnInstruction(result, expr->id()); |
| 4141 return true; |
| 4142 } |
| 4143 } else if (right->IsConstant() && |
| 4144 HConstant::cast(right)->HasInteger32Value() && |
| 4145 HConstant::cast(right)->Integer32Value() == 2) { |
| 4146 result = new HMul(left, left); |
| 4147 ast_context()->ReturnInstruction(result, expr->id()); |
| 4148 return true; |
| 4149 } |
| 4150 |
| 4151 result = new HPower(left, right); |
| 4152 ast_context()->ReturnInstruction(result, expr->id()); |
| 4093 return true; | 4153 return true; |
| 4094 } | 4154 } |
| 4095 break; | 4155 break; |
| 4096 default: | 4156 default: |
| 4097 // Either not a special math function or not yet supported for inlining. | 4157 // Not yet supported for inlining. |
| 4098 break; | 4158 break; |
| 4099 } | 4159 } |
| 4100 return false; | 4160 return false; |
| 4101 } | 4161 } |
| 4102 | 4162 |
| 4103 | 4163 |
| 4104 bool HGraphBuilder::TryCallApply(Call* expr) { | 4164 bool HGraphBuilder::TryCallApply(Call* expr) { |
| 4105 Expression* callee = expr->expression(); | 4165 Expression* callee = expr->expression(); |
| 4106 Property* prop = callee->AsProperty(); | 4166 Property* prop = callee->AsProperty(); |
| 4107 ASSERT(prop != NULL); | 4167 ASSERT(prop != NULL); |
| 4108 | 4168 |
| 4109 if (graph()->info()->scope()->arguments() == NULL) return false; | 4169 if (graph()->info()->scope()->arguments() == NULL) return false; |
| 4110 | 4170 |
| 4111 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4171 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4112 if (!name->IsEqualTo(CStrVector("apply"))) return false; | 4172 if (!name->IsEqualTo(CStrVector("apply"))) return false; |
| 4113 | 4173 |
| 4114 ZoneList<Expression*>* args = expr->arguments(); | 4174 ZoneList<Expression*>* args = expr->arguments(); |
| 4115 if (args->length() != 2) return false; | 4175 if (args->length() != 2) return false; |
| 4116 | 4176 |
| 4117 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 4177 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 4118 if (arg_two == NULL) return false; | 4178 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 4119 HValue* arg_two_value = environment()->Lookup(arg_two->var()); | 4179 HValue* arg_two_value = environment()->Lookup(arg_two->var()); |
| 4120 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 4180 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 4121 | 4181 |
| 4122 if (!expr->IsMonomorphic()) return false; | 4182 if (!expr->IsMonomorphic()) return false; |
| 4123 | 4183 |
| 4124 // Found pattern f.apply(receiver, arguments). | 4184 // Found pattern f.apply(receiver, arguments). |
| 4125 VisitForValue(prop->obj()); | 4185 VisitForValue(prop->obj()); |
| 4126 if (HasStackOverflow()) return false; | 4186 if (HasStackOverflow()) return false; |
| 4127 HValue* function = Pop(); | 4187 HValue* function = Pop(); |
| 4128 VisitForValue(args->at(0)); | 4188 VisitForValue(args->at(0)); |
| 4129 if (HasStackOverflow()) return false; | 4189 if (HasStackOverflow()) return false; |
| 4130 HValue* receiver = Pop(); | 4190 HValue* receiver = Pop(); |
| 4131 HInstruction* elements = AddInstruction(new HArgumentsElements); | 4191 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4132 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 4192 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 4133 AddCheckConstantFunction(expr, | 4193 AddCheckConstantFunction(expr, |
| 4134 function, | 4194 function, |
| 4135 expr->GetReceiverTypes()->first(), | 4195 expr->GetReceiverTypes()->first(), |
| 4136 true); | 4196 true); |
| 4137 PushAndAdd(new HApplyArguments(function, receiver, length, elements), | 4197 HInstruction* result = |
| 4138 expr->position()); | 4198 new HApplyArguments(function, receiver, length, elements); |
| 4199 result->set_position(expr->position()); |
| 4200 ast_context()->ReturnInstruction(result, expr->id()); |
| 4139 return true; | 4201 return true; |
| 4140 } | 4202 } |
| 4141 | 4203 |
| 4142 | 4204 |
| 4143 void HGraphBuilder::VisitCall(Call* expr) { | 4205 void HGraphBuilder::VisitCall(Call* expr) { |
| 4144 Expression* callee = expr->expression(); | 4206 Expression* callee = expr->expression(); |
| 4145 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4207 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4146 HCall* call = NULL; | 4208 HCall* call = NULL; |
| 4147 | 4209 |
| 4148 Property* prop = callee->AsProperty(); | 4210 Property* prop = callee->AsProperty(); |
| 4149 if (prop != NULL) { | 4211 if (prop != NULL) { |
| 4150 if (!prop->key()->IsPropertyName()) { | 4212 if (!prop->key()->IsPropertyName()) { |
| 4151 // Keyed function call. | 4213 // Keyed function call. |
| 4152 VisitArgument(prop->obj()); | 4214 VisitArgument(prop->obj()); |
| 4153 CHECK_BAILOUT; | 4215 CHECK_BAILOUT; |
| 4154 | 4216 |
| 4155 VISIT_FOR_VALUE(prop->key()); | 4217 VISIT_FOR_VALUE(prop->key()); |
| 4156 // Push receiver and key like the non-optimized code generator expects it. | 4218 // Push receiver and key like the non-optimized code generator expects it. |
| 4157 HValue* key = Pop(); | 4219 HValue* key = Pop(); |
| 4158 HValue* receiver = Pop(); | 4220 HValue* receiver = Pop(); |
| 4159 Push(key); | 4221 Push(key); |
| 4160 Push(receiver); | 4222 Push(receiver); |
| 4161 | 4223 |
| 4162 VisitArgumentList(expr->arguments()); | 4224 VisitArgumentList(expr->arguments()); |
| 4163 CHECK_BAILOUT; | 4225 CHECK_BAILOUT; |
| 4164 | 4226 |
| 4165 call = new HCallKeyed(key, argument_count); | 4227 call = new HCallKeyed(key, argument_count); |
| 4166 ProcessCall(call, expr->position()); | 4228 call->set_position(expr->position()); |
| 4167 HValue* result = Pop(); | 4229 ProcessCall(call); |
| 4168 // Drop the receiver from the environment and put back the result of | 4230 Drop(1); // Key. |
| 4169 // the call. | 4231 ast_context()->ReturnInstruction(call, expr->id()); |
| 4170 Drop(1); | |
| 4171 Push(result); | |
| 4172 return; | 4232 return; |
| 4173 } | 4233 } |
| 4174 | 4234 |
| 4175 // Named function call. | 4235 // Named function call. |
| 4176 expr->RecordTypeFeedback(oracle()); | 4236 expr->RecordTypeFeedback(oracle()); |
| 4177 | 4237 |
| 4178 if (TryCallApply(expr)) return; | 4238 if (TryCallApply(expr)) return; |
| 4179 CHECK_BAILOUT; | 4239 CHECK_BAILOUT; |
| 4180 | 4240 |
| 4181 HValue* receiver = VisitArgument(prop->obj()); | 4241 HValue* receiver = VisitArgument(prop->obj()); |
| 4182 CHECK_BAILOUT; | 4242 CHECK_BAILOUT; |
| 4183 VisitArgumentList(expr->arguments()); | 4243 VisitArgumentList(expr->arguments()); |
| 4184 CHECK_BAILOUT; | 4244 CHECK_BAILOUT; |
| 4185 | 4245 |
| 4186 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4246 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4187 | 4247 |
| 4188 expr->RecordTypeFeedback(oracle()); | 4248 expr->RecordTypeFeedback(oracle()); |
| 4189 ZoneMapList* types = expr->GetReceiverTypes(); | 4249 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4190 | 4250 |
| 4191 if (expr->IsMonomorphic()) { | 4251 if (expr->IsMonomorphic()) { |
| 4192 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4252 AddCheckConstantFunction(expr, receiver, types->first(), true); |
| 4193 | 4253 |
| 4194 if (TryMathFunctionInline(expr) || TryInline(expr)) { | 4254 if (TryMathFunctionInline(expr)) { |
| 4255 return; |
| 4256 } else if (TryInline(expr)) { |
| 4257 if (subgraph()->HasExit()) { |
| 4258 HValue* return_value = Pop(); |
| 4259 // If we inlined a function in a test context then we need to emit |
| 4260 // a simulate here to shadow the ones at the end of the |
| 4261 // predecessor blocks. Those environments contain the return |
| 4262 // value on top and do not correspond to any actual state of the |
| 4263 // unoptimized code. |
| 4264 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4265 ast_context()->ReturnValue(return_value); |
| 4266 } |
| 4195 return; | 4267 return; |
| 4196 } else { | 4268 } else { |
| 4197 // Check for bailout, as the TryInline call in the if condition above | 4269 // Check for bailout, as the TryInline call in the if condition above |
| 4198 // might return false due to bailout during hydrogen processing. | 4270 // might return false due to bailout during hydrogen processing. |
| 4199 CHECK_BAILOUT; | 4271 CHECK_BAILOUT; |
| 4200 call = new HCallConstantFunction(expr->target(), argument_count); | 4272 call = new HCallConstantFunction(expr->target(), argument_count); |
| 4201 } | 4273 } |
| 4274 |
| 4202 } else if (types != NULL && types->length() > 1) { | 4275 } else if (types != NULL && types->length() > 1) { |
| 4203 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4276 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4204 return; | 4277 return; |
| 4205 | 4278 |
| 4206 } else { | 4279 } else { |
| 4207 call = new HCallNamed(name, argument_count); | 4280 call = new HCallNamed(name, argument_count); |
| 4208 } | 4281 } |
| 4209 | 4282 |
| 4210 } else { | 4283 } else { |
| 4211 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4284 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 4239 | 4312 |
| 4240 // Replace the global object with the global receiver. | 4313 // Replace the global object with the global receiver. |
| 4241 HGlobalReceiver* global_receiver = new HGlobalReceiver; | 4314 HGlobalReceiver* global_receiver = new HGlobalReceiver; |
| 4242 // Index of the receiver from the top of the expression stack. | 4315 // Index of the receiver from the top of the expression stack. |
| 4243 const int receiver_index = argument_count - 1; | 4316 const int receiver_index = argument_count - 1; |
| 4244 AddInstruction(global_receiver); | 4317 AddInstruction(global_receiver); |
| 4245 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4318 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 4246 IsGlobalObject()); | 4319 IsGlobalObject()); |
| 4247 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4320 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 4248 | 4321 |
| 4249 if (TryInline(expr)) return; | 4322 if (TryInline(expr)) { |
| 4323 if (subgraph()->HasExit()) { |
| 4324 HValue* return_value = Pop(); |
| 4325 // If we inlined a function in a test context then we need to |
| 4326 // emit a simulate here to shadow the ones at the end of the |
| 4327 // predecessor blocks. Those environments contain the return |
| 4328 // value on top and do not correspond to any actual state of the |
| 4329 // unoptimized code. |
| 4330 if (ast_context()->IsEffect()) AddSimulate(expr->id()); |
| 4331 ast_context()->ReturnValue(return_value); |
| 4332 } |
| 4333 return; |
| 4334 } |
| 4250 // Check for bailout, as trying to inline might fail due to bailout | 4335 // Check for bailout, as trying to inline might fail due to bailout |
| 4251 // during hydrogen processing. | 4336 // during hydrogen processing. |
| 4252 CHECK_BAILOUT; | 4337 CHECK_BAILOUT; |
| 4253 | 4338 |
| 4254 call = new HCallKnownGlobal(expr->target(), argument_count); | 4339 call = new HCallKnownGlobal(expr->target(), argument_count); |
| 4255 } else { | 4340 } else { |
| 4256 PushAndAdd(new HGlobalObject); | 4341 PushAndAdd(new HGlobalObject); |
| 4257 VisitArgumentList(expr->arguments()); | 4342 VisitArgumentList(expr->arguments()); |
| 4258 CHECK_BAILOUT; | 4343 CHECK_BAILOUT; |
| 4259 | 4344 |
| 4260 call = new HCallGlobal(var->name(), argument_count); | 4345 call = new HCallGlobal(var->name(), argument_count); |
| 4261 } | 4346 } |
| 4262 | 4347 |
| 4263 } else { | 4348 } else { |
| 4264 PushAndAdd(new HGlobalReceiver); | 4349 PushAndAdd(new HGlobalReceiver); |
| 4265 VisitArgumentList(expr->arguments()); | 4350 VisitArgumentList(expr->arguments()); |
| 4266 CHECK_BAILOUT; | 4351 CHECK_BAILOUT; |
| 4267 | 4352 |
| 4268 call = new HCallFunction(argument_count); | 4353 call = new HCallFunction(argument_count); |
| 4269 } | 4354 } |
| 4270 } | 4355 } |
| 4271 | 4356 |
| 4272 ProcessCall(call, expr->position()); | 4357 call->set_position(expr->position()); |
| 4358 ProcessCall(call); |
| 4359 ast_context()->ReturnInstruction(call, expr->id()); |
| 4273 } | 4360 } |
| 4274 | 4361 |
| 4275 | 4362 |
| 4276 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 4363 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 4277 // The constructor function is also used as the receiver argument to the | 4364 // The constructor function is also used as the receiver argument to the |
| 4278 // JS construct call builtin. | 4365 // JS construct call builtin. |
| 4279 VisitArgument(expr->expression()); | 4366 VisitArgument(expr->expression()); |
| 4280 CHECK_BAILOUT; | 4367 CHECK_BAILOUT; |
| 4281 VisitArgumentList(expr->arguments()); | 4368 VisitArgumentList(expr->arguments()); |
| 4282 CHECK_BAILOUT; | 4369 CHECK_BAILOUT; |
| 4283 | 4370 |
| 4284 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 4371 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 4285 HCall* call = new HCallNew(argument_count); | 4372 HCall* call = new HCallNew(argument_count); |
| 4286 | 4373 call->set_position(expr->position()); |
| 4287 ProcessCall(call, expr->position()); | 4374 ProcessCall(call); |
| 4375 ast_context()->ReturnInstruction(call, expr->id()); |
| 4288 } | 4376 } |
| 4289 | 4377 |
| 4290 | 4378 |
| 4291 // Support for generating inlined runtime functions. | 4379 // Support for generating inlined runtime functions. |
| 4292 | 4380 |
| 4293 // Lookup table for generators for runtime calls that are generated inline. | 4381 // Lookup table for generators for runtime calls that are generated inline. |
| 4294 // Elements of the table are member pointers to functions of HGraphBuilder. | 4382 // Elements of the table are member pointers to functions of HGraphBuilder. |
| 4295 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 4383 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 4296 &HGraphBuilder::Generate##Name, | 4384 &HGraphBuilder::Generate##Name, |
| 4297 | 4385 |
| 4298 const HGraphBuilder::InlineFunctionGenerator | 4386 const HGraphBuilder::InlineFunctionGenerator |
| 4299 HGraphBuilder::kInlineFunctionGenerators[] = { | 4387 HGraphBuilder::kInlineFunctionGenerators[] = { |
| 4300 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 4388 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 4301 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 4389 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 4302 }; | 4390 }; |
| 4303 #undef INLINE_FUNCTION_GENERATOR_ADDRESS | 4391 #undef INLINE_FUNCTION_GENERATOR_ADDRESS |
| 4304 | 4392 |
| 4305 | 4393 |
| 4306 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { | 4394 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 4307 Handle<String> name = expr->name(); | 4395 Handle<String> name = expr->name(); |
| 4308 if (name->IsEqualTo(CStrVector("_Log"))) { | 4396 if (name->IsEqualTo(CStrVector("_Log"))) { |
| 4309 Push(graph()->GetConstantUndefined()); | 4397 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4310 return; | 4398 return; |
| 4311 } | 4399 } |
| 4312 | 4400 |
| 4313 const Runtime::Function* function = expr->function(); | 4401 const Runtime::Function* function = expr->function(); |
| 4314 if (expr->is_jsruntime()) { | 4402 if (expr->is_jsruntime()) { |
| 4315 BAILOUT("call to a JavaScript runtime function"); | 4403 BAILOUT("call to a JavaScript runtime function"); |
| 4316 } | 4404 } |
| 4317 ASSERT(function != NULL); | 4405 ASSERT(function != NULL); |
| 4318 | 4406 |
| 4319 VisitArgumentList(expr->arguments()); | 4407 VisitArgumentList(expr->arguments()); |
| 4320 CHECK_BAILOUT; | 4408 CHECK_BAILOUT; |
| 4321 | 4409 |
| 4322 int argument_count = expr->arguments()->length(); | 4410 int argument_count = expr->arguments()->length(); |
| 4323 if (function->intrinsic_type == Runtime::INLINE) { | 4411 if (function->intrinsic_type == Runtime::INLINE) { |
| 4324 ASSERT(name->length() > 0); | 4412 ASSERT(name->length() > 0); |
| 4325 ASSERT(name->Get(0) == '_'); | 4413 ASSERT(name->Get(0) == '_'); |
| 4326 // Call to an inline function. | 4414 // Call to an inline function. |
| 4327 int lookup_index = static_cast<int>(function->function_id) - | 4415 int lookup_index = static_cast<int>(function->function_id) - |
| 4328 static_cast<int>(Runtime::kFirstInlineFunction); | 4416 static_cast<int>(Runtime::kFirstInlineFunction); |
| 4329 ASSERT(lookup_index >= 0); | 4417 ASSERT(lookup_index >= 0); |
| 4330 ASSERT(static_cast<size_t>(lookup_index) < | 4418 ASSERT(static_cast<size_t>(lookup_index) < |
| 4331 ARRAY_SIZE(kInlineFunctionGenerators)); | 4419 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 4332 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 4420 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| 4333 | 4421 |
| 4334 // Call the inline code generator using the pointer-to-member. | 4422 // Call the inline code generator using the pointer-to-member. |
| 4335 (this->*generator)(argument_count); | 4423 (this->*generator)(argument_count, expr->id()); |
| 4336 } else { | 4424 } else { |
| 4337 ASSERT(function->intrinsic_type == Runtime::RUNTIME); | 4425 ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
| 4338 HCall* call = new HCallRuntime(name, expr->function(), argument_count); | 4426 HCall* call = new HCallRuntime(name, expr->function(), argument_count); |
| 4339 ProcessCall(call, RelocInfo::kNoPosition); | 4427 call->set_position(RelocInfo::kNoPosition); |
| 4428 ProcessCall(call); |
| 4429 ast_context()->ReturnInstruction(call, expr->id()); |
| 4340 } | 4430 } |
| 4341 } | 4431 } |
| 4342 | 4432 |
| 4343 | 4433 |
| 4344 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4434 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4345 Token::Value op = expr->op(); | 4435 Token::Value op = expr->op(); |
| 4346 if (op == Token::VOID) { | 4436 if (op == Token::VOID) { |
| 4347 VISIT_FOR_EFFECT(expr->expression()); | 4437 VISIT_FOR_EFFECT(expr->expression()); |
| 4348 Push(graph()->GetConstantUndefined()); | 4438 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4349 } else if (op == Token::DELETE) { | 4439 } else if (op == Token::DELETE) { |
| 4350 Property* prop = expr->expression()->AsProperty(); | 4440 Property* prop = expr->expression()->AsProperty(); |
| 4351 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4441 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4352 if (prop == NULL && var == NULL) { | 4442 if (prop == NULL && var == NULL) { |
| 4353 // Result of deleting non-property, non-variable reference is true. | 4443 // Result of deleting non-property, non-variable reference is true. |
| 4354 // Evaluate the subexpression for side effects. | 4444 // Evaluate the subexpression for side effects. |
| 4355 VISIT_FOR_EFFECT(expr->expression()); | 4445 VISIT_FOR_EFFECT(expr->expression()); |
| 4356 Push(graph_->GetConstantTrue()); | 4446 ast_context()->ReturnValue(graph()->GetConstantTrue()); |
| 4357 } else if (var != NULL && | 4447 } else if (var != NULL && |
| 4358 !var->is_global() && | 4448 !var->is_global() && |
| 4359 var->AsSlot() != NULL && | 4449 var->AsSlot() != NULL && |
| 4360 var->AsSlot()->type() != Slot::LOOKUP) { | 4450 var->AsSlot()->type() != Slot::LOOKUP) { |
| 4361 // Result of deleting non-global, non-dynamic variables is false. | 4451 // Result of deleting non-global, non-dynamic variables is false. |
| 4362 // The subexpression does not have side effects. | 4452 // The subexpression does not have side effects. |
| 4363 Push(graph_->GetConstantFalse()); | 4453 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4364 } else if (prop != NULL) { | 4454 } else if (prop != NULL) { |
| 4365 VISIT_FOR_VALUE(prop->obj()); | 4455 VISIT_FOR_VALUE(prop->obj()); |
| 4366 VISIT_FOR_VALUE(prop->key()); | 4456 VISIT_FOR_VALUE(prop->key()); |
| 4367 HValue* key = Pop(); | 4457 HValue* key = Pop(); |
| 4368 HValue* obj = Pop(); | 4458 HValue* obj = Pop(); |
| 4369 PushAndAdd(new HDeleteProperty(obj, key)); | 4459 ast_context()->ReturnInstruction(new HDeleteProperty(obj, key), |
| 4460 expr->id()); |
| 4370 } else if (var->is_global()) { | 4461 } else if (var->is_global()) { |
| 4371 BAILOUT("delete with global variable"); | 4462 BAILOUT("delete with global variable"); |
| 4372 } else { | 4463 } else { |
| 4373 BAILOUT("delete with non-global variable"); | 4464 BAILOUT("delete with non-global variable"); |
| 4374 } | 4465 } |
| 4375 } else if (op == Token::NOT) { | 4466 } else if (op == Token::NOT) { |
| 4376 HSubgraph* true_graph = CreateEmptySubgraph(); | 4467 if (ast_context()->IsTest()) { |
| 4377 HSubgraph* false_graph = CreateEmptySubgraph(); | 4468 TestContext* context = TestContext::cast(ast_context()); |
| 4378 VisitCondition(expr->expression(), | 4469 VisitForControl(expr->expression(), |
| 4379 false_graph->entry_block(), | 4470 context->if_false(), |
| 4380 true_graph->entry_block(), | 4471 context->if_true()); |
| 4381 true, true); | 4472 } else { |
| 4382 if (HasStackOverflow()) return; | 4473 HSubgraph* true_graph = CreateEmptySubgraph(); |
| 4383 true_graph->environment()->Push(graph_->GetConstantTrue()); | 4474 HSubgraph* false_graph = CreateEmptySubgraph(); |
| 4384 false_graph->environment()->Push(graph_->GetConstantFalse()); | 4475 VISIT_FOR_CONTROL(expr->expression(), |
| 4385 current_subgraph_->AppendJoin(true_graph, false_graph, expr); | 4476 false_graph->entry_block(), |
| 4477 true_graph->entry_block()); |
| 4478 true_graph->entry_block()->SetJoinId(expr->expression()->id()); |
| 4479 true_graph->environment()->Push(graph_->GetConstantTrue()); |
| 4480 |
| 4481 false_graph->entry_block()->SetJoinId(expr->expression()->id()); |
| 4482 false_graph->environment()->Push(graph_->GetConstantFalse()); |
| 4483 |
| 4484 current_subgraph_->AppendJoin(true_graph, false_graph, expr); |
| 4485 ast_context()->ReturnValue(Pop()); |
| 4486 } |
| 4386 } else if (op == Token::BIT_NOT || op == Token::SUB) { | 4487 } else if (op == Token::BIT_NOT || op == Token::SUB) { |
| 4387 VISIT_FOR_VALUE(expr->expression()); | 4488 VISIT_FOR_VALUE(expr->expression()); |
| 4388 HValue* value = Pop(); | 4489 HValue* value = Pop(); |
| 4389 HInstruction* instr = NULL; | 4490 HInstruction* instr = NULL; |
| 4390 switch (op) { | 4491 switch (op) { |
| 4391 case Token::BIT_NOT: | 4492 case Token::BIT_NOT: |
| 4392 instr = new HBitNot(value); | 4493 instr = new HBitNot(value); |
| 4393 break; | 4494 break; |
| 4394 case Token::SUB: | 4495 case Token::SUB: |
| 4395 instr = new HMul(graph_->GetConstantMinus1(), value); | 4496 instr = new HMul(graph_->GetConstantMinus1(), value); |
| 4396 break; | 4497 break; |
| 4397 default: | 4498 default: |
| 4398 UNREACHABLE(); | 4499 UNREACHABLE(); |
| 4399 break; | 4500 break; |
| 4400 } | 4501 } |
| 4401 PushAndAdd(instr); | 4502 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4402 } else if (op == Token::TYPEOF) { | 4503 } else if (op == Token::TYPEOF) { |
| 4403 VISIT_FOR_VALUE(expr->expression()); | 4504 VISIT_FOR_VALUE(expr->expression()); |
| 4404 HValue* value = Pop(); | 4505 HValue* value = Pop(); |
| 4405 PushAndAdd(new HTypeof(value)); | 4506 ast_context()->ReturnInstruction(new HTypeof(value), expr->id()); |
| 4406 } else { | 4507 } else { |
| 4407 BAILOUT("Value: unsupported unary operation"); | 4508 BAILOUT("Value: unsupported unary operation"); |
| 4408 } | 4509 } |
| 4409 } | 4510 } |
| 4410 | 4511 |
| 4411 | 4512 |
| 4412 void HGraphBuilder::VisitIncrementOperation(IncrementOperation* expr) { | 4513 void HGraphBuilder::VisitIncrementOperation(IncrementOperation* expr) { |
| 4413 // IncrementOperation is never visited by the visitor. It only | 4514 // IncrementOperation is never visited by the visitor. It only |
| 4414 // occurs as a subexpression of CountOperation. | 4515 // occurs as a subexpression of CountOperation. |
| 4415 UNREACHABLE(); | 4516 UNREACHABLE(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 4435 ASSERT(var == NULL || prop == NULL); | 4536 ASSERT(var == NULL || prop == NULL); |
| 4436 bool inc = expr->op() == Token::INC; | 4537 bool inc = expr->op() == Token::INC; |
| 4437 | 4538 |
| 4438 if (var != NULL) { | 4539 if (var != NULL) { |
| 4439 if (!var->is_global() && !var->IsStackAllocated()) { | 4540 if (!var->is_global() && !var->IsStackAllocated()) { |
| 4440 BAILOUT("non-stack/non-global variable in count operation"); | 4541 BAILOUT("non-stack/non-global variable in count operation"); |
| 4441 } | 4542 } |
| 4442 | 4543 |
| 4443 VISIT_FOR_VALUE(target); | 4544 VISIT_FOR_VALUE(target); |
| 4444 | 4545 |
| 4445 HValue* value = Pop(); | 4546 // Match the full code generator stack by simulating an extra stack |
| 4446 HInstruction* instr = BuildIncrement(value, inc); | 4547 // element for postfix operations in a non-effect context. |
| 4447 AddInstruction(instr); | 4548 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
| 4448 | 4549 HValue* before = has_extra ? Top() : Pop(); |
| 4449 if (expr->is_prefix()) { | 4550 HInstruction* after = BuildIncrement(before, inc); |
| 4450 Push(instr); | 4551 AddInstruction(after); |
| 4451 } else { | 4552 Push(after); |
| 4452 Push(value); | |
| 4453 } | |
| 4454 | 4553 |
| 4455 if (var->is_global()) { | 4554 if (var->is_global()) { |
| 4456 HandleGlobalVariableAssignment(proxy, instr, expr->position()); | 4555 HandleGlobalVariableAssignment(var, |
| 4556 after, |
| 4557 expr->position(), |
| 4558 expr->AssignmentId()); |
| 4457 } else { | 4559 } else { |
| 4458 ASSERT(var->IsStackAllocated()); | 4560 ASSERT(var->IsStackAllocated()); |
| 4459 Bind(var, instr); | 4561 Bind(var, after); |
| 4460 } | 4562 } |
| 4563 Drop(has_extra ? 2 : 1); |
| 4564 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4461 | 4565 |
| 4462 } else if (prop != NULL) { | 4566 } else if (prop != NULL) { |
| 4463 prop->RecordTypeFeedback(oracle()); | 4567 prop->RecordTypeFeedback(oracle()); |
| 4464 | 4568 |
| 4465 if (prop->key()->IsPropertyName()) { | 4569 if (prop->key()->IsPropertyName()) { |
| 4466 // Named property. | 4570 // Named property. |
| 4467 | 4571 |
| 4468 // Match the full code generator stack by simulate an extra stack element | 4572 // Match the full code generator stack by simulating an extra stack |
| 4469 // for postfix operations in a value context. | 4573 // element for postfix operations in a non-effect context. |
| 4470 if (expr->is_postfix() && !ast_context()->IsEffect()) { | 4574 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
| 4471 Push(graph_->GetConstantUndefined()); | 4575 if (has_extra) Push(graph_->GetConstantUndefined()); |
| 4472 } | |
| 4473 | 4576 |
| 4474 VISIT_FOR_VALUE(prop->obj()); | 4577 VISIT_FOR_VALUE(prop->obj()); |
| 4475 HValue* obj = Top(); | 4578 HValue* obj = Top(); |
| 4476 | 4579 |
| 4477 HInstruction* load = NULL; | 4580 HInstruction* load = NULL; |
| 4478 if (prop->IsMonomorphic()) { | 4581 if (prop->IsMonomorphic()) { |
| 4479 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4582 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4480 Handle<Map> map = prop->GetReceiverTypes()->first(); | 4583 Handle<Map> map = prop->GetReceiverTypes()->first(); |
| 4481 load = BuildLoadNamed(obj, prop, map, name); | 4584 load = BuildLoadNamed(obj, prop, map, name); |
| 4482 } else { | 4585 } else { |
| 4483 load = BuildLoadNamedGeneric(obj, prop); | 4586 load = BuildLoadNamedGeneric(obj, prop); |
| 4484 } | 4587 } |
| 4485 PushAndAdd(load); | 4588 PushAndAdd(load); |
| 4486 if (load->HasSideEffects()) AddSimulate(increment->id()); | 4589 if (load->HasSideEffects()) AddSimulate(increment->id()); |
| 4487 | 4590 |
| 4488 HValue* value = Pop(); | 4591 HValue* before = Pop(); |
| 4592 // There is no deoptimization to after the increment, so we don't need |
| 4593 // to simulate the expression stack after this instruction. |
| 4594 HInstruction* after = BuildIncrement(before, inc); |
| 4595 AddInstruction(after); |
| 4489 | 4596 |
| 4490 HInstruction* instr = BuildIncrement(value, inc); | 4597 HInstruction* store = BuildStoreNamed(obj, after, prop); |
| 4491 AddInstruction(instr); | |
| 4492 | |
| 4493 HInstruction* store = BuildStoreNamed(obj, instr, prop); | |
| 4494 AddInstruction(store); | 4598 AddInstruction(store); |
| 4495 | 4599 |
| 4496 // Drop simulated receiver and push the result. | 4600 // Overwrite the receiver in the bailout environment with the result |
| 4497 // There is no deoptimization to after the increment, so we can simulate | 4601 // of the operation, and the placeholder with the original value if |
| 4498 // the expression stack here. | 4602 // necessary. |
| 4499 Drop(1); | 4603 environment()->SetExpressionStackAt(0, after); |
| 4500 if (expr->is_prefix()) { | 4604 if (has_extra) environment()->SetExpressionStackAt(1, before); |
| 4501 Push(instr); | 4605 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4502 } else { | 4606 Drop(has_extra ? 2 : 1); |
| 4503 if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. | 4607 |
| 4504 Push(value); | 4608 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4505 } | |
| 4506 | 4609 |
| 4507 } else { | 4610 } else { |
| 4508 // Keyed property. | 4611 // Keyed property. |
| 4509 | 4612 |
| 4510 // 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 |
| 4511 // for postfix operations in a value context. | 4614 // for postfix operations in a non-effect context. |
| 4512 if (expr->is_postfix() && !ast_context()->IsEffect()) { | 4615 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); |
| 4513 Push(graph_->GetConstantUndefined()); | 4616 if (has_extra) Push(graph_->GetConstantUndefined()); |
| 4514 } | |
| 4515 | 4617 |
| 4516 VISIT_FOR_VALUE(prop->obj()); | 4618 VISIT_FOR_VALUE(prop->obj()); |
| 4517 VISIT_FOR_VALUE(prop->key()); | 4619 VISIT_FOR_VALUE(prop->key()); |
| 4518 | |
| 4519 HValue* obj = environment()->ExpressionStackAt(1); | 4620 HValue* obj = environment()->ExpressionStackAt(1); |
| 4520 HValue* key = environment()->ExpressionStackAt(0); | 4621 HValue* key = environment()->ExpressionStackAt(0); |
| 4521 | 4622 |
| 4522 bool is_fast_elements = prop->IsMonomorphic() && | 4623 bool is_fast_elements = prop->IsMonomorphic() && |
| 4523 prop->GetMonomorphicReceiverType()->has_fast_elements(); | 4624 prop->GetMonomorphicReceiverType()->has_fast_elements(); |
| 4524 | 4625 |
| 4525 HInstruction* load = is_fast_elements | 4626 HInstruction* load = is_fast_elements |
| 4526 ? BuildLoadKeyedFastElement(obj, key, prop) | 4627 ? BuildLoadKeyedFastElement(obj, key, prop) |
| 4527 : BuildLoadKeyedGeneric(obj, key); | 4628 : BuildLoadKeyedGeneric(obj, key); |
| 4528 PushAndAdd(load); | 4629 PushAndAdd(load); |
| 4529 if (load->HasSideEffects()) AddSimulate(increment->id()); | 4630 if (load->HasSideEffects()) AddSimulate(increment->id()); |
| 4530 | 4631 |
| 4531 HValue* value = Pop(); | 4632 HValue* before = Pop(); |
| 4532 | 4633 // There is no deoptimization to after the increment, so we don't need |
| 4533 HInstruction* instr = BuildIncrement(value, inc); | 4634 // to simulate the expression stack after this instruction. |
| 4534 AddInstruction(instr); | 4635 HInstruction* after = BuildIncrement(before, inc); |
| 4636 AddInstruction(after); |
| 4535 | 4637 |
| 4536 HInstruction* store = is_fast_elements | 4638 HInstruction* store = is_fast_elements |
| 4537 ? BuildStoreKeyedFastElement(obj, key, instr, prop) | 4639 ? BuildStoreKeyedFastElement(obj, key, after, prop) |
| 4538 : new HStoreKeyedGeneric(obj, key, instr); | 4640 : new HStoreKeyedGeneric(obj, key, after); |
| 4539 AddInstruction(store); | 4641 AddInstruction(store); |
| 4540 | 4642 |
| 4541 // Drop simulated receiver and key and push the result. | 4643 // Drop the key from the bailout environment. Overwrite the receiver |
| 4542 // There is no deoptimization to after the increment, so we can simulate | 4644 // with the result of the operation, and the placeholder with the |
| 4543 // the expression stack here. | 4645 // original value if necessary. |
| 4544 Drop(2); | 4646 Drop(1); |
| 4545 if (expr->is_prefix()) { | 4647 environment()->SetExpressionStackAt(0, after); |
| 4546 Push(instr); | 4648 if (has_extra) environment()->SetExpressionStackAt(1, before); |
| 4547 } else { | 4649 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| 4548 if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. | 4650 Drop(has_extra ? 2 : 1); |
| 4549 Push(value); | 4651 |
| 4550 } | 4652 ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
| 4551 } | 4653 } |
| 4654 |
| 4552 } else { | 4655 } else { |
| 4553 BAILOUT("invalid lhs in count operation"); | 4656 BAILOUT("invalid lhs in count operation"); |
| 4554 } | 4657 } |
| 4555 } | 4658 } |
| 4556 | 4659 |
| 4557 | 4660 |
| 4558 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 4661 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4559 HValue* left, | 4662 HValue* left, |
| 4560 HValue* right) { | 4663 HValue* right) { |
| 4561 HInstruction* instr = NULL; | 4664 HInstruction* instr = NULL; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4623 if (!literal->handle()->IsString()) return false; | 4726 if (!literal->handle()->IsString()) return false; |
| 4624 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; | 4727 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; |
| 4625 ASSERT(call->arguments()->length() == 1); | 4728 ASSERT(call->arguments()->length() == 1); |
| 4626 return true; | 4729 return true; |
| 4627 } | 4730 } |
| 4628 | 4731 |
| 4629 | 4732 |
| 4630 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { | 4733 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
| 4631 if (expr->op() == Token::COMMA) { | 4734 if (expr->op() == Token::COMMA) { |
| 4632 VISIT_FOR_EFFECT(expr->left()); | 4735 VISIT_FOR_EFFECT(expr->left()); |
| 4633 VISIT_FOR_VALUE(expr->right()); | 4736 // Visit the right subexpression in the same AST context as the entire |
| 4737 // expression. |
| 4738 Visit(expr->right()); |
| 4739 |
| 4634 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { | 4740 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { |
| 4635 VISIT_FOR_VALUE(expr->left()); | 4741 bool is_logical_and = (expr->op() == Token::AND); |
| 4636 ASSERT(current_subgraph_->HasExit()); | 4742 if (ast_context()->IsTest()) { |
| 4743 TestContext* context = TestContext::cast(ast_context()); |
| 4744 // Translate left subexpression. |
| 4745 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 4746 if (is_logical_and) { |
| 4747 VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false()); |
| 4748 } else { |
| 4749 VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right); |
| 4750 } |
| 4751 eval_right->SetJoinId(expr->RightId()); |
| 4637 | 4752 |
| 4638 HValue* left = Top(); | 4753 // Translate right subexpression by visiting it in the same AST |
| 4639 bool is_logical_and = (expr->op() == Token::AND); | 4754 // context as the entire expression. |
| 4755 subgraph()->set_exit_block(eval_right); |
| 4756 Visit(expr->right()); |
| 4640 | 4757 |
| 4641 HEnvironment* environment_copy = environment()->Copy(); | 4758 } else { |
| 4642 environment_copy->Pop(); | 4759 VISIT_FOR_VALUE(expr->left()); |
| 4643 HSubgraph* right_subgraph; | 4760 ASSERT(current_subgraph_->HasExit()); |
| 4644 right_subgraph = CreateBranchSubgraph(environment_copy); | 4761 |
| 4645 ADD_TO_SUBGRAPH(right_subgraph, expr->right()); | 4762 HValue* left = Top(); |
| 4646 current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); | 4763 HEnvironment* environment_copy = environment()->Copy(); |
| 4647 current_subgraph_->exit_block()->SetJoinId(expr->id()); | 4764 environment_copy->Pop(); |
| 4765 HSubgraph* right_subgraph; |
| 4766 right_subgraph = CreateBranchSubgraph(environment_copy); |
| 4767 ADD_TO_SUBGRAPH(right_subgraph, expr->right()); |
| 4768 current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); |
| 4769 current_subgraph_->exit_block()->SetJoinId(expr->id()); |
| 4770 ast_context()->ReturnValue(Pop()); |
| 4771 } |
| 4772 |
| 4648 } else { | 4773 } else { |
| 4649 VISIT_FOR_VALUE(expr->left()); | 4774 VISIT_FOR_VALUE(expr->left()); |
| 4650 VISIT_FOR_VALUE(expr->right()); | 4775 VISIT_FOR_VALUE(expr->right()); |
| 4651 | 4776 |
| 4652 HValue* right = Pop(); | 4777 HValue* right = Pop(); |
| 4653 HValue* left = Pop(); | 4778 HValue* left = Pop(); |
| 4654 HInstruction* instr = BuildBinaryOperation(expr, left, right); | 4779 HInstruction* instr = BuildBinaryOperation(expr, left, right); |
| 4655 PushAndAdd(instr, expr->position()); | 4780 instr->set_position(expr->position()); |
| 4781 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4656 } | 4782 } |
| 4657 } | 4783 } |
| 4658 | 4784 |
| 4659 | 4785 |
| 4660 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { | 4786 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { |
| 4661 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { | 4787 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { |
| 4662 if (FLAG_trace_representation) { | 4788 if (FLAG_trace_representation) { |
| 4663 PrintF("Assume representation for %s to be %s (%d)\n", | 4789 PrintF("Assume representation for %s to be %s (%d)\n", |
| 4664 value->Mnemonic(), | 4790 value->Mnemonic(), |
| 4665 r.Mnemonic(), | 4791 r.Mnemonic(), |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4684 | 4810 |
| 4685 | 4811 |
| 4686 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 4812 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 4687 if (IsClassOfTest(expr)) { | 4813 if (IsClassOfTest(expr)) { |
| 4688 CallRuntime* call = expr->left()->AsCallRuntime(); | 4814 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 4689 VISIT_FOR_VALUE(call->arguments()->at(0)); | 4815 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 4690 HValue* value = Pop(); | 4816 HValue* value = Pop(); |
| 4691 Literal* literal = expr->right()->AsLiteral(); | 4817 Literal* literal = expr->right()->AsLiteral(); |
| 4692 Handle<String> rhs = Handle<String>::cast(literal->handle()); | 4818 Handle<String> rhs = Handle<String>::cast(literal->handle()); |
| 4693 HInstruction* instr = new HClassOfTest(value, rhs); | 4819 HInstruction* instr = new HClassOfTest(value, rhs); |
| 4694 PushAndAdd(instr, expr->position()); | 4820 instr->set_position(expr->position()); |
| 4821 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4695 return; | 4822 return; |
| 4696 } | 4823 } |
| 4697 | 4824 |
| 4698 // Check for the pattern: typeof <expression> == <string literal>. | 4825 // Check for the pattern: typeof <expression> == <string literal>. |
| 4699 UnaryOperation* left_unary = expr->left()->AsUnaryOperation(); | 4826 UnaryOperation* left_unary = expr->left()->AsUnaryOperation(); |
| 4700 Literal* right_literal = expr->right()->AsLiteral(); | 4827 Literal* right_literal = expr->right()->AsLiteral(); |
| 4701 if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) && | 4828 if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) && |
| 4702 left_unary != NULL && left_unary->op() == Token::TYPEOF && | 4829 left_unary != NULL && left_unary->op() == Token::TYPEOF && |
| 4703 right_literal != NULL && right_literal->handle()->IsString()) { | 4830 right_literal != NULL && right_literal->handle()->IsString()) { |
| 4704 VISIT_FOR_VALUE(left_unary->expression()); | 4831 VISIT_FOR_VALUE(left_unary->expression()); |
| 4705 HValue* left = Pop(); | 4832 HValue* left = Pop(); |
| 4706 HInstruction* instr = new HTypeofIs(left, | 4833 HInstruction* instr = new HTypeofIs(left, |
| 4707 Handle<String>::cast(right_literal->handle())); | 4834 Handle<String>::cast(right_literal->handle())); |
| 4708 PushAndAdd(instr, expr->position()); | 4835 instr->set_position(expr->position()); |
| 4836 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4709 return; | 4837 return; |
| 4710 } | 4838 } |
| 4711 | 4839 |
| 4712 VISIT_FOR_VALUE(expr->left()); | 4840 VISIT_FOR_VALUE(expr->left()); |
| 4713 VISIT_FOR_VALUE(expr->right()); | 4841 VISIT_FOR_VALUE(expr->right()); |
| 4714 | 4842 |
| 4715 HValue* right = Pop(); | 4843 HValue* right = Pop(); |
| 4716 HValue* left = Pop(); | 4844 HValue* left = Pop(); |
| 4717 Token::Value op = expr->op(); | 4845 Token::Value op = expr->op(); |
| 4718 | 4846 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 4734 default: | 4862 default: |
| 4735 BAILOUT("Unsupported non-primitive compare"); | 4863 BAILOUT("Unsupported non-primitive compare"); |
| 4736 break; | 4864 break; |
| 4737 } | 4865 } |
| 4738 } else { | 4866 } else { |
| 4739 HCompare* compare = new HCompare(left, right, op); | 4867 HCompare* compare = new HCompare(left, right, op); |
| 4740 Representation r = ToRepresentation(info); | 4868 Representation r = ToRepresentation(info); |
| 4741 compare->SetInputRepresentation(r); | 4869 compare->SetInputRepresentation(r); |
| 4742 instr = compare; | 4870 instr = compare; |
| 4743 } | 4871 } |
| 4744 PushAndAdd(instr, expr->position()); | 4872 instr->set_position(expr->position()); |
| 4873 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4745 } | 4874 } |
| 4746 | 4875 |
| 4747 | 4876 |
| 4748 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { | 4877 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { |
| 4749 VISIT_FOR_VALUE(expr->expression()); | 4878 VISIT_FOR_VALUE(expr->expression()); |
| 4750 | 4879 |
| 4751 HValue* value = Pop(); | 4880 HValue* value = Pop(); |
| 4752 HIsNull* compare = new HIsNull(value, expr->is_strict()); | 4881 HIsNull* compare = new HIsNull(value, expr->is_strict()); |
| 4753 | 4882 ast_context()->ReturnInstruction(compare, expr->id()); |
| 4754 PushAndAdd(compare); | |
| 4755 } | 4883 } |
| 4756 | 4884 |
| 4757 | 4885 |
| 4758 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { | 4886 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
| 4759 BAILOUT("ThisFunction"); | 4887 BAILOUT("ThisFunction"); |
| 4760 } | 4888 } |
| 4761 | 4889 |
| 4762 | 4890 |
| 4763 void HGraphBuilder::VisitDeclaration(Declaration* decl) { | 4891 void HGraphBuilder::VisitDeclaration(Declaration* decl) { |
| 4764 // We allow only declarations that do not require code generation. | 4892 // We allow only declarations that do not require code generation. |
| 4765 // The following all require code generation: global variables and | 4893 // The following all require code generation: global variables and |
| 4766 // functions, variables with slot type LOOKUP, declarations with | 4894 // functions, variables with slot type LOOKUP, declarations with |
| 4767 // mode CONST, and functions. | 4895 // mode CONST, and functions. |
| 4768 Variable* var = decl->proxy()->var(); | 4896 Variable* var = decl->proxy()->var(); |
| 4769 Slot* slot = var->AsSlot(); | 4897 Slot* slot = var->AsSlot(); |
| 4770 if (var->is_global() || | 4898 if (var->is_global() || |
| 4771 (slot != NULL && slot->type() == Slot::LOOKUP) || | 4899 (slot != NULL && slot->type() == Slot::LOOKUP) || |
| 4772 decl->mode() == Variable::CONST || | 4900 decl->mode() == Variable::CONST || |
| 4773 decl->fun() != NULL) { | 4901 decl->fun() != NULL) { |
| 4774 BAILOUT("unsupported declaration"); | 4902 BAILOUT("unsupported declaration"); |
| 4775 } | 4903 } |
| 4776 } | 4904 } |
| 4777 | 4905 |
| 4778 | 4906 |
| 4779 // Generators for inline runtime functions. | 4907 // Generators for inline runtime functions. |
| 4780 // Support for types. | 4908 // Support for types. |
| 4781 void HGraphBuilder::GenerateIsSmi(int argument_count) { | 4909 void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) { |
| 4782 ASSERT(argument_count == 1); | 4910 ASSERT(argument_count == 1); |
| 4783 | 4911 HValue* value = Pop(); |
| 4784 HValue* value = Pop(); | 4912 HIsSmi* result = new HIsSmi(value); |
| 4785 PushAndAdd(new HIsSmi(value)); | 4913 ast_context()->ReturnInstruction(result, ast_id); |
| 4786 } | 4914 } |
| 4787 | 4915 |
| 4788 | 4916 |
| 4789 void HGraphBuilder::GenerateIsSpecObject(int argument_count) { | 4917 void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) { |
| 4790 ASSERT(argument_count == 1); | 4918 ASSERT(argument_count == 1); |
| 4791 | 4919 HValue* value = Pop(); |
| 4792 HValue* value = Pop(); | 4920 HHasInstanceType* result = |
| 4793 HHasInstanceType* test = | |
| 4794 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); | 4921 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); |
| 4795 PushAndAdd(test); | 4922 ast_context()->ReturnInstruction(result, ast_id); |
| 4796 } | 4923 } |
| 4797 | 4924 |
| 4798 | 4925 |
| 4799 void HGraphBuilder::GenerateIsFunction(int argument_count) { | 4926 void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) { |
| 4800 ASSERT(argument_count == 1); | 4927 ASSERT(argument_count == 1); |
| 4801 | 4928 HValue* value = Pop(); |
| 4802 HValue* value = Pop(); | 4929 HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); |
| 4803 HHasInstanceType* test = | 4930 ast_context()->ReturnInstruction(result, ast_id); |
| 4804 new HHasInstanceType(value, JS_FUNCTION_TYPE); | 4931 } |
| 4805 PushAndAdd(test); | 4932 |
| 4806 } | 4933 |
| 4807 | 4934 void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count, |
| 4808 | 4935 int ast_id) { |
| 4809 void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count) { | 4936 ASSERT(argument_count == 1); |
| 4810 ASSERT(argument_count == 1); | 4937 HValue* value = Pop(); |
| 4811 | 4938 HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); |
| 4812 HValue* value = Pop(); | 4939 ast_context()->ReturnInstruction(result, ast_id); |
| 4813 HHasCachedArrayIndex* spec_test = new HHasCachedArrayIndex(value); | 4940 } |
| 4814 PushAndAdd(spec_test); | 4941 |
| 4815 } | 4942 |
| 4816 | 4943 void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) { |
| 4817 | 4944 ASSERT(argument_count == 1); |
| 4818 void HGraphBuilder::GenerateIsArray(int argument_count) { | 4945 HValue* value = Pop(); |
| 4819 ASSERT(argument_count == 1); | 4946 HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); |
| 4820 | 4947 ast_context()->ReturnInstruction(result, ast_id); |
| 4821 HValue* value = Pop(); | 4948 } |
| 4822 HHasInstanceType* test = | 4949 |
| 4823 new HHasInstanceType(value, JS_ARRAY_TYPE); | 4950 |
| 4824 PushAndAdd(test); | 4951 void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { |
| 4825 } | 4952 ASSERT(argument_count == 1); |
| 4826 | 4953 HValue* value = Pop(); |
| 4827 | 4954 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); |
| 4828 void HGraphBuilder::GenerateIsRegExp(int argument_count) { | 4955 ast_context()->ReturnInstruction(result, ast_id); |
| 4829 ASSERT(argument_count == 1); | 4956 } |
| 4830 | 4957 |
| 4831 HValue* value = Pop(); | 4958 |
| 4832 HHasInstanceType* test = | 4959 void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { |
| 4833 new HHasInstanceType(value, JS_REGEXP_TYPE); | 4960 ASSERT(argument_count == 1); |
| 4834 PushAndAdd(test); | 4961 |
| 4835 } | 4962 HValue* value = Pop(); |
| 4836 | 4963 HIsObject* test = new HIsObject(value); |
| 4837 | 4964 ast_context()->ReturnInstruction(test, ast_id); |
| 4838 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count) { | 4965 } |
| 4966 |
| 4967 |
| 4968 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, |
| 4969 int ast_id) { |
| 4839 BAILOUT("inlined runtime function: IsNonNegativeSmi"); | 4970 BAILOUT("inlined runtime function: IsNonNegativeSmi"); |
| 4840 } | 4971 } |
| 4841 | 4972 |
| 4842 | 4973 |
| 4843 void HGraphBuilder::GenerateIsObject(int argument_count) { | 4974 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, |
| 4844 BAILOUT("inlined runtime function: IsObject"); | 4975 int ast_id) { |
| 4845 } | |
| 4846 | |
| 4847 | |
| 4848 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count) { | |
| 4849 BAILOUT("inlined runtime function: IsUndetectableObject"); | 4976 BAILOUT("inlined runtime function: IsUndetectableObject"); |
| 4850 } | 4977 } |
| 4851 | 4978 |
| 4852 | 4979 |
| 4853 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 4980 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 4854 int argument_count) { | 4981 int argument_count, |
| 4982 int ast_id) { |
| 4855 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 4983 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 4856 } | 4984 } |
| 4857 | 4985 |
| 4858 | 4986 |
| 4859 // Support for construct call checks. | 4987 // Support for construct call checks. |
| 4860 void HGraphBuilder::GenerateIsConstructCall(int argument_count) { | 4988 void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { |
| 4861 BAILOUT("inlined runtime function: IsConstructCall"); | 4989 BAILOUT("inlined runtime function: IsConstructCall"); |
| 4862 } | 4990 } |
| 4863 | 4991 |
| 4864 | 4992 |
| 4865 // Support for arguments.length and arguments[?]. | 4993 // Support for arguments.length and arguments[?]. |
| 4866 void HGraphBuilder::GenerateArgumentsLength(int argument_count) { | 4994 void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { |
| 4867 ASSERT(argument_count == 0); | 4995 ASSERT(argument_count == 0); |
| 4868 HInstruction* elements = AddInstruction(new HArgumentsElements); | 4996 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4869 PushAndAdd(new HArgumentsLength(elements)); | 4997 HArgumentsLength* result = new HArgumentsLength(elements); |
| 4870 } | 4998 ast_context()->ReturnInstruction(result, ast_id); |
| 4871 | 4999 } |
| 4872 | 5000 |
| 4873 void HGraphBuilder::GenerateArguments(int argument_count) { | 5001 |
| 5002 void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) { |
| 4874 ASSERT(argument_count == 1); | 5003 ASSERT(argument_count == 1); |
| 4875 HValue* index = Pop(); | 5004 HValue* index = Pop(); |
| 4876 HInstruction* elements = AddInstruction(new HArgumentsElements); | 5005 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4877 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 5006 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 4878 PushAndAdd(new HAccessArgumentsAt(elements, length, index)); | 5007 HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); |
| 5008 ast_context()->ReturnInstruction(result, ast_id); |
| 4879 } | 5009 } |
| 4880 | 5010 |
| 4881 | 5011 |
| 4882 // Support for accessing the class and value fields of an object. | 5012 // Support for accessing the class and value fields of an object. |
| 4883 void HGraphBuilder::GenerateClassOf(int argument_count) { | 5013 void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) { |
| 4884 // The special form detected by IsClassOfTest is detected before we get here | 5014 // The special form detected by IsClassOfTest is detected before we get here |
| 4885 // and does not cause a bailout. | 5015 // and does not cause a bailout. |
| 4886 BAILOUT("inlined runtime function: ClassOf"); | 5016 BAILOUT("inlined runtime function: ClassOf"); |
| 4887 } | 5017 } |
| 4888 | 5018 |
| 4889 | 5019 |
| 4890 void HGraphBuilder::GenerateValueOf(int argument_count) { | 5020 void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) { |
| 4891 ASSERT(argument_count == 1); | 5021 ASSERT(argument_count == 1); |
| 4892 | 5022 HValue* value = Pop(); |
| 4893 HValue* value = Pop(); | 5023 HValueOf* result = new HValueOf(value); |
| 4894 HValueOf* op = new HValueOf(value); | 5024 ast_context()->ReturnInstruction(result, ast_id); |
| 4895 PushAndAdd(op); | 5025 } |
| 4896 } | 5026 |
| 4897 | 5027 |
| 4898 | 5028 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { |
| 4899 void HGraphBuilder::GenerateSetValueOf(int argument_count) { | |
| 4900 BAILOUT("inlined runtime function: SetValueOf"); | 5029 BAILOUT("inlined runtime function: SetValueOf"); |
| 4901 } | 5030 } |
| 4902 | 5031 |
| 4903 | 5032 |
| 4904 // Fast support for charCodeAt(n). | 5033 // Fast support for charCodeAt(n). |
| 4905 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count) { | 5034 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { |
| 4906 BAILOUT("inlined runtime function: StringCharCodeAt"); | 5035 BAILOUT("inlined runtime function: StringCharCodeAt"); |
| 4907 } | 5036 } |
| 4908 | 5037 |
| 4909 | 5038 |
| 4910 // Fast support for string.charAt(n) and string[n]. | 5039 // Fast support for string.charAt(n) and string[n]. |
| 4911 void HGraphBuilder::GenerateStringCharFromCode(int argument_count) { | 5040 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, |
| 5041 int ast_id) { |
| 4912 BAILOUT("inlined runtime function: StringCharFromCode"); | 5042 BAILOUT("inlined runtime function: StringCharFromCode"); |
| 4913 } | 5043 } |
| 4914 | 5044 |
| 4915 | 5045 |
| 4916 // Fast support for string.charAt(n) and string[n]. | 5046 // Fast support for string.charAt(n) and string[n]. |
| 4917 void HGraphBuilder::GenerateStringCharAt(int argument_count) { | 5047 void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { |
| 4918 ASSERT_EQ(2, argument_count); | 5048 ASSERT_EQ(2, argument_count); |
| 4919 PushArgumentsForStubCall(argument_count); | 5049 PushArgumentsForStubCall(argument_count); |
| 4920 PushAndAdd(new HCallStub(CodeStub::StringCharAt, argument_count), | 5050 HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count); |
| 4921 RelocInfo::kNoPosition); | 5051 ast_context()->ReturnInstruction(result, ast_id); |
| 4922 } | 5052 } |
| 4923 | 5053 |
| 4924 | 5054 |
| 4925 // Fast support for object equality testing. | 5055 // Fast support for object equality testing. |
| 4926 void HGraphBuilder::GenerateObjectEquals(int argument_count) { | 5056 void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { |
| 4927 ASSERT(argument_count == 2); | 5057 ASSERT(argument_count == 2); |
| 4928 | |
| 4929 HValue* right = Pop(); | 5058 HValue* right = Pop(); |
| 4930 HValue* left = Pop(); | 5059 HValue* left = Pop(); |
| 4931 PushAndAdd(new HCompareJSObjectEq(left, right)); | 5060 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); |
| 4932 } | 5061 ast_context()->ReturnInstruction(result, ast_id); |
| 4933 | 5062 } |
| 4934 | 5063 |
| 4935 void HGraphBuilder::GenerateLog(int argument_count) { | 5064 |
| 5065 void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { |
| 4936 UNREACHABLE(); // We caught this in VisitCallRuntime. | 5066 UNREACHABLE(); // We caught this in VisitCallRuntime. |
| 4937 } | 5067 } |
| 4938 | 5068 |
| 4939 | 5069 |
| 4940 // Fast support for Math.random(). | 5070 // Fast support for Math.random(). |
| 4941 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count) { | 5071 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { |
| 4942 BAILOUT("inlined runtime function: RandomHeapNumber"); | 5072 BAILOUT("inlined runtime function: RandomHeapNumber"); |
| 4943 } | 5073 } |
| 4944 | 5074 |
| 4945 | 5075 |
| 4946 // Fast support for StringAdd. | 5076 // Fast support for StringAdd. |
| 4947 void HGraphBuilder::GenerateStringAdd(int argument_count) { | 5077 void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { |
| 4948 ASSERT_EQ(2, argument_count); | 5078 ASSERT_EQ(2, argument_count); |
| 4949 PushArgumentsForStubCall(argument_count); | 5079 PushArgumentsForStubCall(argument_count); |
| 4950 PushAndAdd(new HCallStub(CodeStub::StringAdd, argument_count), | 5080 HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count); |
| 4951 RelocInfo::kNoPosition); | 5081 ast_context()->ReturnInstruction(result, ast_id); |
| 4952 } | 5082 } |
| 4953 | 5083 |
| 4954 | 5084 |
| 4955 // Fast support for SubString. | 5085 // Fast support for SubString. |
| 4956 void HGraphBuilder::GenerateSubString(int argument_count) { | 5086 void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { |
| 4957 ASSERT_EQ(3, argument_count); | 5087 ASSERT_EQ(3, argument_count); |
| 4958 PushArgumentsForStubCall(argument_count); | 5088 PushArgumentsForStubCall(argument_count); |
| 4959 PushAndAdd(new HCallStub(CodeStub::SubString, argument_count), | 5089 HCallStub* result = new HCallStub(CodeStub::SubString, argument_count); |
| 4960 RelocInfo::kNoPosition); | 5090 ast_context()->ReturnInstruction(result, ast_id); |
| 4961 } | 5091 } |
| 4962 | 5092 |
| 4963 | 5093 |
| 4964 // Fast support for StringCompare. | 5094 // Fast support for StringCompare. |
| 4965 void HGraphBuilder::GenerateStringCompare(int argument_count) { | 5095 void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { |
| 4966 ASSERT_EQ(2, argument_count); | 5096 ASSERT_EQ(2, argument_count); |
| 4967 PushArgumentsForStubCall(argument_count); | 5097 PushArgumentsForStubCall(argument_count); |
| 4968 PushAndAdd(new HCallStub(CodeStub::StringCompare, argument_count), | 5098 HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count); |
| 4969 RelocInfo::kNoPosition); | 5099 ast_context()->ReturnInstruction(result, ast_id); |
| 4970 } | 5100 } |
| 4971 | 5101 |
| 4972 | 5102 |
| 4973 // Support for direct calls from JavaScript to native RegExp code. | 5103 // Support for direct calls from JavaScript to native RegExp code. |
| 4974 void HGraphBuilder::GenerateRegExpExec(int argument_count) { | 5104 void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { |
| 4975 ASSERT_EQ(4, argument_count); | 5105 ASSERT_EQ(4, argument_count); |
| 4976 PushArgumentsForStubCall(argument_count); | 5106 PushArgumentsForStubCall(argument_count); |
| 4977 PushAndAdd(new HCallStub(CodeStub::RegExpExec, argument_count), | 5107 HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count); |
| 4978 RelocInfo::kNoPosition); | 5108 ast_context()->ReturnInstruction(result, ast_id); |
| 4979 } | 5109 } |
| 4980 | 5110 |
| 4981 | 5111 |
| 4982 // Construct a RegExp exec result with two in-object properties. | 5112 // Construct a RegExp exec result with two in-object properties. |
| 4983 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count) { | 5113 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, |
| 5114 int ast_id) { |
| 4984 ASSERT_EQ(3, argument_count); | 5115 ASSERT_EQ(3, argument_count); |
| 4985 PushArgumentsForStubCall(argument_count); | 5116 PushArgumentsForStubCall(argument_count); |
| 4986 PushAndAdd(new HCallStub(CodeStub::RegExpConstructResult, argument_count), | 5117 HCallStub* result = |
| 4987 RelocInfo::kNoPosition); | 5118 new HCallStub(CodeStub::RegExpConstructResult, argument_count); |
| 5119 ast_context()->ReturnInstruction(result, ast_id); |
| 4988 } | 5120 } |
| 4989 | 5121 |
| 4990 | 5122 |
| 4991 // Support for fast native caches. | 5123 // Support for fast native caches. |
| 4992 void HGraphBuilder::GenerateGetFromCache(int argument_count) { | 5124 void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { |
| 4993 BAILOUT("inlined runtime function: GetFromCache"); | 5125 BAILOUT("inlined runtime function: GetFromCache"); |
| 4994 } | 5126 } |
| 4995 | 5127 |
| 4996 | 5128 |
| 4997 // Fast support for number to string. | 5129 // Fast support for number to string. |
| 4998 void HGraphBuilder::GenerateNumberToString(int argument_count) { | 5130 void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { |
| 4999 ASSERT_EQ(1, argument_count); | 5131 ASSERT_EQ(1, argument_count); |
| 5000 PushArgumentsForStubCall(argument_count); | 5132 PushArgumentsForStubCall(argument_count); |
| 5001 PushAndAdd(new HCallStub(CodeStub::NumberToString, argument_count), | 5133 HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count); |
| 5002 RelocInfo::kNoPosition); | 5134 ast_context()->ReturnInstruction(result, ast_id); |
| 5003 } | 5135 } |
| 5004 | 5136 |
| 5005 | 5137 |
| 5006 // Fast swapping of elements. Takes three expressions, the object and two | 5138 // Fast swapping of elements. Takes three expressions, the object and two |
| 5007 // indices. This should only be used if the indices are known to be | 5139 // indices. This should only be used if the indices are known to be |
| 5008 // non-negative and within bounds of the elements array at the call site. | 5140 // non-negative and within bounds of the elements array at the call site. |
| 5009 void HGraphBuilder::GenerateSwapElements(int argument_count) { | 5141 void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { |
| 5010 BAILOUT("inlined runtime function: SwapElements"); | 5142 BAILOUT("inlined runtime function: SwapElements"); |
| 5011 } | 5143 } |
| 5012 | 5144 |
| 5013 | 5145 |
| 5014 // Fast call for custom callbacks. | 5146 // Fast call for custom callbacks. |
| 5015 void HGraphBuilder::GenerateCallFunction(int argument_count) { | 5147 void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) { |
| 5016 BAILOUT("inlined runtime function: CallFunction"); | 5148 BAILOUT("inlined runtime function: CallFunction"); |
| 5017 } | 5149 } |
| 5018 | 5150 |
| 5019 | 5151 |
| 5020 // Fast call to math functions. | 5152 // Fast call to math functions. |
| 5021 void HGraphBuilder::GenerateMathPow(int argument_count) { | 5153 void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) { |
| 5022 ASSERT_EQ(2, argument_count); | 5154 ASSERT_EQ(2, argument_count); |
| 5023 PushArgumentsForStubCall(argument_count); | 5155 HValue* right = Pop(); |
| 5024 PushAndAdd(new HCallStub(CodeStub::MathPow, argument_count), | 5156 HValue* left = Pop(); |
| 5025 RelocInfo::kNoPosition); | 5157 HPower* result = new HPower(left, right); |
| 5026 } | 5158 ast_context()->ReturnInstruction(result, ast_id); |
| 5027 | 5159 } |
| 5028 | 5160 |
| 5029 void HGraphBuilder::GenerateMathSin(int argument_count) { | 5161 |
| 5162 void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { |
| 5030 ASSERT_EQ(1, argument_count); | 5163 ASSERT_EQ(1, argument_count); |
| 5031 PushArgumentsForStubCall(argument_count); | 5164 PushArgumentsForStubCall(argument_count); |
| 5032 HCallStub* instr = | 5165 HCallStub* result = |
| 5033 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5166 new HCallStub(CodeStub::TranscendentalCache, argument_count); |
| 5034 instr->set_transcendental_type(TranscendentalCache::SIN); | 5167 result->set_transcendental_type(TranscendentalCache::SIN); |
| 5035 PushAndAdd(instr, RelocInfo::kNoPosition); | 5168 ast_context()->ReturnInstruction(result, ast_id); |
| 5036 } | 5169 } |
| 5037 | 5170 |
| 5038 | 5171 |
| 5039 void HGraphBuilder::GenerateMathCos(int argument_count) { | 5172 void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { |
| 5040 ASSERT_EQ(1, argument_count); | 5173 ASSERT_EQ(1, argument_count); |
| 5041 PushArgumentsForStubCall(argument_count); | 5174 PushArgumentsForStubCall(argument_count); |
| 5042 HCallStub* instr = | 5175 HCallStub* result = |
| 5043 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5176 new HCallStub(CodeStub::TranscendentalCache, argument_count); |
| 5044 instr->set_transcendental_type(TranscendentalCache::COS); | 5177 result->set_transcendental_type(TranscendentalCache::COS); |
| 5045 PushAndAdd(instr, RelocInfo::kNoPosition); | 5178 ast_context()->ReturnInstruction(result, ast_id); |
| 5046 } | 5179 } |
| 5047 | 5180 |
| 5048 | 5181 |
| 5049 void HGraphBuilder::GenerateMathLog(int argument_count) { | 5182 void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { |
| 5050 ASSERT_EQ(1, argument_count); | 5183 ASSERT_EQ(1, argument_count); |
| 5051 PushArgumentsForStubCall(argument_count); | 5184 PushArgumentsForStubCall(argument_count); |
| 5052 HCallStub* instr = | 5185 HCallStub* result = |
| 5053 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5186 new HCallStub(CodeStub::TranscendentalCache, argument_count); |
| 5054 instr->set_transcendental_type(TranscendentalCache::LOG); | 5187 result->set_transcendental_type(TranscendentalCache::LOG); |
| 5055 PushAndAdd(instr, RelocInfo::kNoPosition); | 5188 ast_context()->ReturnInstruction(result, ast_id); |
| 5056 } | 5189 } |
| 5057 | 5190 |
| 5058 | 5191 |
| 5059 void HGraphBuilder::GenerateMathSqrt(int argument_count) { | 5192 void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { |
| 5060 BAILOUT("inlined runtime function: MathSqrt"); | 5193 BAILOUT("inlined runtime function: MathSqrt"); |
| 5061 } | 5194 } |
| 5062 | 5195 |
| 5063 | 5196 |
| 5064 // Check whether two RegExps are equivalent | 5197 // Check whether two RegExps are equivalent |
| 5065 void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count) { | 5198 void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count, |
| 5199 int ast_id) { |
| 5066 BAILOUT("inlined runtime function: IsRegExpEquivalent"); | 5200 BAILOUT("inlined runtime function: IsRegExpEquivalent"); |
| 5067 } | 5201 } |
| 5068 | 5202 |
| 5069 | 5203 |
| 5070 void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count) { | 5204 void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count, |
| 5205 int ast_id) { |
| 5071 BAILOUT("inlined runtime function: GetCachedArrayIndex"); | 5206 BAILOUT("inlined runtime function: GetCachedArrayIndex"); |
| 5072 } | 5207 } |
| 5073 | 5208 |
| 5074 | 5209 |
| 5075 void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count) { | 5210 void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count, |
| 5211 int ast_id) { |
| 5076 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); | 5212 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); |
| 5077 } | 5213 } |
| 5078 | 5214 |
| 5079 | 5215 |
| 5080 #undef BAILOUT | 5216 #undef BAILOUT |
| 5081 #undef CHECK_BAILOUT | 5217 #undef CHECK_BAILOUT |
| 5082 #undef VISIT_FOR_EFFECT | 5218 #undef VISIT_FOR_EFFECT |
| 5083 #undef VISIT_FOR_VALUE | 5219 #undef VISIT_FOR_VALUE |
| 5084 #undef ADD_TO_SUBGRAPH | 5220 #undef ADD_TO_SUBGRAPH |
| 5085 | 5221 |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5541 } | 5677 } |
| 5542 | 5678 |
| 5543 #ifdef DEBUG | 5679 #ifdef DEBUG |
| 5544 if (graph_ != NULL) graph_->Verify(); | 5680 if (graph_ != NULL) graph_->Verify(); |
| 5545 if (chunk_ != NULL) chunk_->Verify(); | 5681 if (chunk_ != NULL) chunk_->Verify(); |
| 5546 if (allocator_ != NULL) allocator_->Verify(); | 5682 if (allocator_ != NULL) allocator_->Verify(); |
| 5547 #endif | 5683 #endif |
| 5548 } | 5684 } |
| 5549 | 5685 |
| 5550 } } // namespace v8::internal | 5686 } } // namespace v8::internal |
| OLD | NEW |