OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 3240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3251 : NewScope(scope_, FUNCTION_SCOPE); | 3251 : NewScope(scope_, FUNCTION_SCOPE); |
3252 ZoneList<Statement*>* body = NULL; | 3252 ZoneList<Statement*>* body = NULL; |
3253 int materialized_literal_count = -1; | 3253 int materialized_literal_count = -1; |
3254 int expected_property_count = -1; | 3254 int expected_property_count = -1; |
3255 int handler_count = 0; | 3255 int handler_count = 0; |
3256 FunctionLiteral::ParameterFlag duplicate_parameters = | 3256 FunctionLiteral::ParameterFlag duplicate_parameters = |
3257 FunctionLiteral::kNoDuplicateParameters; | 3257 FunctionLiteral::kNoDuplicateParameters; |
3258 FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ | 3258 FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ |
3259 ? FunctionLiteral::kIsParenthesized | 3259 ? FunctionLiteral::kIsParenthesized |
3260 : FunctionLiteral::kNotParenthesized; | 3260 : FunctionLiteral::kNotParenthesized; |
3261 FunctionLiteral::IsGeneratorFlag generator = is_generator | |
3262 ? FunctionLiteral::kIsGenerator | |
3263 : FunctionLiteral::kNotGenerator; | |
3264 DeferredFeedbackSlotProcessor* slot_processor; | 3261 DeferredFeedbackSlotProcessor* slot_processor; |
3265 AstProperties ast_properties; | 3262 AstProperties ast_properties; |
3266 BailoutReason dont_optimize_reason = kNoReason; | 3263 BailoutReason dont_optimize_reason = kNoReason; |
3267 // Parse function body. | 3264 // Parse function body. |
3268 { FunctionState function_state(&function_state_, &scope_, scope, zone()); | 3265 { FunctionState function_state(&function_state_, &scope_, scope, zone()); |
3269 scope_->SetScopeName(function_name); | 3266 scope_->SetScopeName(function_name); |
3270 | 3267 |
3271 if (is_generator) { | 3268 if (is_generator) { |
3272 // For generators, allocating variables in contexts is currently a win | 3269 // For generators, allocating variables in contexts is currently a win |
3273 // because it minimizes the work needed to suspend and resume an | 3270 // because it minimizes the work needed to suspend and resume an |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3382 // that it will be compiled lazily. | 3379 // that it will be compiled lazily. |
3383 | 3380 |
3384 // To make this additional case work, both Parser and PreParser implement a | 3381 // To make this additional case work, both Parser and PreParser implement a |
3385 // logic where only top-level functions will be parsed lazily. | 3382 // logic where only top-level functions will be parsed lazily. |
3386 bool is_lazily_parsed = (mode() == PARSE_LAZILY && | 3383 bool is_lazily_parsed = (mode() == PARSE_LAZILY && |
3387 scope_->AllowsLazyCompilation() && | 3384 scope_->AllowsLazyCompilation() && |
3388 !parenthesized_function_); | 3385 !parenthesized_function_); |
3389 parenthesized_function_ = false; // The bit was set for this function only. | 3386 parenthesized_function_ = false; // The bit was set for this function only. |
3390 | 3387 |
3391 if (is_lazily_parsed) { | 3388 if (is_lazily_parsed) { |
3392 int function_block_pos = position(); | 3389 SkipLazyFunctionBody(function_name, &materialized_literal_count, |
3393 FunctionEntry entry; | 3390 &expected_property_count, CHECK_OK); |
3394 if (cached_data_mode_ == CONSUME_CACHED_DATA) { | 3391 } else { |
3395 // If we have cached data, we use it to skip parsing the function body. | 3392 body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op, |
3396 // The data contains the information we need to construct the lazy | 3393 is_generator, CHECK_OK); |
3397 // function. | |
3398 entry = (*cached_data())->GetFunctionEntry(function_block_pos); | |
3399 if (entry.is_valid()) { | |
3400 if (entry.end_pos() <= function_block_pos) { | |
3401 // End position greater than end of stream is safe, and hard | |
3402 // to check. | |
3403 ReportInvalidCachedData(function_name, CHECK_OK); | |
3404 } | |
3405 scanner()->SeekForward(entry.end_pos() - 1); | |
3406 | |
3407 scope->set_end_position(entry.end_pos()); | |
3408 Expect(Token::RBRACE, CHECK_OK); | |
3409 isolate()->counters()->total_preparse_skipped()->Increment( | |
3410 scope->end_position() - function_block_pos); | |
3411 materialized_literal_count = entry.literal_count(); | |
3412 expected_property_count = entry.property_count(); | |
3413 scope_->SetStrictMode(entry.strict_mode()); | |
3414 } else { | |
3415 // This case happens when we have preparse data but it doesn't contain | |
3416 // an entry for the function. Fail the compilation. | |
3417 ReportInvalidCachedData(function_name, CHECK_OK); | |
3418 } | |
3419 } else { | |
3420 // With no cached data, we partially parse the function, without | |
3421 // building an AST. This gathers the data needed to build a lazy | |
3422 // function. | |
3423 SingletonLogger logger; | |
3424 PreParser::PreParseResult result = LazyParseFunctionLiteral(&logger); | |
3425 if (result == PreParser::kPreParseStackOverflow) { | |
3426 // Propagate stack overflow. | |
3427 set_stack_overflow(); | |
3428 *ok = false; | |
3429 return NULL; | |
3430 } | |
3431 if (logger.has_error()) { | |
3432 const char* arg = logger.argument_opt(); | |
3433 Vector<const char*> args; | |
3434 if (arg != NULL) { | |
3435 args = Vector<const char*>(&arg, 1); | |
3436 } | |
3437 ParserTraits::ReportMessageAt( | |
3438 Scanner::Location(logger.start(), logger.end()), | |
3439 logger.message(), args, logger.is_reference_error()); | |
3440 *ok = false; | |
3441 return NULL; | |
3442 } | |
3443 scope->set_end_position(logger.end()); | |
3444 Expect(Token::RBRACE, CHECK_OK); | |
3445 isolate()->counters()->total_preparse_skipped()->Increment( | |
3446 scope->end_position() - function_block_pos); | |
3447 materialized_literal_count = logger.literals(); | |
3448 expected_property_count = logger.properties(); | |
3449 scope_->SetStrictMode(logger.strict_mode()); | |
3450 if (cached_data_mode_ == PRODUCE_CACHED_DATA) { | |
3451 ASSERT(log_); | |
3452 // Position right after terminal '}'. | |
3453 int body_end = scanner()->location().end_pos; | |
3454 log_->LogFunction(function_block_pos, body_end, | |
3455 materialized_literal_count, | |
3456 expected_property_count, | |
3457 scope_->strict_mode()); | |
3458 } | |
3459 } | |
3460 } | |
3461 | |
3462 if (!is_lazily_parsed) { | |
3463 // Everything inside an eagerly parsed function will be parsed eagerly | |
3464 // (see comment above). | |
3465 ParsingModeScope parsing_mode(this, PARSE_EAGERLY); | |
3466 body = new(zone()) ZoneList<Statement*>(8, zone()); | |
3467 if (fvar != NULL) { | |
3468 VariableProxy* fproxy = scope_->NewUnresolved( | |
3469 factory(), function_name, Interface::NewConst()); | |
3470 fproxy->BindTo(fvar); | |
3471 body->Add(factory()->NewExpressionStatement( | |
3472 factory()->NewAssignment(fvar_init_op, | |
3473 fproxy, | |
3474 factory()->NewThisFunction(pos), | |
3475 RelocInfo::kNoPosition), | |
3476 RelocInfo::kNoPosition), zone()); | |
3477 } | |
3478 | |
3479 // For generators, allocate and yield an iterator on function entry. | |
3480 if (is_generator) { | |
3481 ZoneList<Expression*>* arguments = | |
3482 new(zone()) ZoneList<Expression*>(0, zone()); | |
3483 CallRuntime* allocation = factory()->NewCallRuntime( | |
3484 isolate()->factory()->empty_string(), | |
3485 Runtime::FunctionForId(Runtime::kHiddenCreateJSGeneratorObject), | |
3486 arguments, pos); | |
3487 VariableProxy* init_proxy = factory()->NewVariableProxy( | |
3488 function_state_->generator_object_variable()); | |
3489 Assignment* assignment = factory()->NewAssignment( | |
3490 Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition); | |
3491 VariableProxy* get_proxy = factory()->NewVariableProxy( | |
3492 function_state_->generator_object_variable()); | |
3493 Yield* yield = factory()->NewYield( | |
3494 get_proxy, assignment, Yield::INITIAL, RelocInfo::kNoPosition); | |
3495 body->Add(factory()->NewExpressionStatement( | |
3496 yield, RelocInfo::kNoPosition), zone()); | |
3497 } | |
3498 | |
3499 ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK); | |
3500 | |
3501 if (is_generator) { | |
3502 VariableProxy* get_proxy = factory()->NewVariableProxy( | |
3503 function_state_->generator_object_variable()); | |
3504 Expression *undefined = factory()->NewLiteral( | |
3505 isolate()->factory()->undefined_value(), RelocInfo::kNoPosition); | |
3506 Yield* yield = factory()->NewYield( | |
3507 get_proxy, undefined, Yield::FINAL, RelocInfo::kNoPosition); | |
3508 body->Add(factory()->NewExpressionStatement( | |
3509 yield, RelocInfo::kNoPosition), zone()); | |
3510 } | |
3511 | |
3512 materialized_literal_count = function_state.materialized_literal_count(); | 3394 materialized_literal_count = function_state.materialized_literal_count(); |
3513 expected_property_count = function_state.expected_property_count(); | 3395 expected_property_count = function_state.expected_property_count(); |
3514 handler_count = function_state.handler_count(); | 3396 handler_count = function_state.handler_count(); |
3515 | |
3516 Expect(Token::RBRACE, CHECK_OK); | |
3517 scope->set_end_position(scanner()->location().end_pos); | |
3518 } | 3397 } |
3519 | 3398 |
3520 // Validate strict mode. We can do this only after parsing the function, | 3399 // Validate strict mode. We can do this only after parsing the function, |
3521 // since the function can declare itself strict. | 3400 // since the function can declare itself strict. |
3522 if (strict_mode() == STRICT) { | 3401 if (strict_mode() == STRICT) { |
3523 if (IsEvalOrArguments(function_name)) { | 3402 if (IsEvalOrArguments(function_name)) { |
3524 ReportMessageAt(function_name_location, "strict_eval_arguments"); | 3403 ReportMessageAt(function_name_location, "strict_eval_arguments"); |
3525 *ok = false; | 3404 *ok = false; |
3526 return NULL; | 3405 return NULL; |
3527 } | 3406 } |
(...skipping 23 matching lines...) Expand all Loading... |
3551 } | 3430 } |
3552 ast_properties = *factory()->visitor()->ast_properties(); | 3431 ast_properties = *factory()->visitor()->ast_properties(); |
3553 slot_processor = factory()->visitor()->slot_processor(); | 3432 slot_processor = factory()->visitor()->slot_processor(); |
3554 dont_optimize_reason = factory()->visitor()->dont_optimize_reason(); | 3433 dont_optimize_reason = factory()->visitor()->dont_optimize_reason(); |
3555 } | 3434 } |
3556 | 3435 |
3557 if (allow_harmony_scoping() && strict_mode() == STRICT) { | 3436 if (allow_harmony_scoping() && strict_mode() == STRICT) { |
3558 CheckConflictingVarDeclarations(scope, CHECK_OK); | 3437 CheckConflictingVarDeclarations(scope, CHECK_OK); |
3559 } | 3438 } |
3560 | 3439 |
| 3440 FunctionLiteral::IsGeneratorFlag generator = is_generator |
| 3441 ? FunctionLiteral::kIsGenerator |
| 3442 : FunctionLiteral::kNotGenerator; |
3561 FunctionLiteral* function_literal = | 3443 FunctionLiteral* function_literal = |
3562 factory()->NewFunctionLiteral(function_name, | 3444 factory()->NewFunctionLiteral(function_name, |
3563 scope, | 3445 scope, |
3564 body, | 3446 body, |
3565 materialized_literal_count, | 3447 materialized_literal_count, |
3566 expected_property_count, | 3448 expected_property_count, |
3567 handler_count, | 3449 handler_count, |
3568 num_parameters, | 3450 num_parameters, |
3569 duplicate_parameters, | 3451 duplicate_parameters, |
3570 function_type, | 3452 function_type, |
3571 FunctionLiteral::kIsFunction, | 3453 FunctionLiteral::kIsFunction, |
3572 parenthesized, | 3454 parenthesized, |
3573 generator, | 3455 generator, |
3574 pos); | 3456 pos); |
3575 function_literal->set_function_token_position(function_token_pos); | 3457 function_literal->set_function_token_position(function_token_pos); |
3576 function_literal->set_ast_properties(&ast_properties); | 3458 function_literal->set_ast_properties(&ast_properties); |
3577 function_literal->set_slot_processor(slot_processor); | 3459 function_literal->set_slot_processor(slot_processor); |
3578 function_literal->set_dont_optimize_reason(dont_optimize_reason); | 3460 function_literal->set_dont_optimize_reason(dont_optimize_reason); |
3579 | 3461 |
3580 if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal); | 3462 if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal); |
3581 return function_literal; | 3463 return function_literal; |
3582 } | 3464 } |
3583 | 3465 |
3584 | 3466 |
3585 PreParser::PreParseResult Parser::LazyParseFunctionLiteral( | 3467 void Parser::SkipLazyFunctionBody(Handle<String> function_name, |
| 3468 int* materialized_literal_count, |
| 3469 int* expected_property_count, |
| 3470 bool* ok) { |
| 3471 int function_block_pos = position(); |
| 3472 if (cached_data_mode_ == CONSUME_CACHED_DATA) { |
| 3473 // If we have cached data, we use it to skip parsing the function body. The |
| 3474 // data contains the information we need to construct the lazy function. |
| 3475 FunctionEntry entry = |
| 3476 (*cached_data())->GetFunctionEntry(function_block_pos); |
| 3477 if (entry.is_valid()) { |
| 3478 if (entry.end_pos() <= function_block_pos) { |
| 3479 // End position greater than end of stream is safe, and hard to check. |
| 3480 ReportInvalidCachedData(function_name, ok); |
| 3481 if (!*ok) { |
| 3482 return; |
| 3483 } |
| 3484 } |
| 3485 scanner()->SeekForward(entry.end_pos() - 1); |
| 3486 |
| 3487 scope_->set_end_position(entry.end_pos()); |
| 3488 Expect(Token::RBRACE, ok); |
| 3489 if (!*ok) { |
| 3490 return; |
| 3491 } |
| 3492 isolate()->counters()->total_preparse_skipped()->Increment( |
| 3493 scope_->end_position() - function_block_pos); |
| 3494 *materialized_literal_count = entry.literal_count(); |
| 3495 *expected_property_count = entry.property_count(); |
| 3496 scope_->SetStrictMode(entry.strict_mode()); |
| 3497 } else { |
| 3498 // This case happens when we have preparse data but it doesn't contain an |
| 3499 // entry for the function. Fail the compilation. |
| 3500 ReportInvalidCachedData(function_name, ok); |
| 3501 return; |
| 3502 } |
| 3503 } else { |
| 3504 // With no cached data, we partially parse the function, without building an |
| 3505 // AST. This gathers the data needed to build a lazy function. |
| 3506 SingletonLogger logger; |
| 3507 PreParser::PreParseResult result = |
| 3508 ParseLazyFunctionBodyWithPreParser(&logger); |
| 3509 if (result == PreParser::kPreParseStackOverflow) { |
| 3510 // Propagate stack overflow. |
| 3511 set_stack_overflow(); |
| 3512 *ok = false; |
| 3513 return; |
| 3514 } |
| 3515 if (logger.has_error()) { |
| 3516 const char* arg = logger.argument_opt(); |
| 3517 Vector<const char*> args; |
| 3518 if (arg != NULL) { |
| 3519 args = Vector<const char*>(&arg, 1); |
| 3520 } |
| 3521 ParserTraits::ReportMessageAt( |
| 3522 Scanner::Location(logger.start(), logger.end()), |
| 3523 logger.message(), args, logger.is_reference_error()); |
| 3524 *ok = false; |
| 3525 return; |
| 3526 } |
| 3527 scope_->set_end_position(logger.end()); |
| 3528 Expect(Token::RBRACE, ok); |
| 3529 if (!*ok) { |
| 3530 return; |
| 3531 } |
| 3532 isolate()->counters()->total_preparse_skipped()->Increment( |
| 3533 scope_->end_position() - function_block_pos); |
| 3534 *materialized_literal_count = logger.literals(); |
| 3535 *expected_property_count = logger.properties(); |
| 3536 scope_->SetStrictMode(logger.strict_mode()); |
| 3537 if (cached_data_mode_ == PRODUCE_CACHED_DATA) { |
| 3538 ASSERT(log_); |
| 3539 // Position right after terminal '}'. |
| 3540 int body_end = scanner()->location().end_pos; |
| 3541 log_->LogFunction(function_block_pos, body_end, |
| 3542 *materialized_literal_count, |
| 3543 *expected_property_count, |
| 3544 scope_->strict_mode()); |
| 3545 } |
| 3546 } |
| 3547 } |
| 3548 |
| 3549 |
| 3550 ZoneList<Statement*>* Parser::ParseEagerFunctionBody( |
| 3551 Handle<String> function_name, int pos, Variable* fvar, |
| 3552 Token::Value fvar_init_op, bool is_generator, bool* ok) { |
| 3553 // Everything inside an eagerly parsed function will be parsed eagerly |
| 3554 // (see comment above). |
| 3555 ParsingModeScope parsing_mode(this, PARSE_EAGERLY); |
| 3556 ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8, zone()); |
| 3557 if (fvar != NULL) { |
| 3558 VariableProxy* fproxy = scope_->NewUnresolved( |
| 3559 factory(), function_name, Interface::NewConst()); |
| 3560 fproxy->BindTo(fvar); |
| 3561 body->Add(factory()->NewExpressionStatement( |
| 3562 factory()->NewAssignment(fvar_init_op, |
| 3563 fproxy, |
| 3564 factory()->NewThisFunction(pos), |
| 3565 RelocInfo::kNoPosition), |
| 3566 RelocInfo::kNoPosition), zone()); |
| 3567 } |
| 3568 |
| 3569 // For generators, allocate and yield an iterator on function entry. |
| 3570 if (is_generator) { |
| 3571 ZoneList<Expression*>* arguments = |
| 3572 new(zone()) ZoneList<Expression*>(0, zone()); |
| 3573 CallRuntime* allocation = factory()->NewCallRuntime( |
| 3574 isolate()->factory()->empty_string(), |
| 3575 Runtime::FunctionForId(Runtime::kHiddenCreateJSGeneratorObject), |
| 3576 arguments, pos); |
| 3577 VariableProxy* init_proxy = factory()->NewVariableProxy( |
| 3578 function_state_->generator_object_variable()); |
| 3579 Assignment* assignment = factory()->NewAssignment( |
| 3580 Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition); |
| 3581 VariableProxy* get_proxy = factory()->NewVariableProxy( |
| 3582 function_state_->generator_object_variable()); |
| 3583 Yield* yield = factory()->NewYield( |
| 3584 get_proxy, assignment, Yield::INITIAL, RelocInfo::kNoPosition); |
| 3585 body->Add(factory()->NewExpressionStatement( |
| 3586 yield, RelocInfo::kNoPosition), zone()); |
| 3587 } |
| 3588 |
| 3589 ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK); |
| 3590 |
| 3591 if (is_generator) { |
| 3592 VariableProxy* get_proxy = factory()->NewVariableProxy( |
| 3593 function_state_->generator_object_variable()); |
| 3594 Expression *undefined = factory()->NewLiteral( |
| 3595 isolate()->factory()->undefined_value(), RelocInfo::kNoPosition); |
| 3596 Yield* yield = factory()->NewYield( |
| 3597 get_proxy, undefined, Yield::FINAL, RelocInfo::kNoPosition); |
| 3598 body->Add(factory()->NewExpressionStatement( |
| 3599 yield, RelocInfo::kNoPosition), zone()); |
| 3600 } |
| 3601 |
| 3602 Expect(Token::RBRACE, CHECK_OK); |
| 3603 scope_->set_end_position(scanner()->location().end_pos); |
| 3604 |
| 3605 return body; |
| 3606 } |
| 3607 |
| 3608 |
| 3609 PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( |
3586 SingletonLogger* logger) { | 3610 SingletonLogger* logger) { |
3587 HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse()); | 3611 HistogramTimerScope preparse_scope(isolate()->counters()->pre_parse()); |
3588 ASSERT_EQ(Token::LBRACE, scanner()->current_token()); | 3612 ASSERT_EQ(Token::LBRACE, scanner()->current_token()); |
3589 | 3613 |
3590 if (reusable_preparser_ == NULL) { | 3614 if (reusable_preparser_ == NULL) { |
3591 intptr_t stack_limit = isolate()->stack_guard()->real_climit(); | 3615 intptr_t stack_limit = isolate()->stack_guard()->real_climit(); |
3592 reusable_preparser_ = new PreParser(&scanner_, NULL, stack_limit); | 3616 reusable_preparser_ = new PreParser(&scanner_, NULL, stack_limit); |
3593 reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping()); | 3617 reusable_preparser_->set_allow_harmony_scoping(allow_harmony_scoping()); |
3594 reusable_preparser_->set_allow_modules(allow_modules()); | 3618 reusable_preparser_->set_allow_modules(allow_modules()); |
3595 reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax()); | 3619 reusable_preparser_->set_allow_natives_syntax(allow_natives_syntax()); |
(...skipping 1073 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4669 ASSERT(info()->isolate()->has_pending_exception()); | 4693 ASSERT(info()->isolate()->has_pending_exception()); |
4670 } else { | 4694 } else { |
4671 result = ParseProgram(); | 4695 result = ParseProgram(); |
4672 } | 4696 } |
4673 } | 4697 } |
4674 info()->SetFunction(result); | 4698 info()->SetFunction(result); |
4675 return (result != NULL); | 4699 return (result != NULL); |
4676 } | 4700 } |
4677 | 4701 |
4678 } } // namespace v8::internal | 4702 } } // namespace v8::internal |
OLD | NEW |