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 3559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3570 if (expr->is_compound()) { | 3570 if (expr->is_compound()) { |
3571 HandleCompoundAssignment(expr); | 3571 HandleCompoundAssignment(expr); |
3572 return; | 3572 return; |
3573 } | 3573 } |
3574 | 3574 |
3575 if (var != NULL) { | 3575 if (var != NULL) { |
3576 if (var->mode() == Variable::CONST) { | 3576 if (var->mode() == Variable::CONST) { |
3577 if (expr->op() != Token::INIT_CONST) { | 3577 if (expr->op() != Token::INIT_CONST) { |
3578 return Bailout("non-initializer assignment to const"); | 3578 return Bailout("non-initializer assignment to const"); |
3579 } | 3579 } |
| 3580 if (!var->IsStackAllocated()) { |
| 3581 return Bailout("assignment to const context slot"); |
| 3582 } |
3580 // We insert a use of the old value to detect unsupported uses of const | 3583 // We insert a use of the old value to detect unsupported uses of const |
3581 // variables (e.g. initialization inside a loop). | 3584 // variables (e.g. initialization inside a loop). |
3582 HValue* old_value = environment()->Lookup(var); | 3585 HValue* old_value = environment()->Lookup(var); |
3583 AddInstruction(new HUseConst(old_value)); | 3586 AddInstruction(new HUseConst(old_value)); |
3584 } | 3587 } |
3585 | 3588 |
3586 if (proxy->IsArguments()) return Bailout("assignment to arguments"); | 3589 if (proxy->IsArguments()) return Bailout("assignment to arguments"); |
3587 | 3590 |
3588 // Handle the assignment. | 3591 // Handle the assignment. |
3589 if (var->IsStackAllocated()) { | 3592 if (var->IsStackAllocated()) { |
3590 // We do not allow the arguments object to occur in a context where it | 3593 // We do not allow the arguments object to occur in a context where it |
3591 // may escape, but assignments to stack-allocated locals are | 3594 // may escape, but assignments to stack-allocated locals are |
3592 // permitted. | 3595 // permitted. |
3593 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); | 3596 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); |
3594 HValue* value = Pop(); | 3597 HValue* value = Pop(); |
3595 Bind(var, value); | 3598 Bind(var, value); |
3596 ast_context()->ReturnValue(value); | 3599 ast_context()->ReturnValue(value); |
3597 | 3600 |
3598 } else if (var->IsContextSlot() && var->mode() != Variable::CONST) { | 3601 } else if (var->IsContextSlot()) { |
| 3602 ASSERT(var->mode() != Variable::CONST); |
3599 CHECK_ALIVE(VisitForValue(expr->value())); | 3603 CHECK_ALIVE(VisitForValue(expr->value())); |
3600 HValue* context = BuildContextChainWalk(var); | 3604 HValue* context = BuildContextChainWalk(var); |
3601 int index = var->AsSlot()->index(); | 3605 int index = var->AsSlot()->index(); |
3602 HStoreContextSlot* instr = | 3606 HStoreContextSlot* instr = |
3603 new(zone()) HStoreContextSlot(context, index, Top()); | 3607 new(zone()) HStoreContextSlot(context, index, Top()); |
3604 AddInstruction(instr); | 3608 AddInstruction(instr); |
3605 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3609 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
3606 ast_context()->ReturnValue(Pop()); | 3610 ast_context()->ReturnValue(Pop()); |
3607 | 3611 |
3608 } else if (var->is_global()) { | 3612 } else if (var->is_global()) { |
(...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4184 } | 4188 } |
4185 FunctionLiteral* function = target_info.function(); | 4189 FunctionLiteral* function = target_info.function(); |
4186 | 4190 |
4187 // Count the number of AST nodes added by inlining this call. | 4191 // Count the number of AST nodes added by inlining this call. |
4188 int nodes_added = AstNode::Count() - count_before; | 4192 int nodes_added = AstNode::Count() - count_before; |
4189 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { | 4193 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { |
4190 TraceInline(target, caller, "target AST is too large"); | 4194 TraceInline(target, caller, "target AST is too large"); |
4191 return false; | 4195 return false; |
4192 } | 4196 } |
4193 | 4197 |
4194 // Check if we can handle all declarations in the inlined functions. | |
4195 VisitDeclarations(target_info.scope()->declarations()); | |
4196 if (HasStackOverflow()) { | |
4197 TraceInline(target, caller, "target has non-trivial declaration"); | |
4198 ClearStackOverflow(); | |
4199 return false; | |
4200 } | |
4201 | |
4202 // Don't inline functions that uses the arguments object or that | 4198 // Don't inline functions that uses the arguments object or that |
4203 // have a mismatching number of parameters. | 4199 // have a mismatching number of parameters. |
4204 int arity = expr->arguments()->length(); | 4200 int arity = expr->arguments()->length(); |
4205 if (function->scope()->arguments() != NULL || | 4201 if (function->scope()->arguments() != NULL || |
4206 arity != target_shared->formal_parameter_count()) { | 4202 arity != target_shared->formal_parameter_count()) { |
4207 TraceInline(target, caller, "target requires special argument handling"); | 4203 TraceInline(target, caller, "target requires special argument handling"); |
4208 return false; | 4204 return false; |
4209 } | 4205 } |
4210 | 4206 |
| 4207 // All declarations must be inlineable. |
| 4208 ZoneList<Declaration*>* decls = target_info.scope()->declarations(); |
| 4209 int decl_count = decls->length(); |
| 4210 for (int i = 0; i < decl_count; ++i) { |
| 4211 if (!decls->at(i)->IsInlineable()) { |
| 4212 TraceInline(target, caller, "target has non-trivial declaration"); |
| 4213 return false; |
| 4214 } |
| 4215 } |
4211 // All statements in the body must be inlineable. | 4216 // All statements in the body must be inlineable. |
4212 for (int i = 0, count = function->body()->length(); i < count; ++i) { | 4217 for (int i = 0, count = function->body()->length(); i < count; ++i) { |
4213 if (!function->body()->at(i)->IsInlineable()) { | 4218 if (!function->body()->at(i)->IsInlineable()) { |
4214 TraceInline(target, caller, "target contains unsupported syntax"); | 4219 TraceInline(target, caller, "target contains unsupported syntax"); |
4215 return false; | 4220 return false; |
4216 } | 4221 } |
4217 } | 4222 } |
4218 | 4223 |
4219 // Generate the deoptimization data for the unoptimized version of | 4224 // Generate the deoptimization data for the unoptimized version of |
4220 // the target function if we don't already have it. | 4225 // the target function if we don't already have it. |
4221 if (!target_shared->has_deoptimization_support()) { | 4226 if (!target_shared->has_deoptimization_support()) { |
4222 // Note that we compile here using the same AST that we will use for | 4227 // Note that we compile here using the same AST that we will use for |
4223 // generating the optimized inline code. | 4228 // generating the optimized inline code. |
4224 target_info.EnableDeoptimizationSupport(); | 4229 target_info.EnableDeoptimizationSupport(); |
4225 if (!FullCodeGenerator::MakeCode(&target_info)) { | 4230 if (!FullCodeGenerator::MakeCode(&target_info)) { |
4226 TraceInline(target, caller, "could not generate deoptimization info"); | 4231 TraceInline(target, caller, "could not generate deoptimization info"); |
4227 return false; | 4232 return false; |
4228 } | 4233 } |
4229 target_shared->EnableDeoptimizationSupport(*target_info.code()); | 4234 target_shared->EnableDeoptimizationSupport(*target_info.code()); |
4230 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, | 4235 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, |
4231 &target_info, | 4236 &target_info, |
4232 target_shared); | 4237 target_shared); |
4233 } | 4238 } |
4234 | 4239 |
4235 // ---------------------------------------------------------------- | 4240 // ---------------------------------------------------------------- |
| 4241 // After this point, we've made a decision to inline this function (so |
| 4242 // TryInline should always return true). |
| 4243 |
4236 // Save the pending call context and type feedback oracle. Set up new ones | 4244 // Save the pending call context and type feedback oracle. Set up new ones |
4237 // for the inlined function. | 4245 // for the inlined function. |
4238 ASSERT(target_shared->has_deoptimization_support()); | 4246 ASSERT(target_shared->has_deoptimization_support()); |
4239 TypeFeedbackOracle target_oracle( | 4247 TypeFeedbackOracle target_oracle( |
4240 Handle<Code>(target_shared->code()), | 4248 Handle<Code>(target_shared->code()), |
4241 Handle<Context>(target->context()->global_context())); | 4249 Handle<Context>(target->context()->global_context())); |
4242 FunctionState target_state(this, &target_info, &target_oracle); | 4250 FunctionState target_state(this, &target_info, &target_oracle); |
4243 | 4251 |
4244 HConstant* undefined = graph()->GetConstantUndefined(); | 4252 HConstant* undefined = graph()->GetConstantUndefined(); |
4245 HEnvironment* inner_env = | 4253 HEnvironment* inner_env = |
4246 environment()->CopyForInlining(target, | 4254 environment()->CopyForInlining(target, |
4247 function, | 4255 function, |
4248 HEnvironment::HYDROGEN, | 4256 HEnvironment::HYDROGEN, |
4249 undefined, | 4257 undefined, |
4250 call_kind); | 4258 call_kind); |
4251 HBasicBlock* body_entry = CreateBasicBlock(inner_env); | 4259 HBasicBlock* body_entry = CreateBasicBlock(inner_env); |
4252 current_block()->Goto(body_entry); | 4260 current_block()->Goto(body_entry); |
4253 | |
4254 body_entry->SetJoinId(expr->ReturnId()); | 4261 body_entry->SetJoinId(expr->ReturnId()); |
4255 set_current_block(body_entry); | 4262 set_current_block(body_entry); |
4256 AddInstruction(new(zone()) HEnterInlined(target, | 4263 AddInstruction(new(zone()) HEnterInlined(target, |
4257 function, | 4264 function, |
4258 call_kind)); | 4265 call_kind)); |
| 4266 VisitDeclarations(target_info.scope()->declarations()); |
4259 VisitStatements(function->body()); | 4267 VisitStatements(function->body()); |
4260 if (HasStackOverflow()) { | 4268 if (HasStackOverflow()) { |
4261 // Bail out if the inline function did, as we cannot residualize a call | 4269 // Bail out if the inline function did, as we cannot residualize a call |
4262 // instead. | 4270 // instead. |
4263 TraceInline(target, caller, "inline graph construction failed"); | 4271 TraceInline(target, caller, "inline graph construction failed"); |
4264 target_shared->DisableOptimization(*target); | 4272 target_shared->DisableOptimization(*target); |
4265 inline_bailout_ = true; | 4273 inline_bailout_ = true; |
4266 return true; | 4274 return true; |
4267 } | 4275 } |
4268 | 4276 |
(...skipping 817 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5086 ASSERT(call->arguments()->length() == 1); | 5094 ASSERT(call->arguments()->length() == 1); |
5087 return true; | 5095 return true; |
5088 } | 5096 } |
5089 | 5097 |
5090 | 5098 |
5091 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { | 5099 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { |
5092 ASSERT(!HasStackOverflow()); | 5100 ASSERT(!HasStackOverflow()); |
5093 ASSERT(current_block() != NULL); | 5101 ASSERT(current_block() != NULL); |
5094 ASSERT(current_block()->HasPredecessor()); | 5102 ASSERT(current_block()->HasPredecessor()); |
5095 switch (expr->op()) { | 5103 switch (expr->op()) { |
5096 case Token::COMMA: return VisitComma(expr); | 5104 case Token::COMMA: |
5097 case Token::OR: return VisitAndOr(expr, false); | 5105 return VisitComma(expr); |
5098 case Token::AND: return VisitAndOr(expr, true); | 5106 case Token::OR: |
5099 default: return VisitCommon(expr); | 5107 case Token::AND: |
| 5108 return VisitLogicalExpression(expr); |
| 5109 default: |
| 5110 return VisitArithmeticExpression(expr); |
5100 } | 5111 } |
5101 } | 5112 } |
5102 | 5113 |
5103 | 5114 |
5104 void HGraphBuilder::VisitComma(BinaryOperation* expr) { | 5115 void HGraphBuilder::VisitComma(BinaryOperation* expr) { |
5105 CHECK_ALIVE(VisitForEffect(expr->left())); | 5116 CHECK_ALIVE(VisitForEffect(expr->left())); |
5106 // Visit the right subexpression in the same AST context as the entire | 5117 // Visit the right subexpression in the same AST context as the entire |
5107 // expression. | 5118 // expression. |
5108 Visit(expr->right()); | 5119 Visit(expr->right()); |
5109 } | 5120 } |
5110 | 5121 |
5111 | 5122 |
5112 void HGraphBuilder::VisitAndOr(BinaryOperation* expr, bool is_logical_and) { | 5123 void HGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { |
| 5124 bool is_logical_and = expr->op() == Token::AND; |
5113 if (ast_context()->IsTest()) { | 5125 if (ast_context()->IsTest()) { |
5114 TestContext* context = TestContext::cast(ast_context()); | 5126 TestContext* context = TestContext::cast(ast_context()); |
5115 // Translate left subexpression. | 5127 // Translate left subexpression. |
5116 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 5128 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
5117 if (is_logical_and) { | 5129 if (is_logical_and) { |
5118 CHECK_BAILOUT(VisitForControl(expr->left(), | 5130 CHECK_BAILOUT(VisitForControl(expr->left(), |
5119 eval_right, | 5131 eval_right, |
5120 context->if_false())); | 5132 context->if_false())); |
5121 } else { | 5133 } else { |
5122 CHECK_BAILOUT(VisitForControl(expr->left(), | 5134 CHECK_BAILOUT(VisitForControl(expr->left(), |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5189 | 5201 |
5190 HBasicBlock* join_block = | 5202 HBasicBlock* join_block = |
5191 CreateJoin(empty_block, right_block, expr->id()); | 5203 CreateJoin(empty_block, right_block, expr->id()); |
5192 set_current_block(join_block); | 5204 set_current_block(join_block); |
5193 // We did not materialize any value in the predecessor environments, | 5205 // We did not materialize any value in the predecessor environments, |
5194 // so there is no need to handle it here. | 5206 // so there is no need to handle it here. |
5195 } | 5207 } |
5196 } | 5208 } |
5197 | 5209 |
5198 | 5210 |
5199 void HGraphBuilder::VisitCommon(BinaryOperation* expr) { | 5211 void HGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { |
5200 CHECK_ALIVE(VisitForValue(expr->left())); | 5212 CHECK_ALIVE(VisitForValue(expr->left())); |
5201 CHECK_ALIVE(VisitForValue(expr->right())); | 5213 CHECK_ALIVE(VisitForValue(expr->right())); |
5202 HValue* right = Pop(); | 5214 HValue* right = Pop(); |
5203 HValue* left = Pop(); | 5215 HValue* left = Pop(); |
5204 HInstruction* instr = BuildBinaryOperation(expr, left, right); | 5216 HInstruction* instr = BuildBinaryOperation(expr, left, right); |
5205 instr->set_position(expr->position()); | 5217 instr->set_position(expr->position()); |
5206 ast_context()->ReturnInstruction(instr, expr->id()); | 5218 ast_context()->ReturnInstruction(instr, expr->id()); |
5207 } | 5219 } |
5208 | 5220 |
5209 | 5221 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5357 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { | 5369 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { |
5358 ASSERT(!HasStackOverflow()); | 5370 ASSERT(!HasStackOverflow()); |
5359 ASSERT(current_block() != NULL); | 5371 ASSERT(current_block() != NULL); |
5360 ASSERT(current_block()->HasPredecessor()); | 5372 ASSERT(current_block()->HasPredecessor()); |
5361 HThisFunction* self = new(zone()) HThisFunction; | 5373 HThisFunction* self = new(zone()) HThisFunction; |
5362 return ast_context()->ReturnInstruction(self, expr->id()); | 5374 return ast_context()->ReturnInstruction(self, expr->id()); |
5363 } | 5375 } |
5364 | 5376 |
5365 | 5377 |
5366 void HGraphBuilder::VisitDeclaration(Declaration* decl) { | 5378 void HGraphBuilder::VisitDeclaration(Declaration* decl) { |
5367 // We allow only declarations that do not require code generation. | 5379 // We support only declarations that do not require code generation. |
5368 // The following all require code generation: global variables, | |
5369 // functions, and variables with slot type LOOKUP | |
5370 Variable* var = decl->proxy()->var(); | 5380 Variable* var = decl->proxy()->var(); |
5371 Slot* slot = var->AsSlot(); | 5381 if (!var->IsStackAllocated() || decl->fun() != NULL) { |
5372 if (var->is_global() || | |
5373 !var->IsStackAllocated() || | |
5374 (slot != NULL && slot->type() == Slot::LOOKUP) || | |
5375 decl->fun() != NULL) { | |
5376 return Bailout("unsupported declaration"); | 5382 return Bailout("unsupported declaration"); |
5377 } | 5383 } |
5378 | 5384 |
5379 if (decl->mode() == Variable::CONST) { | 5385 if (decl->mode() == Variable::CONST) { |
| 5386 ASSERT(var->IsStackAllocated()); |
5380 environment()->Bind(var, graph()->GetConstantHole()); | 5387 environment()->Bind(var, graph()->GetConstantHole()); |
5381 } | 5388 } |
5382 } | 5389 } |
5383 | 5390 |
5384 | 5391 |
5385 // Generators for inline runtime functions. | 5392 // Generators for inline runtime functions. |
5386 // Support for types. | 5393 // Support for types. |
5387 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { | 5394 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { |
5388 ASSERT(call->arguments()->length() == 1); | 5395 ASSERT(call->arguments()->length() == 1); |
5389 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 5396 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
(...skipping 916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6306 } | 6313 } |
6307 } | 6314 } |
6308 | 6315 |
6309 #ifdef DEBUG | 6316 #ifdef DEBUG |
6310 if (graph_ != NULL) graph_->Verify(); | 6317 if (graph_ != NULL) graph_->Verify(); |
6311 if (allocator_ != NULL) allocator_->Verify(); | 6318 if (allocator_ != NULL) allocator_->Verify(); |
6312 #endif | 6319 #endif |
6313 } | 6320 } |
6314 | 6321 |
6315 } } // namespace v8::internal | 6322 } } // namespace v8::internal |
OLD | NEW |