Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 39381) |
+++ runtime/vm/parser.cc (working copy) |
@@ -828,10 +828,6 @@ |
node_sequence = parser.ParseStaticFinalGetter(func); |
CompilerStats::num_implicit_final_getters++; |
break; |
- case RawFunction::kStaticInitializer: |
- node_sequence = parser.ParseStaticInitializer(func); |
- CompilerStats::num_static_initializer_funcs++; |
- break; |
case RawFunction::kMethodExtractor: |
node_sequence = parser.ParseMethodExtractor(func); |
break; |
@@ -1003,6 +999,74 @@ |
} |
+SequenceNode* Parser::ParseStaticInitializer() { |
+ ExpectIdentifier("field name expected"); |
+ CheckToken(Token::kASSIGN, "field initialier expected"); |
+ ConsumeToken(); |
+ OpenFunctionBlock(parsed_function()->function()); |
+ intptr_t expr_pos = TokenPos(); |
+ AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); |
+ ReturnNode* ret = new(I) ReturnNode(expr_pos, expr); |
+ current_block_->statements->Add(ret); |
+ return CloseBlock(); |
+} |
+ |
+ |
+ParsedFunction* Parser::ParseStaticFieldInitializer(const Field& field) { |
+ ASSERT(field.is_static()); |
+ ASSERT(field.value() == Object::transition_sentinel().raw()); |
+ Isolate* isolate = Isolate::Current(); |
+ |
+ const Class& script_cls = Class::Handle(isolate, field.origin()); |
+ const Script& script = Script::Handle(isolate, script_cls.script()); |
+ |
+ const String& field_name = String::Handle(isolate, field.name()); |
+ String& init_name = String::Handle(isolate, |
+ String::Concat(Symbols::InitPrefix(), field_name)); |
+ init_name = Symbols::New(init_name); |
+ |
+ const Function& initializer = Function::ZoneHandle(isolate, |
+ Function::New(init_name, |
+ RawFunction::kRegularFunction, |
+ true, // static |
+ false, // !const |
+ false, // !abstract |
+ false, // !external |
+ false, // !native |
+ Class::Handle(field.owner()), |
+ field.token_pos())); |
+ initializer.set_result_type(AbstractType::Handle(isolate, field.type())); |
+ // Static initializer functions are hidden from the user. |
+ // Since they are only executed once, we avoid optimizing |
+ // and inlining them. After the field is initialized, the |
+ // compiler can eliminate the call to the static initializer. |
+ initializer.set_is_visible(false); |
+ initializer.SetIsOptimizable(false); |
+ initializer.set_is_inlinable(false); |
+ |
+ ParsedFunction* parsed_function = new ParsedFunction(isolate, initializer); |
+ Parser parser(script, parsed_function, field.token_pos()); |
+ |
+ SequenceNode* body = parser.ParseStaticInitializer(); |
+ parsed_function->SetNodeSequence(body); |
+ parsed_function->set_default_parameter_values(Object::null_array()); |
+ |
+ if (parsed_function->has_expression_temp_var()) { |
+ body->scope()->AddVariable(parsed_function->expression_temp_var()); |
+ } |
+ if (parsed_function->has_saved_current_context_var()) { |
+ body->scope()->AddVariable(parsed_function->saved_current_context_var()); |
+ } |
+ if (parsed_function->has_finally_return_temp_var()) { |
+ body->scope()->AddVariable(parsed_function->finally_return_temp_var()); |
+ } |
+ // The instantiator is not required in a static expression. |
+ ASSERT(!parser.IsInstantiatorRequired()); |
+ |
+ return parsed_function; |
+} |
+ |
+ |
SequenceNode* Parser::ParseStaticFinalGetter(const Function& func) { |
TRACE_PARSER("ParseStaticFinalGetter"); |
ParamList params; |
@@ -1039,188 +1103,20 @@ |
current_block_->statements->Add(return_node); |
} else { |
// This getter may be called each time the static field is accessed. |
- // The following generated code lazily initializes the field: |
- // if (field.value === transition_sentinel) { |
- // field.value = null; |
- // throw("circular dependency in field initialization"); |
- // } |
- // if (field.value === sentinel) { |
- // field.value = transition_sentinel; |
- // field.value = expr; |
- // } |
- // return field.value; // Type check is executed here in checked mode. |
- |
- // Generate code checking for circular dependency in field initialization. |
- AstNode* compare_circular = new ComparisonNode( |
- ident_pos, |
- Token::kEQ_STRICT, |
- new LoadStaticFieldNode(ident_pos, field), |
- new LiteralNode(ident_pos, Object::transition_sentinel())); |
- // Set field to null prior to throwing exception, so that subsequent |
- // accesses to the field do not throw again, since initializers should only |
- // be executed once. |
- SequenceNode* report_circular = new SequenceNode(ident_pos, NULL); |
- report_circular->Add( |
- new StoreStaticFieldNode( |
- ident_pos, |
- field, |
- new LiteralNode(ident_pos, Instance::ZoneHandle(I)))); |
- // Call CyclicInitializationError._throwNew(field_name). |
- ArgumentListNode* error_arguments = new ArgumentListNode(ident_pos); |
- error_arguments->Add(new LiteralNode(ident_pos, field_name)); |
- report_circular->Add( |
- MakeStaticCall(Symbols::CyclicInitializationError(), |
- Library::PrivateCoreLibName(Symbols::ThrowNew()), |
- error_arguments)); |
- AstNode* circular_check = |
- new IfNode(ident_pos, compare_circular, report_circular, NULL); |
- current_block_->statements->Add(circular_check); |
- |
- // Generate code checking for uninitialized field. |
- AstNode* compare_uninitialized = new ComparisonNode( |
- ident_pos, |
- Token::kEQ_STRICT, |
- new LoadStaticFieldNode(ident_pos, field), |
- new LiteralNode(ident_pos, Object::sentinel())); |
- SequenceNode* initialize_field = new SequenceNode(ident_pos, NULL); |
- initialize_field->Add( |
- new StoreStaticFieldNode( |
- ident_pos, |
- field, |
- new LiteralNode(ident_pos, Object::transition_sentinel()))); |
- const String& init_name = String::Handle(I, Symbols::New( |
- String::Handle(I, String::Concat( |
- Symbols::InitPrefix(), String::Handle(I, field.name()))))); |
- const Function& init_function = Function::ZoneHandle(I, |
- field_class.LookupStaticFunction(init_name)); |
- ASSERT(!init_function.IsNull()); |
- ArgumentListNode* arguments = new ArgumentListNode(expr_pos); |
- StaticCallNode* init_call = |
- new StaticCallNode(expr_pos, init_function, arguments); |
- initialize_field->Add(init_call); |
- |
- AstNode* uninitialized_check = |
- new IfNode(ident_pos, compare_uninitialized, initialize_field, NULL); |
- current_block_->statements->Add(uninitialized_check); |
- |
- // Generate code returning the field value. |
+ // Call runtime support to parse and evaluate the initializer expression. |
+ // The runtime function will detect circular dependencies in expressions |
+ // and handle errors while evaluating the expression. |
+ current_block_->statements->Add( |
+ new (I) InitStaticFieldNode(ident_pos, field)); |
ReturnNode* return_node = |
- new ReturnNode(ident_pos, new LoadStaticFieldNode(ident_pos, field)); |
+ new ReturnNode(ident_pos, |
+ new LoadStaticFieldNode(ident_pos, field)); |
current_block_->statements->Add(return_node); |
} |
return CloseBlock(); |
} |
-SequenceNode* Parser::ParseStaticInitializer(const Function& func) { |
- TRACE_PARSER("ParseStaticInitializer"); |
- ParamList params; |
- ASSERT(func.num_fixed_parameters() == 0); // static. |
- ASSERT(!func.HasOptionalParameters()); |
- ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved()); |
- |
- // Build local scope for function and populate with the formal parameters. |
- OpenFunctionBlock(func); |
- AddFormalParamsToScope(¶ms, current_block_->scope); |
- |
- // Move forward to the start of the initializer expression. |
- intptr_t ident_pos = TokenPos(); |
- ExpectIdentifier("identifier expected"); |
- ExpectToken(Token::kASSIGN); |
- intptr_t token_pos = TokenPos(); |
- |
- // Synthesize a try-catch block to wrap the initializer expression. |
- LocalVariable* context_var = |
- current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar()); |
- if (context_var == NULL) { |
- context_var = new(I) LocalVariable( |
- token_pos, |
- Symbols::SavedTryContextVar(), |
- Type::ZoneHandle(I, Type::DynamicType())); |
- current_block_->scope->AddVariable(context_var); |
- } |
- LocalVariable* catch_excp_var = |
- current_block_->scope->LocalLookupVariable(Symbols::ExceptionVar()); |
- if (catch_excp_var == NULL) { |
- catch_excp_var = new (I) LocalVariable( |
- token_pos, |
- Symbols::ExceptionVar(), |
- Type::ZoneHandle(I, Type::DynamicType())); |
- current_block_->scope->AddVariable(catch_excp_var); |
- } |
- LocalVariable* catch_trace_var = |
- current_block_->scope->LocalLookupVariable(Symbols::StackTraceVar()); |
- if (catch_trace_var == NULL) { |
- catch_trace_var = new (I) LocalVariable( |
- token_pos, |
- Symbols::StackTraceVar(), |
- Type::ZoneHandle(I, Type::DynamicType())); |
- current_block_->scope->AddVariable(catch_trace_var); |
- } |
- |
- OpenBlock(); // Start try block. |
- AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); |
- const Field& field = Field::ZoneHandle(I, func.saved_static_field()); |
- ASSERT(!field.is_const()); |
- if (FLAG_enable_type_checks) { |
- expr = new AssignableNode( |
- field.token_pos(), |
- expr, |
- AbstractType::ZoneHandle(I, field.type()), |
- String::ZoneHandle(I, field.name())); |
- } |
- StoreStaticFieldNode* store = new StoreStaticFieldNode(field.token_pos(), |
- field, |
- expr); |
- current_block_->statements->Add(store); |
- SequenceNode* try_block = CloseBlock(); // End try block. |
- |
- OpenBlock(); // Start catch handler list. |
- OpenBlock(); // Start catch clause. |
- AstNode* compare_transition_sentinel = new ComparisonNode( |
- token_pos, |
- Token::kEQ_STRICT, |
- new LoadStaticFieldNode(ident_pos, field), |
- new LiteralNode(field.token_pos(), Object::transition_sentinel())); |
- |
- SequenceNode* store_null = new SequenceNode(token_pos, NULL); |
- store_null->Add(new StoreStaticFieldNode( |
- field.token_pos(), |
- field, |
- new LiteralNode(token_pos, Instance::ZoneHandle(I)))); |
- AstNode* transition_sentinel_check = |
- new IfNode(token_pos, compare_transition_sentinel, store_null, NULL); |
- current_block_->statements->Add(transition_sentinel_check); |
- |
- current_block_->statements->Add( |
- new ThrowNode(token_pos, |
- new LoadLocalNode(token_pos, catch_excp_var), |
- new LoadLocalNode(token_pos, catch_trace_var))); |
- SequenceNode* catch_clause = CloseBlock(); // End catch clause. |
- |
- current_block_->statements->Add(catch_clause); |
- SequenceNode* catch_handler_list = CloseBlock(); // End catch handler list. |
- CatchClauseNode* catch_block = |
- new CatchClauseNode(token_pos, |
- catch_handler_list, |
- Array::ZoneHandle(I, Object::empty_array().raw()), |
- context_var, |
- catch_excp_var, |
- catch_trace_var, |
- CatchClauseNode::kInvalidTryIndex, |
- false); // No stack trace needed. |
- |
- AstNode* try_catch_node = new TryCatchNode(token_pos, |
- try_block, |
- context_var, |
- catch_block, |
- NULL, // No finally block. |
- AllocateTryIndex()); |
- current_block_->statements->Add(try_catch_node); |
- return CloseBlock(); |
-} |
- |
- |
// Create AstNodes for an implicit instance getter method: |
// LoadLocalNode 0 ('this'); |
// LoadInstanceFieldNode (field_name); |
@@ -3695,13 +3591,6 @@ |
field->name_pos); |
getter.set_result_type(*field->type); |
members->AddFunction(getter); |
- |
- // Create initializer function for non-const fields. |
- if (!class_field.is_const()) { |
- const Function& init_function = Function::ZoneHandle(I, |
- Function::NewStaticInitializer(class_field)); |
- members->AddFunction(init_function); |
- } |
} |
} |
@@ -4860,13 +4749,6 @@ |
name_pos); |
getter.set_result_type(type); |
top_level->functions.Add(getter); |
- |
- // Create initializer function. |
- if (!field.is_const()) { |
- const Function& init_function = Function::ZoneHandle(I, |
- Function::NewStaticInitializer(field)); |
- top_level->functions.Add(init_function); |
- } |
} |
} else if (is_final) { |
ReportError(name_pos, "missing initializer for final or const variable"); |
@@ -11030,8 +10912,7 @@ |
// Compile time constant expressions cannot reference anything from a |
// local scope. |
LocalScope* empty_scope = new(I) LocalScope(NULL, 0, 0); |
- SequenceNode* seq = new(I) SequenceNode(expr->token_pos(), |
- empty_scope); |
+ SequenceNode* seq = new(I) SequenceNode(expr->token_pos(), empty_scope); |
seq->Add(ret); |
Object& result = Object::Handle(I, Compiler::ExecuteOnce(seq)); |