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 3955 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3966 VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST; | 3966 VariableMode fvar_mode = is_extended_mode() ? CONST_HARMONY : CONST; |
3967 fvar = new(zone()) Variable(scope_, | 3967 fvar = new(zone()) Variable(scope_, |
3968 function_name, fvar_mode, true /* is valid LHS */, | 3968 function_name, fvar_mode, true /* is valid LHS */, |
3969 Variable::NORMAL, kCreatedInitialized, Interface::NewConst()); | 3969 Variable::NORMAL, kCreatedInitialized, Interface::NewConst()); |
3970 VariableProxy* proxy = factory()->NewVariableProxy(fvar); | 3970 VariableProxy* proxy = factory()->NewVariableProxy(fvar); |
3971 VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration( | 3971 VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration( |
3972 proxy, fvar_mode, scope_, RelocInfo::kNoPosition); | 3972 proxy, fvar_mode, scope_, RelocInfo::kNoPosition); |
3973 scope_->DeclareFunctionVar(fvar_declaration); | 3973 scope_->DeclareFunctionVar(fvar_declaration); |
3974 } | 3974 } |
3975 | 3975 |
3976 // Determine whether the function will be lazily compiled. | 3976 // Determine if the function can be parsed lazily. Lazy parsing is different |
3977 // The heuristics are: | 3977 // from lazy compilation; we need to parse more eagerly than we compile. |
| 3978 |
| 3979 // We can only parse lazily if we also compile lazily. The heuristics for |
| 3980 // lazy compilation are: |
3978 // - It must not have been prohibited by the caller to Parse (some callers | 3981 // - It must not have been prohibited by the caller to Parse (some callers |
3979 // need a full AST). | 3982 // need a full AST). |
3980 // - The outer scope must allow lazy compilation of inner functions. | 3983 // - The outer scope must allow lazy compilation of inner functions. |
3981 // - The function mustn't be a function expression with an open parenthesis | 3984 // - The function mustn't be a function expression with an open parenthesis |
3982 // before; we consider that a hint that the function will be called | 3985 // before; we consider that a hint that the function will be called |
3983 // immediately, and it would be a waste of time to make it lazily | 3986 // immediately, and it would be a waste of time to make it lazily |
3984 // compiled. | 3987 // compiled. |
3985 // These are all things we can know at this point, without looking at the | 3988 // These are all things we can know at this point, without looking at the |
3986 // function itself. | 3989 // function itself. |
3987 bool is_lazily_compiled = (mode() == PARSE_LAZILY && | 3990 |
3988 scope_->AllowsLazyCompilation() && | 3991 // In addition, we need to distinguish between these cases: |
3989 !parenthesized_function_); | 3992 // (function foo() { |
| 3993 // bar = function() { return 1; } |
| 3994 // })(); |
| 3995 // and |
| 3996 // (function foo() { |
| 3997 // var a = 1; |
| 3998 // bar = function() { return a; } |
| 3999 // })(); |
| 4000 |
| 4001 // Now foo will be parsed eagerly and compiled eagerly (optimization: assume |
| 4002 // parenthesis before the function means that it will be called |
| 4003 // immediately). The inner function *must* be parsed eagerly to resolve the |
| 4004 // possible reference to the variable in foo's scope. However, it's possible |
| 4005 // that it will be compiled lazily. |
| 4006 |
| 4007 // To make this additional case work, both Parser and PreParser implement a |
| 4008 // logic where only top-level functions will be parsed lazily. |
| 4009 bool is_lazily_parsed = (mode() == PARSE_LAZILY && |
| 4010 scope_->AllowsLazyCompilation() && |
| 4011 !parenthesized_function_); |
3990 parenthesized_function_ = false; // The bit was set for this function only. | 4012 parenthesized_function_ = false; // The bit was set for this function only. |
3991 | 4013 |
3992 if (is_lazily_compiled) { | 4014 if (is_lazily_parsed) { |
3993 int function_block_pos = position(); | 4015 int function_block_pos = position(); |
3994 FunctionEntry entry; | 4016 FunctionEntry entry; |
3995 if (pre_parse_data_ != NULL) { | 4017 if (pre_parse_data_ != NULL) { |
3996 // If we have pre_parse_data_, we use it to skip parsing the function | 4018 // If we have pre_parse_data_, we use it to skip parsing the function |
3997 // body. The preparser data contains the information we need to | 4019 // body. The preparser data contains the information we need to |
3998 // construct the lazy function. | 4020 // construct the lazy function. |
3999 entry = pre_parse_data()->GetFunctionEntry(function_block_pos); | 4021 entry = pre_parse_data()->GetFunctionEntry(function_block_pos); |
4000 if (entry.is_valid()) { | 4022 if (entry.is_valid()) { |
4001 if (entry.end_pos() <= function_block_pos) { | 4023 if (entry.end_pos() <= function_block_pos) { |
4002 // End position greater than end of stream is safe, and hard | 4024 // End position greater than end of stream is safe, and hard |
4003 // to check. | 4025 // to check. |
4004 ReportInvalidPreparseData(function_name, CHECK_OK); | 4026 ReportInvalidPreparseData(function_name, CHECK_OK); |
4005 } | 4027 } |
4006 scanner()->SeekForward(entry.end_pos() - 1); | 4028 scanner()->SeekForward(entry.end_pos() - 1); |
4007 | 4029 |
4008 scope->set_end_position(entry.end_pos()); | 4030 scope->set_end_position(entry.end_pos()); |
4009 Expect(Token::RBRACE, CHECK_OK); | 4031 Expect(Token::RBRACE, CHECK_OK); |
4010 isolate()->counters()->total_preparse_skipped()->Increment( | 4032 isolate()->counters()->total_preparse_skipped()->Increment( |
4011 scope->end_position() - function_block_pos); | 4033 scope->end_position() - function_block_pos); |
4012 materialized_literal_count = entry.literal_count(); | 4034 materialized_literal_count = entry.literal_count(); |
4013 expected_property_count = entry.property_count(); | 4035 expected_property_count = entry.property_count(); |
4014 scope_->SetLanguageMode(entry.language_mode()); | 4036 scope_->SetLanguageMode(entry.language_mode()); |
4015 } else { | 4037 } else { |
4016 is_lazily_compiled = false; | 4038 // This case happens when we have preparse data but it doesn't contain |
| 4039 // an entry for the function. As a safety net, fall back to eager |
| 4040 // parsing. It is unclear whether PreParser's laziness analysis can |
| 4041 // produce different results than the Parser's laziness analysis (see |
| 4042 // https://codereview.chromium.org/7565003 ). This safety net is |
| 4043 // guarding against the case where Parser thinks a function should be |
| 4044 // lazily parsed, but PreParser thinks it should be eagerly parsed -- |
| 4045 // in that case we fall back to eager parsing in Parser, too. Note |
| 4046 // that the opposite case is worse: if PreParser thinks a function |
| 4047 // should be lazily parsed, but Parser thinks it should be eagerly |
| 4048 // parsed, it will never advance the preparse data beyond that |
| 4049 // function and all further laziness will fail (all functions will be |
| 4050 // parsed eagerly). |
| 4051 is_lazily_parsed = false; |
4017 } | 4052 } |
4018 } else { | 4053 } else { |
4019 // With no preparser data, we partially parse the function, without | 4054 // With no preparser data, we partially parse the function, without |
4020 // building an AST. This gathers the data needed to build a lazy | 4055 // building an AST. This gathers the data needed to build a lazy |
4021 // function. | 4056 // function. |
4022 SingletonLogger logger; | 4057 SingletonLogger logger; |
4023 PreParser::PreParseResult result = LazyParseFunctionLiteral(&logger); | 4058 PreParser::PreParseResult result = LazyParseFunctionLiteral(&logger); |
4024 if (result == PreParser::kPreParseStackOverflow) { | 4059 if (result == PreParser::kPreParseStackOverflow) { |
4025 // Propagate stack overflow. | 4060 // Propagate stack overflow. |
4026 set_stack_overflow(); | 4061 set_stack_overflow(); |
(...skipping 16 matching lines...) Expand all Loading... |
4043 scope->set_end_position(logger.end()); | 4078 scope->set_end_position(logger.end()); |
4044 Expect(Token::RBRACE, CHECK_OK); | 4079 Expect(Token::RBRACE, CHECK_OK); |
4045 isolate()->counters()->total_preparse_skipped()->Increment( | 4080 isolate()->counters()->total_preparse_skipped()->Increment( |
4046 scope->end_position() - function_block_pos); | 4081 scope->end_position() - function_block_pos); |
4047 materialized_literal_count = logger.literals(); | 4082 materialized_literal_count = logger.literals(); |
4048 expected_property_count = logger.properties(); | 4083 expected_property_count = logger.properties(); |
4049 scope_->SetLanguageMode(logger.language_mode()); | 4084 scope_->SetLanguageMode(logger.language_mode()); |
4050 } | 4085 } |
4051 } | 4086 } |
4052 | 4087 |
4053 if (!is_lazily_compiled) { | 4088 if (!is_lazily_parsed) { |
| 4089 // Everything inside an eagerly parsed function will be parsed eagerly |
| 4090 // (see comment above). |
4054 ParsingModeScope parsing_mode(this, PARSE_EAGERLY); | 4091 ParsingModeScope parsing_mode(this, PARSE_EAGERLY); |
4055 body = new(zone()) ZoneList<Statement*>(8, zone()); | 4092 body = new(zone()) ZoneList<Statement*>(8, zone()); |
4056 if (fvar != NULL) { | 4093 if (fvar != NULL) { |
4057 VariableProxy* fproxy = scope_->NewUnresolved( | 4094 VariableProxy* fproxy = scope_->NewUnresolved( |
4058 factory(), function_name, Interface::NewConst()); | 4095 factory(), function_name, Interface::NewConst()); |
4059 fproxy->BindTo(fvar); | 4096 fproxy->BindTo(fvar); |
4060 body->Add(factory()->NewExpressionStatement( | 4097 body->Add(factory()->NewExpressionStatement( |
4061 factory()->NewAssignment(fvar_init_op, | 4098 factory()->NewAssignment(fvar_init_op, |
4062 fproxy, | 4099 fproxy, |
4063 factory()->NewThisFunction(pos), | 4100 factory()->NewThisFunction(pos), |
(...skipping 1301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5365 ASSERT(info()->isolate()->has_pending_exception()); | 5402 ASSERT(info()->isolate()->has_pending_exception()); |
5366 } else { | 5403 } else { |
5367 result = ParseProgram(); | 5404 result = ParseProgram(); |
5368 } | 5405 } |
5369 } | 5406 } |
5370 info()->SetFunction(result); | 5407 info()->SetFunction(result); |
5371 return (result != NULL); | 5408 return (result != NULL); |
5372 } | 5409 } |
5373 | 5410 |
5374 } } // namespace v8::internal | 5411 } } // namespace v8::internal |
OLD | NEW |