| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/parser.h" | 5 #include "vm/parser.h" |
| 6 | 6 |
| 7 #include "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
| 8 #include "vm/class_finalizer.h" | 8 #include "vm/class_finalizer.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/compiler_stats.h" | 10 #include "vm/compiler_stats.h" |
| (...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 parsed_function->set_instantiator( | 682 parsed_function->set_instantiator( |
| 683 new LoadLocalNode(node_sequence->token_index(), *receiver)); | 683 new LoadLocalNode(node_sequence->token_index(), *receiver)); |
| 684 } | 684 } |
| 685 } | 685 } |
| 686 | 686 |
| 687 parsed_function->set_default_parameter_values(default_parameter_values); | 687 parsed_function->set_default_parameter_values(default_parameter_values); |
| 688 isolate->set_ast_node_id(prev_ast_node_id); | 688 isolate->set_ast_node_id(prev_ast_node_id); |
| 689 } | 689 } |
| 690 | 690 |
| 691 | 691 |
| 692 // TODO(regis): Implement support for non-const final static fields (currently |
| 693 // supported "final" fields are actually const fields). |
| 694 // TODO(regis): Since a const variable is implicitly final, |
| 695 // rename ParseStaticConstGetter to ParseStaticFinalGetter and |
| 696 // rename kConstImplicitGetter to kImplicitFinalGetter. |
| 692 SequenceNode* Parser::ParseStaticConstGetter(const Function& func) { | 697 SequenceNode* Parser::ParseStaticConstGetter(const Function& func) { |
| 693 TRACE_PARSER("ParseStaticConstGetter"); | 698 TRACE_PARSER("ParseStaticConstGetter"); |
| 694 ParamList params; | 699 ParamList params; |
| 695 ASSERT(func.num_fixed_parameters() == 0); // static. | 700 ASSERT(func.num_fixed_parameters() == 0); // static. |
| 696 ASSERT(func.num_optional_parameters() == 0); | 701 ASSERT(func.num_optional_parameters() == 0); |
| 697 ASSERT(AbstractType::Handle(func.result_type()).IsResolved()); | 702 ASSERT(AbstractType::Handle(func.result_type()).IsResolved()); |
| 698 | 703 |
| 699 // Build local scope for function and populate with the formal parameters. | 704 // Build local scope for function and populate with the formal parameters. |
| 700 OpenFunctionBlock(func); | 705 OpenFunctionBlock(func); |
| 701 AddFormalParamsToScope(¶ms, current_block_->scope); | 706 AddFormalParamsToScope(¶ms, current_block_->scope); |
| 702 | 707 |
| 708 const String& field_name = *ExpectIdentifier("field name expected"); |
| 709 const Class& field_class = Class::Handle(func.owner()); |
| 710 const Field& field = |
| 711 Field::ZoneHandle(field_class.LookupStaticField(field_name)); |
| 712 |
| 703 // Static const fields must have an initializer. | 713 // Static const fields must have an initializer. |
| 704 ExpectIdentifier("field name expected"); | |
| 705 ExpectToken(Token::kASSIGN); | 714 ExpectToken(Token::kASSIGN); |
| 706 | 715 |
| 707 // We don't want to use ParseConstExpr() here because we don't want | 716 // We don't want to use ParseConstExpr() here because we don't want |
| 708 // the constant folding code to create, compile and execute a code | 717 // the constant folding code to create, compile and execute a code |
| 709 // fragment to evaluate the expression. Instead, we just make sure | 718 // fragment to evaluate the expression. Instead, we just make sure |
| 710 // the static const field initializer is a constant expression and | 719 // the static const field initializer is a constant expression and |
| 711 // leave the evaluation to the getter function. | 720 // leave the evaluation to the getter function. |
| 712 const intptr_t expr_pos = token_index_; | 721 const intptr_t expr_pos = token_index_; |
| 713 AstNode* expr = ParseExpr(kAllowConst); | 722 AstNode* expr = ParseExpr(kAllowConst); |
| 714 if (expr->EvalConstExpr() == NULL) { | 723 if (field.is_const()) { |
| 715 ErrorMsg(expr_pos, "initializer must be a compile time constant"); | 724 // This getter will only be called once at compile time. |
| 725 if (expr->EvalConstExpr() == NULL) { |
| 726 ErrorMsg(expr_pos, "initializer must be a compile time constant"); |
| 727 } |
| 728 ReturnNode* return_node = new ReturnNode(token_index_, expr); |
| 729 current_block_->statements->Add(return_node); |
| 730 } else { |
| 731 // This getter may be called each time the static field is accessed. |
| 732 // The following generated code lazily initializes the field: |
| 733 // if (field.value === transition_sentinel) { |
| 734 // field.value = null; |
| 735 // throw("circular dependency in field initialization"); |
| 736 // } |
| 737 // if (field.value === sentinel) { |
| 738 // field.value = transition_sentinel; |
| 739 // field.value = expr; |
| 740 // } |
| 741 // return field.value; // Type check is executed here in checked mode. |
| 742 |
| 743 // TODO(regis): Remove this check once we support proper const fields. |
| 744 if (expr->EvalConstExpr() == NULL) { |
| 745 ErrorMsg(expr_pos, "initializer must be a compile time constant"); |
| 746 } |
| 747 |
| 748 // Generate code checking for circular dependency in field initialization. |
| 749 AstNode* compare_circular = new ComparisonNode( |
| 750 token_index_, |
| 751 Token::kEQ_STRICT, |
| 752 new LoadStaticFieldNode(token_index_, field), |
| 753 new LiteralNode(token_index_, |
| 754 Instance::ZoneHandle(Object::transition_sentinel()))); |
| 755 // Set field to null prior to throwing exception, so that subsequent |
| 756 // accesses to the field do not throw again, since initializers should only |
| 757 // be executed once. |
| 758 SequenceNode* report_circular = new SequenceNode(token_index_, NULL); |
| 759 report_circular->Add( |
| 760 new StoreStaticFieldNode( |
| 761 token_index_, |
| 762 field, |
| 763 new LiteralNode(token_index_, Instance::ZoneHandle()))); |
| 764 // TODO(regis): Exception to throw is not specified by spec. |
| 765 const String& circular_error = String::ZoneHandle( |
| 766 String::NewSymbol("circular dependency in field initialization")); |
| 767 report_circular->Add( |
| 768 new ThrowNode(token_index_, |
| 769 new LiteralNode(token_index_, circular_error), |
| 770 NULL)); |
| 771 AstNode* circular_check = |
| 772 new IfNode(token_index_, compare_circular, report_circular, NULL); |
| 773 current_block_->statements->Add(circular_check); |
| 774 |
| 775 // Generate code checking for uninitialized field. |
| 776 AstNode* compare_uninitialized = new ComparisonNode( |
| 777 token_index_, |
| 778 Token::kEQ_STRICT, |
| 779 new LoadStaticFieldNode(token_index_, field), |
| 780 new LiteralNode(token_index_, |
| 781 Instance::ZoneHandle(Object::sentinel()))); |
| 782 SequenceNode* initialize_field = new SequenceNode(token_index_, NULL); |
| 783 initialize_field->Add( |
| 784 new StoreStaticFieldNode( |
| 785 token_index_, |
| 786 field, |
| 787 new LiteralNode( |
| 788 token_index_, |
| 789 Instance::ZoneHandle(Object::transition_sentinel())))); |
| 790 initialize_field->Add(new StoreStaticFieldNode(token_index_, field, expr)); |
| 791 AstNode* uninitialized_check = |
| 792 new IfNode(token_index_, compare_uninitialized, initialize_field, NULL); |
| 793 current_block_->statements->Add(uninitialized_check); |
| 794 |
| 795 // Generate code returning the field value. |
| 796 ReturnNode* return_node = |
| 797 new ReturnNode(token_index_, |
| 798 new LoadStaticFieldNode(token_index_, field)); |
| 799 current_block_->statements->Add(return_node); |
| 716 } | 800 } |
| 717 ReturnNode* return_node = new ReturnNode(token_index_, expr); | |
| 718 current_block_->statements->Add(return_node); | |
| 719 return CloseBlock(); | 801 return CloseBlock(); |
| 720 } | 802 } |
| 721 | 803 |
| 722 | 804 |
| 723 // Create AstNodes for an implicit instance getter method: | 805 // Create AstNodes for an implicit instance getter method: |
| 724 // LoadLocalNode 0 ('this'); | 806 // LoadLocalNode 0 ('this'); |
| 725 // LoadInstanceFieldNode (field_name); | 807 // LoadInstanceFieldNode (field_name); |
| 726 // ReturnNode (field's value); | 808 // ReturnNode (field's value); |
| 727 SequenceNode* Parser::ParseInstanceGetter(const Function& func) { | 809 SequenceNode* Parser::ParseInstanceGetter(const Function& func) { |
| 728 TRACE_PARSER("ParseInstanceGetter"); | 810 TRACE_PARSER("ParseInstanceGetter"); |
| (...skipping 5444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6173 access = load_access->MakeAssignmentNode(value); | 6255 access = load_access->MakeAssignmentNode(value); |
| 6174 } else { | 6256 } else { |
| 6175 access = CallGetter(call_pos, receiver, field_name); | 6257 access = CallGetter(call_pos, receiver, field_name); |
| 6176 } | 6258 } |
| 6177 return access; | 6259 return access; |
| 6178 } | 6260 } |
| 6179 | 6261 |
| 6180 | 6262 |
| 6181 AstNode* Parser::GenerateStaticFieldLookup(const Field& field, | 6263 AstNode* Parser::GenerateStaticFieldLookup(const Field& field, |
| 6182 intptr_t ident_pos) { | 6264 intptr_t ident_pos) { |
| 6183 // Run static field initializer first if necessary. | 6265 // If the static field has an initializer, initialize the field at compile |
| 6184 // May return an exception throwing ast node. | 6266 // time, which is only possible if the field is const. |
| 6185 AstNode* throw_exception = RunStaticFieldInitializer(field); | 6267 AstNode* initializing_getter = RunStaticFieldInitializer(field); |
| 6186 if (throw_exception != NULL) { | 6268 if (initializing_getter != NULL) { |
| 6187 return throw_exception; | 6269 // The field is not yet initialized and could not be initialized at compile |
| 6270 // time. The getter will initialize the field. |
| 6271 return initializing_getter; |
| 6188 } | 6272 } |
| 6189 // Access the field. | 6273 // The field is initialized. |
| 6190 if (field.is_final()) { | 6274 if (field.is_const()) { |
| 6275 ASSERT(field.value() != Object::sentinel()); |
| 6276 ASSERT(field.value() != Object::transition_sentinel()); |
| 6191 return new LiteralNode(ident_pos, Instance::ZoneHandle(field.value())); | 6277 return new LiteralNode(ident_pos, Instance::ZoneHandle(field.value())); |
| 6192 } else { | |
| 6193 return new LoadStaticFieldNode(ident_pos, | |
| 6194 Field::ZoneHandle(field.raw())); | |
| 6195 } | 6278 } |
| 6279 // Access the field directly. |
| 6280 return new LoadStaticFieldNode(ident_pos, Field::ZoneHandle(field.raw())); |
| 6196 } | 6281 } |
| 6197 | 6282 |
| 6198 | 6283 |
| 6199 AstNode* Parser::ParseStaticFieldAccess(const Class& cls, | 6284 AstNode* Parser::ParseStaticFieldAccess(const Class& cls, |
| 6200 const String& field_name, | 6285 const String& field_name, |
| 6201 intptr_t ident_pos) { | 6286 intptr_t ident_pos) { |
| 6202 TRACE_PARSER("ParseStaticFieldAccess"); | 6287 TRACE_PARSER("ParseStaticFieldAccess"); |
| 6203 AstNode* access = NULL; | 6288 AstNode* access = NULL; |
| 6204 const intptr_t call_pos = token_index_; | 6289 const intptr_t call_pos = token_index_; |
| 6205 const Field& field = Field::ZoneHandle(cls.LookupStaticField(field_name)); | 6290 const Field& field = Field::ZoneHandle(cls.LookupStaticField(field_name)); |
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6646 while (outer_function.IsLocalFunction()) { | 6731 while (outer_function.IsLocalFunction()) { |
| 6647 outer_function = outer_function.parent_function(); | 6732 outer_function = outer_function.parent_function(); |
| 6648 } | 6733 } |
| 6649 if (outer_function.IsFactory() || !outer_function.is_static()) { | 6734 if (outer_function.IsFactory() || !outer_function.is_static()) { |
| 6650 return current_class().NumTypeParameters() > 0; | 6735 return current_class().NumTypeParameters() > 0; |
| 6651 } | 6736 } |
| 6652 return false; | 6737 return false; |
| 6653 } | 6738 } |
| 6654 | 6739 |
| 6655 | 6740 |
| 6656 // Returns null on success. | 6741 // If the field is already initialized, return no ast (NULL). |
| 6657 // Returns a throw node if evaluation of the static initializer results in an | 6742 // Otherwise, if the field is constant, initialize the field and return no ast. |
| 6658 // unhandled exception. | 6743 // If the field is not initialized and not const, return the ast for the getter. |
| 6659 AstNode* Parser::RunStaticFieldInitializer(const Field& field) { | 6744 AstNode* Parser::RunStaticFieldInitializer(const Field& field) { |
| 6660 ASSERT(field.is_static()); | 6745 ASSERT(field.is_static()); |
| 6661 const Instance& value = Instance::Handle(field.value()); | 6746 const Instance& value = Instance::Handle(field.value()); |
| 6662 if (value.raw() == Object::transition_sentinel()) { | 6747 if (value.raw() == Object::transition_sentinel()) { |
| 6663 ErrorMsg("circular dependency while initializing static field '%s'", | 6748 if (field.is_const()) { |
| 6664 String::Handle(field.name()).ToCString()); | 6749 ErrorMsg("circular dependency while initializing static field '%s'", |
| 6665 | 6750 String::Handle(field.name()).ToCString()); |
| 6751 } else { |
| 6752 // The implicit static getter will throw the exception if necessary. |
| 6753 return new StaticGetterNode(token_index_, |
| 6754 Class::ZoneHandle(field.owner()), |
| 6755 String::ZoneHandle(field.name())); |
| 6756 } |
| 6666 } else if (value.raw() == Object::sentinel()) { | 6757 } else if (value.raw() == Object::sentinel()) { |
| 6667 // This field has not been referenced yet and thus the value has | 6758 // This field has not been referenced yet and thus the value has |
| 6668 // not been evaluated. Call the static getter method to evaluate | 6759 // not been evaluated. If the field is const, call the static getter method |
| 6669 // the expression and canonicalize the value. | 6760 // to evaluate the expression and canonicalize the value. |
| 6670 | 6761 if (field.is_const()) { |
| 6671 field.set_value(Instance::Handle(Object::transition_sentinel())); | 6762 field.set_value(Instance::Handle(Object::transition_sentinel())); |
| 6672 const String& field_name = String::Handle(field.name()); | 6763 const String& field_name = String::Handle(field.name()); |
| 6673 const String& getter_name = | 6764 const String& getter_name = |
| 6674 String::Handle(Field::GetterName(field_name)); | 6765 String::Handle(Field::GetterName(field_name)); |
| 6675 const Class& cls = Class::Handle(field.owner()); | 6766 const Class& cls = Class::Handle(field.owner()); |
| 6676 GrowableArray<const Object*> arguments; // no arguments. | 6767 GrowableArray<const Object*> arguments; // no arguments. |
| 6677 const int kNumArguments = 0; // no arguments. | 6768 const int kNumArguments = 0; // no arguments. |
| 6678 const Array& kNoArgumentNames = Array::Handle(); | 6769 const Array& kNoArgumentNames = Array::Handle(); |
| 6679 const Function& func = | 6770 const Function& func = |
| 6680 Function::Handle(Resolver::ResolveStatic(cls, | 6771 Function::Handle(Resolver::ResolveStatic(cls, |
| 6681 getter_name, | 6772 getter_name, |
| 6682 kNumArguments, | 6773 kNumArguments, |
| 6683 kNoArgumentNames, | 6774 kNoArgumentNames, |
| 6684 Resolver::kIsQualified)); | 6775 Resolver::kIsQualified)); |
| 6685 ASSERT(!func.IsNull()); | 6776 ASSERT(!func.IsNull()); |
| 6686 ASSERT(func.kind() == RawFunction::kConstImplicitGetter); | 6777 ASSERT(func.kind() == RawFunction::kConstImplicitGetter); |
| 6687 Object& const_value = Object::Handle( | 6778 Object& const_value = Object::Handle( |
| 6688 DartEntry::InvokeStatic(func, arguments, kNoArgumentNames)); | 6779 DartEntry::InvokeStatic(func, arguments, kNoArgumentNames)); |
| 6689 if (const_value.IsError()) { | 6780 if (const_value.IsError()) { |
| 6690 Error& error = Error::Handle(); | 6781 Error& error = Error::Handle(); |
| 6691 error ^= const_value.raw(); | 6782 error ^= const_value.raw(); |
| 6692 if (const_value.IsUnhandledException()) { | 6783 if (const_value.IsUnhandledException()) { |
| 6693 field.set_value(Instance::Handle()); | 6784 field.set_value(Instance::Handle()); |
| 6694 // It is a compile-time error if evaluation of a compile-time constant | 6785 // It is a compile-time error if evaluation of a compile-time constant |
| 6695 // would raise an exception. | 6786 // would raise an exception. |
| 6696 if (field.is_final()) { | |
| 6697 AppendErrorMsg(error, token_index_, | 6787 AppendErrorMsg(error, token_index_, |
| 6698 "error initializing final field '%s'", | 6788 "error initializing final field '%s'", |
| 6699 String::Handle(field.name()).ToCString()); | 6789 String::Handle(field.name()).ToCString()); |
| 6700 } else { | 6790 } else { |
| 6701 return GenerateRethrow(token_index_, const_value); | 6791 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 6702 } | 6792 } |
| 6703 } else { | |
| 6704 Isolate::Current()->long_jump_base()->Jump(1, error); | |
| 6705 } | 6793 } |
| 6794 ASSERT(const_value.IsNull() || const_value.IsInstance()); |
| 6795 Instance& instance = Instance::Handle(); |
| 6796 instance ^= const_value.raw(); |
| 6797 if (!instance.IsNull()) { |
| 6798 instance ^= instance.Canonicalize(); |
| 6799 } |
| 6800 field.set_value(instance); |
| 6801 } else { |
| 6802 return new StaticGetterNode(token_index_, |
| 6803 Class::ZoneHandle(field.owner()), |
| 6804 String::ZoneHandle(field.name())); |
| 6706 } | 6805 } |
| 6707 ASSERT(const_value.IsNull() || const_value.IsInstance()); | |
| 6708 Instance& instance = Instance::Handle(); | |
| 6709 instance ^= const_value.raw(); | |
| 6710 if (!instance.IsNull()) { | |
| 6711 instance ^= instance.Canonicalize(); | |
| 6712 } | |
| 6713 field.set_value(instance); | |
| 6714 } | 6806 } |
| 6715 return NULL; | 6807 return NULL; |
| 6716 } | 6808 } |
| 6717 | 6809 |
| 6718 | 6810 |
| 6719 RawObject* Parser::EvaluateConstConstructorCall( | 6811 RawObject* Parser::EvaluateConstConstructorCall( |
| 6720 const Class& type_class, | 6812 const Class& type_class, |
| 6721 const AbstractTypeArguments& type_arguments, | 6813 const AbstractTypeArguments& type_arguments, |
| 6722 const Function& constructor, | 6814 const Function& constructor, |
| 6723 ArgumentListNode* arguments) { | 6815 ArgumentListNode* arguments) { |
| (...skipping 1538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8262 void Parser::SkipQualIdent() { | 8354 void Parser::SkipQualIdent() { |
| 8263 ASSERT(IsIdentifier()); | 8355 ASSERT(IsIdentifier()); |
| 8264 ConsumeToken(); | 8356 ConsumeToken(); |
| 8265 if (CurrentToken() == Token::kPERIOD) { | 8357 if (CurrentToken() == Token::kPERIOD) { |
| 8266 ConsumeToken(); // Consume the kPERIOD token. | 8358 ConsumeToken(); // Consume the kPERIOD token. |
| 8267 ExpectIdentifier("identifier expected after '.'"); | 8359 ExpectIdentifier("identifier expected after '.'"); |
| 8268 } | 8360 } |
| 8269 } | 8361 } |
| 8270 | 8362 |
| 8271 } // namespace dart | 8363 } // namespace dart |
| OLD | NEW |