Chromium Code Reviews| 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 1965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1976 } | 1976 } |
| 1977 } | 1977 } |
| 1978 } | 1978 } |
| 1979 | 1979 |
| 1980 | 1980 |
| 1981 // Implementation of utility classes to represent an expression's context in | 1981 // Implementation of utility classes to represent an expression's context in |
| 1982 // the AST. | 1982 // the AST. |
| 1983 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) | 1983 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
| 1984 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { | 1984 : owner_(owner), kind_(kind), outer_(owner->ast_context()) { |
| 1985 owner->set_ast_context(this); // Push. | 1985 owner->set_ast_context(this); // Push. |
| 1986 #ifdef DEBUG | |
| 1987 original_count_ = owner->environment()->total_count(); | |
| 1988 #endif | |
| 1986 } | 1989 } |
| 1987 | 1990 |
| 1988 | 1991 |
| 1989 AstContext::~AstContext() { | 1992 AstContext::~AstContext() { |
| 1990 owner_->set_ast_context(outer_); // Pop. | 1993 owner_->set_ast_context(outer_); // Pop. |
| 1991 } | 1994 } |
| 1992 | 1995 |
| 1993 | 1996 |
| 1997 EffectContext::~EffectContext() { | |
| 1998 ASSERT(owner()->HasStackOverflow() || | |
| 1999 !owner()->subgraph()->HasExit() || | |
| 2000 owner()->environment()->total_count() == original_count_); | |
| 2001 } | |
| 2002 | |
| 2003 | |
| 2004 ValueContext::~ValueContext() { | |
| 2005 ASSERT(owner()->HasStackOverflow() || | |
| 2006 !owner()->subgraph()->HasExit() || | |
| 2007 owner()->environment()->total_count() == original_count_ + 1); | |
| 2008 } | |
| 2009 | |
| 2010 | |
| 2011 void EffectContext::ReturnValue(HValue* value) { | |
| 2012 // The value is simply ignored. | |
| 2013 } | |
| 2014 | |
| 2015 | |
| 2016 void ValueContext::ReturnValue(HValue* value) { | |
| 2017 // The value is tracked in the bailout environment, and communicated | |
| 2018 // through the environment as the result of the expression. | |
| 2019 owner()->Push(value); | |
| 2020 } | |
| 2021 | |
| 2022 | |
| 2023 void TestContext::ReturnValue(HValue* value) { | |
| 2024 BuildBranch(value); | |
| 2025 } | |
| 2026 | |
| 2027 | |
| 2028 void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) { | |
| 2029 owner()->AddInstruction(instr); | |
| 2030 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); | |
| 2031 } | |
| 2032 | |
| 2033 | |
| 2034 void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) { | |
| 2035 owner()->AddInstruction(instr); | |
| 2036 owner()->Push(instr); | |
| 2037 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); | |
| 2038 } | |
| 2039 | |
| 2040 | |
| 2041 void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) { | |
| 2042 HGraphBuilder* builder = owner(); | |
| 2043 builder->AddInstruction(instr); | |
| 2044 // We expect a simulate after every expression with side effects, though | |
| 2045 // this one isn't actually needed (and wouldn't work if it were targeted). | |
| 2046 if (instr->HasSideEffects()) { | |
| 2047 builder->Push(instr); | |
| 2048 builder->AddSimulate(ast_id); | |
| 2049 builder->Pop(); | |
| 2050 } | |
| 2051 BuildBranch(instr); | |
| 2052 } | |
| 2053 | |
| 2054 | |
| 2055 void TestContext::BuildBranch(HValue* value) { | |
| 2056 HGraphBuilder* builder = owner(); | |
| 2057 HBasicBlock* materialize_true = builder->graph()->CreateBasicBlock(); | |
| 2058 HBasicBlock* materialize_false = builder->graph()->CreateBasicBlock(); | |
| 2059 HBranch* branch = new HBranch(materialize_true, materialize_false, value); | |
| 2060 builder->CurrentBlock()->Finish(branch); | |
| 2061 | |
| 2062 HBasicBlock* true_block = if_true(); | |
| 2063 HValue* true_value = invert_true() | |
|
Kasper Lund
2010/12/09 11:40:08
Add a helper for this pattern. GetConstantBoolean(
Kevin Millikin (Chromium)
2010/12/09 12:45:54
I think I want to get rid of all occurrences of it
| |
| 2064 ? builder->graph()->GetConstantFalse() | |
| 2065 : builder->graph()->GetConstantTrue(); | |
| 2066 materialize_true->set_inverted(invert_true()); | |
| 2067 true_block->set_deopt_predecessor(materialize_true); | |
| 2068 | |
| 2069 if (true_block->IsInlineReturnTarget()) { | |
| 2070 materialize_true->AddLeaveInlined(true_value, true_block); | |
| 2071 } else { | |
| 2072 materialize_true->last_environment()->Push(true_value); | |
| 2073 materialize_true->Goto(true_block); | |
| 2074 } | |
| 2075 | |
| 2076 HBasicBlock* false_block = if_false(); | |
| 2077 HValue* false_value = invert_false() | |
| 2078 ? builder->graph()->GetConstantTrue() | |
| 2079 : builder->graph()->GetConstantFalse(); | |
| 2080 materialize_false->set_inverted(invert_false()); | |
| 2081 false_block->set_deopt_predecessor(materialize_false); | |
| 2082 | |
| 2083 if (false_block->IsInlineReturnTarget()) { | |
| 2084 materialize_false->AddLeaveInlined(false_value, false_block); | |
| 2085 } else { | |
| 2086 materialize_false->last_environment()->Push(false_value); | |
| 2087 materialize_false->Goto(false_block); | |
| 2088 } | |
| 2089 builder->subgraph()->set_exit_block(NULL); | |
| 2090 } | |
| 2091 | |
| 1994 | 2092 |
| 1995 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2093 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
| 1996 #define BAILOUT(reason) \ | 2094 #define BAILOUT(reason) \ |
| 1997 do { \ | 2095 do { \ |
| 1998 Bailout(reason); \ | 2096 Bailout(reason); \ |
| 1999 return; \ | 2097 return; \ |
| 2000 } while (false) | 2098 } while (false) |
| 2001 | 2099 |
| 2002 | 2100 |
| 2003 #define CHECK_BAILOUT \ | 2101 #define CHECK_BAILOUT \ |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2054 void HGraphBuilder::Bailout(const char* reason) { | 2152 void HGraphBuilder::Bailout(const char* reason) { |
| 2055 if (FLAG_trace_bailout) { | 2153 if (FLAG_trace_bailout) { |
| 2056 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); | 2154 SmartPointer<char> debug_name = graph()->debug_name()->ToCString(); |
| 2057 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *debug_name, reason); | 2155 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *debug_name, reason); |
| 2058 } | 2156 } |
| 2059 SetStackOverflow(); | 2157 SetStackOverflow(); |
| 2060 } | 2158 } |
| 2061 | 2159 |
| 2062 | 2160 |
| 2063 void HGraphBuilder::VisitForEffect(Expression* expr) { | 2161 void HGraphBuilder::VisitForEffect(Expression* expr) { |
| 2064 #ifdef DEBUG | 2162 EffectContext for_effect(this); |
| 2065 int original_count = environment()->total_count(); | 2163 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 } | 2164 } |
| 2096 | 2165 |
| 2097 | 2166 |
| 2098 void HGraphBuilder::VisitForValue(Expression* expr) { | 2167 void HGraphBuilder::VisitForValue(Expression* expr) { |
| 2099 #ifdef DEBUG | 2168 ValueContext for_value(this); |
| 2100 int original_height = environment()->values()->length(); | 2169 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 } | 2170 } |
| 2114 | 2171 |
| 2115 | 2172 |
| 2116 HValue* HGraphBuilder::VisitArgument(Expression* expr) { | 2173 HValue* HGraphBuilder::VisitArgument(Expression* expr) { |
| 2117 VisitForValue(expr); | 2174 VisitForValue(expr); |
| 2118 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; | 2175 if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; |
| 2119 return environment()->Top(); | 2176 return environment()->Top(); |
| 2120 } | 2177 } |
| 2121 | 2178 |
| 2122 | 2179 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2237 } | 2294 } |
| 2238 | 2295 |
| 2239 | 2296 |
| 2240 void HGraphBuilder::VisitForControl(Expression* expr, | 2297 void HGraphBuilder::VisitForControl(Expression* expr, |
| 2241 HBasicBlock* true_block, | 2298 HBasicBlock* true_block, |
| 2242 HBasicBlock* false_block, | 2299 HBasicBlock* false_block, |
| 2243 bool invert_true, | 2300 bool invert_true, |
| 2244 bool invert_false) { | 2301 bool invert_false) { |
| 2245 TestContext for_test(this, true_block, false_block, | 2302 TestContext for_test(this, true_block, false_block, |
| 2246 invert_true, invert_false); | 2303 invert_true, invert_false); |
| 2247 BinaryOperation* binary_op = expr->AsBinaryOperation(); | 2304 Visit(expr); |
| 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 } | 2305 } |
| 2341 | 2306 |
| 2342 | 2307 |
| 2343 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, | 2308 void HGraphBuilder::AddToSubgraph(HSubgraph* graph, |
| 2344 ZoneList<Statement*>* stmts) { | 2309 ZoneList<Statement*>* stmts) { |
| 2345 SubgraphScope scope(this, graph); | 2310 SubgraphScope scope(this, graph); |
| 2346 VisitStatements(stmts); | 2311 VisitStatements(stmts); |
| 2347 } | 2312 } |
| 2348 | 2313 |
| 2349 | 2314 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 2365 current_subgraph_->exit_block()->AddPhi(instr); | 2330 current_subgraph_->exit_block()->AddPhi(instr); |
| 2366 } | 2331 } |
| 2367 | 2332 |
| 2368 | 2333 |
| 2369 void HGraphBuilder::PushAndAdd(HInstruction* instr) { | 2334 void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
| 2370 Push(instr); | 2335 Push(instr); |
| 2371 AddInstruction(instr); | 2336 AddInstruction(instr); |
| 2372 } | 2337 } |
| 2373 | 2338 |
| 2374 | 2339 |
| 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) { | 2340 void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { |
| 2382 const int kMaxStubArguments = 4; | 2341 const int kMaxStubArguments = 4; |
| 2383 ASSERT_GE(kMaxStubArguments, argument_count); | 2342 ASSERT_GE(kMaxStubArguments, argument_count); |
| 2384 // Push the arguments on the stack. | 2343 // Push the arguments on the stack. |
| 2385 HValue* arguments[kMaxStubArguments]; | 2344 HValue* arguments[kMaxStubArguments]; |
| 2386 for (int i = argument_count - 1; i >= 0; i--) { | 2345 for (int i = argument_count - 1; i >= 0; i--) { |
| 2387 arguments[i] = Pop(); | 2346 arguments[i] = Pop(); |
| 2388 } | 2347 } |
| 2389 for (int i = 0; i < argument_count; i++) { | 2348 for (int i = 0; i < argument_count; i++) { |
| 2390 AddInstruction(new HPushArgument(arguments[i])); | 2349 AddInstruction(new HPushArgument(arguments[i])); |
| 2391 } | 2350 } |
| 2392 } | 2351 } |
| 2393 | 2352 |
| 2394 | 2353 |
| 2395 void HGraphBuilder::ProcessCall(HCall* call, int source_position) { | 2354 void HGraphBuilder::ProcessCall(HCall* call) { |
| 2396 for (int i = call->argument_count() - 1; i >= 0; --i) { | 2355 for (int i = call->argument_count() - 1; i >= 0; --i) { |
| 2397 HValue* value = Pop(); | 2356 HValue* value = Pop(); |
| 2398 HPushArgument* push = new HPushArgument(value); | 2357 HPushArgument* push = new HPushArgument(value); |
| 2399 call->SetArgumentAt(i, push); | 2358 call->SetArgumentAt(i, push); |
| 2400 } | 2359 } |
| 2401 | 2360 |
| 2402 for (int i = 0; i < call->argument_count(); ++i) { | 2361 for (int i = 0; i < call->argument_count(); ++i) { |
| 2403 AddInstruction(call->PushArgumentAt(i)); | 2362 AddInstruction(call->PushArgumentAt(i)); |
| 2404 } | 2363 } |
| 2405 | |
| 2406 PushAndAdd(call, source_position); | |
| 2407 } | 2364 } |
| 2408 | 2365 |
| 2409 | 2366 |
| 2410 void HGraphBuilder::SetupScope(Scope* scope) { | 2367 void HGraphBuilder::SetupScope(Scope* scope) { |
| 2411 // We don't yet handle the function name for named function expressions. | 2368 // We don't yet handle the function name for named function expressions. |
| 2412 if (scope->function() != NULL) BAILOUT("named function expression"); | 2369 if (scope->function() != NULL) BAILOUT("named function expression"); |
| 2413 | 2370 |
| 2414 // We can't handle heap-allocated locals. | 2371 // We can't handle heap-allocated locals. |
| 2415 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); | 2372 if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals"); |
| 2416 | 2373 |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2907 | 2864 |
| 2908 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | 2865 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 2909 BAILOUT("DebuggerStatement"); | 2866 BAILOUT("DebuggerStatement"); |
| 2910 } | 2867 } |
| 2911 | 2868 |
| 2912 | 2869 |
| 2913 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { | 2870 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 2914 Handle<SharedFunctionInfo> shared_info = | 2871 Handle<SharedFunctionInfo> shared_info = |
| 2915 Compiler::BuildFunctionInfo(expr, graph_->info()->script()); | 2872 Compiler::BuildFunctionInfo(expr, graph_->info()->script()); |
| 2916 CHECK_BAILOUT; | 2873 CHECK_BAILOUT; |
| 2917 PushAndAdd(new HFunctionLiteral(shared_info, expr->pretenure())); | 2874 HFunctionLiteral* instr = |
| 2875 new HFunctionLiteral(shared_info, expr->pretenure()); | |
| 2876 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 2918 } | 2877 } |
| 2919 | 2878 |
| 2920 | 2879 |
| 2921 void HGraphBuilder::VisitSharedFunctionInfoLiteral( | 2880 void HGraphBuilder::VisitSharedFunctionInfoLiteral( |
| 2922 SharedFunctionInfoLiteral* expr) { | 2881 SharedFunctionInfoLiteral* expr) { |
| 2923 BAILOUT("SharedFunctionInfoLiteral"); | 2882 BAILOUT("SharedFunctionInfoLiteral"); |
| 2924 } | 2883 } |
| 2925 | 2884 |
| 2926 | 2885 |
| 2927 void HGraphBuilder::VisitConditional(Conditional* expr) { | 2886 void HGraphBuilder::VisitConditional(Conditional* expr) { |
| 2928 HSubgraph* then_graph = CreateEmptySubgraph(); | 2887 HSubgraph* then_graph = CreateEmptySubgraph(); |
| 2929 HSubgraph* else_graph = CreateEmptySubgraph(); | 2888 HSubgraph* else_graph = CreateEmptySubgraph(); |
| 2930 VisitCondition(expr->condition(), | 2889 VisitCondition(expr->condition(), |
| 2931 then_graph->entry_block(), | 2890 then_graph->entry_block(), |
| 2932 else_graph->entry_block(), | 2891 else_graph->entry_block(), |
| 2933 false, false); | 2892 false, false); |
| 2934 if (HasStackOverflow()) return; | 2893 if (HasStackOverflow()) return; |
| 2935 ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); | 2894 ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); |
| 2936 ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); | 2895 ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); |
| 2937 current_subgraph_->AppendJoin(then_graph, else_graph, expr); | 2896 current_subgraph_->AppendJoin(then_graph, else_graph, expr); |
| 2897 ast_context()->ReturnValue(Pop()); | |
| 2938 } | 2898 } |
| 2939 | 2899 |
| 2940 | 2900 |
| 2941 void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr, | 2901 void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
| 2942 LookupResult* lookup, | 2902 LookupResult* lookup, |
| 2943 bool is_store) { | 2903 bool is_store) { |
| 2944 if (expr->is_this()) { | 2904 if (var->is_this()) { |
| 2945 BAILOUT("global this reference"); | 2905 BAILOUT("global this reference"); |
| 2946 } | 2906 } |
| 2947 if (!graph()->info()->has_global_object()) { | 2907 if (!graph()->info()->has_global_object()) { |
| 2948 BAILOUT("no global object to optimize VariableProxy"); | 2908 BAILOUT("no global object to optimize VariableProxy"); |
| 2949 } | 2909 } |
| 2950 Handle<GlobalObject> global(graph()->info()->global_object()); | 2910 Handle<GlobalObject> global(graph()->info()->global_object()); |
| 2951 global->Lookup(*expr->name(), lookup); | 2911 global->Lookup(*var->name(), lookup); |
| 2952 if (!lookup->IsProperty()) { | 2912 if (!lookup->IsProperty()) { |
| 2953 BAILOUT("global variable cell not yet introduced"); | 2913 BAILOUT("global variable cell not yet introduced"); |
| 2954 } | 2914 } |
| 2955 if (lookup->type() != NORMAL) { | 2915 if (lookup->type() != NORMAL) { |
| 2956 BAILOUT("global variable has accessors"); | 2916 BAILOUT("global variable has accessors"); |
| 2957 } | 2917 } |
| 2958 if (is_store && lookup->IsReadOnly()) { | 2918 if (is_store && lookup->IsReadOnly()) { |
| 2959 BAILOUT("read-only global variable"); | 2919 BAILOUT("read-only global variable"); |
| 2960 } | 2920 } |
| 2961 } | 2921 } |
| 2962 | 2922 |
| 2963 | 2923 |
| 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) { | 2924 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 2982 Variable* variable = expr->AsVariable(); | 2925 Variable* variable = expr->AsVariable(); |
| 2983 if (variable == NULL) { | 2926 if (variable == NULL) { |
| 2984 BAILOUT("reference to rewritten variable"); | 2927 BAILOUT("reference to rewritten variable"); |
| 2985 } else if (variable->IsStackAllocated()) { | 2928 } else if (variable->IsStackAllocated()) { |
| 2986 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { | 2929 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { |
| 2987 BAILOUT("unsupported context for arguments object"); | 2930 BAILOUT("unsupported context for arguments object"); |
| 2988 } | 2931 } |
| 2989 Push(environment()->Lookup(variable)); | 2932 ast_context()->ReturnValue(environment()->Lookup(variable)); |
| 2990 } else if (variable->is_global()) { | 2933 } else if (variable->is_global()) { |
| 2991 HandleGlobalVariableLoad(expr); | 2934 LookupResult lookup; |
| 2935 LookupGlobalPropertyCell(variable, &lookup, false); | |
| 2936 CHECK_BAILOUT; | |
| 2937 | |
| 2938 Handle<GlobalObject> global(graph()->info()->global_object()); | |
| 2939 // TODO(3039103): Handle global property load through an IC call when access | |
| 2940 // checks are enabled. | |
| 2941 if (global->IsAccessCheckNeeded()) { | |
| 2942 BAILOUT("global object requires access check"); | |
| 2943 } | |
| 2944 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | |
| 2945 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); | |
| 2946 HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); | |
| 2947 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 2992 } else { | 2948 } else { |
| 2993 BAILOUT("reference to non-stack-allocated/non-global variable"); | 2949 BAILOUT("reference to non-stack-allocated/non-global variable"); |
| 2994 } | 2950 } |
| 2995 } | 2951 } |
| 2996 | 2952 |
| 2997 | 2953 |
| 2998 void HGraphBuilder::VisitLiteral(Literal* expr) { | 2954 void HGraphBuilder::VisitLiteral(Literal* expr) { |
| 2999 PushAndAdd(new HConstant(expr->handle(), Representation::Tagged())); | 2955 HConstant* instr = new HConstant(expr->handle(), Representation::Tagged()); |
| 2956 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 3000 } | 2957 } |
| 3001 | 2958 |
| 3002 | 2959 |
| 3003 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { | 2960 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 3004 PushAndAdd(new HRegExpLiteral(expr->pattern(), | 2961 HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(), |
| 3005 expr->flags(), | 2962 expr->flags(), |
| 3006 expr->literal_index())); | 2963 expr->literal_index()); |
| 2964 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 3007 } | 2965 } |
| 3008 | 2966 |
| 3009 | 2967 |
| 3010 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | 2968 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 3011 HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(), | 2969 HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(), |
| 3012 expr->fast_elements(), | 2970 expr->fast_elements(), |
| 3013 expr->literal_index(), | 2971 expr->literal_index(), |
| 3014 expr->depth())); | 2972 expr->depth())); |
| 2973 // The object is expected in the bailout environment during computation | |
| 2974 // of the property values and is the value of the entire expression. | |
| 3015 PushAndAdd(literal); | 2975 PushAndAdd(literal); |
| 3016 | 2976 |
| 3017 expr->CalculateEmitStore(); | 2977 expr->CalculateEmitStore(); |
| 3018 | 2978 |
| 3019 for (int i = 0; i < expr->properties()->length(); i++) { | 2979 for (int i = 0; i < expr->properties()->length(); i++) { |
| 3020 ObjectLiteral::Property* property = expr->properties()->at(i); | 2980 ObjectLiteral::Property* property = expr->properties()->at(i); |
| 3021 if (property->IsCompileTimeValue()) continue; | 2981 if (property->IsCompileTimeValue()) continue; |
| 3022 | 2982 |
| 3023 Literal* key = property->key(); | 2983 Literal* key = property->key(); |
| 3024 Expression* value = property->value(); | 2984 Expression* value = property->value(); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 3041 break; | 3001 break; |
| 3042 } | 3002 } |
| 3043 // Fall through. | 3003 // Fall through. |
| 3044 case ObjectLiteral::Property::PROTOTYPE: | 3004 case ObjectLiteral::Property::PROTOTYPE: |
| 3045 case ObjectLiteral::Property::SETTER: | 3005 case ObjectLiteral::Property::SETTER: |
| 3046 case ObjectLiteral::Property::GETTER: | 3006 case ObjectLiteral::Property::GETTER: |
| 3047 BAILOUT("Object literal with complex property"); | 3007 BAILOUT("Object literal with complex property"); |
| 3048 default: UNREACHABLE(); | 3008 default: UNREACHABLE(); |
| 3049 } | 3009 } |
| 3050 } | 3010 } |
| 3011 ast_context()->ReturnValue(Pop()); | |
| 3051 } | 3012 } |
| 3052 | 3013 |
| 3053 | 3014 |
| 3054 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { | 3015 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
| 3055 ZoneList<Expression*>* subexprs = expr->values(); | 3016 ZoneList<Expression*>* subexprs = expr->values(); |
| 3056 int length = subexprs->length(); | 3017 int length = subexprs->length(); |
| 3057 | 3018 |
| 3058 HArrayLiteral* literal = new HArrayLiteral(expr->constant_elements(), | 3019 HArrayLiteral* literal = new HArrayLiteral(expr->constant_elements(), |
| 3059 length, | 3020 length, |
| 3060 expr->literal_index(), | 3021 expr->literal_index(), |
| 3061 expr->depth()); | 3022 expr->depth()); |
| 3023 // The array is expected in the bailout environment during computation | |
| 3024 // of the property values and is the value of the entire expression. | |
| 3062 PushAndAdd(literal); | 3025 PushAndAdd(literal); |
| 3063 HValue* elements = AddInstruction(new HLoadElements(literal)); | 3026 HValue* elements = AddInstruction(new HLoadElements(literal)); |
| 3064 | 3027 |
| 3065 for (int i = 0; i < length; i++) { | 3028 for (int i = 0; i < length; i++) { |
| 3066 Expression* subexpr = subexprs->at(i); | 3029 Expression* subexpr = subexprs->at(i); |
| 3067 // If the subexpression is a literal or a simple materialized literal it | 3030 // If the subexpression is a literal or a simple materialized literal it |
| 3068 // is already set in the cloned array. | 3031 // is already set in the cloned array. |
| 3069 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 3032 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
| 3070 | 3033 |
| 3071 VISIT_FOR_VALUE(subexpr); | 3034 VISIT_FOR_VALUE(subexpr); |
| 3072 HValue* value = Pop(); | 3035 HValue* value = Pop(); |
| 3073 if (!Smi::IsValid(i)) BAILOUT("Non-smi key in array literal"); | 3036 if (!Smi::IsValid(i)) BAILOUT("Non-smi key in array literal"); |
| 3074 HValue* key = AddInstruction(new HConstant(Handle<Object>(Smi::FromInt(i)), | 3037 HValue* key = AddInstruction(new HConstant(Handle<Object>(Smi::FromInt(i)), |
| 3075 Representation::Integer32())); | 3038 Representation::Integer32())); |
| 3076 AddInstruction(new HStoreKeyedFastElement(elements, key, value)); | 3039 AddInstruction(new HStoreKeyedFastElement(elements, key, value)); |
| 3077 AddSimulate(expr->GetIdForElement(i)); | 3040 AddSimulate(expr->GetIdForElement(i)); |
| 3078 } | 3041 } |
| 3042 ast_context()->ReturnValue(Pop()); | |
| 3079 } | 3043 } |
| 3080 | 3044 |
| 3081 | 3045 |
| 3082 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 3046 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
| 3083 BAILOUT("CatchExtensionObject"); | 3047 BAILOUT("CatchExtensionObject"); |
| 3084 } | 3048 } |
| 3085 | 3049 |
| 3086 | 3050 |
| 3087 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, | 3051 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, |
| 3088 ZoneList<HSubgraph*>* subgraphs, | 3052 ZoneList<HSubgraph*>* subgraphs, |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3250 } | 3214 } |
| 3251 } | 3215 } |
| 3252 | 3216 |
| 3253 // If none of the properties were named fields we generate a | 3217 // If none of the properties were named fields we generate a |
| 3254 // generic store. | 3218 // generic store. |
| 3255 if (maps.length() == 0) { | 3219 if (maps.length() == 0) { |
| 3256 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | 3220 HInstruction* instr = new HStoreNamedGeneric(object, name, value); |
| 3257 Push(value); | 3221 Push(value); |
| 3258 instr->set_position(expr->position()); | 3222 instr->set_position(expr->position()); |
| 3259 AddInstruction(instr); | 3223 AddInstruction(instr); |
| 3260 return; | 3224 if (instr->HasSideEffects()) AddSimulate(expr->id()); |
| 3225 } else { | |
| 3226 // Build subgraph for generic store through IC. | |
| 3227 { | |
|
Kasper Lund
2010/12/09 11:40:08
Consider factoring the inner scope out into a sepa
| |
| 3228 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | |
| 3229 SubgraphScope scope(this, subgraph); | |
| 3230 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3231 subgraph->FinishExit(new HDeoptimize()); | |
| 3232 } else { | |
| 3233 HInstruction* instr = new HStoreNamedGeneric(object, name, value); | |
| 3234 Push(value); | |
| 3235 instr->set_position(expr->position()); | |
| 3236 AddInstruction(instr); | |
| 3237 } | |
| 3238 subgraphs.Add(subgraph); | |
| 3239 } | |
| 3240 | |
| 3241 HBasicBlock* new_exit_block = | |
| 3242 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | |
| 3243 subgraph()->set_exit_block(new_exit_block); | |
| 3261 } | 3244 } |
| 3262 | 3245 |
| 3263 // Build subgraph for generic store through IC. | 3246 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 } | 3247 } |
| 3282 | 3248 |
| 3283 | 3249 |
| 3284 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 3250 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
| 3285 Property* prop = expr->target()->AsProperty(); | 3251 Property* prop = expr->target()->AsProperty(); |
| 3286 ASSERT(prop != NULL); | 3252 ASSERT(prop != NULL); |
| 3287 expr->RecordTypeFeedback(oracle()); | 3253 expr->RecordTypeFeedback(oracle()); |
| 3288 VISIT_FOR_VALUE(prop->obj()); | 3254 VISIT_FOR_VALUE(prop->obj()); |
| 3289 | 3255 |
| 3290 HValue* value = NULL; | 3256 HValue* value = NULL; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3326 expr->GetMonomorphicReceiverType()->has_fast_elements(); | 3292 expr->GetMonomorphicReceiverType()->has_fast_elements(); |
| 3327 | 3293 |
| 3328 instr = is_fast_elements | 3294 instr = is_fast_elements |
| 3329 ? BuildStoreKeyedFastElement(object, key, value, expr) | 3295 ? BuildStoreKeyedFastElement(object, key, value, expr) |
| 3330 : BuildStoreKeyedGeneric(object, key, value); | 3296 : BuildStoreKeyedGeneric(object, key, value); |
| 3331 } | 3297 } |
| 3332 | 3298 |
| 3333 Push(value); | 3299 Push(value); |
| 3334 instr->set_position(expr->position()); | 3300 instr->set_position(expr->position()); |
| 3335 AddInstruction(instr); | 3301 AddInstruction(instr); |
| 3302 if (instr->HasSideEffects()) AddSimulate(expr->id()); | |
| 3303 ast_context()->ReturnValue(Pop()); | |
| 3336 } | 3304 } |
| 3337 | 3305 |
| 3338 | 3306 |
| 3339 void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy, | 3307 // Because not every expression has a position and there is not common |
| 3308 // superclass of Assignment and CountOperation, we cannot just pass the | |
| 3309 // owning expression instead of position and ast_id separately. | |
| 3310 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, | |
| 3340 HValue* value, | 3311 HValue* value, |
| 3341 int position) { | 3312 int position, |
| 3313 int ast_id) { | |
| 3342 LookupResult lookup; | 3314 LookupResult lookup; |
| 3343 LookupGlobalPropertyCell(proxy, &lookup, true); | 3315 LookupGlobalPropertyCell(var, &lookup, true); |
| 3344 CHECK_BAILOUT; | 3316 CHECK_BAILOUT; |
| 3345 | 3317 |
| 3346 Handle<GlobalObject> global(graph()->info()->global_object()); | 3318 Handle<GlobalObject> global(graph()->info()->global_object()); |
| 3347 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3319 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 3348 HInstruction* instr = new HStoreGlobal(value, cell); | 3320 HInstruction* instr = new HStoreGlobal(value, cell); |
| 3349 instr->set_position(position); | 3321 instr->set_position(position); |
| 3350 AddInstruction(instr); | 3322 AddInstruction(instr); |
| 3323 if (instr->HasSideEffects()) AddSimulate(ast_id); | |
| 3351 } | 3324 } |
| 3352 | 3325 |
| 3353 | 3326 |
| 3354 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3327 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
| 3355 Expression* target = expr->target(); | 3328 Expression* target = expr->target(); |
| 3356 VariableProxy* proxy = target->AsVariableProxy(); | 3329 VariableProxy* proxy = target->AsVariableProxy(); |
| 3357 Variable* var = proxy->AsVariable(); | 3330 Variable* var = proxy->AsVariable(); |
| 3358 Property* prop = target->AsProperty(); | 3331 Property* prop = target->AsProperty(); |
| 3359 ASSERT(var == NULL || prop == NULL); | 3332 ASSERT(var == NULL || prop == NULL); |
| 3360 | 3333 |
| 3361 // We have a second position recorded in the FullCodeGenerator to have | 3334 // We have a second position recorded in the FullCodeGenerator to have |
| 3362 // type feedback for the binary operation. | 3335 // type feedback for the binary operation. |
| 3363 BinaryOperation* operation = expr->binary_operation(); | 3336 BinaryOperation* operation = expr->binary_operation(); |
| 3364 operation->RecordTypeFeedback(oracle()); | 3337 operation->RecordTypeFeedback(oracle()); |
| 3365 | 3338 |
| 3366 if (var != NULL) { | 3339 if (var != NULL) { |
| 3367 if (!var->is_global() && !var->IsStackAllocated()) { | 3340 if (!var->is_global() && !var->IsStackAllocated()) { |
| 3368 BAILOUT("non-stack/non-global in compound assignment"); | 3341 BAILOUT("non-stack/non-global in compound assignment"); |
| 3369 } | 3342 } |
| 3370 | 3343 |
| 3371 VISIT_FOR_VALUE(operation); | 3344 VISIT_FOR_VALUE(operation); |
| 3372 | 3345 |
| 3373 if (var->is_global()) { | 3346 if (var->is_global()) { |
| 3374 HandleGlobalVariableAssignment(proxy, Top(), expr->position()); | 3347 HandleGlobalVariableAssignment(var, Top(), expr->position(), expr->id()); |
| 3375 } else { | 3348 } else { |
| 3376 Bind(var, Top()); | 3349 Bind(var, Top()); |
| 3377 } | 3350 } |
| 3351 ast_context()->ReturnValue(Pop()); | |
| 3352 | |
| 3378 } else if (prop != NULL) { | 3353 } else if (prop != NULL) { |
| 3379 prop->RecordTypeFeedback(oracle()); | 3354 prop->RecordTypeFeedback(oracle()); |
| 3380 | 3355 |
| 3381 if (prop->key()->IsPropertyName()) { | 3356 if (prop->key()->IsPropertyName()) { |
| 3382 // Named property. | 3357 // Named property. |
| 3383 VISIT_FOR_VALUE(prop->obj()); | 3358 VISIT_FOR_VALUE(prop->obj()); |
| 3384 HValue* obj = Top(); | 3359 HValue* obj = Top(); |
| 3385 | 3360 |
| 3386 HInstruction* load = NULL; | 3361 HInstruction* load = NULL; |
| 3387 if (prop->IsMonomorphic()) { | 3362 if (prop->IsMonomorphic()) { |
| 3388 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 3363 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 3389 Handle<Map> map = prop->GetReceiverTypes()->first(); | 3364 Handle<Map> map = prop->GetReceiverTypes()->first(); |
| 3390 load = BuildLoadNamed(obj, prop, map, name); | 3365 load = BuildLoadNamed(obj, prop, map, name); |
| 3391 } else { | 3366 } else { |
| 3392 load = BuildLoadNamedGeneric(obj, prop); | 3367 load = BuildLoadNamedGeneric(obj, prop); |
| 3393 } | 3368 } |
| 3394 PushAndAdd(load); | 3369 PushAndAdd(load); |
| 3395 if (load->HasSideEffects()) { | 3370 if (load->HasSideEffects()) AddSimulate(expr->compound_bailout_id()); |
| 3396 AddSimulate(expr->compound_bailout_id()); | |
| 3397 } | |
| 3398 | 3371 |
| 3399 VISIT_FOR_VALUE(expr->value()); | 3372 VISIT_FOR_VALUE(expr->value()); |
| 3400 HValue* right = Pop(); | 3373 HValue* right = Pop(); |
| 3401 HValue* left = Pop(); | 3374 HValue* left = Pop(); |
| 3402 | 3375 |
| 3403 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 3376 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
| 3404 PushAndAdd(instr); | 3377 PushAndAdd(instr); |
| 3405 if (instr->HasSideEffects()) AddSimulate(operation->id()); | 3378 if (instr->HasSideEffects()) AddSimulate(operation->id()); |
| 3406 | 3379 |
| 3407 HInstruction* store = BuildStoreNamed(obj, instr, prop); | 3380 HInstruction* store = BuildStoreNamed(obj, instr, prop); |
| 3408 AddInstruction(store); | 3381 AddInstruction(store); |
| 3382 if (store->HasSideEffects()) AddSimulate(expr->id()); | |
| 3409 | 3383 |
| 3410 // Drop the simulated receiver and value and put back the value. | 3384 // Drop the simulated receiver and value. Return the value. |
| 3411 Drop(2); | 3385 Drop(2); |
| 3412 Push(instr); | 3386 ast_context()->ReturnValue(instr); |
| 3413 | 3387 |
| 3414 } else { | 3388 } else { |
| 3415 // Keyed property. | 3389 // Keyed property. |
| 3416 VISIT_FOR_VALUE(prop->obj()); | 3390 VISIT_FOR_VALUE(prop->obj()); |
| 3417 VISIT_FOR_VALUE(prop->key()); | 3391 VISIT_FOR_VALUE(prop->key()); |
| 3418 HValue* obj = environment()->ExpressionStackAt(1); | 3392 HValue* obj = environment()->ExpressionStackAt(1); |
| 3419 HValue* key = environment()->ExpressionStackAt(0); | 3393 HValue* key = environment()->ExpressionStackAt(0); |
| 3420 | 3394 |
| 3421 bool is_fast_elements = prop->IsMonomorphic() && | 3395 bool is_fast_elements = prop->IsMonomorphic() && |
| 3422 prop->GetMonomorphicReceiverType()->has_fast_elements(); | 3396 prop->GetMonomorphicReceiverType()->has_fast_elements(); |
| 3423 | 3397 |
| 3424 HInstruction* load = is_fast_elements | 3398 HInstruction* load = is_fast_elements |
| 3425 ? BuildLoadKeyedFastElement(obj, key, prop) | 3399 ? BuildLoadKeyedFastElement(obj, key, prop) |
| 3426 : BuildLoadKeyedGeneric(obj, key); | 3400 : BuildLoadKeyedGeneric(obj, key); |
| 3427 PushAndAdd(load); | 3401 PushAndAdd(load); |
| 3428 if (load->HasSideEffects()) { | 3402 if (load->HasSideEffects()) AddSimulate(expr->compound_bailout_id()); |
| 3429 AddSimulate(expr->compound_bailout_id()); | |
| 3430 } | |
| 3431 | 3403 |
| 3432 VISIT_FOR_VALUE(expr->value()); | 3404 VISIT_FOR_VALUE(expr->value()); |
| 3433 HValue* right = Pop(); | 3405 HValue* right = Pop(); |
| 3434 HValue* left = Pop(); | 3406 HValue* left = Pop(); |
| 3435 | 3407 |
| 3436 HInstruction* instr = BuildBinaryOperation(operation, left, right); | 3408 HInstruction* instr = BuildBinaryOperation(operation, left, right); |
| 3437 PushAndAdd(instr); | 3409 PushAndAdd(instr); |
| 3438 if (instr->HasSideEffects()) AddSimulate(operation->id()); | 3410 if (instr->HasSideEffects()) AddSimulate(operation->id()); |
| 3439 | 3411 |
| 3440 HInstruction* store = is_fast_elements | 3412 HInstruction* store = is_fast_elements |
| 3441 ? BuildStoreKeyedFastElement(obj, key, instr, prop) | 3413 ? BuildStoreKeyedFastElement(obj, key, instr, prop) |
| 3442 : BuildStoreKeyedGeneric(obj, key, instr); | 3414 : BuildStoreKeyedGeneric(obj, key, instr); |
| 3443 AddInstruction(store); | 3415 AddInstruction(store); |
| 3416 if (store->HasSideEffects()) AddSimulate(expr->id()); | |
| 3444 | 3417 |
| 3445 // Drop the simulated receiver, key and value and put back the value. | 3418 // Drop the simulated receiver, key, and value. Return the value. |
| 3446 Drop(3); | 3419 Drop(3); |
| 3447 Push(instr); | 3420 ast_context()->ReturnValue(instr); |
| 3448 } | 3421 } |
| 3422 | |
| 3449 } else { | 3423 } else { |
| 3450 BAILOUT("invalid lhs in compound assignment"); | 3424 BAILOUT("invalid lhs in compound assignment"); |
| 3451 } | 3425 } |
| 3452 } | 3426 } |
| 3453 | 3427 |
| 3454 | 3428 |
| 3455 void HGraphBuilder::VisitAssignment(Assignment* expr) { | 3429 void HGraphBuilder::VisitAssignment(Assignment* expr) { |
| 3456 VariableProxy* proxy = expr->target()->AsVariableProxy(); | 3430 VariableProxy* proxy = expr->target()->AsVariableProxy(); |
| 3457 Variable* var = proxy->AsVariable(); | 3431 Variable* var = proxy->AsVariable(); |
| 3458 Property* prop = expr->target()->AsProperty(); | 3432 Property* prop = expr->target()->AsProperty(); |
| 3459 ASSERT(var == NULL || prop == NULL); | 3433 ASSERT(var == NULL || prop == NULL); |
| 3460 | 3434 |
| 3461 if (expr->is_compound()) { | 3435 if (expr->is_compound()) { |
| 3462 HandleCompoundAssignment(expr); | 3436 HandleCompoundAssignment(expr); |
| 3463 return; | 3437 return; |
| 3464 } | 3438 } |
| 3465 | 3439 |
| 3466 if (var != NULL) { | 3440 if (var != NULL) { |
| 3467 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); | 3441 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); |
| 3442 | |
| 3443 // Handle the assignment. | |
| 3468 if (var->is_global()) { | 3444 if (var->is_global()) { |
| 3469 VISIT_FOR_VALUE(expr->value()); | 3445 VISIT_FOR_VALUE(expr->value()); |
| 3470 HandleGlobalVariableAssignment(proxy, Top(), expr->position()); | 3446 HandleGlobalVariableAssignment(var, Top(), expr->position(), expr->id()); |
| 3471 } else { | 3447 } else { |
| 3472 // We allow reference to the arguments object only in assignemtns | 3448 // We allow reference to the arguments object only in assignemtns |
| 3473 // to local variables to make sure that the arguments object does | 3449 // to local variables to make sure that the arguments object does |
| 3474 // not escape and is not modified. | 3450 // not escape and is not modified. |
| 3475 VariableProxy* rhs = expr->value()->AsVariableProxy(); | 3451 VariableProxy* rhs = expr->value()->AsVariableProxy(); |
| 3476 if (rhs != NULL && | 3452 if (rhs != NULL && |
| 3477 rhs->var()->IsStackAllocated() && | 3453 rhs->var()->IsStackAllocated() && |
| 3478 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { | 3454 environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { |
| 3479 Push(environment()->Lookup(rhs->var())); | 3455 Push(environment()->Lookup(rhs->var())); |
| 3480 } else { | 3456 } else { |
| 3481 VISIT_FOR_VALUE(expr->value()); | 3457 VISIT_FOR_VALUE(expr->value()); |
| 3482 } | 3458 } |
| 3483 | |
| 3484 Bind(proxy->var(), Top()); | 3459 Bind(proxy->var(), Top()); |
| 3485 } | 3460 } |
| 3461 // Return the value. | |
| 3462 ast_context()->ReturnValue(Pop()); | |
| 3463 | |
| 3486 } else if (prop != NULL) { | 3464 } else if (prop != NULL) { |
| 3487 HandlePropertyAssignment(expr); | 3465 HandlePropertyAssignment(expr); |
| 3488 } else { | 3466 } else { |
| 3489 BAILOUT("unsupported invalid lhs"); | 3467 BAILOUT("unsupported invalid lhs"); |
| 3490 } | 3468 } |
| 3491 } | 3469 } |
| 3492 | 3470 |
| 3493 | 3471 |
| 3494 void HGraphBuilder::VisitThrow(Throw* expr) { | 3472 void HGraphBuilder::VisitThrow(Throw* expr) { |
| 3473 // We don't optimize functions with invalid left-hand sides in | |
| 3474 // assignments, count operations, or for-in. Consequently throw can | |
| 3475 // currently only occur in an effect context. | |
| 3476 ASSERT(ast_context()->IsEffect()); | |
| 3495 VISIT_FOR_VALUE(expr->exception()); | 3477 VISIT_FOR_VALUE(expr->exception()); |
| 3496 | 3478 |
| 3497 HValue* value = environment()->Pop(); | 3479 HValue* value = environment()->Pop(); |
| 3498 HControlInstruction* instr = new HThrow(value); | 3480 HControlInstruction* instr = new HThrow(value); |
| 3499 instr->set_position(expr->position()); | 3481 instr->set_position(expr->position()); |
| 3500 current_subgraph_->FinishExit(instr); | 3482 current_subgraph_->FinishExit(instr); |
| 3501 } | 3483 } |
| 3502 | 3484 |
| 3503 | 3485 |
| 3504 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3486 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 3518 for (int i = 0; i < number_of_types; ++i) { | 3500 for (int i = 0; i < number_of_types; ++i) { |
| 3519 Handle<Map> map = types->at(i); | 3501 Handle<Map> map = types->at(i); |
| 3520 LookupResult lookup; | 3502 LookupResult lookup; |
| 3521 map->LookupInDescriptors(NULL, *name, &lookup); | 3503 map->LookupInDescriptors(NULL, *name, &lookup); |
| 3522 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3504 if (lookup.IsProperty() && lookup.type() == FIELD) { |
| 3523 maps.Add(map); | 3505 maps.Add(map); |
| 3524 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3506 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3525 SubgraphScope scope(this, subgraph); | 3507 SubgraphScope scope(this, subgraph); |
| 3526 HInstruction* instr = | 3508 HInstruction* instr = |
| 3527 BuildLoadNamedField(object, expr, map, &lookup, false); | 3509 BuildLoadNamedField(object, expr, map, &lookup, false); |
| 3528 PushAndAdd(instr, expr->position()); | 3510 instr->set_position(expr->position()); |
| 3511 PushAndAdd(instr); | |
| 3529 subgraphs.Add(subgraph); | 3512 subgraphs.Add(subgraph); |
| 3530 } else { | 3513 } else { |
| 3531 needs_generic = true; | 3514 needs_generic = true; |
| 3532 } | 3515 } |
| 3533 } | 3516 } |
| 3534 | 3517 |
| 3535 // If none of the properties were named fields we generate a | 3518 // If none of the properties were named fields we generate a |
| 3536 // generic load. | 3519 // generic load. |
| 3537 if (maps.length() == 0) { | 3520 if (maps.length() == 0) { |
| 3538 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3521 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
| 3539 PushAndAdd(instr, expr->position()); | 3522 instr->set_position(expr->position()); |
| 3540 return; | 3523 PushAndAdd(instr); |
| 3524 if (instr->HasSideEffects()) AddSimulate(expr->id()); | |
| 3525 } else { | |
| 3526 // Build subgraph for generic load through IC. | |
| 3527 { | |
|
Kasper Lund
2010/12/09 11:40:08
Helper?
| |
| 3528 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | |
| 3529 SubgraphScope scope(this, subgraph); | |
| 3530 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3531 subgraph->FinishExit(new HDeoptimize()); | |
| 3532 } else { | |
| 3533 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | |
| 3534 instr->set_position(expr->position()); | |
| 3535 PushAndAdd(instr); | |
| 3536 } | |
| 3537 subgraphs.Add(subgraph); | |
| 3538 } | |
| 3539 | |
| 3540 HBasicBlock* new_exit_block = | |
| 3541 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | |
| 3542 subgraph()->set_exit_block(new_exit_block); | |
| 3541 } | 3543 } |
| 3542 | 3544 |
| 3543 // Build subgraph for generic load through IC. | 3545 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 } | 3546 } |
| 3560 | 3547 |
| 3561 | 3548 |
| 3562 HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object, | 3549 HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 3563 Property* expr, | 3550 Property* expr, |
| 3564 Handle<Map> type, | 3551 Handle<Map> type, |
| 3565 LookupResult* lookup, | 3552 LookupResult* lookup, |
| 3566 bool smi_and_map_check) { | 3553 bool smi_and_map_check) { |
| 3567 if (smi_and_map_check) { | 3554 if (smi_and_map_check) { |
| 3568 AddInstruction(new HCheckNonSmi(object)); | 3555 AddInstruction(new HCheckNonSmi(object)); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3661 | 3648 |
| 3662 | 3649 |
| 3663 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 3650 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
| 3664 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 3651 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
| 3665 if (proxy == NULL) return false; | 3652 if (proxy == NULL) return false; |
| 3666 if (!proxy->var()->IsStackAllocated()) return false; | 3653 if (!proxy->var()->IsStackAllocated()) return false; |
| 3667 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 3654 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
| 3668 return false; | 3655 return false; |
| 3669 } | 3656 } |
| 3670 | 3657 |
| 3658 HInstruction* result = NULL; | |
| 3671 if (expr->key()->IsPropertyName()) { | 3659 if (expr->key()->IsPropertyName()) { |
| 3672 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 3660 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 3673 if (!name->IsEqualTo(CStrVector("length"))) return false; | 3661 if (!name->IsEqualTo(CStrVector("length"))) return false; |
| 3674 HInstruction* elements = AddInstruction(new HArgumentsElements); | 3662 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 3675 PushAndAdd(new HArgumentsLength(elements)); | 3663 result = new HArgumentsLength(elements); |
| 3676 } else { | 3664 } else { |
| 3677 VisitForValue(expr->key()); | 3665 VisitForValue(expr->key()); |
| 3678 if (HasStackOverflow()) return false; | 3666 if (HasStackOverflow()) return false; |
| 3679 HValue* key = Pop(); | 3667 HValue* key = Pop(); |
| 3680 HInstruction* elements = AddInstruction(new HArgumentsElements); | 3668 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 3681 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 3669 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 3682 AddInstruction(new HBoundsCheck(key, length)); | 3670 AddInstruction(new HBoundsCheck(key, length)); |
| 3683 PushAndAdd(new HAccessArgumentsAt(elements, length, key)); | 3671 result = new HAccessArgumentsAt(elements, length, key); |
| 3684 } | 3672 } |
| 3673 ast_context()->ReturnInstruction(result, expr->id()); | |
| 3685 return true; | 3674 return true; |
| 3686 } | 3675 } |
| 3687 | 3676 |
| 3688 | 3677 |
| 3689 void HGraphBuilder::VisitProperty(Property* expr) { | 3678 void HGraphBuilder::VisitProperty(Property* expr) { |
| 3690 expr->RecordTypeFeedback(oracle()); | 3679 expr->RecordTypeFeedback(oracle()); |
| 3691 | 3680 |
| 3692 if (TryArgumentsAccess(expr)) return; | 3681 if (TryArgumentsAccess(expr)) return; |
| 3693 CHECK_BAILOUT; | 3682 CHECK_BAILOUT; |
| 3694 | 3683 |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 3721 HValue* key = Pop(); | 3710 HValue* key = Pop(); |
| 3722 HValue* obj = Pop(); | 3711 HValue* obj = Pop(); |
| 3723 | 3712 |
| 3724 bool is_fast_elements = expr->IsMonomorphic() && | 3713 bool is_fast_elements = expr->IsMonomorphic() && |
| 3725 expr->GetMonomorphicReceiverType()->has_fast_elements(); | 3714 expr->GetMonomorphicReceiverType()->has_fast_elements(); |
| 3726 | 3715 |
| 3727 instr = is_fast_elements | 3716 instr = is_fast_elements |
| 3728 ? BuildLoadKeyedFastElement(obj, key, expr) | 3717 ? BuildLoadKeyedFastElement(obj, key, expr) |
| 3729 : BuildLoadKeyedGeneric(obj, key); | 3718 : BuildLoadKeyedGeneric(obj, key); |
| 3730 } | 3719 } |
| 3731 PushAndAdd(instr, expr->position()); | 3720 instr->set_position(expr->position()); |
| 3721 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 3732 } | 3722 } |
| 3733 | 3723 |
| 3734 | 3724 |
| 3735 void HGraphBuilder::AddCheckConstantFunction(Call* expr, | 3725 void HGraphBuilder::AddCheckConstantFunction(Call* expr, |
| 3736 HValue* receiver, | 3726 HValue* receiver, |
| 3737 Handle<Map> receiver_map, | 3727 Handle<Map> receiver_map, |
| 3738 bool smi_and_map_check) { | 3728 bool smi_and_map_check) { |
| 3739 // Constant functions have the nice property that the map will change if they | 3729 // 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 | 3730 // are overwritten. Therefore it is enough to check the map of the holder and |
| 3741 // its prototypes. | 3731 // its prototypes. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 3756 ZoneMapList* types, | 3746 ZoneMapList* types, |
| 3757 Handle<String> name) { | 3747 Handle<String> name) { |
| 3758 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 3748 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 3759 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | 3749 int number_of_types = Min(types->length(), kMaxCallPolymorphism); |
| 3760 ZoneMapList maps(number_of_types); | 3750 ZoneMapList maps(number_of_types); |
| 3761 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3751 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); |
| 3762 bool needs_generic = (types->length() > kMaxCallPolymorphism); | 3752 bool needs_generic = (types->length() > kMaxCallPolymorphism); |
| 3763 | 3753 |
| 3764 // Build subgraphs for each of the specific maps. | 3754 // Build subgraphs for each of the specific maps. |
| 3765 // | 3755 // |
| 3766 // TODO(ager): We should recognize when the prototype chains for | 3756 // TODO(ager): We should recognize when the prototype chains for different |
| 3767 // different maps are identical. In that case we can avoid | 3757 // maps are identical. In that case we can avoid repeatedly generating the |
| 3768 // repeatedly generating the same prototype map checks. | 3758 // same prototype map checks. |
| 3769 for (int i = 0; i < number_of_types; ++i) { | 3759 for (int i = 0; i < number_of_types; ++i) { |
| 3770 Handle<Map> map = types->at(i); | 3760 Handle<Map> map = types->at(i); |
| 3771 if (expr->ComputeTarget(map, name)) { | 3761 if (expr->ComputeTarget(map, name)) { |
| 3772 maps.Add(map); | 3762 maps.Add(map); |
| 3773 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3763 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| 3774 SubgraphScope scope(this, subgraph); | 3764 SubgraphScope scope(this, subgraph); |
| 3775 AddCheckConstantFunction(expr, receiver, map, false); | 3765 AddCheckConstantFunction(expr, receiver, map, false); |
| 3776 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 3766 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 3777 PrintF("Trying to inline the polymorphic call to %s\n", | 3767 PrintF("Trying to inline the polymorphic call to %s\n", |
| 3778 *name->ToCString()); | 3768 *name->ToCString()); |
| 3779 } | 3769 } |
| 3780 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { | 3770 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { |
| 3781 // Check for bailout, as trying to inline might fail due to bailout | 3771 // Check for bailout, as trying to inline might fail due to bailout |
| 3782 // during hydrogen processing. | 3772 // during hydrogen processing. |
| 3783 CHECK_BAILOUT; | 3773 CHECK_BAILOUT; |
| 3784 HCall* call = new HCallConstantFunction(expr->target(), argument_count); | 3774 HCall* call = new HCallConstantFunction(expr->target(), argument_count); |
| 3785 ProcessCall(call, expr->position()); | 3775 call->set_position(expr->position()); |
| 3776 ProcessCall(call); | |
| 3777 PushAndAdd(call); | |
| 3786 } | 3778 } |
| 3787 subgraphs.Add(subgraph); | 3779 subgraphs.Add(subgraph); |
| 3788 } else { | 3780 } else { |
| 3789 needs_generic = true; | 3781 needs_generic = true; |
| 3790 } | 3782 } |
| 3791 } | 3783 } |
| 3792 | 3784 |
| 3793 // If we couldn't compute the target for any of the maps just | 3785 // If we couldn't compute the target for any of the maps just perform an |
| 3794 // perform an IC call. | 3786 // IC call. |
| 3795 if (maps.length() == 0) { | 3787 if (maps.length() == 0) { |
| 3796 HCall* call = new HCallNamed(name, argument_count); | 3788 HCall* call = new HCallNamed(name, argument_count); |
| 3797 ProcessCall(call, expr->position()); | 3789 call->set_position(expr->position()); |
| 3798 return; | 3790 ProcessCall(call); |
| 3791 ast_context()->ReturnInstruction(call, expr->id()); | |
| 3792 } else { | |
| 3793 // Build subgraph for generic call through IC. | |
| 3794 { | |
| 3795 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | |
|
Kasper Lund
2010/12/09 11:40:08
Helper? Maybe the three helpers can actually share
| |
| 3796 SubgraphScope scope(this, subgraph); | |
| 3797 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | |
| 3798 subgraph->FinishExit(new HDeoptimize()); | |
| 3799 } else { | |
| 3800 HCall* call = new HCallNamed(name, argument_count); | |
| 3801 call->set_position(expr->position()); | |
| 3802 ProcessCall(call); | |
| 3803 PushAndAdd(call); | |
| 3804 } | |
| 3805 subgraphs.Add(subgraph); | |
| 3806 } | |
| 3807 | |
| 3808 HBasicBlock* new_exit_block = | |
| 3809 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); | |
| 3810 subgraph()->set_exit_block(new_exit_block); | |
| 3811 if (new_exit_block != NULL) ast_context()->ReturnValue(Pop()); | |
| 3799 } | 3812 } |
| 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 } | 3813 } |
| 3818 | 3814 |
| 3819 | 3815 |
| 3820 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { | 3816 void HGraphBuilder::TraceInline(Handle<JSFunction> target, bool result) { |
| 3821 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); | 3817 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); |
| 3822 SmartPointer<char> caller = | 3818 SmartPointer<char> caller = |
| 3823 graph()->info()->function()->debug_name()->ToCString(); | 3819 graph()->info()->function()->debug_name()->ToCString(); |
| 3824 if (result) { | 3820 if (result) { |
| 3825 PrintF("Inlined %s called from %s.\n", *callee, *caller); | 3821 PrintF("Inlined %s called from %s.\n", *callee, *caller); |
| 3826 } else { | 3822 } else { |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4054 | 4050 |
| 4055 } else { | 4051 } else { |
| 4056 function_return_->SetJoinId(expr->id()); | 4052 function_return_->SetJoinId(expr->id()); |
| 4057 subgraph()->set_exit_block(function_return_); | 4053 subgraph()->set_exit_block(function_return_); |
| 4058 } | 4054 } |
| 4059 | 4055 |
| 4060 call_context_ = saved_call_context; | 4056 call_context_ = saved_call_context; |
| 4061 function_return_ = saved_function_return; | 4057 function_return_ = saved_function_return; |
| 4062 oracle_ = saved_oracle; | 4058 oracle_ = saved_oracle; |
| 4063 graph()->info()->SetOsrAstId(saved_osr_ast_id); | 4059 graph()->info()->SetOsrAstId(saved_osr_ast_id); |
| 4060 | |
| 4064 return true; | 4061 return true; |
| 4065 } | 4062 } |
| 4066 | 4063 |
| 4067 | 4064 |
| 4068 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 4065 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { |
| 4069 ASSERT(target->IsInlineReturnTarget()); | 4066 ASSERT(target->IsInlineReturnTarget()); |
| 4070 AddInstruction(new HLeaveInlined); | 4067 AddInstruction(new HLeaveInlined); |
| 4071 HEnvironment* outer = last_environment()->outer(); | 4068 HEnvironment* outer = last_environment()->outer(); |
| 4072 outer->Push(return_value); | 4069 outer->Push(return_value); |
| 4073 UpdateEnvironment(outer); | 4070 UpdateEnvironment(outer); |
| 4074 Goto(target); | 4071 Goto(target); |
| 4075 } | 4072 } |
| 4076 | 4073 |
| 4077 | 4074 |
| 4078 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { | 4075 bool HGraphBuilder::TryMathFunctionInline(Call* expr) { |
| 4079 // Try to inline calls like Math.* as operations in the calling function. | 4076 // Try to inline calls like Math.* as operations in the calling function. |
| 4080 MathFunctionId id = expr->target()->shared()->math_function_id(); | 4077 MathFunctionId id = expr->target()->shared()->math_function_id(); |
| 4081 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4078 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4082 switch (id) { | 4079 switch (id) { |
| 4083 case kMathRound: | 4080 case kMathRound: |
| 4084 case kMathFloor: | 4081 case kMathFloor: |
| 4085 case kMathAbs: | 4082 case kMathAbs: |
| 4086 case kMathSqrt: | 4083 case kMathSqrt: |
| 4087 if (argument_count == 2) { | 4084 if (argument_count == 2) { |
| 4088 HValue* argument = Pop(); | 4085 HValue* argument = Pop(); |
| 4089 // Pop receiver. | 4086 Drop(1); // Receiver. |
| 4090 Pop(); | |
| 4091 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); | 4087 HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); |
| 4092 PushAndAdd(op, expr->position()); | 4088 op->set_position(expr->position()); |
| 4089 ast_context()->ReturnInstruction(op, expr->id()); | |
| 4093 return true; | 4090 return true; |
| 4094 } | 4091 } |
| 4095 break; | 4092 break; |
| 4096 case kMathPow: | 4093 case kMathPow: |
| 4097 if (argument_count == 3) { | 4094 if (argument_count == 3) { |
| 4098 HValue* right = Pop(); | 4095 HValue* right = Pop(); |
| 4099 HValue* left = Pop(); | 4096 HValue* left = Pop(); |
| 4100 Pop(); // Pop receiver. | 4097 Pop(); // Pop receiver. |
| 4098 HInstruction* result = NULL; | |
| 4101 // Use sqrt() if exponent is 0.5 or -0.5. | 4099 // Use sqrt() if exponent is 0.5 or -0.5. |
| 4102 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 4100 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 4103 double exponent = HConstant::cast(right)->DoubleValue(); | 4101 double exponent = HConstant::cast(right)->DoubleValue(); |
| 4104 if (exponent == 0.5) { | 4102 if (exponent == 0.5) { |
| 4105 PushAndAdd(new HUnaryMathOperation(left, kMathPowHalf)); | 4103 result = new HUnaryMathOperation(left, kMathPowHalf); |
| 4104 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4106 return true; | 4105 return true; |
| 4107 } else if (exponent == -0.5) { | 4106 } else if (exponent == -0.5) { |
| 4108 HConstant* double_one = | 4107 HConstant* double_one = |
| 4109 new HConstant(Handle<Object>(Smi::FromInt(1)), | 4108 new HConstant(Handle<Object>(Smi::FromInt(1)), |
| 4110 Representation::Double()); | 4109 Representation::Double()); |
| 4111 AddInstruction(double_one); | 4110 AddInstruction(double_one); |
| 4112 HUnaryMathOperation* square_root = | 4111 HUnaryMathOperation* square_root = |
| 4113 new HUnaryMathOperation(left, kMathPowHalf); | 4112 new HUnaryMathOperation(left, kMathPowHalf); |
| 4114 AddInstruction(square_root); | 4113 AddInstruction(square_root); |
| 4115 PushAndAdd(new HDiv(double_one, square_root)); | 4114 // MathPowHalf doesn't have side effects so there's no need for |
| 4115 // an environment simulation here. | |
| 4116 ASSERT(!square_root->HasSideEffects()); | |
| 4117 result = new HDiv(double_one, square_root); | |
| 4118 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4116 return true; | 4119 return true; |
| 4117 } else if (exponent == 2.0) { | 4120 } else if (exponent == 2.0) { |
| 4118 PushAndAdd(new HMul(left, left)); | 4121 result = new HMul(left, left); |
| 4122 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4119 return true; | 4123 return true; |
| 4120 } | 4124 } |
| 4121 } else if (right->IsConstant() && | 4125 } else if (right->IsConstant() && |
| 4122 HConstant::cast(right)->HasInteger32Value() && | 4126 HConstant::cast(right)->HasInteger32Value() && |
| 4123 HConstant::cast(right)->Integer32Value() == 2) { | 4127 HConstant::cast(right)->Integer32Value() == 2) { |
| 4124 PushAndAdd(new HMul(left, left)); | 4128 result = new HMul(left, left); |
| 4129 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4125 return true; | 4130 return true; |
| 4126 } | 4131 } |
| 4127 | 4132 |
| 4128 PushAndAdd(new HPower(left, right)); | 4133 result = new HPower(left, right); |
| 4134 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4129 return true; | 4135 return true; |
| 4130 } | 4136 } |
| 4131 break; | 4137 break; |
| 4132 default: | 4138 default: |
| 4133 // Either not a special math function or not yet supported for inlining. | 4139 // Either not a special math function or not yet supported for inlining. |
| 4134 break; | 4140 break; |
| 4135 } | 4141 } |
| 4136 return false; | 4142 return false; |
| 4137 } | 4143 } |
| 4138 | 4144 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 4163 HValue* function = Pop(); | 4169 HValue* function = Pop(); |
| 4164 VisitForValue(args->at(0)); | 4170 VisitForValue(args->at(0)); |
| 4165 if (HasStackOverflow()) return false; | 4171 if (HasStackOverflow()) return false; |
| 4166 HValue* receiver = Pop(); | 4172 HValue* receiver = Pop(); |
| 4167 HInstruction* elements = AddInstruction(new HArgumentsElements); | 4173 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4168 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 4174 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 4169 AddCheckConstantFunction(expr, | 4175 AddCheckConstantFunction(expr, |
| 4170 function, | 4176 function, |
| 4171 expr->GetReceiverTypes()->first(), | 4177 expr->GetReceiverTypes()->first(), |
| 4172 true); | 4178 true); |
| 4173 PushAndAdd(new HApplyArguments(function, receiver, length, elements), | 4179 HInstruction* result = |
| 4174 expr->position()); | 4180 new HApplyArguments(function, receiver, length, elements); |
| 4181 result->set_position(expr->position()); | |
| 4182 ast_context()->ReturnInstruction(result, expr->id()); | |
| 4175 return true; | 4183 return true; |
| 4176 } | 4184 } |
| 4177 | 4185 |
| 4178 | 4186 |
| 4179 void HGraphBuilder::VisitCall(Call* expr) { | 4187 void HGraphBuilder::VisitCall(Call* expr) { |
| 4180 Expression* callee = expr->expression(); | 4188 Expression* callee = expr->expression(); |
| 4181 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 4189 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 4182 HCall* call = NULL; | 4190 HCall* call = NULL; |
| 4183 | 4191 |
| 4184 Property* prop = callee->AsProperty(); | 4192 Property* prop = callee->AsProperty(); |
| 4185 if (prop != NULL) { | 4193 if (prop != NULL) { |
| 4186 if (!prop->key()->IsPropertyName()) { | 4194 if (!prop->key()->IsPropertyName()) { |
| 4187 // Keyed function call. | 4195 // Keyed function call. |
| 4188 VisitArgument(prop->obj()); | 4196 VisitArgument(prop->obj()); |
| 4189 CHECK_BAILOUT; | 4197 CHECK_BAILOUT; |
| 4190 | 4198 |
| 4191 VISIT_FOR_VALUE(prop->key()); | 4199 VISIT_FOR_VALUE(prop->key()); |
| 4192 // Push receiver and key like the non-optimized code generator expects it. | 4200 // Push receiver and key like the non-optimized code generator expects it. |
| 4193 HValue* key = Pop(); | 4201 HValue* key = Pop(); |
| 4194 HValue* receiver = Pop(); | 4202 HValue* receiver = Pop(); |
| 4195 Push(key); | 4203 Push(key); |
| 4196 Push(receiver); | 4204 Push(receiver); |
| 4197 | 4205 |
| 4198 VisitArgumentList(expr->arguments()); | 4206 VisitArgumentList(expr->arguments()); |
| 4199 CHECK_BAILOUT; | 4207 CHECK_BAILOUT; |
| 4200 | 4208 |
| 4201 call = new HCallKeyed(key, argument_count); | 4209 call = new HCallKeyed(key, argument_count); |
| 4202 ProcessCall(call, expr->position()); | 4210 call->set_position(expr->position()); |
| 4203 HValue* result = Pop(); | 4211 ProcessCall(call); |
| 4204 // Drop the receiver from the environment and put back the result of | 4212 Drop(1); // Key. |
| 4205 // the call. | 4213 ast_context()->ReturnInstruction(call, expr->id()); |
| 4206 Drop(1); | |
| 4207 Push(result); | |
| 4208 return; | 4214 return; |
| 4209 } | 4215 } |
| 4210 | 4216 |
| 4211 // Named function call. | 4217 // Named function call. |
| 4212 expr->RecordTypeFeedback(oracle()); | 4218 expr->RecordTypeFeedback(oracle()); |
| 4213 | 4219 |
| 4214 if (TryCallApply(expr)) return; | 4220 if (TryCallApply(expr)) return; |
| 4215 CHECK_BAILOUT; | 4221 CHECK_BAILOUT; |
| 4216 | 4222 |
| 4217 HValue* receiver = VisitArgument(prop->obj()); | 4223 HValue* receiver = VisitArgument(prop->obj()); |
| 4218 CHECK_BAILOUT; | 4224 CHECK_BAILOUT; |
| 4219 VisitArgumentList(expr->arguments()); | 4225 VisitArgumentList(expr->arguments()); |
| 4220 CHECK_BAILOUT; | 4226 CHECK_BAILOUT; |
| 4221 | 4227 |
| 4222 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4228 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4223 | 4229 |
| 4224 expr->RecordTypeFeedback(oracle()); | 4230 expr->RecordTypeFeedback(oracle()); |
| 4225 ZoneMapList* types = expr->GetReceiverTypes(); | 4231 ZoneMapList* types = expr->GetReceiverTypes(); |
| 4226 | 4232 |
| 4227 if (expr->IsMonomorphic()) { | 4233 if (expr->IsMonomorphic()) { |
| 4228 AddCheckConstantFunction(expr, receiver, types->first(), true); | 4234 AddCheckConstantFunction(expr, receiver, types->first(), true); |
| 4229 | 4235 |
| 4230 if (TryMathFunctionInline(expr) || TryInline(expr)) { | 4236 if (TryMathFunctionInline(expr)) { |
| 4237 return; | |
| 4238 } else if (TryInline(expr)) { | |
| 4239 if (subgraph()->HasExit()) { | |
|
Kasper Lund
2010/12/09 11:40:08
This code is duplicated below (along with a nice b
| |
| 4240 HValue* return_value = Pop(); | |
| 4241 // If we inlined a function in a test context then we need to emit | |
| 4242 // a simulate here to shadow the ones at the end of the | |
| 4243 // predecessor blocks. Those environments contain the return | |
| 4244 // value on top and do not correspond to any actual state of the | |
| 4245 // unoptimized code. | |
| 4246 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4247 ast_context()->ReturnValue(return_value); | |
| 4248 } | |
| 4231 return; | 4249 return; |
| 4232 } else { | 4250 } else { |
| 4233 // Check for bailout, as the TryInline call in the if condition above | 4251 // Check for bailout, as the TryInline call in the if condition above |
| 4234 // might return false due to bailout during hydrogen processing. | 4252 // might return false due to bailout during hydrogen processing. |
| 4235 CHECK_BAILOUT; | 4253 CHECK_BAILOUT; |
| 4236 call = new HCallConstantFunction(expr->target(), argument_count); | 4254 call = new HCallConstantFunction(expr->target(), argument_count); |
| 4237 } | 4255 } |
| 4256 | |
| 4238 } else if (types != NULL && types->length() > 1) { | 4257 } else if (types != NULL && types->length() > 1) { |
| 4239 HandlePolymorphicCallNamed(expr, receiver, types, name); | 4258 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 4240 return; | 4259 return; |
| 4241 | 4260 |
| 4242 } else { | 4261 } else { |
| 4243 call = new HCallNamed(name, argument_count); | 4262 call = new HCallNamed(name, argument_count); |
| 4244 } | 4263 } |
| 4245 | 4264 |
| 4246 } else { | 4265 } else { |
| 4247 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4266 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 4275 | 4294 |
| 4276 // Replace the global object with the global receiver. | 4295 // Replace the global object with the global receiver. |
| 4277 HGlobalReceiver* global_receiver = new HGlobalReceiver; | 4296 HGlobalReceiver* global_receiver = new HGlobalReceiver; |
| 4278 // Index of the receiver from the top of the expression stack. | 4297 // Index of the receiver from the top of the expression stack. |
| 4279 const int receiver_index = argument_count - 1; | 4298 const int receiver_index = argument_count - 1; |
| 4280 AddInstruction(global_receiver); | 4299 AddInstruction(global_receiver); |
| 4281 ASSERT(environment()->ExpressionStackAt(receiver_index)-> | 4300 ASSERT(environment()->ExpressionStackAt(receiver_index)-> |
| 4282 IsGlobalObject()); | 4301 IsGlobalObject()); |
| 4283 environment()->SetExpressionStackAt(receiver_index, global_receiver); | 4302 environment()->SetExpressionStackAt(receiver_index, global_receiver); |
| 4284 | 4303 |
| 4285 if (TryInline(expr)) return; | 4304 if (TryInline(expr)) { |
| 4305 if (subgraph()->HasExit()) { | |
| 4306 HValue* return_value = Pop(); | |
| 4307 // If we inlined a function in a test context then we need to | |
| 4308 // emit a simulate here to shadow the ones at the end of the | |
| 4309 // predecessor blocks. Those environments contain the return | |
| 4310 // value on top and do not correspond to any actual state of the | |
| 4311 // unoptimized code. | |
| 4312 if (ast_context()->IsEffect()) AddSimulate(expr->id()); | |
| 4313 ast_context()->ReturnValue(return_value); | |
| 4314 } | |
| 4315 return; | |
| 4316 } | |
| 4286 // Check for bailout, as trying to inline might fail due to bailout | 4317 // Check for bailout, as trying to inline might fail due to bailout |
| 4287 // during hydrogen processing. | 4318 // during hydrogen processing. |
| 4288 CHECK_BAILOUT; | 4319 CHECK_BAILOUT; |
| 4289 | 4320 |
| 4290 call = new HCallKnownGlobal(expr->target(), argument_count); | 4321 call = new HCallKnownGlobal(expr->target(), argument_count); |
| 4291 } else { | 4322 } else { |
| 4292 PushAndAdd(new HGlobalObject); | 4323 PushAndAdd(new HGlobalObject); |
| 4293 VisitArgumentList(expr->arguments()); | 4324 VisitArgumentList(expr->arguments()); |
| 4294 CHECK_BAILOUT; | 4325 CHECK_BAILOUT; |
| 4295 | 4326 |
| 4296 call = new HCallGlobal(var->name(), argument_count); | 4327 call = new HCallGlobal(var->name(), argument_count); |
| 4297 } | 4328 } |
| 4298 | 4329 |
| 4299 } else { | 4330 } else { |
| 4300 PushAndAdd(new HGlobalReceiver); | 4331 PushAndAdd(new HGlobalReceiver); |
| 4301 VisitArgumentList(expr->arguments()); | 4332 VisitArgumentList(expr->arguments()); |
| 4302 CHECK_BAILOUT; | 4333 CHECK_BAILOUT; |
| 4303 | 4334 |
| 4304 call = new HCallFunction(argument_count); | 4335 call = new HCallFunction(argument_count); |
| 4305 } | 4336 } |
| 4306 } | 4337 } |
| 4307 | 4338 |
| 4308 ProcessCall(call, expr->position()); | 4339 call->set_position(expr->position()); |
| 4340 ProcessCall(call); | |
| 4341 ast_context()->ReturnInstruction(call, expr->id()); | |
| 4309 } | 4342 } |
| 4310 | 4343 |
| 4311 | 4344 |
| 4312 void HGraphBuilder::VisitCallNew(CallNew* expr) { | 4345 void HGraphBuilder::VisitCallNew(CallNew* expr) { |
| 4313 // The constructor function is also used as the receiver argument to the | 4346 // The constructor function is also used as the receiver argument to the |
| 4314 // JS construct call builtin. | 4347 // JS construct call builtin. |
| 4315 VisitArgument(expr->expression()); | 4348 VisitArgument(expr->expression()); |
| 4316 CHECK_BAILOUT; | 4349 CHECK_BAILOUT; |
| 4317 VisitArgumentList(expr->arguments()); | 4350 VisitArgumentList(expr->arguments()); |
| 4318 CHECK_BAILOUT; | 4351 CHECK_BAILOUT; |
| 4319 | 4352 |
| 4320 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 4353 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 4321 HCall* call = new HCallNew(argument_count); | 4354 HCall* call = new HCallNew(argument_count); |
| 4322 | 4355 call->set_position(expr->position()); |
| 4323 ProcessCall(call, expr->position()); | 4356 ProcessCall(call); |
| 4357 ast_context()->ReturnInstruction(call, expr->id()); | |
| 4324 } | 4358 } |
| 4325 | 4359 |
| 4326 | 4360 |
| 4327 // Support for generating inlined runtime functions. | 4361 // Support for generating inlined runtime functions. |
| 4328 | 4362 |
| 4329 // Lookup table for generators for runtime calls that are generated inline. | 4363 // Lookup table for generators for runtime calls that are generated inline. |
| 4330 // Elements of the table are member pointers to functions of HGraphBuilder. | 4364 // Elements of the table are member pointers to functions of HGraphBuilder. |
| 4331 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ | 4365 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ |
| 4332 &HGraphBuilder::Generate##Name, | 4366 &HGraphBuilder::Generate##Name, |
| 4333 | 4367 |
| 4334 const HGraphBuilder::InlineFunctionGenerator | 4368 const HGraphBuilder::InlineFunctionGenerator |
| 4335 HGraphBuilder::kInlineFunctionGenerators[] = { | 4369 HGraphBuilder::kInlineFunctionGenerators[] = { |
| 4336 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 4370 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 4337 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) | 4371 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) |
| 4338 }; | 4372 }; |
| 4339 #undef INLINE_FUNCTION_GENERATOR_ADDRESS | 4373 #undef INLINE_FUNCTION_GENERATOR_ADDRESS |
| 4340 | 4374 |
| 4341 | 4375 |
| 4342 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { | 4376 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
| 4343 Handle<String> name = expr->name(); | 4377 Handle<String> name = expr->name(); |
| 4344 if (name->IsEqualTo(CStrVector("_Log"))) { | 4378 if (name->IsEqualTo(CStrVector("_Log"))) { |
| 4345 Push(graph()->GetConstantUndefined()); | 4379 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4346 return; | 4380 return; |
| 4347 } | 4381 } |
| 4348 | 4382 |
| 4349 Runtime::Function* function = expr->function(); | 4383 Runtime::Function* function = expr->function(); |
| 4350 if (expr->is_jsruntime()) { | 4384 if (expr->is_jsruntime()) { |
| 4351 BAILOUT("call to a JavaScript runtime function"); | 4385 BAILOUT("call to a JavaScript runtime function"); |
| 4352 } | 4386 } |
| 4353 ASSERT(function != NULL); | 4387 ASSERT(function != NULL); |
| 4354 | 4388 |
| 4355 VisitArgumentList(expr->arguments()); | 4389 VisitArgumentList(expr->arguments()); |
| 4356 CHECK_BAILOUT; | 4390 CHECK_BAILOUT; |
| 4357 | 4391 |
| 4358 int argument_count = expr->arguments()->length(); | 4392 int argument_count = expr->arguments()->length(); |
| 4359 if (function->intrinsic_type == Runtime::INLINE) { | 4393 if (function->intrinsic_type == Runtime::INLINE) { |
| 4360 ASSERT(name->length() > 0); | 4394 ASSERT(name->length() > 0); |
| 4361 ASSERT(name->Get(0) == '_'); | 4395 ASSERT(name->Get(0) == '_'); |
| 4362 // Call to an inline function. | 4396 // Call to an inline function. |
| 4363 int lookup_index = static_cast<int>(function->function_id) - | 4397 int lookup_index = static_cast<int>(function->function_id) - |
| 4364 static_cast<int>(Runtime::kFirstInlineFunction); | 4398 static_cast<int>(Runtime::kFirstInlineFunction); |
| 4365 ASSERT(lookup_index >= 0); | 4399 ASSERT(lookup_index >= 0); |
| 4366 ASSERT(static_cast<size_t>(lookup_index) < | 4400 ASSERT(static_cast<size_t>(lookup_index) < |
| 4367 ARRAY_SIZE(kInlineFunctionGenerators)); | 4401 ARRAY_SIZE(kInlineFunctionGenerators)); |
| 4368 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; | 4402 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; |
| 4369 | 4403 |
| 4370 // Call the inline code generator using the pointer-to-member. | 4404 // Call the inline code generator using the pointer-to-member. |
| 4371 (this->*generator)(argument_count); | 4405 (this->*generator)(argument_count, expr->id()); |
| 4372 } else { | 4406 } else { |
| 4373 ASSERT(function->intrinsic_type == Runtime::RUNTIME); | 4407 ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
| 4374 HCall* call = new HCallRuntime(name, expr->function(), argument_count); | 4408 HCall* call = new HCallRuntime(name, expr->function(), argument_count); |
| 4375 ProcessCall(call, RelocInfo::kNoPosition); | 4409 call->set_position(RelocInfo::kNoPosition); |
| 4410 ProcessCall(call); | |
| 4411 ast_context()->ReturnInstruction(call, expr->id()); | |
| 4376 } | 4412 } |
| 4377 } | 4413 } |
| 4378 | 4414 |
| 4379 | 4415 |
| 4380 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { | 4416 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
| 4381 Token::Value op = expr->op(); | 4417 Token::Value op = expr->op(); |
| 4382 if (op == Token::VOID) { | 4418 if (op == Token::VOID) { |
| 4383 VISIT_FOR_EFFECT(expr->expression()); | 4419 VISIT_FOR_EFFECT(expr->expression()); |
| 4384 Push(graph()->GetConstantUndefined()); | 4420 ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 4385 } else if (op == Token::DELETE) { | 4421 } else if (op == Token::DELETE) { |
| 4386 Property* prop = expr->expression()->AsProperty(); | 4422 Property* prop = expr->expression()->AsProperty(); |
| 4387 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 4423 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 4388 if (prop == NULL && var == NULL) { | 4424 if (prop == NULL && var == NULL) { |
| 4389 // Result of deleting non-property, non-variable reference is true. | 4425 // Result of deleting non-property, non-variable reference is true. |
| 4390 // Evaluate the subexpression for side effects. | 4426 // Evaluate the subexpression for side effects. |
| 4391 VISIT_FOR_EFFECT(expr->expression()); | 4427 VISIT_FOR_EFFECT(expr->expression()); |
| 4392 Push(graph_->GetConstantTrue()); | 4428 ast_context()->ReturnValue(graph()->GetConstantTrue()); |
| 4393 } else if (var != NULL && | 4429 } else if (var != NULL && |
| 4394 !var->is_global() && | 4430 !var->is_global() && |
| 4395 var->AsSlot() != NULL && | 4431 var->AsSlot() != NULL && |
| 4396 var->AsSlot()->type() != Slot::LOOKUP) { | 4432 var->AsSlot()->type() != Slot::LOOKUP) { |
| 4397 // Result of deleting non-global, non-dynamic variables is false. | 4433 // Result of deleting non-global, non-dynamic variables is false. |
| 4398 // The subexpression does not have side effects. | 4434 // The subexpression does not have side effects. |
| 4399 Push(graph_->GetConstantFalse()); | 4435 ast_context()->ReturnValue(graph()->GetConstantFalse()); |
| 4400 } else if (prop != NULL) { | 4436 } else if (prop != NULL) { |
| 4401 VISIT_FOR_VALUE(prop->obj()); | 4437 VISIT_FOR_VALUE(prop->obj()); |
| 4402 VISIT_FOR_VALUE(prop->key()); | 4438 VISIT_FOR_VALUE(prop->key()); |
| 4403 HValue* key = Pop(); | 4439 HValue* key = Pop(); |
| 4404 HValue* obj = Pop(); | 4440 HValue* obj = Pop(); |
| 4405 PushAndAdd(new HDeleteProperty(obj, key)); | 4441 ast_context()->ReturnInstruction(new HDeleteProperty(obj, key), |
| 4442 expr->id()); | |
| 4406 } else if (var->is_global()) { | 4443 } else if (var->is_global()) { |
| 4407 BAILOUT("delete with global variable"); | 4444 BAILOUT("delete with global variable"); |
| 4408 } else { | 4445 } else { |
| 4409 BAILOUT("delete with non-global variable"); | 4446 BAILOUT("delete with non-global variable"); |
| 4410 } | 4447 } |
| 4411 } else if (op == Token::NOT) { | 4448 } else if (op == Token::NOT) { |
| 4412 HSubgraph* true_graph = CreateEmptySubgraph(); | 4449 if (ast_context()->IsTest()) { |
| 4413 HSubgraph* false_graph = CreateEmptySubgraph(); | 4450 TestContext* context = TestContext::cast(ast_context()); |
| 4414 VisitCondition(expr->expression(), | 4451 VisitForControl(expr->expression(), |
| 4415 false_graph->entry_block(), | 4452 context->if_false(), |
| 4416 true_graph->entry_block(), | 4453 context->if_true(), |
| 4417 true, true); | 4454 !context->invert_false(), |
| 4418 if (HasStackOverflow()) return; | 4455 !context->invert_true()); |
| 4419 true_graph->environment()->Push(graph_->GetConstantTrue()); | 4456 } else { |
| 4420 false_graph->environment()->Push(graph_->GetConstantFalse()); | 4457 HSubgraph* true_graph = CreateEmptySubgraph(); |
| 4421 current_subgraph_->AppendJoin(true_graph, false_graph, expr); | 4458 HSubgraph* false_graph = CreateEmptySubgraph(); |
| 4459 VisitCondition(expr->expression(), | |
| 4460 false_graph->entry_block(), | |
| 4461 true_graph->entry_block(), | |
| 4462 true, true); | |
| 4463 if (HasStackOverflow()) return; | |
| 4464 true_graph->environment()->Push(graph_->GetConstantTrue()); | |
| 4465 false_graph->environment()->Push(graph_->GetConstantFalse()); | |
| 4466 current_subgraph_->AppendJoin(true_graph, false_graph, expr); | |
| 4467 ast_context()->ReturnValue(Pop()); | |
| 4468 } | |
| 4422 } else if (op == Token::BIT_NOT || op == Token::SUB) { | 4469 } else if (op == Token::BIT_NOT || op == Token::SUB) { |
| 4423 VISIT_FOR_VALUE(expr->expression()); | 4470 VISIT_FOR_VALUE(expr->expression()); |
| 4424 HValue* value = Pop(); | 4471 HValue* value = Pop(); |
| 4425 HInstruction* instr = NULL; | 4472 HInstruction* instr = NULL; |
| 4426 switch (op) { | 4473 switch (op) { |
| 4427 case Token::BIT_NOT: | 4474 case Token::BIT_NOT: |
| 4428 instr = new HBitNot(value); | 4475 instr = new HBitNot(value); |
| 4429 break; | 4476 break; |
| 4430 case Token::SUB: | 4477 case Token::SUB: |
| 4431 instr = new HMul(graph_->GetConstantMinus1(), value); | 4478 instr = new HMul(graph_->GetConstantMinus1(), value); |
| 4432 break; | 4479 break; |
| 4433 default: | 4480 default: |
| 4434 UNREACHABLE(); | 4481 UNREACHABLE(); |
| 4435 break; | 4482 break; |
| 4436 } | 4483 } |
| 4437 PushAndAdd(instr); | 4484 ast_context()->ReturnInstruction(instr, expr->id()); |
| 4438 } else if (op == Token::TYPEOF) { | 4485 } else if (op == Token::TYPEOF) { |
| 4439 VISIT_FOR_VALUE(expr->expression()); | 4486 VISIT_FOR_VALUE(expr->expression()); |
| 4440 HValue* value = Pop(); | 4487 HValue* value = Pop(); |
| 4441 PushAndAdd(new HTypeof(value)); | 4488 ast_context()->ReturnInstruction(new HTypeof(value), expr->id()); |
| 4442 } else { | 4489 } else { |
| 4443 BAILOUT("Value: unsupported unary operation"); | 4490 BAILOUT("Value: unsupported unary operation"); |
| 4444 } | 4491 } |
| 4445 } | 4492 } |
| 4446 | 4493 |
| 4447 | 4494 |
| 4448 void HGraphBuilder::VisitIncrementOperation(IncrementOperation* expr) { | 4495 void HGraphBuilder::VisitIncrementOperation(IncrementOperation* expr) { |
| 4449 // IncrementOperation is never visited by the visitor. It only | 4496 // IncrementOperation is never visited by the visitor. It only |
| 4450 // occurs as a subexpression of CountOperation. | 4497 // occurs as a subexpression of CountOperation. |
| 4451 UNREACHABLE(); | 4498 UNREACHABLE(); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 4482 HInstruction* instr = BuildIncrement(value, inc); | 4529 HInstruction* instr = BuildIncrement(value, inc); |
| 4483 AddInstruction(instr); | 4530 AddInstruction(instr); |
| 4484 | 4531 |
| 4485 if (expr->is_prefix()) { | 4532 if (expr->is_prefix()) { |
| 4486 Push(instr); | 4533 Push(instr); |
| 4487 } else { | 4534 } else { |
| 4488 Push(value); | 4535 Push(value); |
| 4489 } | 4536 } |
| 4490 | 4537 |
| 4491 if (var->is_global()) { | 4538 if (var->is_global()) { |
| 4492 HandleGlobalVariableAssignment(proxy, instr, expr->position()); | 4539 HandleGlobalVariableAssignment(var, instr, expr->position(), expr->id()); |
| 4493 } else { | 4540 } else { |
| 4494 ASSERT(var->IsStackAllocated()); | 4541 ASSERT(var->IsStackAllocated()); |
| 4495 Bind(var, instr); | 4542 Bind(var, instr); |
| 4496 } | 4543 } |
| 4544 ast_context()->ReturnValue(Pop()); | |
| 4497 | 4545 |
| 4498 } else if (prop != NULL) { | 4546 } else if (prop != NULL) { |
| 4499 prop->RecordTypeFeedback(oracle()); | 4547 prop->RecordTypeFeedback(oracle()); |
| 4500 | 4548 |
| 4501 if (prop->key()->IsPropertyName()) { | 4549 if (prop->key()->IsPropertyName()) { |
| 4502 // Named property. | 4550 // Named property. |
| 4503 | 4551 |
| 4504 // Match the full code generator stack by simulate an extra stack element | 4552 // Match the full code generator stack by simulating an extra stack |
| 4505 // for postfix operations in a value context. | 4553 // element for postfix operations in a value context. |
| 4506 if (expr->is_postfix() && !ast_context()->IsEffect()) { | 4554 if (expr->is_postfix() && !ast_context()->IsEffect()) { |
| 4507 Push(graph_->GetConstantUndefined()); | 4555 Push(graph_->GetConstantUndefined()); |
| 4508 } | 4556 } |
| 4509 | 4557 |
| 4510 VISIT_FOR_VALUE(prop->obj()); | 4558 VISIT_FOR_VALUE(prop->obj()); |
| 4511 HValue* obj = Top(); | 4559 HValue* obj = Top(); |
| 4512 | 4560 |
| 4513 HInstruction* load = NULL; | 4561 HInstruction* load = NULL; |
| 4514 if (prop->IsMonomorphic()) { | 4562 if (prop->IsMonomorphic()) { |
| 4515 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 4563 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 4516 Handle<Map> map = prop->GetReceiverTypes()->first(); | 4564 Handle<Map> map = prop->GetReceiverTypes()->first(); |
| 4517 load = BuildLoadNamed(obj, prop, map, name); | 4565 load = BuildLoadNamed(obj, prop, map, name); |
| 4518 } else { | 4566 } else { |
| 4519 load = BuildLoadNamedGeneric(obj, prop); | 4567 load = BuildLoadNamedGeneric(obj, prop); |
| 4520 } | 4568 } |
| 4521 PushAndAdd(load); | 4569 PushAndAdd(load); |
| 4522 if (load->HasSideEffects()) AddSimulate(increment->id()); | 4570 if (load->HasSideEffects()) AddSimulate(increment->id()); |
| 4523 | 4571 |
| 4524 HValue* value = Pop(); | 4572 HValue* value = Pop(); |
| 4525 | 4573 |
| 4574 // There is no deoptimization to after the increment, so we don't need | |
| 4575 // to simulate the expression stack after this instruction. | |
| 4526 HInstruction* instr = BuildIncrement(value, inc); | 4576 HInstruction* instr = BuildIncrement(value, inc); |
| 4527 AddInstruction(instr); | 4577 AddInstruction(instr); |
| 4528 | 4578 |
| 4529 HInstruction* store = BuildStoreNamed(obj, instr, prop); | 4579 HInstruction* store = BuildStoreNamed(obj, instr, prop); |
| 4530 AddInstruction(store); | 4580 AddInstruction(store); |
| 4531 | 4581 |
| 4532 // Drop simulated receiver and push the result. | 4582 // Drop simulated receiver and push the result. |
| 4533 // There is no deoptimization to after the increment, so we can simulate | |
| 4534 // the expression stack here. | |
| 4535 Drop(1); | 4583 Drop(1); |
| 4536 if (expr->is_prefix()) { | 4584 if (expr->is_prefix()) { |
| 4537 Push(instr); | 4585 Push(instr); |
| 4538 } else { | 4586 } else { |
| 4539 if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. | 4587 if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. |
| 4540 Push(value); | 4588 Push(value); |
| 4541 } | 4589 } |
| 4542 | 4590 |
| 4591 if (store->HasSideEffects()) AddSimulate(expr->id()); | |
| 4592 ast_context()->ReturnValue(Pop()); | |
| 4593 | |
| 4543 } else { | 4594 } else { |
| 4544 // Keyed property. | 4595 // Keyed property. |
| 4545 | 4596 |
| 4546 // Match the full code generator stack by simulate an extra stack element | 4597 // Match the full code generator stack by simulate an extra stack element |
| 4547 // for postfix operations in a value context. | 4598 // for postfix operations in a value context. |
| 4548 if (expr->is_postfix() && !ast_context()->IsEffect()) { | 4599 if (expr->is_postfix() && !ast_context()->IsEffect()) { |
| 4549 Push(graph_->GetConstantUndefined()); | 4600 Push(graph_->GetConstantUndefined()); |
| 4550 } | 4601 } |
| 4551 | 4602 |
| 4552 VISIT_FOR_VALUE(prop->obj()); | 4603 VISIT_FOR_VALUE(prop->obj()); |
| 4553 VISIT_FOR_VALUE(prop->key()); | 4604 VISIT_FOR_VALUE(prop->key()); |
| 4554 | 4605 |
| 4555 HValue* obj = environment()->ExpressionStackAt(1); | 4606 HValue* obj = environment()->ExpressionStackAt(1); |
| 4556 HValue* key = environment()->ExpressionStackAt(0); | 4607 HValue* key = environment()->ExpressionStackAt(0); |
| 4557 | 4608 |
| 4558 bool is_fast_elements = prop->IsMonomorphic() && | 4609 bool is_fast_elements = prop->IsMonomorphic() && |
| 4559 prop->GetMonomorphicReceiverType()->has_fast_elements(); | 4610 prop->GetMonomorphicReceiverType()->has_fast_elements(); |
| 4560 | 4611 |
| 4561 HInstruction* load = is_fast_elements | 4612 HInstruction* load = is_fast_elements |
| 4562 ? BuildLoadKeyedFastElement(obj, key, prop) | 4613 ? BuildLoadKeyedFastElement(obj, key, prop) |
| 4563 : BuildLoadKeyedGeneric(obj, key); | 4614 : BuildLoadKeyedGeneric(obj, key); |
| 4564 PushAndAdd(load); | 4615 PushAndAdd(load); |
| 4565 if (load->HasSideEffects()) AddSimulate(increment->id()); | 4616 if (load->HasSideEffects()) AddSimulate(increment->id()); |
| 4566 | 4617 |
| 4567 HValue* value = Pop(); | 4618 HValue* value = Pop(); |
| 4568 | 4619 |
| 4620 // There is no deoptimization to after the increment, so we don't need | |
| 4621 // to simulate the expression stack after this instruction. | |
| 4569 HInstruction* instr = BuildIncrement(value, inc); | 4622 HInstruction* instr = BuildIncrement(value, inc); |
| 4570 AddInstruction(instr); | 4623 AddInstruction(instr); |
| 4571 | 4624 |
| 4572 HInstruction* store = is_fast_elements | 4625 HInstruction* store = is_fast_elements |
| 4573 ? BuildStoreKeyedFastElement(obj, key, instr, prop) | 4626 ? BuildStoreKeyedFastElement(obj, key, instr, prop) |
| 4574 : new HStoreKeyedGeneric(obj, key, instr); | 4627 : new HStoreKeyedGeneric(obj, key, instr); |
| 4575 AddInstruction(store); | 4628 AddInstruction(store); |
| 4576 | 4629 |
| 4577 // Drop simulated receiver and key and push the result. | 4630 // Drop simulated receiver and key and push the result. |
| 4578 // There is no deoptimization to after the increment, so we can simulate | |
| 4579 // the expression stack here. | |
| 4580 Drop(2); | 4631 Drop(2); |
| 4581 if (expr->is_prefix()) { | 4632 if (expr->is_prefix()) { |
| 4582 Push(instr); | 4633 Push(instr); |
| 4583 } else { | 4634 } else { |
| 4584 if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. | 4635 if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. |
| 4585 Push(value); | 4636 Push(value); |
| 4586 } | 4637 } |
| 4638 | |
| 4639 if (store->HasSideEffects()) AddSimulate(expr->id()); | |
| 4640 ast_context()->ReturnValue(Pop()); | |
| 4587 } | 4641 } |
| 4642 | |
| 4588 } else { | 4643 } else { |
| 4589 BAILOUT("invalid lhs in count operation"); | 4644 BAILOUT("invalid lhs in count operation"); |
| 4590 } | 4645 } |
| 4591 } | 4646 } |
| 4592 | 4647 |
| 4593 | 4648 |
| 4594 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, | 4649 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, |
| 4595 HValue* left, | 4650 HValue* left, |
| 4596 HValue* right) { | 4651 HValue* right) { |
| 4597 HInstruction* instr = NULL; | 4652 HInstruction* instr = NULL; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4659 if (!literal->handle()->IsString()) return false; | 4714 if (!literal->handle()->IsString()) return false; |
| 4660 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; | 4715 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; |
| 4661 ASSERT(call->arguments()->length() == 1); | 4716 ASSERT(call->arguments()->length() == 1); |
| 4662 return true; | 4717 return true; |
| 4663 } | 4718 } |
| 4664 | 4719 |
| 4665 | 4720 |
| 4666 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { | 4721 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
| 4667 if (expr->op() == Token::COMMA) { | 4722 if (expr->op() == Token::COMMA) { |
| 4668 VISIT_FOR_EFFECT(expr->left()); | 4723 VISIT_FOR_EFFECT(expr->left()); |
| 4669 VISIT_FOR_VALUE(expr->right()); | 4724 // Visit the right subexpression in the same AST context as the entire |
| 4725 // expression. | |
| 4726 Visit(expr->right()); | |
| 4727 | |
| 4670 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { | 4728 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { |
| 4671 VISIT_FOR_VALUE(expr->left()); | 4729 bool is_logical_and = (expr->op() == Token::AND); |
| 4672 ASSERT(current_subgraph_->HasExit()); | 4730 if (ast_context()->IsTest()) { |
| 4731 TestContext* context = TestContext::cast(ast_context()); | |
| 4732 // Translate left subexpression. | |
| 4733 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | |
| 4734 if (is_logical_and) { | |
| 4735 VisitForControl(expr->left(), eval_right, context->if_false(), | |
| 4736 false, context->invert_false()); | |
| 4737 } else { | |
| 4738 VisitForControl(expr->left(), context->if_true(), eval_right, | |
| 4739 context->invert_true(), false); | |
| 4740 } | |
| 4741 if (HasStackOverflow()) return; | |
| 4742 eval_right->SetJoinId(expr->left()->id()); | |
| 4673 | 4743 |
| 4674 HValue* left = Top(); | 4744 // Translate right subexpression by visiting it in the same AST |
| 4675 bool is_logical_and = (expr->op() == Token::AND); | 4745 // context as the entire expression. |
| 4746 eval_right->last_environment()->Pop(); | |
| 4747 subgraph()->set_exit_block(eval_right); | |
| 4748 Visit(expr->right()); | |
| 4676 | 4749 |
| 4677 HEnvironment* environment_copy = environment()->Copy(); | 4750 } else { |
| 4678 environment_copy->Pop(); | 4751 VISIT_FOR_VALUE(expr->left()); |
| 4679 HSubgraph* right_subgraph; | 4752 ASSERT(current_subgraph_->HasExit()); |
| 4680 right_subgraph = CreateBranchSubgraph(environment_copy); | 4753 |
| 4681 ADD_TO_SUBGRAPH(right_subgraph, expr->right()); | 4754 HValue* left = Top(); |
| 4682 current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); | 4755 HEnvironment* environment_copy = environment()->Copy(); |
| 4683 current_subgraph_->exit_block()->SetJoinId(expr->id()); | 4756 environment_copy->Pop(); |
| 4757 HSubgraph* right_subgraph; | |
| 4758 right_subgraph = CreateBranchSubgraph(environment_copy); | |
| 4759 ADD_TO_SUBGRAPH(right_subgraph, expr->right()); | |
| 4760 current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); | |
| 4761 current_subgraph_->exit_block()->SetJoinId(expr->id()); | |
| 4762 ast_context()->ReturnValue(Pop()); | |
| 4763 } | |
| 4764 | |
| 4684 } else { | 4765 } else { |
| 4685 VISIT_FOR_VALUE(expr->left()); | 4766 VISIT_FOR_VALUE(expr->left()); |
| 4686 VISIT_FOR_VALUE(expr->right()); | 4767 VISIT_FOR_VALUE(expr->right()); |
| 4687 | 4768 |
| 4688 HValue* right = Pop(); | 4769 HValue* right = Pop(); |
| 4689 HValue* left = Pop(); | 4770 HValue* left = Pop(); |
| 4690 HInstruction* instr = BuildBinaryOperation(expr, left, right); | 4771 HInstruction* instr = BuildBinaryOperation(expr, left, right); |
| 4691 PushAndAdd(instr, expr->position()); | 4772 instr->set_position(expr->position()); |
| 4773 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4692 } | 4774 } |
| 4693 } | 4775 } |
| 4694 | 4776 |
| 4695 | 4777 |
| 4696 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { | 4778 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { |
| 4697 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { | 4779 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { |
| 4698 if (FLAG_trace_representation) { | 4780 if (FLAG_trace_representation) { |
| 4699 PrintF("Assume representation for %s to be %s (%d)\n", | 4781 PrintF("Assume representation for %s to be %s (%d)\n", |
| 4700 value->Mnemonic(), | 4782 value->Mnemonic(), |
| 4701 r.Mnemonic(), | 4783 r.Mnemonic(), |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 4720 | 4802 |
| 4721 | 4803 |
| 4722 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 4804 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 4723 if (IsClassOfTest(expr)) { | 4805 if (IsClassOfTest(expr)) { |
| 4724 CallRuntime* call = expr->left()->AsCallRuntime(); | 4806 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 4725 VISIT_FOR_VALUE(call->arguments()->at(0)); | 4807 VISIT_FOR_VALUE(call->arguments()->at(0)); |
| 4726 HValue* value = Pop(); | 4808 HValue* value = Pop(); |
| 4727 Literal* literal = expr->right()->AsLiteral(); | 4809 Literal* literal = expr->right()->AsLiteral(); |
| 4728 Handle<String> rhs = Handle<String>::cast(literal->handle()); | 4810 Handle<String> rhs = Handle<String>::cast(literal->handle()); |
| 4729 HInstruction* instr = new HClassOfTest(value, rhs); | 4811 HInstruction* instr = new HClassOfTest(value, rhs); |
| 4730 PushAndAdd(instr, expr->position()); | 4812 instr->set_position(expr->position()); |
| 4813 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4731 return; | 4814 return; |
| 4732 } | 4815 } |
| 4733 | 4816 |
| 4734 // Check for the pattern: typeof <expression> == <string literal>. | 4817 // Check for the pattern: typeof <expression> == <string literal>. |
| 4735 UnaryOperation* left_unary = expr->left()->AsUnaryOperation(); | 4818 UnaryOperation* left_unary = expr->left()->AsUnaryOperation(); |
| 4736 Literal* right_literal = expr->right()->AsLiteral(); | 4819 Literal* right_literal = expr->right()->AsLiteral(); |
| 4737 if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) && | 4820 if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) && |
| 4738 left_unary != NULL && left_unary->op() == Token::TYPEOF && | 4821 left_unary != NULL && left_unary->op() == Token::TYPEOF && |
| 4739 right_literal != NULL && right_literal->handle()->IsString()) { | 4822 right_literal != NULL && right_literal->handle()->IsString()) { |
| 4740 VISIT_FOR_VALUE(left_unary->expression()); | 4823 VISIT_FOR_VALUE(left_unary->expression()); |
| 4741 HValue* left = Pop(); | 4824 HValue* left = Pop(); |
| 4742 HInstruction* instr = new HTypeofIs(left, | 4825 HInstruction* instr = new HTypeofIs(left, |
| 4743 Handle<String>::cast(right_literal->handle())); | 4826 Handle<String>::cast(right_literal->handle())); |
| 4744 PushAndAdd(instr, expr->position()); | 4827 instr->set_position(expr->position()); |
| 4828 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4745 return; | 4829 return; |
| 4746 } | 4830 } |
| 4747 | 4831 |
| 4748 VISIT_FOR_VALUE(expr->left()); | 4832 VISIT_FOR_VALUE(expr->left()); |
| 4749 VISIT_FOR_VALUE(expr->right()); | 4833 VISIT_FOR_VALUE(expr->right()); |
| 4750 | 4834 |
| 4751 HValue* right = Pop(); | 4835 HValue* right = Pop(); |
| 4752 HValue* left = Pop(); | 4836 HValue* left = Pop(); |
| 4753 Token::Value op = expr->op(); | 4837 Token::Value op = expr->op(); |
| 4754 | 4838 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 4770 default: | 4854 default: |
| 4771 BAILOUT("Unsupported non-primitive compare"); | 4855 BAILOUT("Unsupported non-primitive compare"); |
| 4772 break; | 4856 break; |
| 4773 } | 4857 } |
| 4774 } else { | 4858 } else { |
| 4775 HCompare* compare = new HCompare(left, right, op); | 4859 HCompare* compare = new HCompare(left, right, op); |
| 4776 Representation r = ToRepresentation(info); | 4860 Representation r = ToRepresentation(info); |
| 4777 compare->SetInputRepresentation(r); | 4861 compare->SetInputRepresentation(r); |
| 4778 instr = compare; | 4862 instr = compare; |
| 4779 } | 4863 } |
| 4780 PushAndAdd(instr, expr->position()); | 4864 instr->set_position(expr->position()); |
| 4865 ast_context()->ReturnInstruction(instr, expr->id()); | |
| 4781 } | 4866 } |
| 4782 | 4867 |
| 4783 | 4868 |
| 4784 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { | 4869 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { |
| 4785 VISIT_FOR_VALUE(expr->expression()); | 4870 VISIT_FOR_VALUE(expr->expression()); |
| 4786 | 4871 |
| 4787 HValue* value = Pop(); | 4872 HValue* value = Pop(); |
| 4788 HIsNull* compare = new HIsNull(value, expr->is_strict()); | 4873 HIsNull* compare = new HIsNull(value, expr->is_strict()); |
| 4789 | 4874 ast_context()->ReturnInstruction(compare, expr->id()); |
| 4790 PushAndAdd(compare); | |
| 4791 } | 4875 } |
| 4792 | 4876 |
| 4793 | 4877 |
| 4794 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { | 4878 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
| 4795 BAILOUT("ThisFunction"); | 4879 BAILOUT("ThisFunction"); |
| 4796 } | 4880 } |
| 4797 | 4881 |
| 4798 | 4882 |
| 4799 void HGraphBuilder::VisitDeclaration(Declaration* decl) { | 4883 void HGraphBuilder::VisitDeclaration(Declaration* decl) { |
| 4800 // We allow only declarations that do not require code generation. | 4884 // We allow only declarations that do not require code generation. |
| 4801 // The following all require code generation: global variables and | 4885 // The following all require code generation: global variables and |
| 4802 // functions, variables with slot type LOOKUP, declarations with | 4886 // functions, variables with slot type LOOKUP, declarations with |
| 4803 // mode CONST, and functions. | 4887 // mode CONST, and functions. |
| 4804 Variable* var = decl->proxy()->var(); | 4888 Variable* var = decl->proxy()->var(); |
| 4805 Slot* slot = var->AsSlot(); | 4889 Slot* slot = var->AsSlot(); |
| 4806 if (var->is_global() || | 4890 if (var->is_global() || |
| 4807 (slot != NULL && slot->type() == Slot::LOOKUP) || | 4891 (slot != NULL && slot->type() == Slot::LOOKUP) || |
| 4808 decl->mode() == Variable::CONST || | 4892 decl->mode() == Variable::CONST || |
| 4809 decl->fun() != NULL) { | 4893 decl->fun() != NULL) { |
| 4810 BAILOUT("unsupported declaration"); | 4894 BAILOUT("unsupported declaration"); |
| 4811 } | 4895 } |
| 4812 } | 4896 } |
| 4813 | 4897 |
| 4814 | 4898 |
| 4815 // Generators for inline runtime functions. | 4899 // Generators for inline runtime functions. |
| 4816 // Support for types. | 4900 // Support for types. |
| 4817 void HGraphBuilder::GenerateIsSmi(int argument_count) { | 4901 void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) { |
| 4818 ASSERT(argument_count == 1); | 4902 ASSERT(argument_count == 1); |
| 4819 | 4903 HValue* value = Pop(); |
| 4820 HValue* value = Pop(); | 4904 HIsSmi* result = new HIsSmi(value); |
| 4821 PushAndAdd(new HIsSmi(value)); | 4905 ast_context()->ReturnInstruction(result, ast_id); |
| 4822 } | 4906 } |
| 4823 | 4907 |
| 4824 | 4908 |
| 4825 void HGraphBuilder::GenerateIsSpecObject(int argument_count) { | 4909 void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) { |
| 4826 ASSERT(argument_count == 1); | 4910 ASSERT(argument_count == 1); |
| 4827 | 4911 HValue* value = Pop(); |
| 4828 HValue* value = Pop(); | 4912 HHasInstanceType* result = |
| 4829 HHasInstanceType* test = | |
| 4830 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); | 4913 new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); |
| 4831 PushAndAdd(test); | 4914 ast_context()->ReturnInstruction(result, ast_id); |
| 4832 } | 4915 } |
| 4833 | 4916 |
| 4834 | 4917 |
| 4835 void HGraphBuilder::GenerateIsFunction(int argument_count) { | 4918 void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) { |
| 4836 ASSERT(argument_count == 1); | 4919 ASSERT(argument_count == 1); |
| 4837 | 4920 HValue* value = Pop(); |
| 4838 HValue* value = Pop(); | 4921 HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); |
| 4839 HHasInstanceType* test = | 4922 ast_context()->ReturnInstruction(result, ast_id); |
| 4840 new HHasInstanceType(value, JS_FUNCTION_TYPE); | 4923 } |
| 4841 PushAndAdd(test); | 4924 |
| 4842 } | 4925 |
| 4843 | 4926 void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count, |
| 4844 | 4927 int ast_id) { |
| 4845 void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count) { | 4928 ASSERT(argument_count == 1); |
| 4846 ASSERT(argument_count == 1); | 4929 HValue* value = Pop(); |
| 4847 | 4930 HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); |
| 4848 HValue* value = Pop(); | 4931 ast_context()->ReturnInstruction(result, ast_id); |
| 4849 HHasCachedArrayIndex* spec_test = new HHasCachedArrayIndex(value); | 4932 } |
| 4850 PushAndAdd(spec_test); | 4933 |
| 4851 } | 4934 |
| 4852 | 4935 void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) { |
| 4853 | 4936 ASSERT(argument_count == 1); |
| 4854 void HGraphBuilder::GenerateIsArray(int argument_count) { | 4937 HValue* value = Pop(); |
| 4855 ASSERT(argument_count == 1); | 4938 HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); |
| 4856 | 4939 ast_context()->ReturnInstruction(result, ast_id); |
| 4857 HValue* value = Pop(); | 4940 } |
| 4858 HHasInstanceType* test = | 4941 |
| 4859 new HHasInstanceType(value, JS_ARRAY_TYPE); | 4942 |
| 4860 PushAndAdd(test); | 4943 void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { |
| 4861 } | 4944 ASSERT(argument_count == 1); |
| 4862 | 4945 HValue* value = Pop(); |
| 4863 | 4946 HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); |
| 4864 void HGraphBuilder::GenerateIsRegExp(int argument_count) { | 4947 ast_context()->ReturnInstruction(result, ast_id); |
| 4865 ASSERT(argument_count == 1); | 4948 } |
| 4866 | 4949 |
| 4867 HValue* value = Pop(); | 4950 |
| 4868 HHasInstanceType* test = | 4951 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, |
| 4869 new HHasInstanceType(value, JS_REGEXP_TYPE); | 4952 int ast_id) { |
| 4870 PushAndAdd(test); | |
| 4871 } | |
| 4872 | |
| 4873 | |
| 4874 void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count) { | |
| 4875 BAILOUT("inlined runtime function: IsNonNegativeSmi"); | 4953 BAILOUT("inlined runtime function: IsNonNegativeSmi"); |
| 4876 } | 4954 } |
| 4877 | 4955 |
| 4878 | 4956 |
| 4879 void HGraphBuilder::GenerateIsObject(int argument_count) { | 4957 void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { |
| 4880 BAILOUT("inlined runtime function: IsObject"); | 4958 BAILOUT("inlined runtime function: IsObject"); |
| 4881 } | 4959 } |
| 4882 | 4960 |
| 4883 | 4961 |
| 4884 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count) { | 4962 void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, |
| 4963 int ast_id) { | |
| 4885 BAILOUT("inlined runtime function: IsUndetectableObject"); | 4964 BAILOUT("inlined runtime function: IsUndetectableObject"); |
| 4886 } | 4965 } |
| 4887 | 4966 |
| 4888 | 4967 |
| 4889 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( | 4968 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
| 4890 int argument_count) { | 4969 int argument_count, |
| 4970 int ast_id) { | |
| 4891 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); | 4971 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); |
| 4892 } | 4972 } |
| 4893 | 4973 |
| 4894 | 4974 |
| 4895 // Support for construct call checks. | 4975 // Support for construct call checks. |
| 4896 void HGraphBuilder::GenerateIsConstructCall(int argument_count) { | 4976 void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { |
| 4897 BAILOUT("inlined runtime function: IsConstructCall"); | 4977 BAILOUT("inlined runtime function: IsConstructCall"); |
| 4898 } | 4978 } |
| 4899 | 4979 |
| 4900 | 4980 |
| 4901 // Support for arguments.length and arguments[?]. | 4981 // Support for arguments.length and arguments[?]. |
| 4902 void HGraphBuilder::GenerateArgumentsLength(int argument_count) { | 4982 void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { |
| 4903 ASSERT(argument_count == 0); | 4983 ASSERT(argument_count == 0); |
| 4904 HInstruction* elements = AddInstruction(new HArgumentsElements); | 4984 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4905 PushAndAdd(new HArgumentsLength(elements)); | 4985 HArgumentsLength* result = new HArgumentsLength(elements); |
| 4906 } | 4986 ast_context()->ReturnInstruction(result, ast_id); |
| 4907 | 4987 } |
| 4908 | 4988 |
| 4909 void HGraphBuilder::GenerateArguments(int argument_count) { | 4989 |
| 4990 void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) { | |
| 4910 ASSERT(argument_count == 1); | 4991 ASSERT(argument_count == 1); |
| 4911 HValue* index = Pop(); | 4992 HValue* index = Pop(); |
| 4912 HInstruction* elements = AddInstruction(new HArgumentsElements); | 4993 HInstruction* elements = AddInstruction(new HArgumentsElements); |
| 4913 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); | 4994 HInstruction* length = AddInstruction(new HArgumentsLength(elements)); |
| 4914 PushAndAdd(new HAccessArgumentsAt(elements, length, index)); | 4995 HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); |
| 4996 ast_context()->ReturnInstruction(result, ast_id); | |
| 4915 } | 4997 } |
| 4916 | 4998 |
| 4917 | 4999 |
| 4918 // Support for accessing the class and value fields of an object. | 5000 // Support for accessing the class and value fields of an object. |
| 4919 void HGraphBuilder::GenerateClassOf(int argument_count) { | 5001 void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) { |
| 4920 // The special form detected by IsClassOfTest is detected before we get here | 5002 // The special form detected by IsClassOfTest is detected before we get here |
| 4921 // and does not cause a bailout. | 5003 // and does not cause a bailout. |
| 4922 BAILOUT("inlined runtime function: ClassOf"); | 5004 BAILOUT("inlined runtime function: ClassOf"); |
| 4923 } | 5005 } |
| 4924 | 5006 |
| 4925 | 5007 |
| 4926 void HGraphBuilder::GenerateValueOf(int argument_count) { | 5008 void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) { |
| 4927 ASSERT(argument_count == 1); | 5009 ASSERT(argument_count == 1); |
| 4928 | 5010 HValue* value = Pop(); |
| 4929 HValue* value = Pop(); | 5011 HValueOf* result = new HValueOf(value); |
| 4930 HValueOf* op = new HValueOf(value); | 5012 ast_context()->ReturnInstruction(result, ast_id); |
| 4931 PushAndAdd(op); | 5013 } |
| 4932 } | 5014 |
| 4933 | 5015 |
| 4934 | 5016 void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { |
| 4935 void HGraphBuilder::GenerateSetValueOf(int argument_count) { | |
| 4936 BAILOUT("inlined runtime function: SetValueOf"); | 5017 BAILOUT("inlined runtime function: SetValueOf"); |
| 4937 } | 5018 } |
| 4938 | 5019 |
| 4939 | 5020 |
| 4940 // Fast support for charCodeAt(n). | 5021 // Fast support for charCodeAt(n). |
| 4941 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count) { | 5022 void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { |
| 4942 BAILOUT("inlined runtime function: StringCharCodeAt"); | 5023 BAILOUT("inlined runtime function: StringCharCodeAt"); |
| 4943 } | 5024 } |
| 4944 | 5025 |
| 4945 | 5026 |
| 4946 // Fast support for string.charAt(n) and string[n]. | 5027 // Fast support for string.charAt(n) and string[n]. |
| 4947 void HGraphBuilder::GenerateStringCharFromCode(int argument_count) { | 5028 void HGraphBuilder::GenerateStringCharFromCode(int argument_count, |
| 5029 int ast_id) { | |
| 4948 BAILOUT("inlined runtime function: StringCharFromCode"); | 5030 BAILOUT("inlined runtime function: StringCharFromCode"); |
| 4949 } | 5031 } |
| 4950 | 5032 |
| 4951 | 5033 |
| 4952 // Fast support for string.charAt(n) and string[n]. | 5034 // Fast support for string.charAt(n) and string[n]. |
| 4953 void HGraphBuilder::GenerateStringCharAt(int argument_count) { | 5035 void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { |
| 4954 ASSERT_EQ(2, argument_count); | 5036 ASSERT_EQ(2, argument_count); |
| 4955 PushArgumentsForStubCall(argument_count); | 5037 PushArgumentsForStubCall(argument_count); |
| 4956 PushAndAdd(new HCallStub(CodeStub::StringCharAt, argument_count), | 5038 HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count); |
| 4957 RelocInfo::kNoPosition); | 5039 ast_context()->ReturnInstruction(result, ast_id); |
| 4958 } | 5040 } |
| 4959 | 5041 |
| 4960 | 5042 |
| 4961 // Fast support for object equality testing. | 5043 // Fast support for object equality testing. |
| 4962 void HGraphBuilder::GenerateObjectEquals(int argument_count) { | 5044 void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { |
| 4963 ASSERT(argument_count == 2); | 5045 ASSERT(argument_count == 2); |
| 4964 | |
| 4965 HValue* right = Pop(); | 5046 HValue* right = Pop(); |
| 4966 HValue* left = Pop(); | 5047 HValue* left = Pop(); |
| 4967 PushAndAdd(new HCompareJSObjectEq(left, right)); | 5048 HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); |
| 4968 } | 5049 ast_context()->ReturnInstruction(result, ast_id); |
| 4969 | 5050 } |
| 4970 | 5051 |
| 4971 void HGraphBuilder::GenerateLog(int argument_count) { | 5052 |
| 5053 void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { | |
| 4972 UNREACHABLE(); // We caught this in VisitCallRuntime. | 5054 UNREACHABLE(); // We caught this in VisitCallRuntime. |
| 4973 } | 5055 } |
| 4974 | 5056 |
| 4975 | 5057 |
| 4976 // Fast support for Math.random(). | 5058 // Fast support for Math.random(). |
| 4977 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count) { | 5059 void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { |
| 4978 BAILOUT("inlined runtime function: RandomHeapNumber"); | 5060 BAILOUT("inlined runtime function: RandomHeapNumber"); |
| 4979 } | 5061 } |
| 4980 | 5062 |
| 4981 | 5063 |
| 4982 // Fast support for StringAdd. | 5064 // Fast support for StringAdd. |
| 4983 void HGraphBuilder::GenerateStringAdd(int argument_count) { | 5065 void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { |
| 4984 ASSERT_EQ(2, argument_count); | 5066 ASSERT_EQ(2, argument_count); |
| 4985 PushArgumentsForStubCall(argument_count); | 5067 PushArgumentsForStubCall(argument_count); |
| 4986 PushAndAdd(new HCallStub(CodeStub::StringAdd, argument_count), | 5068 HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count); |
| 4987 RelocInfo::kNoPosition); | 5069 ast_context()->ReturnInstruction(result, ast_id); |
| 4988 } | 5070 } |
| 4989 | 5071 |
| 4990 | 5072 |
| 4991 // Fast support for SubString. | 5073 // Fast support for SubString. |
| 4992 void HGraphBuilder::GenerateSubString(int argument_count) { | 5074 void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { |
| 4993 ASSERT_EQ(3, argument_count); | 5075 ASSERT_EQ(3, argument_count); |
| 4994 PushArgumentsForStubCall(argument_count); | 5076 PushArgumentsForStubCall(argument_count); |
| 4995 PushAndAdd(new HCallStub(CodeStub::SubString, argument_count), | 5077 HCallStub* result = new HCallStub(CodeStub::SubString, argument_count); |
| 4996 RelocInfo::kNoPosition); | 5078 ast_context()->ReturnInstruction(result, ast_id); |
| 4997 } | 5079 } |
| 4998 | 5080 |
| 4999 | 5081 |
| 5000 // Fast support for StringCompare. | 5082 // Fast support for StringCompare. |
| 5001 void HGraphBuilder::GenerateStringCompare(int argument_count) { | 5083 void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { |
| 5002 ASSERT_EQ(2, argument_count); | 5084 ASSERT_EQ(2, argument_count); |
| 5003 PushArgumentsForStubCall(argument_count); | 5085 PushArgumentsForStubCall(argument_count); |
| 5004 PushAndAdd(new HCallStub(CodeStub::StringCompare, argument_count), | 5086 HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count); |
| 5005 RelocInfo::kNoPosition); | 5087 ast_context()->ReturnInstruction(result, ast_id); |
| 5006 } | 5088 } |
| 5007 | 5089 |
| 5008 | 5090 |
| 5009 // Support for direct calls from JavaScript to native RegExp code. | 5091 // Support for direct calls from JavaScript to native RegExp code. |
| 5010 void HGraphBuilder::GenerateRegExpExec(int argument_count) { | 5092 void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { |
| 5011 ASSERT_EQ(4, argument_count); | 5093 ASSERT_EQ(4, argument_count); |
| 5012 PushArgumentsForStubCall(argument_count); | 5094 PushArgumentsForStubCall(argument_count); |
| 5013 PushAndAdd(new HCallStub(CodeStub::RegExpExec, argument_count), | 5095 HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count); |
| 5014 RelocInfo::kNoPosition); | 5096 ast_context()->ReturnInstruction(result, ast_id); |
| 5015 } | 5097 } |
| 5016 | 5098 |
| 5017 | 5099 |
| 5018 // Construct a RegExp exec result with two in-object properties. | 5100 // Construct a RegExp exec result with two in-object properties. |
| 5019 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count) { | 5101 void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, |
| 5102 int ast_id) { | |
| 5020 ASSERT_EQ(3, argument_count); | 5103 ASSERT_EQ(3, argument_count); |
| 5021 PushArgumentsForStubCall(argument_count); | 5104 PushArgumentsForStubCall(argument_count); |
| 5022 PushAndAdd(new HCallStub(CodeStub::RegExpConstructResult, argument_count), | 5105 HCallStub* result = |
| 5023 RelocInfo::kNoPosition); | 5106 new HCallStub(CodeStub::RegExpConstructResult, argument_count); |
| 5107 ast_context()->ReturnInstruction(result, ast_id); | |
| 5024 } | 5108 } |
| 5025 | 5109 |
| 5026 | 5110 |
| 5027 // Support for fast native caches. | 5111 // Support for fast native caches. |
| 5028 void HGraphBuilder::GenerateGetFromCache(int argument_count) { | 5112 void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { |
| 5029 BAILOUT("inlined runtime function: GetFromCache"); | 5113 BAILOUT("inlined runtime function: GetFromCache"); |
| 5030 } | 5114 } |
| 5031 | 5115 |
| 5032 | 5116 |
| 5033 // Fast support for number to string. | 5117 // Fast support for number to string. |
| 5034 void HGraphBuilder::GenerateNumberToString(int argument_count) { | 5118 void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { |
| 5035 ASSERT_EQ(1, argument_count); | 5119 ASSERT_EQ(1, argument_count); |
| 5036 PushArgumentsForStubCall(argument_count); | 5120 PushArgumentsForStubCall(argument_count); |
| 5037 PushAndAdd(new HCallStub(CodeStub::NumberToString, argument_count), | 5121 HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count); |
| 5038 RelocInfo::kNoPosition); | 5122 ast_context()->ReturnInstruction(result, ast_id); |
| 5039 } | 5123 } |
| 5040 | 5124 |
| 5041 | 5125 |
| 5042 // Fast swapping of elements. Takes three expressions, the object and two | 5126 // Fast swapping of elements. Takes three expressions, the object and two |
| 5043 // indices. This should only be used if the indices are known to be | 5127 // indices. This should only be used if the indices are known to be |
| 5044 // non-negative and within bounds of the elements array at the call site. | 5128 // non-negative and within bounds of the elements array at the call site. |
| 5045 void HGraphBuilder::GenerateSwapElements(int argument_count) { | 5129 void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { |
| 5046 BAILOUT("inlined runtime function: SwapElements"); | 5130 BAILOUT("inlined runtime function: SwapElements"); |
| 5047 } | 5131 } |
| 5048 | 5132 |
| 5049 | 5133 |
| 5050 // Fast call for custom callbacks. | 5134 // Fast call for custom callbacks. |
| 5051 void HGraphBuilder::GenerateCallFunction(int argument_count) { | 5135 void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) { |
| 5052 BAILOUT("inlined runtime function: CallFunction"); | 5136 BAILOUT("inlined runtime function: CallFunction"); |
| 5053 } | 5137 } |
| 5054 | 5138 |
| 5055 | 5139 |
| 5056 // Fast call to math functions. | 5140 // Fast call to math functions. |
| 5057 void HGraphBuilder::GenerateMathPow(int argument_count) { | 5141 void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) { |
| 5058 ASSERT_EQ(2, argument_count); | 5142 ASSERT_EQ(2, argument_count); |
| 5059 HValue* right = Pop(); | 5143 HValue* right = Pop(); |
| 5060 HValue* left = Pop(); | 5144 HValue* left = Pop(); |
| 5061 PushAndAdd(new HPower(left, right)); | 5145 HPower* result = new HPower(left, right); |
| 5062 } | 5146 ast_context()->ReturnInstruction(result, ast_id); |
| 5063 | 5147 } |
| 5064 | 5148 |
| 5065 void HGraphBuilder::GenerateMathSin(int argument_count) { | 5149 |
| 5150 void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { | |
| 5066 ASSERT_EQ(1, argument_count); | 5151 ASSERT_EQ(1, argument_count); |
| 5067 PushArgumentsForStubCall(argument_count); | 5152 PushArgumentsForStubCall(argument_count); |
| 5068 HCallStub* instr = | 5153 HCallStub* result = |
| 5069 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5154 new HCallStub(CodeStub::TranscendentalCache, argument_count); |
| 5070 instr->set_transcendental_type(TranscendentalCache::SIN); | 5155 result->set_transcendental_type(TranscendentalCache::SIN); |
| 5071 PushAndAdd(instr, RelocInfo::kNoPosition); | 5156 ast_context()->ReturnInstruction(result, ast_id); |
| 5072 } | 5157 } |
| 5073 | 5158 |
| 5074 | 5159 |
| 5075 void HGraphBuilder::GenerateMathCos(int argument_count) { | 5160 void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { |
| 5076 ASSERT_EQ(1, argument_count); | 5161 ASSERT_EQ(1, argument_count); |
| 5077 PushArgumentsForStubCall(argument_count); | 5162 PushArgumentsForStubCall(argument_count); |
| 5078 HCallStub* instr = | 5163 HCallStub* result = |
| 5079 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5164 new HCallStub(CodeStub::TranscendentalCache, argument_count); |
| 5080 instr->set_transcendental_type(TranscendentalCache::COS); | 5165 result->set_transcendental_type(TranscendentalCache::COS); |
| 5081 PushAndAdd(instr, RelocInfo::kNoPosition); | 5166 ast_context()->ReturnInstruction(result, ast_id); |
| 5082 } | 5167 } |
| 5083 | 5168 |
| 5084 | 5169 |
| 5085 void HGraphBuilder::GenerateMathLog(int argument_count) { | 5170 void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { |
| 5086 ASSERT_EQ(1, argument_count); | 5171 ASSERT_EQ(1, argument_count); |
| 5087 PushArgumentsForStubCall(argument_count); | 5172 PushArgumentsForStubCall(argument_count); |
| 5088 HCallStub* instr = | 5173 HCallStub* result = |
| 5089 new HCallStub(CodeStub::TranscendentalCache, argument_count); | 5174 new HCallStub(CodeStub::TranscendentalCache, argument_count); |
| 5090 instr->set_transcendental_type(TranscendentalCache::LOG); | 5175 result->set_transcendental_type(TranscendentalCache::LOG); |
| 5091 PushAndAdd(instr, RelocInfo::kNoPosition); | 5176 ast_context()->ReturnInstruction(result, ast_id); |
| 5092 } | 5177 } |
| 5093 | 5178 |
| 5094 | 5179 |
| 5095 void HGraphBuilder::GenerateMathSqrt(int argument_count) { | 5180 void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { |
| 5096 BAILOUT("inlined runtime function: MathSqrt"); | 5181 BAILOUT("inlined runtime function: MathSqrt"); |
| 5097 } | 5182 } |
| 5098 | 5183 |
| 5099 | 5184 |
| 5100 // Check whether two RegExps are equivalent | 5185 // Check whether two RegExps are equivalent |
| 5101 void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count) { | 5186 void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count, |
| 5187 int ast_id) { | |
| 5102 BAILOUT("inlined runtime function: IsRegExpEquivalent"); | 5188 BAILOUT("inlined runtime function: IsRegExpEquivalent"); |
| 5103 } | 5189 } |
| 5104 | 5190 |
| 5105 | 5191 |
| 5106 void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count) { | 5192 void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count, |
| 5193 int ast_id) { | |
| 5107 BAILOUT("inlined runtime function: GetCachedArrayIndex"); | 5194 BAILOUT("inlined runtime function: GetCachedArrayIndex"); |
| 5108 } | 5195 } |
| 5109 | 5196 |
| 5110 | 5197 |
| 5111 void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count) { | 5198 void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count, |
| 5199 int ast_id) { | |
| 5112 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); | 5200 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); |
| 5113 } | 5201 } |
| 5114 | 5202 |
| 5115 | 5203 |
| 5116 #undef BAILOUT | 5204 #undef BAILOUT |
| 5117 #undef CHECK_BAILOUT | 5205 #undef CHECK_BAILOUT |
| 5118 #undef VISIT_FOR_EFFECT | 5206 #undef VISIT_FOR_EFFECT |
| 5119 #undef VISIT_FOR_VALUE | 5207 #undef VISIT_FOR_VALUE |
| 5120 #undef ADD_TO_SUBGRAPH | 5208 #undef ADD_TO_SUBGRAPH |
| 5121 | 5209 |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5577 } | 5665 } |
| 5578 | 5666 |
| 5579 #ifdef DEBUG | 5667 #ifdef DEBUG |
| 5580 if (graph_ != NULL) graph_->Verify(); | 5668 if (graph_ != NULL) graph_->Verify(); |
| 5581 if (chunk_ != NULL) chunk_->Verify(); | 5669 if (chunk_ != NULL) chunk_->Verify(); |
| 5582 if (allocator_ != NULL) allocator_->Verify(); | 5670 if (allocator_ != NULL) allocator_->Verify(); |
| 5583 #endif | 5671 #endif |
| 5584 } | 5672 } |
| 5585 | 5673 |
| 5586 } } // namespace v8::internal | 5674 } } // namespace v8::internal |
| OLD | NEW |