OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 void HBasicBlock::Finish(HControlInstruction* end) { | 157 void HBasicBlock::Finish(HControlInstruction* end) { |
158 ASSERT(!IsFinished()); | 158 ASSERT(!IsFinished()); |
159 AddInstruction(end); | 159 AddInstruction(end); |
160 end_ = end; | 160 end_ = end; |
161 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { | 161 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { |
162 it.Current()->RegisterPredecessor(this); | 162 it.Current()->RegisterPredecessor(this); |
163 } | 163 } |
164 } | 164 } |
165 | 165 |
166 | 166 |
167 void HBasicBlock::Goto(HBasicBlock* block) { | 167 void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { |
168 if (block->IsInlineReturnTarget()) { | 168 if (block->IsInlineReturnTarget()) { |
169 AddInstruction(new(zone()) HLeaveInlined); | 169 AddInstruction(new(zone()) HLeaveInlined); |
170 last_environment_ = last_environment()->outer(); | 170 last_environment_ = last_environment()->outer(); |
| 171 if (drop_extra) last_environment_->Drop(1); |
171 } | 172 } |
172 AddSimulate(AstNode::kNoNumber); | 173 AddSimulate(AstNode::kNoNumber); |
173 HGoto* instr = new(zone()) HGoto(block); | 174 HGoto* instr = new(zone()) HGoto(block); |
174 Finish(instr); | 175 Finish(instr); |
175 } | 176 } |
176 | 177 |
177 | 178 |
178 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { | 179 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
| 180 HBasicBlock* target, |
| 181 bool drop_extra) { |
179 ASSERT(target->IsInlineReturnTarget()); | 182 ASSERT(target->IsInlineReturnTarget()); |
180 ASSERT(return_value != NULL); | 183 ASSERT(return_value != NULL); |
181 AddInstruction(new(zone()) HLeaveInlined); | 184 AddInstruction(new(zone()) HLeaveInlined); |
182 last_environment_ = last_environment()->outer(); | 185 last_environment_ = last_environment()->outer(); |
| 186 if (drop_extra) last_environment_->Drop(1); |
183 last_environment()->Push(return_value); | 187 last_environment()->Push(return_value); |
184 AddSimulate(AstNode::kNoNumber); | 188 AddSimulate(AstNode::kNoNumber); |
185 HGoto* instr = new(zone()) HGoto(target); | 189 HGoto* instr = new(zone()) HGoto(target); |
186 Finish(instr); | 190 Finish(instr); |
187 } | 191 } |
188 | 192 |
189 | 193 |
190 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { | 194 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { |
191 ASSERT(!HasEnvironment()); | 195 ASSERT(!HasEnvironment()); |
192 ASSERT(first() == NULL); | 196 ASSERT(first() == NULL); |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
534 | 538 |
535 | 539 |
536 HConstant* HGraph::GetConstantHole() { | 540 HConstant* HGraph::GetConstantHole() { |
537 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); | 541 return GetConstant(&constant_hole_, isolate()->heap()->the_hole_value()); |
538 } | 542 } |
539 | 543 |
540 | 544 |
541 HGraphBuilder::HGraphBuilder(CompilationInfo* info, | 545 HGraphBuilder::HGraphBuilder(CompilationInfo* info, |
542 TypeFeedbackOracle* oracle) | 546 TypeFeedbackOracle* oracle) |
543 : function_state_(NULL), | 547 : function_state_(NULL), |
544 initial_function_state_(this, info, oracle), | 548 initial_function_state_(this, info, oracle, false), |
545 ast_context_(NULL), | 549 ast_context_(NULL), |
546 break_scope_(NULL), | 550 break_scope_(NULL), |
547 graph_(NULL), | 551 graph_(NULL), |
548 current_block_(NULL), | 552 current_block_(NULL), |
549 inlined_count_(0), | 553 inlined_count_(0), |
550 zone_(info->isolate()->zone()), | 554 zone_(info->isolate()->zone()), |
551 inline_bailout_(false) { | 555 inline_bailout_(false) { |
552 // This is not initialized in the initializer list because the | 556 // This is not initialized in the initializer list because the |
553 // constructor for the initial state relies on function_state_ == NULL | 557 // constructor for the initial state relies on function_state_ == NULL |
554 // to know it's the initial state. | 558 // to know it's the initial state. |
(...skipping 937 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1492 | 1496 |
1493 int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( | 1497 int HGlobalValueNumberer::CollectSideEffectsOnPathsToDominatedBlock( |
1494 HBasicBlock* dominator, HBasicBlock* dominated) { | 1498 HBasicBlock* dominator, HBasicBlock* dominated) { |
1495 int side_effects = 0; | 1499 int side_effects = 0; |
1496 for (int i = 0; i < dominated->predecessors()->length(); ++i) { | 1500 for (int i = 0; i < dominated->predecessors()->length(); ++i) { |
1497 HBasicBlock* block = dominated->predecessors()->at(i); | 1501 HBasicBlock* block = dominated->predecessors()->at(i); |
1498 if (dominator->block_id() < block->block_id() && | 1502 if (dominator->block_id() < block->block_id() && |
1499 block->block_id() < dominated->block_id() && | 1503 block->block_id() < dominated->block_id() && |
1500 visited_on_paths_.Add(block->block_id())) { | 1504 visited_on_paths_.Add(block->block_id())) { |
1501 side_effects |= block_side_effects_[block->block_id()]; | 1505 side_effects |= block_side_effects_[block->block_id()]; |
| 1506 if (block->IsLoopHeader()) { |
| 1507 side_effects |= loop_side_effects_[block->block_id()]; |
| 1508 } |
1502 side_effects |= CollectSideEffectsOnPathsToDominatedBlock( | 1509 side_effects |= CollectSideEffectsOnPathsToDominatedBlock( |
1503 dominator, block); | 1510 dominator, block); |
1504 } | 1511 } |
1505 } | 1512 } |
1506 return side_effects; | 1513 return side_effects; |
1507 } | 1514 } |
1508 | 1515 |
1509 | 1516 |
1510 void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { | 1517 void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { |
1511 TraceGVN("Analyzing block B%d%s\n", | 1518 TraceGVN("Analyzing block B%d%s\n", |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1998 } | 2005 } |
1999 } | 2006 } |
2000 } | 2007 } |
2001 } | 2008 } |
2002 | 2009 |
2003 | 2010 |
2004 // Implementation of utility class to encapsulate the translation state for | 2011 // Implementation of utility class to encapsulate the translation state for |
2005 // a (possibly inlined) function. | 2012 // a (possibly inlined) function. |
2006 FunctionState::FunctionState(HGraphBuilder* owner, | 2013 FunctionState::FunctionState(HGraphBuilder* owner, |
2007 CompilationInfo* info, | 2014 CompilationInfo* info, |
2008 TypeFeedbackOracle* oracle) | 2015 TypeFeedbackOracle* oracle, |
| 2016 bool drop_extra) |
2009 : owner_(owner), | 2017 : owner_(owner), |
2010 compilation_info_(info), | 2018 compilation_info_(info), |
2011 oracle_(oracle), | 2019 oracle_(oracle), |
2012 call_context_(NULL), | 2020 call_context_(NULL), |
| 2021 drop_extra_(drop_extra), |
2013 function_return_(NULL), | 2022 function_return_(NULL), |
2014 test_context_(NULL), | 2023 test_context_(NULL), |
2015 outer_(owner->function_state()) { | 2024 outer_(owner->function_state()) { |
2016 if (outer_ != NULL) { | 2025 if (outer_ != NULL) { |
2017 // State for an inline function. | 2026 // State for an inline function. |
2018 if (owner->ast_context()->IsTest()) { | 2027 if (owner->ast_context()->IsTest()) { |
2019 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 2028 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
2020 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 2029 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
2021 if_true->MarkAsInlineReturnTarget(); | 2030 if_true->MarkAsInlineReturnTarget(); |
2022 if_false->MarkAsInlineReturnTarget(); | 2031 if_false->MarkAsInlineReturnTarget(); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2161 } | 2170 } |
2162 | 2171 |
2163 | 2172 |
2164 void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { | 2173 void TestContext::ReturnControl(HControlInstruction* instr, int ast_id) { |
2165 ASSERT(!instr->HasSideEffects()); | 2174 ASSERT(!instr->HasSideEffects()); |
2166 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); | 2175 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); |
2167 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); | 2176 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); |
2168 instr->SetSuccessorAt(0, empty_true); | 2177 instr->SetSuccessorAt(0, empty_true); |
2169 instr->SetSuccessorAt(1, empty_false); | 2178 instr->SetSuccessorAt(1, empty_false); |
2170 owner()->current_block()->Finish(instr); | 2179 owner()->current_block()->Finish(instr); |
2171 empty_true->Goto(if_true()); | 2180 empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
2172 empty_false->Goto(if_false()); | 2181 empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
2173 owner()->set_current_block(NULL); | 2182 owner()->set_current_block(NULL); |
2174 } | 2183 } |
2175 | 2184 |
2176 | 2185 |
2177 void TestContext::BuildBranch(HValue* value) { | 2186 void TestContext::BuildBranch(HValue* value) { |
2178 // We expect the graph to be in edge-split form: there is no edge that | 2187 // We expect the graph to be in edge-split form: there is no edge that |
2179 // connects a branch node to a join node. We conservatively ensure that | 2188 // connects a branch node to a join node. We conservatively ensure that |
2180 // property by always adding an empty block on the outgoing edges of this | 2189 // property by always adding an empty block on the outgoing edges of this |
2181 // branch. | 2190 // branch. |
2182 HGraphBuilder* builder = owner(); | 2191 HGraphBuilder* builder = owner(); |
2183 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { | 2192 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { |
2184 builder->Bailout("arguments object value in a test context"); | 2193 builder->Bailout("arguments object value in a test context"); |
2185 } | 2194 } |
2186 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); | 2195 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); |
2187 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); | 2196 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); |
2188 unsigned test_id = condition()->test_id(); | 2197 unsigned test_id = condition()->test_id(); |
2189 ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id)); | 2198 ToBooleanStub::Types expected(builder->oracle()->ToBooleanTypes(test_id)); |
2190 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); | 2199 HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected); |
2191 builder->current_block()->Finish(test); | 2200 builder->current_block()->Finish(test); |
2192 | 2201 |
2193 empty_true->Goto(if_true()); | 2202 empty_true->Goto(if_true(), owner()->function_state()->drop_extra()); |
2194 empty_false->Goto(if_false()); | 2203 empty_false->Goto(if_false(), owner()->function_state()->drop_extra()); |
2195 builder->set_current_block(NULL); | 2204 builder->set_current_block(NULL); |
2196 } | 2205 } |
2197 | 2206 |
2198 | 2207 |
2199 // HGraphBuilder infrastructure for bailing out and checking bailouts. | 2208 // HGraphBuilder infrastructure for bailing out and checking bailouts. |
2200 #define CHECK_BAILOUT(call) \ | 2209 #define CHECK_BAILOUT(call) \ |
2201 do { \ | 2210 do { \ |
2202 call; \ | 2211 call; \ |
2203 if (HasStackOverflow()) return; \ | 2212 if (HasStackOverflow()) return; \ |
2204 } while (false) | 2213 } while (false) |
(...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2645 } else { | 2654 } else { |
2646 // Return from an inlined function, visit the subexpression in the | 2655 // Return from an inlined function, visit the subexpression in the |
2647 // expression context of the call. | 2656 // expression context of the call. |
2648 if (context->IsTest()) { | 2657 if (context->IsTest()) { |
2649 TestContext* test = TestContext::cast(context); | 2658 TestContext* test = TestContext::cast(context); |
2650 VisitForControl(stmt->expression(), | 2659 VisitForControl(stmt->expression(), |
2651 test->if_true(), | 2660 test->if_true(), |
2652 test->if_false()); | 2661 test->if_false()); |
2653 } else if (context->IsEffect()) { | 2662 } else if (context->IsEffect()) { |
2654 CHECK_ALIVE(VisitForEffect(stmt->expression())); | 2663 CHECK_ALIVE(VisitForEffect(stmt->expression())); |
2655 current_block()->Goto(function_return()); | 2664 current_block()->Goto(function_return(), function_state()->drop_extra()); |
2656 } else { | 2665 } else { |
2657 ASSERT(context->IsValue()); | 2666 ASSERT(context->IsValue()); |
2658 CHECK_ALIVE(VisitForValue(stmt->expression())); | 2667 CHECK_ALIVE(VisitForValue(stmt->expression())); |
2659 HValue* return_value = environment()->Pop(); | 2668 HValue* return_value = environment()->Pop(); |
2660 current_block()->AddLeaveInlined(return_value, function_return()); | 2669 current_block()->AddLeaveInlined(return_value, |
| 2670 function_return(), |
| 2671 function_state()->drop_extra()); |
2661 } | 2672 } |
2662 set_current_block(NULL); | 2673 set_current_block(NULL); |
2663 } | 2674 } |
2664 } | 2675 } |
2665 | 2676 |
2666 | 2677 |
2667 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 2678 void HGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
2668 ASSERT(!HasStackOverflow()); | 2679 ASSERT(!HasStackOverflow()); |
2669 ASSERT(current_block() != NULL); | 2680 ASSERT(current_block() != NULL); |
2670 ASSERT(current_block()->HasPredecessor()); | 2681 ASSERT(current_block()->HasPredecessor()); |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3149 // Handle known global constants like 'undefined' specially to avoid a | 3160 // Handle known global constants like 'undefined' specially to avoid a |
3150 // load from a global cell for them. | 3161 // load from a global cell for them. |
3151 Handle<Object> constant_value = | 3162 Handle<Object> constant_value = |
3152 isolate()->factory()->GlobalConstantFor(variable->name()); | 3163 isolate()->factory()->GlobalConstantFor(variable->name()); |
3153 if (!constant_value.is_null()) { | 3164 if (!constant_value.is_null()) { |
3154 HConstant* instr = | 3165 HConstant* instr = |
3155 new(zone()) HConstant(constant_value, Representation::Tagged()); | 3166 new(zone()) HConstant(constant_value, Representation::Tagged()); |
3156 return ast_context()->ReturnInstruction(instr, expr->id()); | 3167 return ast_context()->ReturnInstruction(instr, expr->id()); |
3157 } | 3168 } |
3158 | 3169 |
3159 LookupResult lookup; | 3170 LookupResult lookup(isolate()); |
3160 GlobalPropertyAccess type = | 3171 GlobalPropertyAccess type = |
3161 LookupGlobalProperty(variable, &lookup, false); | 3172 LookupGlobalProperty(variable, &lookup, false); |
3162 | 3173 |
3163 if (type == kUseCell && | 3174 if (type == kUseCell && |
3164 info()->global_object()->IsAccessCheckNeeded()) { | 3175 info()->global_object()->IsAccessCheckNeeded()) { |
3165 type = kUseGeneric; | 3176 type = kUseGeneric; |
3166 } | 3177 } |
3167 | 3178 |
3168 if (type == kUseCell) { | 3179 if (type == kUseCell) { |
3169 Handle<GlobalObject> global(info()->global_object()); | 3180 Handle<GlobalObject> global(info()->global_object()); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3269 if (property->emit_store()) { | 3280 if (property->emit_store()) { |
3270 CHECK_ALIVE(VisitForValue(value)); | 3281 CHECK_ALIVE(VisitForValue(value)); |
3271 HValue* value = Pop(); | 3282 HValue* value = Pop(); |
3272 Handle<String> name = Handle<String>::cast(key->handle()); | 3283 Handle<String> name = Handle<String>::cast(key->handle()); |
3273 HStoreNamedGeneric* store = | 3284 HStoreNamedGeneric* store = |
3274 new(zone()) HStoreNamedGeneric( | 3285 new(zone()) HStoreNamedGeneric( |
3275 context, | 3286 context, |
3276 literal, | 3287 literal, |
3277 name, | 3288 name, |
3278 value, | 3289 value, |
3279 function_strict_mode()); | 3290 function_strict_mode_flag()); |
3280 AddInstruction(store); | 3291 AddInstruction(store); |
3281 AddSimulate(key->id()); | 3292 AddSimulate(key->id()); |
3282 } else { | 3293 } else { |
3283 CHECK_ALIVE(VisitForEffect(value)); | 3294 CHECK_ALIVE(VisitForEffect(value)); |
3284 } | 3295 } |
3285 break; | 3296 break; |
3286 } | 3297 } |
3287 // Fall through. | 3298 // Fall through. |
3288 case ObjectLiteral::Property::PROTOTYPE: | 3299 case ObjectLiteral::Property::PROTOTYPE: |
3289 case ObjectLiteral::Property::SETTER: | 3300 case ObjectLiteral::Property::SETTER: |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3330 for (int i = 0; i < length; i++) { | 3341 for (int i = 0; i < length; i++) { |
3331 Expression* subexpr = subexprs->at(i); | 3342 Expression* subexpr = subexprs->at(i); |
3332 // If the subexpression is a literal or a simple materialized literal it | 3343 // If the subexpression is a literal or a simple materialized literal it |
3333 // is already set in the cloned array. | 3344 // is already set in the cloned array. |
3334 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 3345 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
3335 | 3346 |
3336 CHECK_ALIVE(VisitForValue(subexpr)); | 3347 CHECK_ALIVE(VisitForValue(subexpr)); |
3337 HValue* value = Pop(); | 3348 HValue* value = Pop(); |
3338 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); | 3349 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); |
3339 | 3350 |
3340 // Load the elements array before the first store. | 3351 elements = new(zone()) HLoadElements(literal); |
3341 if (elements == NULL) { | 3352 AddInstruction(elements); |
3342 elements = new(zone()) HLoadElements(literal); | |
3343 AddInstruction(elements); | |
3344 } | |
3345 | 3353 |
3346 HValue* key = AddInstruction( | 3354 HValue* key = AddInstruction( |
3347 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), | 3355 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
3348 Representation::Integer32())); | 3356 Representation::Integer32())); |
3349 HInstruction* elements_kind = | 3357 HInstruction* elements_kind = |
3350 AddInstruction(new(zone()) HElementsKind(literal)); | 3358 AddInstruction(new(zone()) HElementsKind(literal)); |
3351 HBasicBlock* store_fast = graph()->CreateBasicBlock(); | 3359 HBasicBlock* store_fast = graph()->CreateBasicBlock(); |
3352 // Two empty blocks to satisfy edge split form. | 3360 // Two empty blocks to satisfy edge split form. |
3353 HBasicBlock* store_fast_edgesplit1 = graph()->CreateBasicBlock(); | 3361 HBasicBlock* store_fast_edgesplit1 = graph()->CreateBasicBlock(); |
3354 HBasicBlock* store_fast_edgesplit2 = graph()->CreateBasicBlock(); | 3362 HBasicBlock* store_fast_edgesplit2 = graph()->CreateBasicBlock(); |
3355 HBasicBlock* store_generic = graph()->CreateBasicBlock(); | 3363 HBasicBlock* store_generic = graph()->CreateBasicBlock(); |
3356 HBasicBlock* check_smi_only_elements = graph()->CreateBasicBlock(); | 3364 HBasicBlock* check_smi_only_elements = graph()->CreateBasicBlock(); |
3357 HBasicBlock* join = graph()->CreateBasicBlock(); | 3365 HBasicBlock* join = graph()->CreateBasicBlock(); |
3358 | 3366 |
3359 HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(value); | 3367 HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(value); |
3360 smicheck->SetSuccessorAt(0, store_fast_edgesplit1); | 3368 smicheck->SetSuccessorAt(0, store_fast_edgesplit1); |
3361 smicheck->SetSuccessorAt(1, check_smi_only_elements); | 3369 smicheck->SetSuccessorAt(1, check_smi_only_elements); |
3362 current_block()->Finish(smicheck); | 3370 current_block()->Finish(smicheck); |
3363 store_fast_edgesplit1->Finish(new(zone()) HGoto(store_fast)); | 3371 store_fast_edgesplit1->Finish(new(zone()) HGoto(store_fast)); |
3364 | 3372 |
3365 set_current_block(check_smi_only_elements); | 3373 set_current_block(check_smi_only_elements); |
3366 HCompareConstantEqAndBranch* smi_elements_check = | 3374 HCompareConstantEqAndBranch* smi_elements_check = |
3367 new(zone()) HCompareConstantEqAndBranch(elements_kind, | 3375 new(zone()) HCompareConstantEqAndBranch(elements_kind, |
3368 FAST_SMI_ONLY_ELEMENTS, | 3376 FAST_ELEMENTS, |
3369 Token::EQ_STRICT); | 3377 Token::EQ_STRICT); |
3370 smi_elements_check->SetSuccessorAt(0, store_generic); | 3378 smi_elements_check->SetSuccessorAt(0, store_fast_edgesplit2); |
3371 smi_elements_check->SetSuccessorAt(1, store_fast_edgesplit2); | 3379 smi_elements_check->SetSuccessorAt(1, store_generic); |
3372 current_block()->Finish(smi_elements_check); | 3380 current_block()->Finish(smi_elements_check); |
3373 store_fast_edgesplit2->Finish(new(zone()) HGoto(store_fast)); | 3381 store_fast_edgesplit2->Finish(new(zone()) HGoto(store_fast)); |
3374 | 3382 |
3375 set_current_block(store_fast); | 3383 set_current_block(store_fast); |
3376 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); | 3384 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); |
3377 store_fast->Goto(join); | 3385 store_fast->Goto(join); |
3378 | 3386 |
3379 set_current_block(store_generic); | 3387 set_current_block(store_generic); |
3380 AddInstruction(BuildStoreKeyedGeneric(literal, key, value)); | 3388 AddInstruction(BuildStoreKeyedGeneric(literal, key, value)); |
3381 store_generic->Goto(join); | 3389 store_generic->Goto(join); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3450 | 3458 |
3451 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, | 3459 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, |
3452 Handle<String> name, | 3460 Handle<String> name, |
3453 HValue* value) { | 3461 HValue* value) { |
3454 HValue* context = environment()->LookupContext(); | 3462 HValue* context = environment()->LookupContext(); |
3455 return new(zone()) HStoreNamedGeneric( | 3463 return new(zone()) HStoreNamedGeneric( |
3456 context, | 3464 context, |
3457 object, | 3465 object, |
3458 name, | 3466 name, |
3459 value, | 3467 value, |
3460 function_strict_mode()); | 3468 function_strict_mode_flag()); |
3461 } | 3469 } |
3462 | 3470 |
3463 | 3471 |
3464 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, | 3472 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, |
3465 HValue* value, | 3473 HValue* value, |
3466 Expression* expr) { | 3474 Expression* expr) { |
3467 Property* prop = (expr->AsProperty() != NULL) | 3475 Property* prop = (expr->AsProperty() != NULL) |
3468 ? expr->AsProperty() | 3476 ? expr->AsProperty() |
3469 : expr->AsAssignment()->target()->AsProperty(); | 3477 : expr->AsAssignment()->target()->AsProperty(); |
3470 Literal* key = prop->key()->AsLiteral(); | 3478 Literal* key = prop->key()->AsLiteral(); |
3471 Handle<String> name = Handle<String>::cast(key->handle()); | 3479 Handle<String> name = Handle<String>::cast(key->handle()); |
3472 ASSERT(!name.is_null()); | 3480 ASSERT(!name.is_null()); |
3473 | 3481 |
3474 LookupResult lookup; | 3482 LookupResult lookup(isolate()); |
3475 SmallMapList* types = expr->GetReceiverTypes(); | 3483 SmallMapList* types = expr->GetReceiverTypes(); |
3476 bool is_monomorphic = expr->IsMonomorphic() && | 3484 bool is_monomorphic = expr->IsMonomorphic() && |
3477 ComputeStoredField(types->first(), name, &lookup); | 3485 ComputeStoredField(types->first(), name, &lookup); |
3478 | 3486 |
3479 return is_monomorphic | 3487 return is_monomorphic |
3480 ? BuildStoreNamedField(object, name, value, types->first(), &lookup, | 3488 ? BuildStoreNamedField(object, name, value, types->first(), &lookup, |
3481 true) // Needs smi and map check. | 3489 true) // Needs smi and map check. |
3482 : BuildStoreNamedGeneric(object, name, value); | 3490 : BuildStoreNamedGeneric(object, name, value); |
3483 } | 3491 } |
3484 | 3492 |
3485 | 3493 |
3486 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, | 3494 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
3487 HValue* object, | 3495 HValue* object, |
3488 HValue* value, | 3496 HValue* value, |
3489 SmallMapList* types, | 3497 SmallMapList* types, |
3490 Handle<String> name) { | 3498 Handle<String> name) { |
3491 // TODO(ager): We should recognize when the prototype chains for different | 3499 // TODO(ager): We should recognize when the prototype chains for different |
3492 // maps are identical. In that case we can avoid repeatedly generating the | 3500 // maps are identical. In that case we can avoid repeatedly generating the |
3493 // same prototype map checks. | 3501 // same prototype map checks. |
3494 int count = 0; | 3502 int count = 0; |
3495 HBasicBlock* join = NULL; | 3503 HBasicBlock* join = NULL; |
3496 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | 3504 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
3497 Handle<Map> map = types->at(i); | 3505 Handle<Map> map = types->at(i); |
3498 LookupResult lookup; | 3506 LookupResult lookup(isolate()); |
3499 if (ComputeStoredField(map, name, &lookup)) { | 3507 if (ComputeStoredField(map, name, &lookup)) { |
3500 if (count == 0) { | 3508 if (count == 0) { |
3501 AddInstruction(new(zone()) HCheckNonSmi(object)); // Only needed once. | 3509 AddInstruction(new(zone()) HCheckNonSmi(object)); // Only needed once. |
3502 join = graph()->CreateBasicBlock(); | 3510 join = graph()->CreateBasicBlock(); |
3503 } | 3511 } |
3504 ++count; | 3512 ++count; |
3505 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 3513 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
3506 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 3514 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
3507 HCompareMap* compare = | 3515 HCompareMap* compare = |
3508 new(zone()) HCompareMap(object, map, if_true, if_false); | 3516 new(zone()) HCompareMap(object, map, if_true, if_false); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3571 // Named store. | 3579 // Named store. |
3572 CHECK_ALIVE(VisitForValue(expr->value())); | 3580 CHECK_ALIVE(VisitForValue(expr->value())); |
3573 value = Pop(); | 3581 value = Pop(); |
3574 HValue* object = Pop(); | 3582 HValue* object = Pop(); |
3575 | 3583 |
3576 Literal* key = prop->key()->AsLiteral(); | 3584 Literal* key = prop->key()->AsLiteral(); |
3577 Handle<String> name = Handle<String>::cast(key->handle()); | 3585 Handle<String> name = Handle<String>::cast(key->handle()); |
3578 ASSERT(!name.is_null()); | 3586 ASSERT(!name.is_null()); |
3579 | 3587 |
3580 SmallMapList* types = expr->GetReceiverTypes(); | 3588 SmallMapList* types = expr->GetReceiverTypes(); |
3581 LookupResult lookup; | 3589 LookupResult lookup(isolate()); |
3582 | 3590 |
3583 if (expr->IsMonomorphic()) { | 3591 if (expr->IsMonomorphic()) { |
3584 instr = BuildStoreNamed(object, value, expr); | 3592 instr = BuildStoreNamed(object, value, expr); |
3585 | 3593 |
3586 } else if (types != NULL && types->length() > 1) { | 3594 } else if (types != NULL && types->length() > 1) { |
3587 HandlePolymorphicStoreNamedField(expr, object, value, types, name); | 3595 HandlePolymorphicStoreNamedField(expr, object, value, types, name); |
3588 return; | 3596 return; |
3589 | 3597 |
3590 } else { | 3598 } else { |
3591 instr = BuildStoreNamedGeneric(object, name, value); | 3599 instr = BuildStoreNamedGeneric(object, name, value); |
(...skipping 24 matching lines...) Expand all Loading... |
3616 } | 3624 } |
3617 | 3625 |
3618 | 3626 |
3619 // Because not every expression has a position and there is not common | 3627 // Because not every expression has a position and there is not common |
3620 // superclass of Assignment and CountOperation, we cannot just pass the | 3628 // superclass of Assignment and CountOperation, we cannot just pass the |
3621 // owning expression instead of position and ast_id separately. | 3629 // owning expression instead of position and ast_id separately. |
3622 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, | 3630 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, |
3623 HValue* value, | 3631 HValue* value, |
3624 int position, | 3632 int position, |
3625 int ast_id) { | 3633 int ast_id) { |
3626 LookupResult lookup; | 3634 LookupResult lookup(isolate()); |
3627 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); | 3635 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); |
3628 if (type == kUseCell) { | 3636 if (type == kUseCell) { |
3629 Handle<GlobalObject> global(info()->global_object()); | 3637 Handle<GlobalObject> global(info()->global_object()); |
3630 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); | 3638 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); |
3631 HInstruction* instr = | 3639 HInstruction* instr = |
3632 new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails()); | 3640 new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails()); |
3633 instr->set_position(position); | 3641 instr->set_position(position); |
3634 AddInstruction(instr); | 3642 AddInstruction(instr); |
3635 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3643 if (instr->HasSideEffects()) AddSimulate(ast_id); |
3636 } else { | 3644 } else { |
3637 HValue* context = environment()->LookupContext(); | 3645 HValue* context = environment()->LookupContext(); |
3638 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 3646 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
3639 AddInstruction(global_object); | 3647 AddInstruction(global_object); |
3640 HStoreGlobalGeneric* instr = | 3648 HStoreGlobalGeneric* instr = |
3641 new(zone()) HStoreGlobalGeneric(context, | 3649 new(zone()) HStoreGlobalGeneric(context, |
3642 global_object, | 3650 global_object, |
3643 var->name(), | 3651 var->name(), |
3644 value, | 3652 value, |
3645 function_strict_mode()); | 3653 function_strict_mode_flag()); |
3646 instr->set_position(position); | 3654 instr->set_position(position); |
3647 AddInstruction(instr); | 3655 AddInstruction(instr); |
3648 ASSERT(instr->HasSideEffects()); | 3656 ASSERT(instr->HasSideEffects()); |
3649 if (instr->HasSideEffects()) AddSimulate(ast_id); | 3657 if (instr->HasSideEffects()) AddSimulate(ast_id); |
3650 } | 3658 } |
3651 } | 3659 } |
3652 | 3660 |
3653 | 3661 |
3654 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 3662 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
3655 Expression* target = expr->target(); | 3663 Expression* target = expr->target(); |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3931 Handle<Object> name = expr->key()->AsLiteral()->handle(); | 3939 Handle<Object> name = expr->key()->AsLiteral()->handle(); |
3932 HValue* context = environment()->LookupContext(); | 3940 HValue* context = environment()->LookupContext(); |
3933 return new(zone()) HLoadNamedGeneric(context, obj, name); | 3941 return new(zone()) HLoadNamedGeneric(context, obj, name); |
3934 } | 3942 } |
3935 | 3943 |
3936 | 3944 |
3937 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, | 3945 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, |
3938 Property* expr, | 3946 Property* expr, |
3939 Handle<Map> map, | 3947 Handle<Map> map, |
3940 Handle<String> name) { | 3948 Handle<String> name) { |
3941 LookupResult lookup; | 3949 LookupResult lookup(isolate()); |
3942 map->LookupInDescriptors(NULL, *name, &lookup); | 3950 map->LookupInDescriptors(NULL, *name, &lookup); |
3943 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3951 if (lookup.IsProperty() && lookup.type() == FIELD) { |
3944 return BuildLoadNamedField(obj, | 3952 return BuildLoadNamedField(obj, |
3945 expr, | 3953 expr, |
3946 map, | 3954 map, |
3947 &lookup, | 3955 &lookup, |
3948 true); | 3956 true); |
3949 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { | 3957 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { |
3950 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 3958 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
3951 AddInstruction(new(zone()) HCheckMap(obj, map)); | 3959 AddInstruction(new(zone()) HCheckMap(obj, map)); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4030 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); | 4038 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); |
4031 } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. | 4039 } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. |
4032 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | 4040 return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
4033 } | 4041 } |
4034 } | 4042 } |
4035 | 4043 |
4036 | 4044 |
4037 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 4045 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
4038 HValue* key, | 4046 HValue* key, |
4039 HValue* val, | 4047 HValue* val, |
4040 Expression* expr, | 4048 Handle<Map> map, |
4041 bool is_store) { | 4049 bool is_store) { |
4042 ASSERT(expr->IsMonomorphic()); | |
4043 Handle<Map> map = expr->GetMonomorphicReceiverType(); | |
4044 AddInstruction(new(zone()) HCheckNonSmi(object)); | |
4045 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); | 4050 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map)); |
4046 bool fast_smi_only_elements = map->has_fast_smi_only_elements(); | 4051 bool fast_smi_only_elements = map->has_fast_smi_only_elements(); |
4047 bool fast_elements = map->has_fast_elements(); | 4052 bool fast_elements = map->has_fast_elements(); |
4048 bool fast_double_elements = map->has_fast_double_elements(); | 4053 bool fast_double_elements = map->has_fast_double_elements(); |
4049 if (!fast_smi_only_elements && | 4054 if (!fast_smi_only_elements && |
4050 !fast_elements && | 4055 !fast_elements && |
4051 !fast_double_elements && | 4056 !fast_double_elements && |
4052 !map->has_external_array_elements()) { | 4057 !map->has_external_array_elements()) { |
4053 return is_store ? BuildStoreKeyedGeneric(object, key, val) | 4058 return is_store ? BuildStoreKeyedGeneric(object, key, val) |
4054 : BuildLoadKeyedGeneric(object, key); | 4059 : BuildLoadKeyedGeneric(object, key); |
(...skipping 29 matching lines...) Expand all Loading... |
4084 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, | 4089 HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object, |
4085 HValue* key, | 4090 HValue* key, |
4086 HValue* val, | 4091 HValue* val, |
4087 Expression* prop, | 4092 Expression* prop, |
4088 int ast_id, | 4093 int ast_id, |
4089 int position, | 4094 int position, |
4090 bool is_store, | 4095 bool is_store, |
4091 bool* has_side_effects) { | 4096 bool* has_side_effects) { |
4092 *has_side_effects = false; | 4097 *has_side_effects = false; |
4093 AddInstruction(new(zone()) HCheckNonSmi(object)); | 4098 AddInstruction(new(zone()) HCheckNonSmi(object)); |
4094 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); | |
4095 SmallMapList* maps = prop->GetReceiverTypes(); | 4099 SmallMapList* maps = prop->GetReceiverTypes(); |
4096 bool todo_external_array = false; | 4100 bool todo_external_array = false; |
4097 | 4101 |
4098 static const int kNumElementTypes = kElementsKindCount; | 4102 static const int kNumElementTypes = kElementsKindCount; |
4099 bool type_todo[kNumElementTypes]; | 4103 bool type_todo[kNumElementTypes]; |
4100 for (int i = 0; i < kNumElementTypes; ++i) { | 4104 for (int i = 0; i < kNumElementTypes; ++i) { |
4101 type_todo[i] = false; | 4105 type_todo[i] = false; |
4102 } | 4106 } |
4103 | 4107 |
| 4108 // Elements_kind transition support. |
| 4109 MapHandleList transition_target(maps->length()); |
| 4110 // Collect possible transition targets. |
| 4111 MapHandleList possible_transitioned_maps(maps->length()); |
4104 for (int i = 0; i < maps->length(); ++i) { | 4112 for (int i = 0; i < maps->length(); ++i) { |
4105 ASSERT(maps->at(i)->IsMap()); | 4113 Handle<Map> map = maps->at(i); |
4106 type_todo[maps->at(i)->elements_kind()] = true; | 4114 ElementsKind elements_kind = map->elements_kind(); |
4107 if (maps->at(i)->elements_kind() | 4115 if (elements_kind == FAST_DOUBLE_ELEMENTS || |
4108 >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { | 4116 elements_kind == FAST_ELEMENTS) { |
4109 todo_external_array = true; | 4117 possible_transitioned_maps.Add(map); |
| 4118 } |
| 4119 } |
| 4120 // Get transition target for each map (NULL == no transition). |
| 4121 for (int i = 0; i < maps->length(); ++i) { |
| 4122 Handle<Map> map = maps->at(i); |
| 4123 Handle<Map> transitioned_map = |
| 4124 map->FindTransitionedMap(&possible_transitioned_maps); |
| 4125 transition_target.Add(transitioned_map); |
| 4126 } |
| 4127 |
| 4128 int num_untransitionable_maps = 0; |
| 4129 Handle<Map> untransitionable_map; |
| 4130 for (int i = 0; i < maps->length(); ++i) { |
| 4131 Handle<Map> map = maps->at(i); |
| 4132 ASSERT(map->IsMap()); |
| 4133 if (!transition_target.at(i).is_null()) { |
| 4134 object = AddInstruction(new(zone()) HTransitionElementsKind( |
| 4135 object, map, transition_target.at(i))); |
| 4136 } else { |
| 4137 type_todo[map->elements_kind()] = true; |
| 4138 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
| 4139 todo_external_array = true; |
| 4140 } |
| 4141 num_untransitionable_maps++; |
| 4142 untransitionable_map = map; |
4110 } | 4143 } |
4111 } | 4144 } |
4112 | 4145 |
| 4146 // If only one map is left after transitioning, handle this case |
| 4147 // monomorphically. |
| 4148 if (num_untransitionable_maps == 1) { |
| 4149 HInstruction* instr = AddInstruction(BuildMonomorphicElementAccess( |
| 4150 object, key, val, untransitionable_map, is_store)); |
| 4151 *has_side_effects |= instr->HasSideEffects(); |
| 4152 instr->set_position(position); |
| 4153 return is_store ? NULL : instr; |
| 4154 } |
| 4155 |
| 4156 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
4113 HBasicBlock* join = graph()->CreateBasicBlock(); | 4157 HBasicBlock* join = graph()->CreateBasicBlock(); |
4114 | 4158 |
4115 HInstruction* elements_kind_instr = | 4159 HInstruction* elements_kind_instr = |
4116 AddInstruction(new(zone()) HElementsKind(object)); | 4160 AddInstruction(new(zone()) HElementsKind(object)); |
4117 HCompareConstantEqAndBranch* elements_kind_branch = NULL; | 4161 HCompareConstantEqAndBranch* elements_kind_branch = NULL; |
4118 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 4162 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
4119 HLoadExternalArrayPointer* external_elements = NULL; | 4163 HLoadExternalArrayPointer* external_elements = NULL; |
4120 HInstruction* checked_key = NULL; | 4164 HInstruction* checked_key = NULL; |
4121 | 4165 |
4122 // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS, | 4166 // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS, |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4234 HValue* key, | 4278 HValue* key, |
4235 HValue* val, | 4279 HValue* val, |
4236 Expression* expr, | 4280 Expression* expr, |
4237 int ast_id, | 4281 int ast_id, |
4238 int position, | 4282 int position, |
4239 bool is_store, | 4283 bool is_store, |
4240 bool* has_side_effects) { | 4284 bool* has_side_effects) { |
4241 ASSERT(!expr->IsPropertyName()); | 4285 ASSERT(!expr->IsPropertyName()); |
4242 HInstruction* instr = NULL; | 4286 HInstruction* instr = NULL; |
4243 if (expr->IsMonomorphic()) { | 4287 if (expr->IsMonomorphic()) { |
4244 instr = BuildMonomorphicElementAccess(obj, key, val, expr, is_store); | 4288 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 4289 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
| 4290 instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store); |
4245 } else if (expr->GetReceiverTypes() != NULL && | 4291 } else if (expr->GetReceiverTypes() != NULL && |
4246 !expr->GetReceiverTypes()->is_empty()) { | 4292 !expr->GetReceiverTypes()->is_empty()) { |
4247 return HandlePolymorphicElementAccess( | 4293 return HandlePolymorphicElementAccess( |
4248 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | 4294 obj, key, val, expr, ast_id, position, is_store, has_side_effects); |
4249 } else { | 4295 } else { |
4250 if (is_store) { | 4296 if (is_store) { |
4251 instr = BuildStoreKeyedGeneric(obj, key, val); | 4297 instr = BuildStoreKeyedGeneric(obj, key, val); |
4252 } else { | 4298 } else { |
4253 instr = BuildLoadKeyedGeneric(obj, key); | 4299 instr = BuildLoadKeyedGeneric(obj, key); |
4254 } | 4300 } |
4255 } | 4301 } |
4256 instr->set_position(position); | 4302 instr->set_position(position); |
4257 AddInstruction(instr); | 4303 AddInstruction(instr); |
4258 *has_side_effects = instr->HasSideEffects(); | 4304 *has_side_effects = instr->HasSideEffects(); |
4259 return instr; | 4305 return instr; |
4260 } | 4306 } |
4261 | 4307 |
4262 | 4308 |
4263 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, | 4309 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, |
4264 HValue* key, | 4310 HValue* key, |
4265 HValue* value) { | 4311 HValue* value) { |
4266 HValue* context = environment()->LookupContext(); | 4312 HValue* context = environment()->LookupContext(); |
4267 return new(zone()) HStoreKeyedGeneric( | 4313 return new(zone()) HStoreKeyedGeneric( |
4268 context, | 4314 context, |
4269 object, | 4315 object, |
4270 key, | 4316 key, |
4271 value, | 4317 value, |
4272 function_strict_mode()); | 4318 function_strict_mode_flag()); |
4273 } | 4319 } |
4274 | 4320 |
4275 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { | 4321 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { |
4276 VariableProxy* proxy = expr->obj()->AsVariableProxy(); | 4322 VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
4277 if (proxy == NULL) return false; | 4323 if (proxy == NULL) return false; |
4278 if (!proxy->var()->IsStackAllocated()) return false; | 4324 if (!proxy->var()->IsStackAllocated()) return false; |
4279 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { | 4325 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { |
4280 return false; | 4326 return false; |
4281 } | 4327 } |
4282 | 4328 |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4504 if (reason == NULL) { | 4550 if (reason == NULL) { |
4505 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); | 4551 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); |
4506 } else { | 4552 } else { |
4507 PrintF("Did not inline %s called from %s (%s).\n", | 4553 PrintF("Did not inline %s called from %s (%s).\n", |
4508 *target_name, *caller_name, reason); | 4554 *target_name, *caller_name, reason); |
4509 } | 4555 } |
4510 } | 4556 } |
4511 } | 4557 } |
4512 | 4558 |
4513 | 4559 |
4514 bool HGraphBuilder::TryInline(Call* expr) { | 4560 bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { |
4515 if (!FLAG_use_inlining) return false; | 4561 if (!FLAG_use_inlining) return false; |
4516 | 4562 |
4517 // The function call we are inlining is a method call if the call | 4563 // The function call we are inlining is a method call if the call |
4518 // is a property call. | 4564 // is a property call. |
4519 CallKind call_kind = (expr->expression()->AsProperty() == NULL) | 4565 CallKind call_kind = (expr->expression()->AsProperty() == NULL) |
4520 ? CALL_AS_FUNCTION | 4566 ? CALL_AS_FUNCTION |
4521 : CALL_AS_METHOD; | 4567 : CALL_AS_METHOD; |
4522 | 4568 |
4523 // Precondition: call is monomorphic and we have found a target with the | 4569 // Precondition: call is monomorphic and we have found a target with the |
4524 // appropriate arity. | 4570 // appropriate arity. |
4525 Handle<JSFunction> caller = info()->closure(); | 4571 Handle<JSFunction> caller = info()->closure(); |
4526 Handle<JSFunction> target = expr->target(); | 4572 Handle<JSFunction> target = expr->target(); |
4527 Handle<SharedFunctionInfo> target_shared(target->shared()); | 4573 Handle<SharedFunctionInfo> target_shared(target->shared()); |
4528 | 4574 |
4529 // Do a quick check on source code length to avoid parsing large | 4575 // Do a quick check on source code length to avoid parsing large |
4530 // inlining candidates. | 4576 // inlining candidates. |
4531 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { | 4577 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { |
4532 TraceInline(target, caller, "target text too big"); | 4578 TraceInline(target, caller, "target text too big"); |
4533 return false; | 4579 return false; |
4534 } | 4580 } |
4535 | 4581 |
4536 // Target must be inlineable. | 4582 // Target must be inlineable. |
4537 if (!target->IsInlineable()) { | 4583 if (!target->IsInlineable()) { |
4538 TraceInline(target, caller, "target not inlineable"); | 4584 TraceInline(target, caller, "target not inlineable"); |
4539 return false; | 4585 return false; |
4540 } | 4586 } |
4541 | 4587 |
4542 CompilationInfo* outer_info = info(); | |
4543 #if !defined(V8_TARGET_ARCH_IA32) | 4588 #if !defined(V8_TARGET_ARCH_IA32) |
4544 // Target must be able to use caller's context. | 4589 // Target must be able to use caller's context. |
| 4590 CompilationInfo* outer_info = info(); |
4545 if (target->context() != outer_info->closure()->context() || | 4591 if (target->context() != outer_info->closure()->context() || |
4546 outer_info->scope()->contains_with() || | 4592 outer_info->scope()->contains_with() || |
4547 outer_info->scope()->num_heap_slots() > 0) { | 4593 outer_info->scope()->num_heap_slots() > 0) { |
4548 TraceInline(target, caller, "target requires context change"); | 4594 TraceInline(target, caller, "target requires context change"); |
4549 return false; | 4595 return false; |
4550 } | 4596 } |
4551 #endif | 4597 #endif |
4552 | 4598 |
4553 | 4599 |
4554 // Don't inline deeper than kMaxInliningLevels calls. | 4600 // Don't inline deeper than kMaxInliningLevels calls. |
4555 HEnvironment* env = environment(); | 4601 HEnvironment* env = environment(); |
4556 int current_level = 1; | 4602 int current_level = 1; |
4557 while (env->outer() != NULL) { | 4603 while (env->outer() != NULL) { |
4558 if (current_level == (FLAG_limit_inlining | 4604 if (current_level == Compiler::kMaxInliningLevels) { |
4559 ? Compiler::kMaxInliningLevels | |
4560 : 2 * Compiler::kMaxInliningLevels)) { | |
4561 TraceInline(target, caller, "inline depth limit reached"); | 4605 TraceInline(target, caller, "inline depth limit reached"); |
4562 return false; | 4606 return false; |
4563 } | 4607 } |
4564 current_level++; | 4608 current_level++; |
4565 env = env->outer(); | 4609 env = env->outer(); |
4566 } | 4610 } |
4567 | 4611 |
4568 // Don't inline recursive functions. | 4612 // Don't inline recursive functions. |
4569 if (*target_shared == outer_info->closure()->shared()) { | 4613 for (FunctionState* state = function_state(); |
4570 TraceInline(target, caller, "target is recursive"); | 4614 state != NULL; |
4571 return false; | 4615 state = state->outer()) { |
| 4616 if (state->compilation_info()->closure()->shared() == *target_shared) { |
| 4617 TraceInline(target, caller, "target is recursive"); |
| 4618 return false; |
| 4619 } |
4572 } | 4620 } |
4573 | 4621 |
4574 // We don't want to add more than a certain number of nodes from inlining. | 4622 // We don't want to add more than a certain number of nodes from inlining. |
4575 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { | 4623 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { |
4576 TraceInline(target, caller, "cumulative AST node limit reached"); | 4624 TraceInline(target, caller, "cumulative AST node limit reached"); |
4577 return false; | 4625 return false; |
4578 } | 4626 } |
4579 | 4627 |
4580 int count_before = AstNode::Count(); | 4628 int count_before = AstNode::Count(); |
4581 | 4629 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4658 // After this point, we've made a decision to inline this function (so | 4706 // After this point, we've made a decision to inline this function (so |
4659 // TryInline should always return true). | 4707 // TryInline should always return true). |
4660 | 4708 |
4661 // Save the pending call context and type feedback oracle. Set up new ones | 4709 // Save the pending call context and type feedback oracle. Set up new ones |
4662 // for the inlined function. | 4710 // for the inlined function. |
4663 ASSERT(target_shared->has_deoptimization_support()); | 4711 ASSERT(target_shared->has_deoptimization_support()); |
4664 TypeFeedbackOracle target_oracle( | 4712 TypeFeedbackOracle target_oracle( |
4665 Handle<Code>(target_shared->code()), | 4713 Handle<Code>(target_shared->code()), |
4666 Handle<Context>(target->context()->global_context()), | 4714 Handle<Context>(target->context()->global_context()), |
4667 isolate()); | 4715 isolate()); |
4668 FunctionState target_state(this, &target_info, &target_oracle); | 4716 // The function state is new-allocated because we need to delete it |
| 4717 // in two different places. |
| 4718 FunctionState* target_state = |
| 4719 new FunctionState(this, &target_info, &target_oracle, drop_extra); |
4669 | 4720 |
4670 HConstant* undefined = graph()->GetConstantUndefined(); | 4721 HConstant* undefined = graph()->GetConstantUndefined(); |
4671 HEnvironment* inner_env = | 4722 HEnvironment* inner_env = |
4672 environment()->CopyForInlining(target, | 4723 environment()->CopyForInlining(target, |
4673 function, | 4724 function, |
4674 undefined, | 4725 undefined, |
4675 call_kind); | 4726 call_kind); |
4676 #ifdef V8_TARGET_ARCH_IA32 | 4727 #ifdef V8_TARGET_ARCH_IA32 |
4677 // IA32 only, overwrite the caller's context in the deoptimization | 4728 // IA32 only, overwrite the caller's context in the deoptimization |
4678 // environment with the correct one. | 4729 // environment with the correct one. |
(...skipping 13 matching lines...) Expand all Loading... |
4692 function, | 4743 function, |
4693 call_kind)); | 4744 call_kind)); |
4694 VisitDeclarations(target_info.scope()->declarations()); | 4745 VisitDeclarations(target_info.scope()->declarations()); |
4695 VisitStatements(function->body()); | 4746 VisitStatements(function->body()); |
4696 if (HasStackOverflow()) { | 4747 if (HasStackOverflow()) { |
4697 // Bail out if the inline function did, as we cannot residualize a call | 4748 // Bail out if the inline function did, as we cannot residualize a call |
4698 // instead. | 4749 // instead. |
4699 TraceInline(target, caller, "inline graph construction failed"); | 4750 TraceInline(target, caller, "inline graph construction failed"); |
4700 target_shared->DisableOptimization(*target); | 4751 target_shared->DisableOptimization(*target); |
4701 inline_bailout_ = true; | 4752 inline_bailout_ = true; |
| 4753 delete target_state; |
4702 return true; | 4754 return true; |
4703 } | 4755 } |
4704 | 4756 |
4705 // Update inlined nodes count. | 4757 // Update inlined nodes count. |
4706 inlined_count_ += nodes_added; | 4758 inlined_count_ += nodes_added; |
4707 | 4759 |
4708 TraceInline(target, caller, NULL); | 4760 TraceInline(target, caller, NULL); |
4709 | 4761 |
4710 if (current_block() != NULL) { | 4762 if (current_block() != NULL) { |
4711 // Add a return of undefined if control can fall off the body. In a | 4763 // Add a return of undefined if control can fall off the body. In a |
4712 // test context, undefined is false. | 4764 // test context, undefined is false. |
4713 if (inlined_test_context() == NULL) { | 4765 if (inlined_test_context() == NULL) { |
4714 ASSERT(function_return() != NULL); | 4766 ASSERT(function_return() != NULL); |
4715 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); | 4767 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); |
4716 if (call_context()->IsEffect()) { | 4768 if (call_context()->IsEffect()) { |
4717 current_block()->Goto(function_return()); | 4769 current_block()->Goto(function_return(), drop_extra); |
4718 } else { | 4770 } else { |
4719 current_block()->AddLeaveInlined(undefined, function_return()); | 4771 current_block()->AddLeaveInlined(undefined, |
| 4772 function_return(), |
| 4773 drop_extra); |
4720 } | 4774 } |
4721 } else { | 4775 } else { |
4722 // The graph builder assumes control can reach both branches of a | 4776 // The graph builder assumes control can reach both branches of a |
4723 // test, so we materialize the undefined value and test it rather than | 4777 // test, so we materialize the undefined value and test it rather than |
4724 // simply jumping to the false target. | 4778 // simply jumping to the false target. |
4725 // | 4779 // |
4726 // TODO(3168478): refactor to avoid this. | 4780 // TODO(3168478): refactor to avoid this. |
| 4781 ASSERT(call_context()->IsTest()); |
4727 HBasicBlock* empty_true = graph()->CreateBasicBlock(); | 4782 HBasicBlock* empty_true = graph()->CreateBasicBlock(); |
4728 HBasicBlock* empty_false = graph()->CreateBasicBlock(); | 4783 HBasicBlock* empty_false = graph()->CreateBasicBlock(); |
4729 HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); | 4784 HBranch* test = new(zone()) HBranch(undefined, empty_true, empty_false); |
4730 current_block()->Finish(test); | 4785 current_block()->Finish(test); |
4731 | 4786 |
4732 empty_true->Goto(inlined_test_context()->if_true()); | 4787 empty_true->Goto(inlined_test_context()->if_true(), drop_extra); |
4733 empty_false->Goto(inlined_test_context()->if_false()); | 4788 empty_false->Goto(inlined_test_context()->if_false(), drop_extra); |
4734 } | 4789 } |
4735 } | 4790 } |
4736 | 4791 |
4737 // Fix up the function exits. | 4792 // Fix up the function exits. |
4738 if (inlined_test_context() != NULL) { | 4793 if (inlined_test_context() != NULL) { |
4739 HBasicBlock* if_true = inlined_test_context()->if_true(); | 4794 HBasicBlock* if_true = inlined_test_context()->if_true(); |
4740 HBasicBlock* if_false = inlined_test_context()->if_false(); | 4795 HBasicBlock* if_false = inlined_test_context()->if_false(); |
4741 | 4796 |
4742 // Pop the return test context from the expression context stack. | 4797 // Pop the return test context from the expression context stack. |
4743 ASSERT(ast_context() == inlined_test_context()); | 4798 ASSERT(ast_context() == inlined_test_context()); |
4744 ClearInlinedTestContext(); | 4799 ClearInlinedTestContext(); |
| 4800 delete target_state; |
4745 | 4801 |
4746 // Forward to the real test context. | 4802 // Forward to the real test context. |
4747 if (if_true->HasPredecessor()) { | 4803 if (if_true->HasPredecessor()) { |
4748 if_true->SetJoinId(expr->id()); | 4804 if_true->SetJoinId(expr->id()); |
4749 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); | 4805 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); |
4750 if_true->Goto(true_target); | 4806 if_true->Goto(true_target, function_state()->drop_extra()); |
4751 } | 4807 } |
4752 if (if_false->HasPredecessor()) { | 4808 if (if_false->HasPredecessor()) { |
4753 if_false->SetJoinId(expr->id()); | 4809 if_false->SetJoinId(expr->id()); |
4754 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); | 4810 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); |
4755 if_false->Goto(false_target); | 4811 if_false->Goto(false_target, function_state()->drop_extra()); |
4756 } | 4812 } |
4757 set_current_block(NULL); | 4813 set_current_block(NULL); |
| 4814 return true; |
4758 | 4815 |
4759 } else if (function_return()->HasPredecessor()) { | 4816 } else if (function_return()->HasPredecessor()) { |
4760 function_return()->SetJoinId(expr->id()); | 4817 function_return()->SetJoinId(expr->id()); |
4761 set_current_block(function_return()); | 4818 set_current_block(function_return()); |
4762 } else { | 4819 } else { |
4763 set_current_block(NULL); | 4820 set_current_block(NULL); |
4764 } | 4821 } |
4765 | 4822 delete target_state; |
4766 return true; | 4823 return true; |
4767 } | 4824 } |
4768 | 4825 |
4769 | 4826 |
4770 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, | 4827 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, |
4771 HValue* receiver, | 4828 HValue* receiver, |
4772 Handle<Map> receiver_map, | 4829 Handle<Map> receiver_map, |
4773 CheckType check_type) { | 4830 CheckType check_type) { |
4774 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | 4831 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); |
4775 // Try to inline calls like Math.* as operations in the calling function. | 4832 // Try to inline calls like Math.* as operations in the calling function. |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5007 expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); | 5064 expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); |
5008 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 5065 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
5009 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | 5066 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
5010 | 5067 |
5011 if (global_call) { | 5068 if (global_call) { |
5012 Variable* var = proxy->var(); | 5069 Variable* var = proxy->var(); |
5013 bool known_global_function = false; | 5070 bool known_global_function = false; |
5014 // If there is a global property cell for the name at compile time and | 5071 // If there is a global property cell for the name at compile time and |
5015 // access check is not enabled we assume that the function will not change | 5072 // access check is not enabled we assume that the function will not change |
5016 // and generate optimized code for calling the function. | 5073 // and generate optimized code for calling the function. |
5017 LookupResult lookup; | 5074 LookupResult lookup(isolate()); |
5018 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 5075 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
5019 if (type == kUseCell && | 5076 if (type == kUseCell && |
5020 !info()->global_object()->IsAccessCheckNeeded()) { | 5077 !info()->global_object()->IsAccessCheckNeeded()) { |
5021 Handle<GlobalObject> global(info()->global_object()); | 5078 Handle<GlobalObject> global(info()->global_object()); |
5022 known_global_function = expr->ComputeGlobalTarget(global, &lookup); | 5079 known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
5023 } | 5080 } |
5024 if (known_global_function) { | 5081 if (known_global_function) { |
5025 // Push the global object instead of the global receiver because | 5082 // Push the global object instead of the global receiver because |
5026 // code generated by the full code generator expects it. | 5083 // code generated by the full code generator expects it. |
5027 HValue* context = environment()->LookupContext(); | 5084 HValue* context = environment()->LookupContext(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5062 // evaluation of the arguments. | 5119 // evaluation of the arguments. |
5063 CHECK_ALIVE(VisitForValue(expr->expression())); | 5120 CHECK_ALIVE(VisitForValue(expr->expression())); |
5064 HValue* function = Top(); | 5121 HValue* function = Top(); |
5065 HValue* context = environment()->LookupContext(); | 5122 HValue* context = environment()->LookupContext(); |
5066 HGlobalObject* global = new(zone()) HGlobalObject(context); | 5123 HGlobalObject* global = new(zone()) HGlobalObject(context); |
5067 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); | 5124 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global); |
5068 AddInstruction(global); | 5125 AddInstruction(global); |
5069 PushAndAdd(receiver); | 5126 PushAndAdd(receiver); |
5070 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 5127 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
5071 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); | 5128 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); |
5072 if (TryInline(expr)) { | 5129 if (TryInline(expr, true)) { // Drop function from environment. |
5073 // The function is lingering in the deoptimization environment. | |
5074 // Handle it by case analysis on the AST context. | |
5075 if (ast_context()->IsEffect()) { | |
5076 Drop(1); | |
5077 } else if (ast_context()->IsValue()) { | |
5078 HValue* result = Pop(); | |
5079 Drop(1); | |
5080 Push(result); | |
5081 } else if (ast_context()->IsTest()) { | |
5082 TestContext* context = TestContext::cast(ast_context()); | |
5083 if (context->if_true()->HasPredecessor()) { | |
5084 context->if_true()->last_environment()->Drop(1); | |
5085 } | |
5086 if (context->if_false()->HasPredecessor()) { | |
5087 context->if_true()->last_environment()->Drop(1); | |
5088 } | |
5089 } else { | |
5090 UNREACHABLE(); | |
5091 } | |
5092 return; | 5130 return; |
5093 } else { | 5131 } else { |
5094 call = PreProcessCall(new(zone()) HInvokeFunction(context, | 5132 call = PreProcessCall(new(zone()) HInvokeFunction(context, |
5095 function, | 5133 function, |
5096 argument_count)); | 5134 argument_count)); |
| 5135 call->set_position(expr->position()); |
| 5136 AddInstruction(call); |
| 5137 AddSimulate(expr->id()); |
5097 Drop(1); // The function. | 5138 Drop(1); // The function. |
| 5139 return ast_context()->ReturnValue(call); |
5098 } | 5140 } |
5099 | 5141 |
5100 } else { | 5142 } else { |
5101 CHECK_ALIVE(VisitArgument(expr->expression())); | 5143 CHECK_ALIVE(VisitArgument(expr->expression())); |
5102 HValue* context = environment()->LookupContext(); | 5144 HValue* context = environment()->LookupContext(); |
5103 HGlobalObject* global_object = new(zone()) HGlobalObject(context); | 5145 HGlobalObject* global_object = new(zone()) HGlobalObject(context); |
5104 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); | 5146 HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object); |
5105 AddInstruction(global_object); | 5147 AddInstruction(global_object); |
5106 AddInstruction(receiver); | 5148 AddInstruction(receiver); |
5107 PushAndAdd(new(zone()) HPushArgument(receiver)); | 5149 PushAndAdd(new(zone()) HPushArgument(receiver)); |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5297 if (info.IsUninitialized()) { | 5339 if (info.IsUninitialized()) { |
5298 AddInstruction(new(zone()) HSoftDeoptimize); | 5340 AddInstruction(new(zone()) HSoftDeoptimize); |
5299 current_block()->MarkAsDeoptimizing(); | 5341 current_block()->MarkAsDeoptimizing(); |
5300 } | 5342 } |
5301 HInstruction* instr = new(zone()) HBitNot(value); | 5343 HInstruction* instr = new(zone()) HBitNot(value); |
5302 return ast_context()->ReturnInstruction(instr, expr->id()); | 5344 return ast_context()->ReturnInstruction(instr, expr->id()); |
5303 } | 5345 } |
5304 | 5346 |
5305 | 5347 |
5306 void HGraphBuilder::VisitNot(UnaryOperation* expr) { | 5348 void HGraphBuilder::VisitNot(UnaryOperation* expr) { |
5307 // TODO(svenpanne) Perhaps a switch/virtual function is nicer here. | |
5308 if (ast_context()->IsTest()) { | 5349 if (ast_context()->IsTest()) { |
5309 TestContext* context = TestContext::cast(ast_context()); | 5350 TestContext* context = TestContext::cast(ast_context()); |
5310 VisitForControl(expr->expression(), | 5351 VisitForControl(expr->expression(), |
5311 context->if_false(), | 5352 context->if_false(), |
5312 context->if_true()); | 5353 context->if_true()); |
5313 return; | 5354 return; |
5314 } | 5355 } |
5315 | 5356 |
5316 if (ast_context()->IsEffect()) { | 5357 if (ast_context()->IsEffect()) { |
5317 VisitForEffect(expr->expression()); | 5358 VisitForEffect(expr->expression()); |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5784 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { | 5825 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { |
5785 if (info.IsSmi()) return Representation::Integer32(); | 5826 if (info.IsSmi()) return Representation::Integer32(); |
5786 if (info.IsInteger32()) return Representation::Integer32(); | 5827 if (info.IsInteger32()) return Representation::Integer32(); |
5787 if (info.IsDouble()) return Representation::Double(); | 5828 if (info.IsDouble()) return Representation::Double(); |
5788 if (info.IsNumber()) return Representation::Double(); | 5829 if (info.IsNumber()) return Representation::Double(); |
5789 return Representation::Tagged(); | 5830 return Representation::Tagged(); |
5790 } | 5831 } |
5791 | 5832 |
5792 | 5833 |
5793 void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, | 5834 void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, |
5794 Expression* sub_expr, | 5835 HTypeof* typeof_expr, |
5795 Handle<String> check) { | 5836 Handle<String> check) { |
5796 CHECK_ALIVE(VisitForTypeOf(sub_expr)); | 5837 // Note: The HTypeof itself is removed during canonicalization, if possible. |
5797 HValue* value = Pop(); | 5838 HValue* value = typeof_expr->value(); |
5798 HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check); | 5839 HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check); |
5799 instr->set_position(expr->position()); | 5840 instr->set_position(expr->position()); |
5800 return ast_context()->ReturnControl(instr, expr->id()); | 5841 return ast_context()->ReturnControl(instr, expr->id()); |
5801 } | 5842 } |
5802 | 5843 |
5803 | 5844 |
5804 bool HGraphBuilder::TryLiteralCompare(CompareOperation* expr) { | 5845 static bool MatchLiteralCompareNil(HValue* left, |
5805 Expression *sub_expr; | 5846 Token::Value op, |
5806 Handle<String> check; | 5847 HValue* right, |
5807 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { | 5848 Handle<Object> nil, |
5808 HandleLiteralCompareTypeof(expr, sub_expr, check); | 5849 HValue** expr) { |
| 5850 if (left->IsConstant() && |
| 5851 HConstant::cast(left)->handle().is_identical_to(nil) && |
| 5852 Token::IsEqualityOp(op)) { |
| 5853 *expr = right; |
5809 return true; | 5854 return true; |
5810 } | 5855 } |
| 5856 return false; |
| 5857 } |
5811 | 5858 |
5812 if (expr->IsLiteralCompareUndefined(&sub_expr)) { | 5859 |
5813 HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); | 5860 static bool MatchLiteralCompareTypeof(HValue* left, |
| 5861 Token::Value op, |
| 5862 HValue* right, |
| 5863 HTypeof** typeof_expr, |
| 5864 Handle<String>* check) { |
| 5865 if (left->IsTypeof() && |
| 5866 Token::IsEqualityOp(op) && |
| 5867 right->IsConstant() && |
| 5868 HConstant::cast(right)->HasStringValue()) { |
| 5869 *typeof_expr = HTypeof::cast(left); |
| 5870 *check = Handle<String>::cast(HConstant::cast(right)->handle()); |
5814 return true; | 5871 return true; |
5815 } | 5872 } |
| 5873 return false; |
| 5874 } |
5816 | 5875 |
5817 if (expr->IsLiteralCompareNull(&sub_expr)) { | |
5818 HandleLiteralCompareNil(expr, sub_expr, kNullValue); | |
5819 return true; | |
5820 } | |
5821 | 5876 |
5822 return false; | 5877 static bool IsLiteralCompareTypeof(HValue* left, |
| 5878 Token::Value op, |
| 5879 HValue* right, |
| 5880 HTypeof** typeof_expr, |
| 5881 Handle<String>* check) { |
| 5882 return MatchLiteralCompareTypeof(left, op, right, typeof_expr, check) || |
| 5883 MatchLiteralCompareTypeof(right, op, left, typeof_expr, check); |
| 5884 } |
| 5885 |
| 5886 |
| 5887 static bool IsLiteralCompareNil(HValue* left, |
| 5888 Token::Value op, |
| 5889 HValue* right, |
| 5890 Handle<Object> nil, |
| 5891 HValue** expr) { |
| 5892 return MatchLiteralCompareNil(left, op, right, nil, expr) || |
| 5893 MatchLiteralCompareNil(right, op, left, nil, expr); |
5823 } | 5894 } |
5824 | 5895 |
5825 | 5896 |
5826 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 5897 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
5827 ASSERT(!HasStackOverflow()); | 5898 ASSERT(!HasStackOverflow()); |
5828 ASSERT(current_block() != NULL); | 5899 ASSERT(current_block() != NULL); |
5829 ASSERT(current_block()->HasPredecessor()); | 5900 ASSERT(current_block()->HasPredecessor()); |
5830 if (IsClassOfTest(expr)) { | 5901 if (IsClassOfTest(expr)) { |
5831 CallRuntime* call = expr->left()->AsCallRuntime(); | 5902 CallRuntime* call = expr->left()->AsCallRuntime(); |
5832 ASSERT(call->arguments()->length() == 1); | 5903 ASSERT(call->arguments()->length() == 1); |
5833 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5904 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
5834 HValue* value = Pop(); | 5905 HValue* value = Pop(); |
5835 Literal* literal = expr->right()->AsLiteral(); | 5906 Literal* literal = expr->right()->AsLiteral(); |
5836 Handle<String> rhs = Handle<String>::cast(literal->handle()); | 5907 Handle<String> rhs = Handle<String>::cast(literal->handle()); |
5837 HClassOfTestAndBranch* instr = | 5908 HClassOfTestAndBranch* instr = |
5838 new(zone()) HClassOfTestAndBranch(value, rhs); | 5909 new(zone()) HClassOfTestAndBranch(value, rhs); |
5839 instr->set_position(expr->position()); | 5910 instr->set_position(expr->position()); |
5840 return ast_context()->ReturnControl(instr, expr->id()); | 5911 return ast_context()->ReturnControl(instr, expr->id()); |
5841 } | 5912 } |
5842 | 5913 |
5843 // Check for special cases that compare against literals. | |
5844 if (TryLiteralCompare(expr)) return; | |
5845 | |
5846 TypeInfo type_info = oracle()->CompareType(expr); | 5914 TypeInfo type_info = oracle()->CompareType(expr); |
5847 // Check if this expression was ever executed according to type feedback. | 5915 // Check if this expression was ever executed according to type feedback. |
| 5916 // Note that for the special typeof/null/undefined cases we get unknown here. |
5848 if (type_info.IsUninitialized()) { | 5917 if (type_info.IsUninitialized()) { |
5849 AddInstruction(new(zone()) HSoftDeoptimize); | 5918 AddInstruction(new(zone()) HSoftDeoptimize); |
5850 current_block()->MarkAsDeoptimizing(); | 5919 current_block()->MarkAsDeoptimizing(); |
5851 type_info = TypeInfo::Unknown(); | 5920 type_info = TypeInfo::Unknown(); |
5852 } | 5921 } |
5853 | 5922 |
5854 CHECK_ALIVE(VisitForValue(expr->left())); | 5923 CHECK_ALIVE(VisitForValue(expr->left())); |
5855 CHECK_ALIVE(VisitForValue(expr->right())); | 5924 CHECK_ALIVE(VisitForValue(expr->right())); |
5856 | 5925 |
5857 HValue* context = environment()->LookupContext(); | 5926 HValue* context = environment()->LookupContext(); |
5858 HValue* right = Pop(); | 5927 HValue* right = Pop(); |
5859 HValue* left = Pop(); | 5928 HValue* left = Pop(); |
5860 Token::Value op = expr->op(); | 5929 Token::Value op = expr->op(); |
5861 | 5930 |
| 5931 HTypeof* typeof_expr = NULL; |
| 5932 Handle<String> check; |
| 5933 if (IsLiteralCompareTypeof(left, op, right, &typeof_expr, &check)) { |
| 5934 return HandleLiteralCompareTypeof(expr, typeof_expr, check); |
| 5935 } |
| 5936 HValue* sub_expr = NULL; |
| 5937 Factory* f = graph()->isolate()->factory(); |
| 5938 if (IsLiteralCompareNil(left, op, right, f->undefined_value(), &sub_expr)) { |
| 5939 return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); |
| 5940 } |
| 5941 if (IsLiteralCompareNil(left, op, right, f->null_value(), &sub_expr)) { |
| 5942 return HandleLiteralCompareNil(expr, sub_expr, kNullValue); |
| 5943 } |
| 5944 |
5862 if (op == Token::INSTANCEOF) { | 5945 if (op == Token::INSTANCEOF) { |
5863 // Check to see if the rhs of the instanceof is a global function not | 5946 // Check to see if the rhs of the instanceof is a global function not |
5864 // residing in new space. If it is we assume that the function will stay the | 5947 // residing in new space. If it is we assume that the function will stay the |
5865 // same. | 5948 // same. |
5866 Handle<JSFunction> target = Handle<JSFunction>::null(); | 5949 Handle<JSFunction> target = Handle<JSFunction>::null(); |
5867 VariableProxy* proxy = expr->right()->AsVariableProxy(); | 5950 VariableProxy* proxy = expr->right()->AsVariableProxy(); |
5868 bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated(); | 5951 bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated(); |
5869 if (global_function && | 5952 if (global_function && |
5870 info()->has_global_object() && | 5953 info()->has_global_object() && |
5871 !info()->global_object()->IsAccessCheckNeeded()) { | 5954 !info()->global_object()->IsAccessCheckNeeded()) { |
5872 Handle<String> name = proxy->name(); | 5955 Handle<String> name = proxy->name(); |
5873 Handle<GlobalObject> global(info()->global_object()); | 5956 Handle<GlobalObject> global(info()->global_object()); |
5874 LookupResult lookup; | 5957 LookupResult lookup(isolate()); |
5875 global->Lookup(*name, &lookup); | 5958 global->Lookup(*name, &lookup); |
5876 if (lookup.IsProperty() && | 5959 if (lookup.IsProperty() && |
5877 lookup.type() == NORMAL && | 5960 lookup.type() == NORMAL && |
5878 lookup.GetValue()->IsJSFunction()) { | 5961 lookup.GetValue()->IsJSFunction()) { |
5879 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); | 5962 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); |
5880 // If the function is in new space we assume it's more likely to | 5963 // If the function is in new space we assume it's more likely to |
5881 // change and thus prefer the general IC code. | 5964 // change and thus prefer the general IC code. |
5882 if (!isolate()->heap()->InNewSpace(*candidate)) { | 5965 if (!isolate()->heap()->InNewSpace(*candidate)) { |
5883 target = candidate; | 5966 target = candidate; |
5884 } | 5967 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5940 new(zone()) HCompareIDAndBranch(left, right, op); | 6023 new(zone()) HCompareIDAndBranch(left, right, op); |
5941 result->set_position(expr->position()); | 6024 result->set_position(expr->position()); |
5942 result->SetInputRepresentation(r); | 6025 result->SetInputRepresentation(r); |
5943 return ast_context()->ReturnControl(result, expr->id()); | 6026 return ast_context()->ReturnControl(result, expr->id()); |
5944 } | 6027 } |
5945 } | 6028 } |
5946 } | 6029 } |
5947 | 6030 |
5948 | 6031 |
5949 void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, | 6032 void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
5950 Expression* sub_expr, | 6033 HValue* value, |
5951 NilValue nil) { | 6034 NilValue nil) { |
5952 ASSERT(!HasStackOverflow()); | 6035 ASSERT(!HasStackOverflow()); |
5953 ASSERT(current_block() != NULL); | 6036 ASSERT(current_block() != NULL); |
5954 ASSERT(current_block()->HasPredecessor()); | 6037 ASSERT(current_block()->HasPredecessor()); |
5955 CHECK_ALIVE(VisitForValue(sub_expr)); | |
5956 HValue* value = Pop(); | |
5957 EqualityKind kind = | 6038 EqualityKind kind = |
5958 expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality; | 6039 expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality; |
5959 HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil); | 6040 HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil); |
5960 instr->set_position(expr->position()); | 6041 instr->set_position(expr->position()); |
5961 return ast_context()->ReturnControl(instr, expr->id()); | 6042 return ast_context()->ReturnControl(instr, expr->id()); |
5962 } | 6043 } |
5963 | 6044 |
5964 | 6045 |
5965 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { | 6046 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
5966 ASSERT(!HasStackOverflow()); | 6047 ASSERT(!HasStackOverflow()); |
5967 ASSERT(current_block() != NULL); | 6048 ASSERT(current_block() != NULL); |
5968 ASSERT(current_block()->HasPredecessor()); | 6049 ASSERT(current_block()->HasPredecessor()); |
5969 HThisFunction* self = new(zone()) HThisFunction; | 6050 HThisFunction* self = new(zone()) HThisFunction( |
| 6051 function_state()->compilation_info()->closure()); |
5970 return ast_context()->ReturnInstruction(self, expr->id()); | 6052 return ast_context()->ReturnInstruction(self, expr->id()); |
5971 } | 6053 } |
5972 | 6054 |
5973 | 6055 |
5974 void HGraphBuilder::VisitDeclaration(Declaration* decl) { | 6056 void HGraphBuilder::VisitDeclaration(Declaration* decl) { |
5975 HandleDeclaration(decl->proxy(), decl->mode(), decl->fun()); | 6057 HandleDeclaration(decl->proxy(), decl->mode(), decl->fun()); |
5976 } | 6058 } |
5977 | 6059 |
5978 | 6060 |
5979 void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, | 6061 void HGraphBuilder::HandleDeclaration(VariableProxy* proxy, |
5980 VariableMode mode, | 6062 VariableMode mode, |
5981 FunctionLiteral* function) { | 6063 FunctionLiteral* function) { |
5982 if (mode == LET) return Bailout("unsupported let declaration"); | 6064 if (mode == LET || mode == CONST_HARMONY) { |
| 6065 return Bailout("unsupported harmony declaration"); |
| 6066 } |
5983 Variable* var = proxy->var(); | 6067 Variable* var = proxy->var(); |
5984 switch (var->location()) { | 6068 switch (var->location()) { |
5985 case Variable::UNALLOCATED: | 6069 case Variable::UNALLOCATED: |
5986 return Bailout("unsupported global declaration"); | 6070 return Bailout("unsupported global declaration"); |
5987 case Variable::PARAMETER: | 6071 case Variable::PARAMETER: |
5988 case Variable::LOCAL: | 6072 case Variable::LOCAL: |
5989 case Variable::CONTEXT: | 6073 case Variable::CONTEXT: |
5990 if (mode == CONST || function != NULL) { | 6074 if (mode == CONST || function != NULL) { |
5991 HValue* value = NULL; | 6075 HValue* value = NULL; |
5992 if (mode == CONST) { | 6076 if (mode == CONST) { |
(...skipping 946 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6939 } | 7023 } |
6940 } | 7024 } |
6941 | 7025 |
6942 #ifdef DEBUG | 7026 #ifdef DEBUG |
6943 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 7027 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
6944 if (allocator_ != NULL) allocator_->Verify(); | 7028 if (allocator_ != NULL) allocator_->Verify(); |
6945 #endif | 7029 #endif |
6946 } | 7030 } |
6947 | 7031 |
6948 } } // namespace v8::internal | 7032 } } // namespace v8::internal |
OLD | NEW |