| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 29679)
|
| +++ runtime/vm/parser.cc (working copy)
|
| @@ -781,6 +781,9 @@
|
| case RawFunction::kImplicitStaticFinalGetter:
|
| node_sequence = parser.ParseStaticFinalGetter(func);
|
| break;
|
| + case RawFunction::kStaticInitializer:
|
| + node_sequence = parser.ParseStaticInitializer(func);
|
| + break;
|
| case RawFunction::kMethodExtractor:
|
| node_sequence = parser.ParseMethodExtractor(func);
|
| break;
|
| @@ -907,33 +910,17 @@
|
| const Field& field =
|
| Field::ZoneHandle(field_class.LookupStaticField(field_name));
|
|
|
| - if (!field.is_const() &&
|
| - (field.value() != Object::transition_sentinel().raw()) &&
|
| - (field.value() != Object::sentinel().raw())) {
|
| - // The field has already been initialized at compile time (this can
|
| - // happen, e.g., if we are recompiling for optimization). There is no
|
| - // need to check for initialization and compile the potentially very
|
| - // large initialization code. By skipping this code, the deoptimization
|
| - // ids will not line up with the original code, but this is safe because
|
| - // LoadStaticField does not deoptimize.
|
| - LoadStaticFieldNode* load_node = new LoadStaticFieldNode(ident_pos, field);
|
| - ReturnNode* return_node = new ReturnNode(ident_pos, load_node);
|
| - current_block_->statements->Add(return_node);
|
| - return CloseBlock();
|
| - }
|
| -
|
| - // Static const fields must have an initializer.
|
| + // Static final fields must have an initializer.
|
| ExpectToken(Token::kASSIGN);
|
|
|
| - // We don't want to use ParseConstExpr() here because we don't want
|
| - // the constant folding code to create, compile and execute a code
|
| - // fragment to evaluate the expression. Instead, we just make sure
|
| - // the static const field initializer is a constant expression and
|
| - // leave the evaluation to the getter function.
|
| const intptr_t expr_pos = TokenPos();
|
| - AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
|
| -
|
| if (field.is_const()) {
|
| + // We don't want to use ParseConstExpr() here because we don't want
|
| + // the constant folding code to create, compile and execute a code
|
| + // fragment to evaluate the expression. Instead, we just make sure
|
| + // the static const field initializer is a constant expression and
|
| + // leave the evaluation to the getter function.
|
| + AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
|
| // This getter will only be called once at compile time.
|
| if (expr->EvalConstExpr() == NULL) {
|
| ErrorMsg(expr_pos, "initializer is not a valid compile-time constant");
|
| @@ -995,7 +982,19 @@
|
| // we leave the field value as 'transition_sentinel', which is wrong.
|
| // A second reference to the field later throws a circular dependency
|
| // exception. The field should instead be set to null after an exception.
|
| - initialize_field->Add(new StoreStaticFieldNode(ident_pos, field, expr));
|
| + const String& init_name =
|
| + String::Handle(Symbols::New(String::Handle(
|
| + String::Concat(Symbols::InitPrefix(), String::Handle(field.name())))));
|
| + const Function& init_function = Function::ZoneHandle(
|
| + 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(new StoreStaticFieldNode(ident_pos,
|
| + field,
|
| + init_call));
|
| AstNode* uninitialized_check =
|
| new IfNode(ident_pos, compare_uninitialized, initialize_field, NULL);
|
| current_block_->statements->Add(uninitialized_check);
|
| @@ -1010,6 +1009,25 @@
|
| }
|
|
|
|
|
| +SequenceNode* Parser::ParseStaticInitializer(const Function& func) {
|
| + TRACE_PARSER("ParseStaticInitializer");
|
| + ParamList params;
|
| + ASSERT(func.num_fixed_parameters() == 0); // static.
|
| + ASSERT(!func.HasOptionalParameters());
|
| + ASSERT(AbstractType::Handle(func.result_type()).IsResolved());
|
| +
|
| + // Build local scope for function and populate with the formal parameters.
|
| + OpenFunctionBlock(func);
|
| + AddFormalParamsToScope(¶ms, current_block_->scope);
|
| +
|
| + intptr_t expr_pos = func.token_pos();
|
| + AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
|
| + ReturnNode* return_node = new ReturnNode(expr_pos, expr);
|
| + current_block_->statements->Add(return_node);
|
| + return CloseBlock();
|
| +}
|
| +
|
| +
|
| // Create AstNodes for an implicit instance getter method:
|
| // LoadLocalNode 0 ('this');
|
| // LoadInstanceFieldNode (field_name);
|
| @@ -3253,6 +3271,7 @@
|
| Function& setter = Function::Handle();
|
| Field& class_field = Field::ZoneHandle();
|
| Instance& init_value = Instance::Handle();
|
| + intptr_t expr_pos = -1;
|
| while (true) {
|
| bool has_initializer = CurrentToken() == Token::kASSIGN;
|
| bool has_simple_literal = false;
|
| @@ -3277,6 +3296,7 @@
|
| (LookaheadToken(1) == Token::kSEMICOLON)) {
|
| has_simple_literal = IsSimpleLiteral(*field->type, &init_value);
|
| }
|
| + expr_pos = TokenPos();
|
| SkipExpr();
|
| } else {
|
| // Static const and static final fields must have an initializer.
|
| @@ -3320,6 +3340,14 @@
|
| field->name_pos);
|
| getter.set_result_type(*field->type);
|
| members->AddFunction(getter);
|
| +
|
| + // Create initializer function.
|
| + const Function& init_function = Function::ZoneHandle(
|
| + Function::NewStaticInitializer(*field->name,
|
| + *field->type,
|
| + current_class(),
|
| + expr_pos));
|
| + members->AddFunction(init_function);
|
| }
|
| }
|
|
|
| @@ -4429,6 +4457,7 @@
|
| if ((is_const || is_final) && (LookaheadToken(1) == Token::kSEMICOLON)) {
|
| has_simple_literal = IsSimpleLiteral(type, &field_value);
|
| }
|
| + const intptr_t expr_pos = TokenPos();
|
| SkipExpr();
|
| field.set_value(field_value);
|
| if (!has_simple_literal) {
|
| @@ -4444,6 +4473,14 @@
|
| name_pos);
|
| getter.set_result_type(type);
|
| top_level->functions.Add(getter);
|
| +
|
| + // Create initializer function.
|
| + const Function& init_function = Function::ZoneHandle(
|
| + Function::NewStaticInitializer(var_name,
|
| + type,
|
| + current_class(),
|
| + expr_pos));
|
| + top_level->functions.Add(init_function);
|
| }
|
| } else if (is_final) {
|
| ErrorMsg(name_pos, "missing initializer for final or const variable");
|
|
|