OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 "src/parsing/parser.h" | 5 #include "src/parsing/parser.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/ast/ast-expression-rewriter.h" | 10 #include "src/ast/ast-expression-rewriter.h" |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
143 if (compile_options_ == ScriptCompiler::kNoCompileOptions) { | 143 if (compile_options_ == ScriptCompiler::kNoCompileOptions) { |
144 cached_parse_data_ = NULL; | 144 cached_parse_data_ = NULL; |
145 } else { | 145 } else { |
146 DCHECK(info->cached_data() != NULL); | 146 DCHECK(info->cached_data() != NULL); |
147 if (compile_options_ == ScriptCompiler::kConsumeParserCache) { | 147 if (compile_options_ == ScriptCompiler::kConsumeParserCache) { |
148 cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); | 148 cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); |
149 } | 149 } |
150 } | 150 } |
151 } | 151 } |
152 | 152 |
153 Expression* Parser::CallClassFieldInitializer(Scope* scope, | |
154 Expression* this_expr) { | |
Dan Ehrenberg
2016/09/09 22:54:42
For desugarings like this, even simple ones, could
bakkot
2016/09/12 19:10:11
Done.
| |
155 const AstRawString* init_fn_name = | |
156 ast_value_factory()->GetOneByteString(".class-field-initializer"); | |
157 VariableProxy* init_fn_proxy = scope->NewUnresolved(factory(), init_fn_name); | |
158 ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); | |
159 args->Add(init_fn_proxy, zone()); | |
160 args->Add(this_expr, zone()); | |
161 return factory()->NewCallRuntime(Runtime::kInlineCall, args, | |
162 kNoSourcePosition); | |
163 } | |
164 | |
165 Expression* Parser::RewriteSuperCall(Expression* super_call) { | |
Dan Ehrenberg
2016/09/09 22:54:41
Please add a comment showing what this desugars in
bakkot
2016/09/12 19:10:10
Done.
| |
166 if (!allow_harmony_class_fields()) { | |
Dan Ehrenberg
2016/09/09 22:54:41
Ideally we should also take this path if the class
bakkot
2016/09/12 19:10:10
Unfortunately not. The super call might occur befo
| |
167 return super_call; | |
168 } | |
169 // TODO(bakkot) The whole charade with the do expression can be replaced by a | |
170 // ternary conditional, except that the optimizer does not like it if you use | |
171 // an AST node (at least, one containing a variable proxy) in two places. | |
Dan Ehrenberg
2016/09/09 22:54:41
That's right, an AST node is single-use. You can s
bakkot
2016/09/12 19:10:11
At that point the if statement is more efficient a
| |
172 Variable* var_tmp = | |
173 scope()->NewTemporary(ast_value_factory()->empty_string()); | |
174 Block* block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition); | |
175 Assignment* assignment = factory()->NewAssignment( | |
176 Token::ASSIGN, factory()->NewVariableProxy(var_tmp), super_call, | |
177 kNoSourcePosition); | |
178 block->statements()->Add( | |
179 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); | |
180 const AstRawString* init_fn_name = | |
181 ast_value_factory()->GetOneByteString(".class-field-initializer"); | |
182 VariableProxy* init_fn_proxy = | |
183 scope()->NewUnresolved(factory(), init_fn_name); | |
184 Expression* condition = init_fn_proxy; | |
185 Statement* initialize = factory()->NewExpressionStatement( | |
186 CallClassFieldInitializer(scope(), factory()->NewVariableProxy(var_tmp)), | |
187 kNoSourcePosition); | |
188 IfStatement* if_statement = factory()->NewIfStatement( | |
189 condition, initialize, factory()->NewEmptyStatement(kNoSourcePosition), | |
190 kNoSourcePosition); | |
191 block->statements()->Add(if_statement, zone()); | |
192 return factory()->NewDoExpression(block, var_tmp, kNoSourcePosition); | |
193 } | |
194 | |
153 FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, | 195 FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, |
154 bool call_super, | 196 bool call_super, |
155 bool requires_class_field_init, | 197 bool requires_class_field_init, |
156 int pos, int end_pos, | 198 int pos, int end_pos, |
157 LanguageMode language_mode) { | 199 LanguageMode language_mode) { |
158 int materialized_literal_count = -1; | 200 int materialized_literal_count = -1; |
159 int expected_property_count = -1; | 201 int expected_property_count = -1; |
160 int parameter_count = 0; | 202 int parameter_count = 0; |
161 if (name == nullptr) name = ast_value_factory()->empty_string(); | 203 if (name == nullptr) name = ast_value_factory()->empty_string(); |
162 | 204 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
199 args->Add(super_constructor, zone()); | 241 args->Add(super_constructor, zone()); |
200 Spread* spread_args = factory()->NewSpread( | 242 Spread* spread_args = factory()->NewSpread( |
201 factory()->NewVariableProxy(constructor_args), pos, pos); | 243 factory()->NewVariableProxy(constructor_args), pos, pos); |
202 ZoneList<Expression*>* spread_args_expr = | 244 ZoneList<Expression*>* spread_args_expr = |
203 new (zone()) ZoneList<Expression*>(1, zone()); | 245 new (zone()) ZoneList<Expression*>(1, zone()); |
204 spread_args_expr->Add(spread_args, zone()); | 246 spread_args_expr->Add(spread_args, zone()); |
205 args->AddAll(*PrepareSpreadArguments(spread_args_expr), zone()); | 247 args->AddAll(*PrepareSpreadArguments(spread_args_expr), zone()); |
206 VariableProxy* new_target_proxy = | 248 VariableProxy* new_target_proxy = |
207 NewUnresolved(ast_value_factory()->new_target_string(), pos); | 249 NewUnresolved(ast_value_factory()->new_target_string(), pos); |
208 args->Add(new_target_proxy, zone()); | 250 args->Add(new_target_proxy, zone()); |
209 CallRuntime* call = factory()->NewCallRuntime( | 251 Expression* call = factory()->NewCallRuntime( |
210 Context::REFLECT_CONSTRUCT_INDEX, args, pos); | 252 Context::REFLECT_CONSTRUCT_INDEX, args, pos); |
253 if (requires_class_field_init) { | |
254 call = CallClassFieldInitializer(scope(), call); | |
255 } | |
211 body->Add(factory()->NewReturnStatement(call, pos), zone()); | 256 body->Add(factory()->NewReturnStatement(call, pos), zone()); |
212 } | 257 } |
213 | 258 |
214 materialized_literal_count = function_state.materialized_literal_count(); | 259 materialized_literal_count = function_state.materialized_literal_count(); |
215 expected_property_count = function_state.expected_property_count(); | 260 expected_property_count = function_state.expected_property_count(); |
216 } | 261 } |
217 | 262 |
218 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( | 263 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( |
219 name, function_scope, body, materialized_literal_count, | 264 name, function_scope, body, materialized_literal_count, |
220 expected_property_count, parameter_count, | 265 expected_property_count, parameter_count, |
(...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
904 // must produce a FunctionLiteral. | 949 // must produce a FunctionLiteral. |
905 DCHECK(expression->IsFunctionLiteral()); | 950 DCHECK(expression->IsFunctionLiteral()); |
906 result = expression->AsFunctionLiteral(); | 951 result = expression->AsFunctionLiteral(); |
907 } else { | 952 } else { |
908 ok = false; | 953 ok = false; |
909 } | 954 } |
910 } | 955 } |
911 } | 956 } |
912 } else if (info->is_default_constructor()) { | 957 } else if (info->is_default_constructor()) { |
913 DCHECK_EQ(scope(), outer); | 958 DCHECK_EQ(scope(), outer); |
959 bool is_subclass_constructor = | |
960 IsSubclassConstructor(info->function_kind()); | |
914 result = DefaultConstructor( | 961 result = DefaultConstructor( |
915 raw_name, IsSubclassConstructor(info->function_kind()), | 962 raw_name, is_subclass_constructor, info->requires_class_field_init(), |
916 info->requires_class_field_init(), info->start_position(), | 963 info->start_position(), info->end_position(), info->language_mode()); |
917 info->end_position(), info->language_mode()); | 964 if (!is_subclass_constructor && info->requires_class_field_init()) { |
965 result = InsertClassFieldInitializer(result); | |
966 } | |
967 } else if (info->is_class_field_initializer()) { | |
968 Handle<SharedFunctionInfo> shared_info = info->shared_info(); | |
969 DCHECK(!shared_info.is_null()); | |
970 if (shared_info->length() == 0) { | |
971 result = ParseClassFieldForInitializer( | |
972 info->start_position() != info->end_position(), &ok); | |
973 } else { | |
974 result = SynthesizeClassFieldInitializer(shared_info->length()); | |
975 } | |
918 } else { | 976 } else { |
919 result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(), | 977 result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(), |
920 kSkipFunctionNameCheck, | 978 kSkipFunctionNameCheck, |
921 info->function_kind(), kNoSourcePosition, | 979 info->function_kind(), kNoSourcePosition, |
922 function_type, info->language_mode(), &ok); | 980 function_type, info->language_mode(), &ok); |
981 if (info->requires_class_field_init()) { | |
982 result = InsertClassFieldInitializer(result); | |
983 } | |
923 } | 984 } |
924 // Make sure the results agree. | 985 // Make sure the results agree. |
925 DCHECK(ok == (result != nullptr)); | 986 DCHECK(ok == (result != nullptr)); |
926 } | 987 } |
927 | 988 |
928 // Make sure the target stack is empty. | 989 // Make sure the target stack is empty. |
929 DCHECK_NULL(target_stack_); | 990 DCHECK_NULL(target_stack_); |
930 return result; | 991 return result; |
931 } | 992 } |
932 | 993 |
(...skipping 3255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4188 PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( | 4249 PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( |
4189 language_mode(), function_state_->kind(), | 4250 language_mode(), function_state_->kind(), |
4190 scope()->AsDeclarationScope()->has_simple_parameters(), parsing_module_, | 4251 scope()->AsDeclarationScope()->has_simple_parameters(), parsing_module_, |
4191 logger, may_abort, use_counts_); | 4252 logger, may_abort, use_counts_); |
4192 if (pre_parse_timer_ != NULL) { | 4253 if (pre_parse_timer_ != NULL) { |
4193 pre_parse_timer_->Stop(); | 4254 pre_parse_timer_->Stop(); |
4194 } | 4255 } |
4195 return result; | 4256 return result; |
4196 } | 4257 } |
4197 | 4258 |
4259 Expression* Parser::InstallHomeObject(Expression* function_literal, | |
4260 Expression* home_object) { | |
4261 Block* do_block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition); | |
4262 Variable* result_var = | |
4263 scope()->NewTemporary(ast_value_factory()->empty_string()); | |
4264 DoExpression* do_expr = | |
4265 factory()->NewDoExpression(do_block, result_var, kNoSourcePosition); | |
4266 Assignment* init = factory()->NewAssignment( | |
4267 Token::ASSIGN, factory()->NewVariableProxy(result_var), function_literal, | |
4268 kNoSourcePosition); | |
4269 do_block->statements()->Add( | |
4270 factory()->NewExpressionStatement(init, kNoSourcePosition), zone()); | |
4271 Property* home_object_property = factory()->NewProperty( | |
4272 factory()->NewVariableProxy(result_var), | |
4273 factory()->NewSymbolLiteral("home_object_symbol", kNoSourcePosition), | |
4274 kNoSourcePosition); | |
4275 Assignment* assignment = factory()->NewAssignment( | |
4276 Token::ASSIGN, home_object_property, home_object, kNoSourcePosition); | |
4277 do_block->statements()->Add( | |
4278 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); | |
4279 return do_expr; | |
4280 } | |
4281 | |
4282 const AstRawString* ClassFieldVariableName(bool is_name, | |
4283 AstValueFactory* ast_value_factory, | |
4284 int index) { | |
4285 std::string name = | |
4286 ".class-field-" + std::to_string(index) + (is_name ? "-name" : "-func"); | |
Dan Ehrenberg
2016/09/09 22:54:41
Eh, I guess this works, and it's clean code, but t
bakkot
2016/09/12 19:10:10
No, the return value of this function is used by N
| |
4287 return ast_value_factory->GetOneByteString(name.c_str()); | |
4288 } | |
4289 | |
4290 FunctionLiteral* Parser::SynthesizeClassFieldInitializer(int count) { | |
Dan Ehrenberg
2016/09/09 22:54:42
Add a comment showing what this desugars into
bakkot
2016/09/12 19:10:10
Done.
| |
4291 DCHECK(count > 0); | |
4292 // Makes a function which reads the names and initializers for each class | |
4293 // field out of deterministically named local variables and sets each property | |
4294 // to the result of evaluating its corresponding initializer in turn. | |
4295 RaiseLanguageMode(STRICT); | |
4296 FunctionKind kind = FunctionKind::kConciseMethod; | |
4297 DeclarationScope* initializer_scope = NewFunctionScope(kind); | |
4298 SetLanguageMode(initializer_scope, language_mode()); | |
4299 initializer_scope->set_start_position(scanner()->location().end_pos); | |
4300 initializer_scope->set_end_position(scanner()->location().end_pos); | |
4301 FunctionState initializer_state(&function_state_, &scope_state_, | |
4302 initializer_scope, kind); | |
4303 ZoneList<Statement*>* body = new (zone()) ZoneList<Statement*>(count, zone()); | |
4304 for (int i = 0; i < count; ++i) { | |
4305 const AstRawString* name = | |
4306 ClassFieldVariableName(true, ast_value_factory(), i); | |
4307 VariableProxy* name_proxy = scope()->NewUnresolved(factory(), name); | |
4308 const AstRawString* function_name = | |
4309 ClassFieldVariableName(false, ast_value_factory(), i); | |
4310 VariableProxy* function_proxy = | |
4311 scope()->NewUnresolved(factory(), function_name); | |
4312 ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); | |
4313 args->Add(function_proxy, zone()); | |
4314 args->Add(ThisExpression(kNoSourcePosition), zone()); | |
4315 Expression* call = factory()->NewCallRuntime(Runtime::kInlineCall, args, | |
4316 kNoSourcePosition); | |
4317 ZoneList<Expression*>* define_property_args = | |
4318 new (zone()) ZoneList<Expression*>(5, zone()); | |
4319 define_property_args->Add(ThisExpression(kNoSourcePosition), zone()); | |
4320 define_property_args->Add(name_proxy, zone()); | |
4321 define_property_args->Add(call, zone()); | |
4322 define_property_args->Add( | |
4323 factory()->NewNumberLiteral(DONT_ENUM, kNoSourcePosition), zone()); | |
4324 define_property_args->Add( | |
4325 factory()->NewNumberLiteral( | |
4326 false, // TODO(bakkot) function name inference a la class { x = | |
4327 // function(){}; static y = function(){}; } | |
Dan Ehrenberg
2016/09/09 22:54:41
Function name inference sounds like a ship blocker
bakkot
2016/09/12 19:10:10
Nope: https://github.com/tc39/proposal-class-publi
| |
4328 kNoSourcePosition), | |
4329 zone()); | |
4330 body->Add(factory()->NewExpressionStatement( | |
4331 factory()->NewCallRuntime( | |
4332 Runtime::kDefineDataPropertyInLiteral, | |
4333 define_property_args, // TODO(bakkot) verify that this is | |
4334 // the same as object_define_property | |
4335 kNoSourcePosition), | |
4336 kNoSourcePosition), | |
4337 zone()); | |
4338 } | |
4339 body->Add(factory()->NewReturnStatement(ThisExpression(kNoSourcePosition), | |
4340 kNoSourcePosition), | |
4341 zone()); | |
4342 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( | |
4343 ast_value_factory()->empty_string(), initializer_scope, body, | |
4344 initializer_state.materialized_literal_count(), | |
4345 initializer_state.expected_property_count(), 0, | |
4346 FunctionLiteral::kNoDuplicateParameters, | |
4347 FunctionLiteral::kAnonymousExpression, | |
4348 FunctionLiteral::kShouldLazyCompile, kind, | |
4349 initializer_scope->start_position()); | |
4350 function_literal->set_is_class_field_initializer(true); | |
4351 function_literal->scope()->set_default_function_length(count); | |
4352 return function_literal; | |
4353 } | |
4354 | |
4355 FunctionLiteral* Parser::InsertClassFieldInitializer( | |
4356 FunctionLiteral* constructor) { | |
4357 Statement* call_initializer = factory()->NewExpressionStatement( | |
4358 CallClassFieldInitializer( | |
4359 constructor->scope(), | |
4360 constructor->scope()->NewUnresolved( | |
4361 factory(), ast_value_factory()->this_string(), kNoSourcePosition, | |
4362 kNoSourcePosition + 4, Variable::THIS)), | |
4363 kNoSourcePosition); | |
4364 constructor->body()->InsertAt(0, call_initializer, zone()); | |
4365 return constructor; | |
4366 } | |
4367 | |
4198 Expression* Parser::ParseClassLiteral(const AstRawString* name, | 4368 Expression* Parser::ParseClassLiteral(const AstRawString* name, |
4199 Scanner::Location class_name_location, | 4369 Scanner::Location class_name_location, |
4200 bool name_is_strict_reserved, int pos, | 4370 bool name_is_strict_reserved, int pos, |
4201 bool* ok) { | 4371 bool* ok) { |
4202 // All parts of a ClassDeclaration and ClassExpression are strict code. | 4372 // All parts of a ClassDeclaration and ClassExpression are strict code. |
4203 if (name_is_strict_reserved) { | 4373 if (name_is_strict_reserved) { |
4204 ReportMessageAt(class_name_location, | 4374 ReportMessageAt(class_name_location, |
4205 MessageTemplate::kUnexpectedStrictReserved); | 4375 MessageTemplate::kUnexpectedStrictReserved); |
4206 *ok = false; | 4376 *ok = false; |
4207 return nullptr; | 4377 return nullptr; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4269 impl()->AccumulateFormalParameterContainmentErrors(); | 4439 impl()->AccumulateFormalParameterContainmentErrors(); |
4270 | 4440 |
4271 if (has_seen_constructor && constructor == nullptr) { | 4441 if (has_seen_constructor && constructor == nullptr) { |
4272 constructor = GetPropertyValue(property)->AsFunctionLiteral(); | 4442 constructor = GetPropertyValue(property)->AsFunctionLiteral(); |
4273 DCHECK_NOT_NULL(constructor); | 4443 DCHECK_NOT_NULL(constructor); |
4274 constructor->set_raw_name( | 4444 constructor->set_raw_name( |
4275 name != nullptr ? name : ast_value_factory()->empty_string()); | 4445 name != nullptr ? name : ast_value_factory()->empty_string()); |
4276 } else { | 4446 } else { |
4277 if (property->kind() == ClassLiteralProperty::FIELD) { | 4447 if (property->kind() == ClassLiteralProperty::FIELD) { |
4278 DCHECK(allow_harmony_class_fields()); | 4448 DCHECK(allow_harmony_class_fields()); |
4279 continue; // TODO(bakkot) implementation | 4449 if (property->is_static()) { |
4450 if (static_initializer_var == nullptr) { | |
4451 static_initializer_var = | |
4452 NewTemporary(ast_value_factory()->empty_string()); | |
4453 } | |
4454 // TODO(bakkot) only do this conditionally | |
4455 Expression* function = InstallHomeObject( | |
4456 property->value(), | |
4457 factory()->NewVariableProxy(static_initializer_var)); | |
4458 ZoneList<Expression*>* args = | |
4459 new (zone()) ZoneList<Expression*>(2, zone()); | |
4460 args->Add(function, zone()); | |
4461 args->Add(factory()->NewVariableProxy(static_initializer_var), | |
4462 zone()); | |
4463 Expression* call = factory()->NewCallRuntime(Runtime::kInlineCall, | |
4464 args, kNoSourcePosition); | |
4465 property->set_value(call); | |
4466 } else { | |
4467 // if (is_computed_name) { // TODO(bakkot) figure out why this is | |
4468 // necessary for non-computed names in full-codegen | |
Dan Ehrenberg
2016/09/09 22:54:41
What happens when you don't include this on a non-
bakkot
2016/09/12 19:10:10
That argument fails an IsName check in DefineDataP
| |
4469 ZoneList<Expression*>* to_name_args = | |
4470 new (zone()) ZoneList<Expression*>(1, zone()); | |
4471 to_name_args->Add(property->key(), zone()); | |
4472 property->set_key(factory()->NewCallRuntime( | |
4473 Runtime::kToName, to_name_args, kNoSourcePosition)); | |
4474 //} | |
4475 const AstRawString* name = ClassFieldVariableName( | |
4476 true, ast_value_factory(), instance_field_initializers->length()); | |
4477 VariableProxy* name_proxy = NewUnresolved(name); | |
4478 Declaration* name_declaration = | |
4479 factory() | |
4480 ->NewVariableDeclaration( // TODO(bakkot) DeclareLocal? not | |
4481 // clear on the difference... | |
Dan Ehrenberg
2016/09/09 22:54:42
Generally in the parser, you can either use a NewV
| |
4482 name_proxy, scope(), kNoSourcePosition); | |
4483 Variable* name_var = | |
4484 Declare(name_declaration, DeclarationDescriptor::NORMAL, CONST, | |
4485 kNeedsInitialization, ok, scope()); | |
4486 DCHECK(ok); | |
4487 if (!ok) return nullptr; | |
4488 instance_field_initializers->Add(property->value(), zone()); | |
4489 property->set_value(factory()->NewVariableProxy(name_var)); | |
4490 } | |
4280 } | 4491 } |
4281 properties->Add(property, zone()); | 4492 properties->Add(property, zone()); |
4282 } | 4493 } |
4283 | 4494 |
4284 DCHECK_NOT_NULL(fni_); | 4495 DCHECK_NOT_NULL(fni_); |
4285 fni_->Infer(); | 4496 fni_->Infer(); |
4286 } | 4497 } |
4287 | 4498 |
4288 Expect(Token::RBRACE, CHECK_OK); | 4499 Expect(Token::RBRACE, CHECK_OK); |
4289 int end_pos = scanner()->location().end_pos; | 4500 int end_pos = scanner()->location().end_pos; |
4290 | 4501 |
4291 bool has_instance_fields = instance_field_initializers->length() > 0; | 4502 bool has_instance_fields = instance_field_initializers->length() > 0; |
4292 DCHECK(!has_instance_fields || allow_harmony_class_fields()); | 4503 DCHECK(!has_instance_fields || allow_harmony_class_fields()); |
4293 bool has_default_constructor = constructor == nullptr; | 4504 bool has_default_constructor = constructor == nullptr; |
4294 if (has_default_constructor) { | 4505 if (has_default_constructor) { |
4295 constructor = DefaultConstructor(name, has_extends, has_instance_fields, | 4506 constructor = DefaultConstructor(name, has_extends, has_instance_fields, |
4296 pos, end_pos, block_state.language_mode()); | 4507 pos, end_pos, block_state.language_mode()); |
4297 } | 4508 } |
4298 | 4509 |
4299 if (has_instance_fields && extends == nullptr) { | 4510 if (has_instance_fields && extends == nullptr) { |
4511 constructor = InsertClassFieldInitializer(constructor); | |
4300 constructor->set_requires_class_field_init(true); | 4512 constructor->set_requires_class_field_init(true); |
4301 } // The derived case is handled by rewriting super calls. | 4513 } // The derived case is handled by rewriting super calls. |
4302 | 4514 |
4303 block_state.set_end_position(end_pos); | 4515 block_state.set_end_position(end_pos); |
4304 | 4516 |
4305 if (name != nullptr) { | 4517 if (name != nullptr) { |
4306 DCHECK_NOT_NULL(proxy); | 4518 DCHECK_NOT_NULL(proxy); |
4307 proxy->var()->set_initializer_position(end_pos); | 4519 proxy->var()->set_initializer_position(end_pos); |
4308 } | 4520 } |
4309 | 4521 |
4310 ClassLiteral* class_literal = factory()->NewClassLiteral( | 4522 ClassLiteral* class_literal = factory()->NewClassLiteral( |
4311 proxy, extends, constructor, properties, pos, end_pos); | 4523 proxy, extends, constructor, properties, pos, end_pos); |
4312 | 4524 |
4313 if (static_initializer_var != nullptr) { | 4525 if (static_initializer_var != nullptr) { |
4314 class_literal->set_static_initializer_proxy( | 4526 class_literal->set_static_initializer_proxy( |
4315 factory()->NewVariableProxy(static_initializer_var)); | 4527 factory()->NewVariableProxy(static_initializer_var)); |
4316 } | 4528 } |
4317 | 4529 |
4318 do_block->statements()->Add( | 4530 do_block->statements()->Add( |
4319 factory()->NewExpressionStatement( | 4531 factory()->NewExpressionStatement( |
4320 factory()->NewAssignment(Token::ASSIGN, | 4532 factory()->NewAssignment(Token::ASSIGN, |
4321 factory()->NewVariableProxy(result_var), | 4533 factory()->NewVariableProxy(result_var), |
4322 class_literal, kNoSourcePosition), | 4534 class_literal, kNoSourcePosition), |
4323 pos), | 4535 pos), |
4324 zone()); | 4536 zone()); |
4537 if (allow_harmony_class_fields() && | |
4538 (has_instance_fields || | |
4539 (extends != nullptr && !has_default_constructor))) { | |
4540 // Default constructors for derived classes without fields will not try to | |
4541 // read this variable, so there's no need to create it. | |
4542 const AstRawString* init_fn_name = | |
4543 ast_value_factory()->GetOneByteString(".class-field-initializer"); | |
Dan Ehrenberg
2016/09/09 22:54:42
Put in src/heap-symbols.h
bakkot
2016/09/12 19:10:11
Done.
| |
4544 Variable* init_fn_var = | |
4545 scope()->DeclareLocal(init_fn_name, CONST, kCreatedInitialized, | |
4546 Variable::NORMAL); // TODO(bakkot) flags | |
Dan Ehrenberg
2016/09/09 22:54:42
What flags do you think might be wrong here? This
bakkot
2016/09/12 19:10:10
Mostly I wasn't sure if kCreatedInitialized was co
| |
4547 Expression* initializer = | |
4548 has_instance_fields | |
4549 ? static_cast<Expression*>(SynthesizeClassFieldInitializer( | |
4550 instance_field_initializers->length())) | |
4551 : factory()->NewBooleanLiteral(false, kNoSourcePosition); | |
4552 Assignment* assignment = factory()->NewAssignment( | |
4553 Token::INIT, factory()->NewVariableProxy(init_fn_var), initializer, | |
4554 kNoSourcePosition); | |
4555 do_block->statements()->Add( | |
4556 factory()->NewExpressionStatement(assignment, kNoSourcePosition), | |
4557 zone()); | |
4558 } | |
4559 for (int i = 0; i < instance_field_initializers->length(); ++i) { | |
4560 const AstRawString* function_name = | |
4561 ClassFieldVariableName(false, ast_value_factory(), i); | |
4562 VariableProxy* function_proxy = NewUnresolved(function_name); | |
4563 Declaration* function_declaration = factory()->NewVariableDeclaration( | |
4564 function_proxy, scope(), kNoSourcePosition); | |
4565 Variable* function_var = | |
4566 Declare(function_declaration, DeclarationDescriptor::NORMAL, CONST, | |
4567 kNeedsInitialization, ok, | |
4568 scope()); // TODO(bakkot) declare vs declarelocal | |
Dan Ehrenberg
2016/09/09 22:54:42
Declare.
bakkot
2016/09/12 19:10:11
Thanks.
| |
4569 DCHECK(ok); | |
4570 if (!ok) return nullptr; | |
4571 Property* prototype_property = factory()->NewProperty( | |
4572 factory()->NewVariableProxy(result_var), | |
4573 factory()->NewStringLiteral(ast_value_factory()->prototype_string(), | |
4574 kNoSourcePosition), | |
4575 kNoSourcePosition); | |
4576 Expression* function_value = InstallHomeObject( | |
4577 instance_field_initializers->at(i), | |
4578 prototype_property); // TODO(bakkot) ideally this would be conditional, | |
4579 // especially in trivial cases | |
Dan Ehrenberg
2016/09/09 22:54:42
As we discussed off-line, you can use the scope in
bakkot
2016/09/12 19:10:10
I'm going to make that change in a later patch, si
| |
4580 Assignment* function_assignment = factory()->NewAssignment( | |
4581 Token::INIT, factory()->NewVariableProxy(function_var), function_value, | |
4582 kNoSourcePosition); | |
4583 do_block->statements()->Add(factory()->NewExpressionStatement( | |
4584 function_assignment, kNoSourcePosition), | |
4585 zone()); | |
4586 } | |
4325 do_block->set_scope(block_state.FinalizedBlockScope()); | 4587 do_block->set_scope(block_state.FinalizedBlockScope()); |
4326 do_expr->set_represented_function(constructor); | 4588 do_expr->set_represented_function(constructor); |
4327 | 4589 |
4328 return do_expr; | 4590 return do_expr; |
4329 } | 4591 } |
4330 | 4592 |
4331 | 4593 |
4332 Expression* Parser::ParseV8Intrinsic(bool* ok) { | 4594 Expression* Parser::ParseV8Intrinsic(bool* ok) { |
4333 // CallRuntime :: | 4595 // CallRuntime :: |
4334 // '%' Identifier Arguments | 4596 // '%' Identifier Arguments |
(...skipping 1873 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6208 node->Print(Isolate::Current()); | 6470 node->Print(Isolate::Current()); |
6209 } | 6471 } |
6210 #endif // DEBUG | 6472 #endif // DEBUG |
6211 | 6473 |
6212 #undef CHECK_OK | 6474 #undef CHECK_OK |
6213 #undef CHECK_OK_VOID | 6475 #undef CHECK_OK_VOID |
6214 #undef CHECK_FAILED | 6476 #undef CHECK_FAILED |
6215 | 6477 |
6216 } // namespace internal | 6478 } // namespace internal |
6217 } // namespace v8 | 6479 } // namespace v8 |
OLD | NEW |