Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <cmath> | 5 #include <cmath> |
| 6 | 6 |
| 7 #include "src/allocation.h" | 7 #include "src/allocation.h" |
| 8 #include "src/base/logging.h" | 8 #include "src/base/logging.h" |
| 9 #include "src/conversions-inl.h" | 9 #include "src/conversions-inl.h" |
| 10 #include "src/conversions.h" | 10 #include "src/conversions.h" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 if (scanner()->LiteralMatches("prototype", 9)) | 68 if (scanner()->LiteralMatches("prototype", 9)) |
| 69 return PreParserIdentifier::Prototype(); | 69 return PreParserIdentifier::Prototype(); |
| 70 if (scanner()->LiteralMatches("constructor", 11)) | 70 if (scanner()->LiteralMatches("constructor", 11)) |
| 71 return PreParserIdentifier::Constructor(); | 71 return PreParserIdentifier::Constructor(); |
| 72 return PreParserIdentifier::Default(); | 72 return PreParserIdentifier::Default(); |
| 73 } | 73 } |
| 74 } | 74 } |
| 75 | 75 |
| 76 PreParser::PreParseResult PreParser::PreParseLazyFunction( | 76 PreParser::PreParseResult PreParser::PreParseLazyFunction( |
| 77 LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters, | 77 LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters, |
| 78 bool parsing_module, ParserRecorder* log, Scanner::BookmarkScope* bookmark, | 78 bool parsing_module, ParserRecorder* log, bool may_abort, int* use_counts) { |
| 79 int* use_counts) { | |
| 80 parsing_module_ = parsing_module; | 79 parsing_module_ = parsing_module; |
| 81 log_ = log; | 80 log_ = log; |
| 82 use_counts_ = use_counts; | 81 use_counts_ = use_counts; |
| 83 // Lazy functions always have trivial outer scopes (no with/catch scopes). | 82 // Lazy functions always have trivial outer scopes (no with/catch scopes). |
| 84 DCHECK_NULL(scope_state_); | 83 DCHECK_NULL(scope_state_); |
| 85 DeclarationScope* top_scope = NewScriptScope(); | 84 DeclarationScope* top_scope = NewScriptScope(); |
| 86 FunctionState top_state(&function_state_, &scope_state_, top_scope, | 85 FunctionState top_state(&function_state_, &scope_state_, top_scope, |
| 87 kNormalFunction); | 86 kNormalFunction); |
| 88 scope()->SetLanguageMode(language_mode); | 87 scope()->SetLanguageMode(language_mode); |
| 89 DeclarationScope* function_scope = NewFunctionScope(kind); | 88 DeclarationScope* function_scope = NewFunctionScope(kind); |
| 90 if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters(); | 89 if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters(); |
| 91 FunctionState function_state(&function_state_, &scope_state_, function_scope, | 90 FunctionState function_state(&function_state_, &scope_state_, function_scope, |
| 92 kind); | 91 kind); |
| 93 DCHECK_EQ(Token::LBRACE, scanner()->current_token()); | 92 DCHECK_EQ(Token::LBRACE, scanner()->current_token()); |
| 94 bool ok = true; | 93 bool ok = true; |
| 95 int start_position = peek_position(); | 94 int start_position = peek_position(); |
| 96 ParseLazyFunctionLiteralBody(&ok, bookmark); | 95 bool aborted = ParseLazyFunctionLiteralBody(may_abort, &ok); |
| 97 use_counts_ = nullptr; | 96 use_counts_ = nullptr; |
| 98 if (bookmark && bookmark->HasBeenReset()) { | 97 if (aborted) { |
| 99 // Do nothing, as we've just aborted scanning this function. | 98 return kPreParseAbort; |
| 100 } else if (stack_overflow()) { | 99 } else if (stack_overflow()) { |
| 101 return kPreParseStackOverflow; | 100 return kPreParseStackOverflow; |
| 102 } else if (!ok) { | 101 } else if (!ok) { |
| 103 ReportUnexpectedToken(scanner()->current_token()); | 102 ReportUnexpectedToken(scanner()->current_token()); |
| 104 } else { | 103 } else { |
| 105 DCHECK_EQ(Token::RBRACE, scanner()->peek()); | 104 DCHECK_EQ(Token::RBRACE, scanner()->peek()); |
| 106 if (is_strict(scope()->language_mode())) { | 105 if (is_strict(scope()->language_mode())) { |
| 107 int end_pos = scanner()->location().end_pos; | 106 int end_pos = scanner()->location().end_pos; |
| 108 CheckStrictOctalLiteral(start_position, end_pos, &ok); | 107 CheckStrictOctalLiteral(start_position, end_pos, &ok); |
| 109 CheckDecimalLiteralWithLeadingZero(use_counts, start_position, end_pos); | 108 CheckDecimalLiteralWithLeadingZero(use_counts, start_position, end_pos); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 164 Consume(Token::ASYNC); | 163 Consume(Token::ASYNC); |
| 165 return ParseAsyncFunctionDeclaration(ok); | 164 return ParseAsyncFunctionDeclaration(ok); |
| 166 } | 165 } |
| 167 /* falls through */ | 166 /* falls through */ |
| 168 default: | 167 default: |
| 169 break; | 168 break; |
| 170 } | 169 } |
| 171 return ParseStatement(kAllowLabelledFunctionStatement, ok); | 170 return ParseStatement(kAllowLabelledFunctionStatement, ok); |
| 172 } | 171 } |
| 173 | 172 |
| 174 | 173 bool PreParser::ParseStatementList(int end_token, bool may_abort, bool* ok) { |
| 175 void PreParser::ParseStatementList(int end_token, bool* ok, | |
| 176 Scanner::BookmarkScope* bookmark) { | |
| 177 // SourceElements :: | 174 // SourceElements :: |
| 178 // (Statement)* <end_token> | 175 // (Statement)* <end_token> |
| 179 | 176 |
| 180 // Bookkeeping for trial parse if bookmark is set: | |
| 181 DCHECK_IMPLIES(bookmark, bookmark->HasBeenSet()); | |
| 182 bool maybe_reset = bookmark != nullptr; | |
| 183 int count_statements = 0; | 177 int count_statements = 0; |
| 184 | 178 |
| 185 bool directive_prologue = true; | 179 bool directive_prologue = true; |
| 186 while (peek() != end_token) { | 180 while (peek() != end_token) { |
| 187 if (directive_prologue && peek() != Token::STRING) { | 181 if (directive_prologue && peek() != Token::STRING) { |
| 188 directive_prologue = false; | 182 directive_prologue = false; |
| 189 } | 183 } |
| 190 bool starts_with_identifier = peek() == Token::IDENTIFIER; | 184 bool starts_with_identifier = peek() == Token::IDENTIFIER; |
| 191 Scanner::Location token_loc = scanner()->peek_location(); | 185 Scanner::Location token_loc = scanner()->peek_location(); |
| 192 Statement statement = ParseStatementListItem(CHECK_OK_CUSTOM(Void)); | 186 Statement statement = ParseStatementListItem(ok); |
| 187 if (!*ok) return false; | |
| 193 | 188 |
| 194 if (directive_prologue) { | 189 if (directive_prologue) { |
| 195 bool use_strict_found = statement.IsUseStrictLiteral(); | 190 bool use_strict_found = statement.IsUseStrictLiteral(); |
| 196 | 191 |
| 197 if (use_strict_found) { | 192 if (use_strict_found) { |
| 198 scope()->SetLanguageMode( | 193 scope()->SetLanguageMode( |
| 199 static_cast<LanguageMode>(scope()->language_mode() | STRICT)); | 194 static_cast<LanguageMode>(scope()->language_mode() | STRICT)); |
| 200 } else if (!statement.IsStringLiteral()) { | 195 } else if (!statement.IsStringLiteral()) { |
| 201 directive_prologue = false; | 196 directive_prologue = false; |
| 202 } | 197 } |
| 203 | 198 |
| 204 if (use_strict_found && !scope()->HasSimpleParameters()) { | 199 if (use_strict_found && !scope()->HasSimpleParameters()) { |
| 205 // TC39 deemed "use strict" directives to be an error when occurring | 200 // TC39 deemed "use strict" directives to be an error when occurring |
| 206 // in the body of a function with non-simple parameter list, on | 201 // in the body of a function with non-simple parameter list, on |
| 207 // 29/7/2015. https://goo.gl/ueA7Ln | 202 // 29/7/2015. https://goo.gl/ueA7Ln |
| 208 ReportMessageAt(token_loc, | 203 ReportMessageAt(token_loc, |
| 209 MessageTemplate::kIllegalLanguageModeDirective, | 204 MessageTemplate::kIllegalLanguageModeDirective, |
| 210 "use strict"); | 205 "use strict"); |
| 211 *ok = false; | 206 *ok = false; |
| 212 return; | 207 return false; |
| 213 } | 208 } |
| 214 } | 209 } |
| 215 | 210 |
| 216 // If we're allowed to reset to a bookmark, we will do so when we see a long | 211 // If we're allowed to reset to a bookmark, we will do so when we see a long |
| 217 // and trivial function. | 212 // and trivial function. |
| 218 // Our current definition of 'long and trivial' is: | 213 // Our current definition of 'long and trivial' is: |
| 219 // - over 200 statements | 214 // - over 200 statements |
| 220 // - all starting with an identifier (i.e., no if, for, while, etc.) | 215 // - all starting with an identifier (i.e., no if, for, while, etc.) |
| 221 if (maybe_reset && (!starts_with_identifier || | 216 if (may_abort) { |
| 222 ++count_statements > kLazyParseTrialLimit)) { | 217 if (!starts_with_identifier) |
|
adamk
2016/08/30 22:13:14
Please add curly braces around the if/else stateme
nickie
2016/08/31 13:23:36
Done.
| |
| 223 if (count_statements > kLazyParseTrialLimit) { | 218 may_abort = false; |
| 224 bookmark->Reset(); | 219 else if (++count_statements > kLazyParseTrialLimit) |
| 225 return; | 220 return true; |
| 226 } | |
| 227 maybe_reset = false; | |
| 228 } | 221 } |
| 229 } | 222 } |
| 223 return false; | |
| 230 } | 224 } |
| 231 | 225 |
| 232 | 226 |
| 233 PreParser::Statement PreParser::ParseStatement( | 227 PreParser::Statement PreParser::ParseStatement( |
| 234 AllowLabelledFunctionStatement allow_function, bool* ok) { | 228 AllowLabelledFunctionStatement allow_function, bool* ok) { |
| 235 // Statement :: | 229 // Statement :: |
| 236 // EmptyStatement | 230 // EmptyStatement |
| 237 // ... | 231 // ... |
| 238 | 232 |
| 239 if (peek() == Token::SEMICOLON) { | 233 if (peek() == Token::SEMICOLON) { |
| (...skipping 815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1055 CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position, | 1049 CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position, |
| 1056 formals_end_position, CHECK_OK); | 1050 formals_end_position, CHECK_OK); |
| 1057 | 1051 |
| 1058 // See Parser::ParseFunctionLiteral for more information about lazy parsing | 1052 // See Parser::ParseFunctionLiteral for more information about lazy parsing |
| 1059 // and lazy compilation. | 1053 // and lazy compilation. |
| 1060 bool is_lazily_parsed = (outer_is_script_scope && allow_lazy() && | 1054 bool is_lazily_parsed = (outer_is_script_scope && allow_lazy() && |
| 1061 !function_state_->this_function_is_parenthesized()); | 1055 !function_state_->this_function_is_parenthesized()); |
| 1062 | 1056 |
| 1063 Expect(Token::LBRACE, CHECK_OK); | 1057 Expect(Token::LBRACE, CHECK_OK); |
| 1064 if (is_lazily_parsed) { | 1058 if (is_lazily_parsed) { |
| 1065 ParseLazyFunctionLiteralBody(CHECK_OK); | 1059 ParseLazyFunctionLiteralBody(false, CHECK_OK); |
| 1066 } else { | 1060 } else { |
| 1067 ParseStatementList(Token::RBRACE, CHECK_OK); | 1061 ParseStatementList(Token::RBRACE, CHECK_OK); |
| 1068 } | 1062 } |
| 1069 Expect(Token::RBRACE, CHECK_OK); | 1063 Expect(Token::RBRACE, CHECK_OK); |
| 1070 | 1064 |
| 1071 // Parsing the body may change the language mode in our scope. | 1065 // Parsing the body may change the language mode in our scope. |
| 1072 language_mode = function_scope->language_mode(); | 1066 language_mode = function_scope->language_mode(); |
| 1073 | 1067 |
| 1074 // Validate name and parameter names. We can do this only after parsing the | 1068 // Validate name and parameter names. We can do this only after parsing the |
| 1075 // function, since the function can declare itself strict. | 1069 // function, since the function can declare itself strict. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1109 } | 1103 } |
| 1110 | 1104 |
| 1111 ParseFunctionLiteral(name, scanner()->location(), | 1105 ParseFunctionLiteral(name, scanner()->location(), |
| 1112 is_strict_reserved ? kFunctionNameIsStrictReserved | 1106 is_strict_reserved ? kFunctionNameIsStrictReserved |
| 1113 : kFunctionNameValidityUnknown, | 1107 : kFunctionNameValidityUnknown, |
| 1114 FunctionKind::kAsyncFunction, pos, type, language_mode(), | 1108 FunctionKind::kAsyncFunction, pos, type, language_mode(), |
| 1115 CHECK_OK); | 1109 CHECK_OK); |
| 1116 return Expression::Default(); | 1110 return Expression::Default(); |
| 1117 } | 1111 } |
| 1118 | 1112 |
| 1119 void PreParser::ParseLazyFunctionLiteralBody(bool* ok, | 1113 bool PreParser::ParseLazyFunctionLiteralBody(bool may_abort, bool* ok) { |
| 1120 Scanner::BookmarkScope* bookmark) { | |
| 1121 int body_start = position(); | 1114 int body_start = position(); |
| 1122 ParseStatementList(Token::RBRACE, ok, bookmark); | 1115 bool aborted = ParseStatementList(Token::RBRACE, may_abort, ok); |
| 1123 if (!*ok) return; | 1116 if (!*ok) return false; |
| 1124 if (bookmark && bookmark->HasBeenReset()) return; | 1117 if (aborted) return true; |
|
adamk
2016/08/30 22:13:14
And having gotten this far I also think it would b
nickie
2016/08/31 13:23:36
Done.
| |
| 1125 | 1118 |
| 1126 // Position right after terminal '}'. | 1119 // Position right after terminal '}'. |
| 1127 DCHECK_EQ(Token::RBRACE, scanner()->peek()); | 1120 DCHECK_EQ(Token::RBRACE, scanner()->peek()); |
| 1128 int body_end = scanner()->peek_location().end_pos; | 1121 int body_end = scanner()->peek_location().end_pos; |
| 1129 DeclarationScope* scope = this->scope()->AsDeclarationScope(); | 1122 DeclarationScope* scope = this->scope()->AsDeclarationScope(); |
| 1130 DCHECK(scope->is_function_scope()); | 1123 DCHECK(scope->is_function_scope()); |
| 1131 log_->LogFunction(body_start, body_end, | 1124 log_->LogFunction(body_start, body_end, |
| 1132 function_state_->materialized_literal_count(), | 1125 function_state_->materialized_literal_count(), |
| 1133 function_state_->expected_property_count(), language_mode(), | 1126 function_state_->expected_property_count(), language_mode(), |
| 1134 scope->uses_super_property(), scope->calls_eval()); | 1127 scope->uses_super_property(), scope->calls_eval()); |
| 1128 return false; | |
| 1135 } | 1129 } |
| 1136 | 1130 |
| 1137 PreParserExpression PreParser::ParseClassLiteral( | 1131 PreParserExpression PreParser::ParseClassLiteral( |
| 1138 PreParserIdentifier name, Scanner::Location class_name_location, | 1132 PreParserIdentifier name, Scanner::Location class_name_location, |
| 1139 bool name_is_strict_reserved, int pos, bool* ok) { | 1133 bool name_is_strict_reserved, int pos, bool* ok) { |
| 1140 // All parts of a ClassDeclaration and ClassExpression are strict code. | 1134 // All parts of a ClassDeclaration and ClassExpression are strict code. |
| 1141 if (name_is_strict_reserved) { | 1135 if (name_is_strict_reserved) { |
| 1142 ReportMessageAt(class_name_location, | 1136 ReportMessageAt(class_name_location, |
| 1143 MessageTemplate::kUnexpectedStrictReserved); | 1137 MessageTemplate::kUnexpectedStrictReserved); |
| 1144 *ok = false; | 1138 *ok = false; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1233 | 1227 |
| 1234 body->Add(PreParserStatement::ExpressionStatement(return_value), zone()); | 1228 body->Add(PreParserStatement::ExpressionStatement(return_value), zone()); |
| 1235 } | 1229 } |
| 1236 | 1230 |
| 1237 #undef CHECK_OK | 1231 #undef CHECK_OK |
| 1238 #undef CHECK_OK_CUSTOM | 1232 #undef CHECK_OK_CUSTOM |
| 1239 | 1233 |
| 1240 | 1234 |
| 1241 } // namespace internal | 1235 } // namespace internal |
| 1242 } // namespace v8 | 1236 } // namespace v8 |
| OLD | NEW |