Chromium Code Reviews| Index: runtime/vm/parser.cc |
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc |
| index a966b40a639cb4b29aff9cba5fcb7ee7b033ca80..348a47f1815e078c5616dac8fa67247909c49274 100644 |
| --- a/runtime/vm/parser.cc |
| +++ b/runtime/vm/parser.cc |
| @@ -38,15 +38,17 @@ |
| namespace dart { |
| DEFINE_FLAG(bool, enable_debug_break, false, "Allow use of break \"message\"."); |
| +DEFINE_FLAG(bool, enable_mirrors, true, |
| + "Disable to make importing dart:mirrors an error."); |
| DEFINE_FLAG(bool, load_deferred_eagerly, false, |
| "Load deferred libraries eagerly."); |
| DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); |
| DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef."); |
| + |
| +DECLARE_FLAG(bool, lazy_dispatchers); |
| +DECLARE_FLAG(bool, load_deferred_eagerly); |
| DECLARE_FLAG(bool, throw_on_javascript_int_overflow); |
| DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
| -DEFINE_FLAG(bool, enable_mirrors, true, |
| - "Disable to make importing dart:mirrors an error."); |
| -DECLARE_FLAG(bool, lazy_dispatchers); |
| // Quick access to the current isolate and zone. |
| #define I (isolate()) |
| @@ -172,6 +174,9 @@ void ParsedFunction::SetRegExpCompileData( |
| void ParsedFunction::AddDeferredPrefix(const LibraryPrefix& prefix) { |
| + // 'deferred_prefixes_' are used to invalidate code, but no invalidation is |
| + // needed if --load_deferred_eagerly. |
| + ASSERT(!FLAG_load_deferred_eagerly); |
| ASSERT(prefix.is_deferred_load()); |
| ASSERT(!prefix.is_loaded()); |
| for (intptr_t i = 0; i < deferred_prefixes_->length(); i++) { |
| @@ -10038,8 +10043,19 @@ SequenceNode* Parser::NodeAsSequenceNode(intptr_t sequence_pos, |
| } |
| -AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type) { |
| +// Call _throwNewIfNotLoaded if prefix is not NULL, otherwise call _throwNew. |
| +AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type, |
| + LibraryPrefix* prefix) { |
| ArgumentListNode* arguments = new(Z) ArgumentListNode(type_pos); |
| + |
| + String& method_name = String::Handle(); |
|
hausner
2015/07/09 17:10:05
String::Handle(Z);
srdjan
2015/07/09 17:31:19
Done.
|
| + if (prefix == NULL) { |
| + method_name = Library::PrivateCoreLibName(Symbols::ThrowNew()).raw(); |
| + } else { |
| + arguments->Add(new(Z) LiteralNode(type_pos, *prefix)); |
| + method_name = Library::PrivateCoreLibName( |
| + Symbols::ThrowNewIfNotLoaded()).raw(); |
| + } |
| // Location argument. |
| arguments->Add(new(Z) LiteralNode( |
| type_pos, Integer::ZoneHandle(Z, Integer::New(type_pos)))); |
| @@ -10054,20 +10070,29 @@ AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type) { |
| ASSERT(!error.IsNull()); |
| arguments->Add(new(Z) LiteralNode(type_pos, String::ZoneHandle(Z, |
| Symbols::New(error.ToErrorCString())))); |
| - return MakeStaticCall(Symbols::TypeError(), |
| - Library::PrivateCoreLibName(Symbols::ThrowNew()), |
| - arguments); |
| + return MakeStaticCall(Symbols::TypeError(), method_name, arguments); |
| } |
| +// Call _throwNewIfNotLoaded if prefix is not NULL, otherwise call _throwNew. |
| AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos, |
| const Class& cls, |
| const String& function_name, |
| ArgumentListNode* function_arguments, |
| InvocationMirror::Call im_call, |
| InvocationMirror::Type im_type, |
| - const Function* func) { |
| + const Function* func, |
| + const LibraryPrefix* prefix) { |
| ArgumentListNode* arguments = new(Z) ArgumentListNode(call_pos); |
| + |
| + String& method_name = String::Handle(); |
|
hausner
2015/07/09 17:10:05
String::Handle(Z);
srdjan
2015/07/09 17:31:19
Done.
|
| + if (prefix == NULL) { |
| + method_name = Library::PrivateCoreLibName(Symbols::ThrowNew()).raw(); |
| + } else { |
| + arguments->Add(new(Z) LiteralNode(call_pos, *prefix)); |
| + method_name = Library::PrivateCoreLibName( |
| + Symbols::ThrowNewIfNotLoaded()).raw(); |
| + } |
| // Object receiver. |
| // If the function is external and dynamic, pass the actual receiver, |
| // otherwise, pass a class literal of the unresolved method's owner. |
| @@ -10140,9 +10165,7 @@ AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos, |
| } |
| arguments->Add(new(Z) LiteralNode(call_pos, array)); |
| - return MakeStaticCall(Symbols::NoSuchMethodError(), |
| - Library::PrivateCoreLibName(Symbols::ThrowNew()), |
| - arguments); |
| + return MakeStaticCall(Symbols::NoSuchMethodError(), method_name, arguments); |
| } |
| @@ -11816,7 +11839,7 @@ AstNode* Parser::ResolveIdentInPrefixScope(intptr_t ident_pos, |
| return NULL; |
| } |
| Object& obj = Object::Handle(Z); |
| - if (prefix.is_loaded()) { |
| + if (prefix.is_loaded() || FLAG_load_deferred_eagerly) { |
| obj = prefix.LookupObject(ident); |
| } else { |
| // Remember that this function depends on an import prefix of an |
| @@ -11952,16 +11975,26 @@ AstNode* Parser::ResolveIdent(intptr_t ident_pos, |
| } |
| -// Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and |
| -// finalize it according to the given type finalization mode. |
| RawAbstractType* Parser::ParseType( |
| ClassFinalizer::FinalizationKind finalization, |
| bool allow_deferred_type, |
| bool consume_unresolved_prefix) { |
| TRACE_PARSER("ParseType"); |
| + LibraryPrefix& prefix = LibraryPrefix::Handle(Z); |
| + return ParseTypePrefix(finalization, allow_deferred_type, |
| + consume_unresolved_prefix, &prefix); |
| +} |
| + |
| +// Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and |
| +// finalize it according to the given type finalization mode. Returns prefix. |
| +RawAbstractType* Parser::ParseTypePrefix( |
|
hausner
2015/07/09 17:10:05
The name ParseTypePrefix confused me at first. It
srdjan
2015/07/09 17:31:19
Done.
|
| + ClassFinalizer::FinalizationKind finalization, |
| + bool allow_deferred_type, |
| + bool consume_unresolved_prefix, |
| + LibraryPrefix* prefix) { |
| + TRACE_PARSER("ParseTypePrefix"); |
| CheckToken(Token::kIDENT, "type name expected"); |
| intptr_t ident_pos = TokenPos(); |
| - LibraryPrefix& prefix = LibraryPrefix::Handle(Z); |
| String& type_name = String::Handle(Z); |
| if (finalization == ClassFinalizer::kIgnore) { |
| @@ -11972,7 +12005,7 @@ RawAbstractType* Parser::ParseType( |
| } |
| SkipQualIdent(); |
| } else { |
| - prefix = ParsePrefix(); |
| + *prefix = ParsePrefix(); |
| type_name = CurrentLiteral()->raw(); |
| ConsumeToken(); |
| @@ -11982,7 +12015,7 @@ RawAbstractType* Parser::ParseType( |
| // a period and another identifier, consume the qualified identifier |
| // and create a malformed type. |
| if (consume_unresolved_prefix && |
| - prefix.IsNull() && |
| + prefix->IsNull() && |
| (CurrentToken() == Token::kPERIOD) && |
| (Token::IsIdentifier(LookaheadToken(1)))) { |
| if (!is_top_level_ && (current_block_ != NULL)) { |
| @@ -12009,7 +12042,7 @@ RawAbstractType* Parser::ParseType( |
| // If parsing inside a local scope, check whether the type name |
| // is shadowed by a local declaration. |
| if (!is_top_level_ && |
| - (prefix.IsNull()) && |
| + (prefix->IsNull()) && |
| ResolveIdentInLocalScope(ident_pos, type_name, NULL)) { |
| // The type is malformed. Skip over its type arguments. |
| ParseTypeArguments(ClassFinalizer::kIgnore); |
| @@ -12020,29 +12053,30 @@ RawAbstractType* Parser::ParseType( |
| "using '%s' in this context is invalid", |
| type_name.ToCString()); |
| } |
| - if (!prefix.IsNull() && prefix.is_deferred_load()) { |
| + if (!FLAG_load_deferred_eagerly && |
| + !prefix->IsNull() && prefix->is_deferred_load()) { |
| // If deferred prefixes are allowed but it is not yet loaded, |
| // remember that this function depends on the prefix. |
| - if (allow_deferred_type && !prefix.is_loaded()) { |
| + if (allow_deferred_type && !prefix->is_loaded()) { |
| if (parsed_function() != NULL) { |
| - parsed_function()->AddDeferredPrefix(prefix); |
| + parsed_function()->AddDeferredPrefix(*prefix); |
| } |
| } |
| // If the deferred prefixes are not allowed, or if the prefix is not yet |
| // loaded when finalization is requested, return a malformed type. |
| // Otherwise, handle resolution below, as needed. |
| if (!allow_deferred_type || |
| - (!prefix.is_loaded() |
| + (!prefix->is_loaded() |
| && (finalization > ClassFinalizer::kResolveTypeParameters))) { |
| ParseTypeArguments(ClassFinalizer::kIgnore); |
| return ClassFinalizer::NewFinalizedMalformedType( |
| Error::Handle(Z), // No previous error. |
| script_, |
| ident_pos, |
| - !prefix.is_loaded() |
| + !prefix->is_loaded() |
| ? "deferred type '%s.%s' is not yet loaded" |
| : "using deferred type '%s.%s' is invalid", |
| - String::Handle(Z, prefix.name()).ToCString(), |
| + String::Handle(Z, prefix->name()).ToCString(), |
| type_name.ToCString()); |
| } |
| } |
| @@ -12050,7 +12084,7 @@ RawAbstractType* Parser::ParseType( |
| Object& type_class = Object::Handle(Z); |
| // Leave type_class as null if type finalization mode is kIgnore. |
| if (finalization != ClassFinalizer::kIgnore) { |
| - type_class = UnresolvedClass::New(prefix, type_name, ident_pos); |
| + type_class = UnresolvedClass::New(*prefix, type_name, ident_pos); |
| } |
| TypeArguments& type_arguments = TypeArguments::Handle( |
| Z, ParseTypeArguments(finalization)); |
| @@ -12599,10 +12633,28 @@ AstNode* Parser::ParseNewOperator(Token::Kind op_kind) { |
| const bool allow_deferred_type = !is_const; |
| const bool consume_unresolved_prefix = (LookaheadToken(3) == Token::kLT) || |
| (LookaheadToken(3) == Token::kPERIOD); |
| + LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z); |
| AbstractType& type = AbstractType::Handle(Z, |
| - ParseType(ClassFinalizer::kCanonicalizeWellFormed, |
| - allow_deferred_type, |
| - consume_unresolved_prefix)); |
| + ParseTypePrefix(ClassFinalizer::kCanonicalizeWellFormed, |
| + allow_deferred_type, |
| + consume_unresolved_prefix, |
| + &prefix)); |
| + if (FLAG_load_deferred_eagerly && |
| + !prefix.IsNull() && prefix.is_deferred_load() && !prefix.is_loaded()) { |
| + // Add runtime check. |
| + Type& malformed_type = Type::Handle(Z); |
| + malformed_type = ClassFinalizer::NewFinalizedMalformedType( |
| + Error::Handle(Z), // No previous error. |
| + script_, |
| + type_pos, |
| + "deferred type '%s.%s' is not yet loaded", |
| + String::Handle(Z, prefix.name()).ToCString(), |
| + String::Handle(type.Name()).ToCString()); |
| + // Note: Adding a statement to current block is a hack, parsing an |
| + // expression should have no side-effect. |
| + current_block_->statements->Add( |
| + ThrowTypeError(type_pos, malformed_type, &prefix)); |
| + } |
| // In case the type is malformed, throw a dynamic type error after finishing |
| // parsing the instance creation expression. |
| if (!type.IsMalformed() && (type.IsTypeParameter() || type.IsDynamicType())) { |
| @@ -13083,6 +13135,26 @@ AstNode* Parser::ParsePrimary() { |
| call_type, |
| NULL); // No existing function. |
| } |
| + } else if (FLAG_load_deferred_eagerly && prefix.is_deferred_load()) { |
| + // primary != NULL. |
| + String& qualified_name = String::ZoneHandle(Z, prefix.name()); |
| + qualified_name = String::Concat(qualified_name, Symbols::Dot()); |
| + qualified_name = String::Concat(qualified_name, ident); |
| + qualified_name = Symbols::New(qualified_name); |
| + InvocationMirror::Type call_type = |
| + CurrentToken() == Token::kLPAREN ? |
| + InvocationMirror::kMethod : InvocationMirror::kGetter; |
| + // Note: Adding a statement to current block is a hack, parsing an |
| + // espression should have no side-effect. |
| + current_block_->statements->Add(ThrowNoSuchMethodError( |
| + qual_ident_pos, |
| + current_class(), |
| + qualified_name, |
| + NULL, // No arguments. |
| + InvocationMirror::kTopLevel, |
| + call_type, |
| + NULL, // No existing function. |
| + &prefix)); |
| } |
| } |
| ASSERT(primary != NULL); |