Merge commit '5d7786948cca6b292f6d26313f745e786a910761' into analyzer-0.33
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 928d788..bf899ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,18 @@
#### Pub
+#### Linter
+
+The linter was bumped to `0.1.73` which introduces the following new lints to the SDK:
+
+* `unnecessary_await_in_return`
+* `use_function_type_syntax_for_parameters`
+* `avoid_returning_null_for_future`
+* `avoid_shadowing_type_parameters`
+
+In addition, `prefer_bool_in_asserts` has been deprecated as its semantics are
+redundant with Dart 2 checks.
+
#### Other Tools
## 2.2.0-dev.0.0
@@ -24,6 +36,11 @@
for testing and it is no longer supported. `--categories=Server` continues to
work at this time but it is deprecated, please use `--server-mode` instead.
+* The `--library-root` flag was replaced by `--libraries-spec`. This flag is
+ rarely used by developers invoking dart2js directly. It's important for
+ integrating dart2js with build systems. See `--help` for more details on the
+ new flag.
+
## 2.1.0 - 2018-11-15
This is a minor version release. The team's focus was mostly on improving
diff --git a/DEPS b/DEPS
index 965d284..bccc28f 100644
--- a/DEPS
+++ b/DEPS
@@ -36,7 +36,7 @@
"chromium_git": "https://chromium.googlesource.com",
"fuchsia_git": "https://fuchsia.googlesource.com",
- "co19_2_rev": "740cb9e9b3fc8e1da2f55e10554ffeac90461b73",
+ "co19_2_rev": "92eb86a60b26089eaffc4fa9703895f71a251a76",
# As Flutter does, we pull buildtools, including the clang toolchain, from
# Fuchsia. This revision should be kept up to date with the revision pulled
@@ -63,7 +63,7 @@
"convert_tag": "2.0.2",
"crypto_tag" : "2.0.6",
"csslib_tag" : "0.14.4+1",
- "dart2js_info_tag" : "0.5.13",
+ "dart2js_info_tag" : "0.5.15",
# Note: updates to dart_style have to be coordinated carefully with
# the infrastructure-team so that the internal formatter in
@@ -95,7 +95,7 @@
"intl_tag": "0.15.7",
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_tag": "2.0.9",
- "linter_tag": "0.1.71",
+ "linter_tag": "0.1.73",
"logging_tag": "0.11.3+2",
"markdown_tag": "2.0.2",
"matcher_tag": "0.12.3",
diff --git a/WATCHLISTS b/WATCHLISTS
index aefd0f2..598f0ab 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -66,7 +66,7 @@
'filepath': '^runtime/',
},
'vm_compiler': {
- 'filepath': '^runtime/compiler/',
+ 'filepath': '^runtime/(vm|docs)/compiler/',
},
},
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 8025521..4bdcda6 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -261,12 +261,12 @@
cflags += [ "-fcolor-diagnostics" ]
}
- # C++14 compiler flags setup.
+ # C++11 compiler flags setup.
# ---------------------------
if (is_win) {
- cc_std = [ "/std:c++14" ]
+ cc_std = [ "/std:c++11" ]
} else {
- cc_std = [ "-std=c++14" ]
+ cc_std = [ "-std=c++11" ]
}
cflags_cc += cc_std
cflags_objcc += cc_std
diff --git a/docs/language/dart.sty b/docs/language/dart.sty
index 0aede6b..90fcab4 100644
--- a/docs/language/dart.sty
+++ b/docs/language/dart.sty
@@ -84,11 +84,20 @@
\newcommand{\argumentList}[1]{\metavar{{#1}s}}
\newcommand{\parameterList}[1]{\metavar{{#1}s}}
-\newenvironment{Q}[1]{{\bf #1}}{}
-\newenvironment{rationale}[1]{{\it #1}}{}
-\newenvironment{commentary}[1]{{\sf #1}}{}
+% Colors used for for different kinds of text.
+\definecolor{normativeColor}{rgb}{0,0,0}
+\definecolor{commentaryColor}{rgb}{0.6,0.6,0.6}
+\definecolor{rationaleColor}{rgb}{0.6,0.6,0.6}
+% Environments for different kinds of text.
+\newenvironment{Q}[1]{{\bf #1}}{}
+\newenvironment{rationale}[1]{{\color{rationaleColor}\it{#1}}}{}
+\newenvironment{commentary}[1]{{\color{commentaryColor}\sf{#1}}}{}
+
+% Auxiliary functions.
\newcommand{\flatten}[1]{\ensuremath{\mbox{\it flatten}({#1})}}
+\newcommand{\overrides}[1]{\ensuremath{\mbox{\it overrides}({#1})}}
+\newcommand{\inherited}[1]{\ensuremath{\mbox{\it inherited}({#1})}}
% Used as a mini-section marker, indicating visibly that a range of
% text (usually just a couple of paragraphs) are concerned with one
@@ -100,9 +109,17 @@
\def\@programcr{\@addfield\strut}%
\let\\=\@programcr%
\relax\@vobeyspaces\obeylines%
- \ttfamily%
+ \ttfamily\color{commentaryColor}%
\vspace{1em}
-}{\vspace{1em}}
+}{\normalcolor\vspace{1em}}
+
+\newenvironment{normativeDartCode}[1][!ht] {
+ \def\@programcr{\@addfield\strut}%
+ \let\\=\@programcr%
+ \relax\@vobeyspaces\obeylines%
+ \ttfamily\color{normativeColor}%
+ \vspace{1em}
+}{\normalcolor\vspace{1em}}
% Used for comments in a code context.
\def\comment#1{\textsf{#1}}
@@ -121,6 +138,103 @@
\newcommand{\NoIndex}[1]{
\leavevmode\marginpar{\ensuremath{\diamond}}\emph{#1}}
+% Used to specify comma separated lists of similar symbols.
+\newcommand{\List}[3]{\ensuremath{{#1}_{#2},\,\ldots,\ {#1}_{#3}}}
+
+% Used to specify comma separated lists of pairs of similar symbols,
+% as needed, e.g., for declarations of formal parameters.
+% Parameters: Name of first part of pair, name of second part,
+% index at start, index at end.
+\newcommand{\PairList}[4]{\ensuremath{%
+ {#1}_{#3}\ {#2}_{#3},\,\ldots,\ {#1}_{#4}\ {#2}_{#4}}}
+
+% Used to specify comma separated lists of triples of similar symbols,
+% as needed, e.g., for declarations of formal parameters with defaults.
+% Parameters: Name of first part of triple, name of second part,
+% name of third part, index at start, index at end.
+\newcommand{\TripleList}[5]{\ensuremath{%
+ {#1}_{#4}\ {#2}_{#4}\ {#3}_{#4},\,\ldots,\ {#1}_{#5}\ {#2}_{#5}\ {#3}_{#5}}}
+
+% Used to abbreviate \EXTENDS{} in function types.
+\newcommand{\FunctionTypeExtends}{\ensuremath{\triangleleft}}
+
+% Used to specify comma separated lists of pairs of symbols
+% separated by \EXTENDS{}, as needed for type parameter declarations.
+% Parameters: Type parameter name, bound name, number of type parameters.
+\newcommand{\TypeParameters}[3]{\ensuremath{%
+ {#1}_1\,\EXTENDS\,{#2}_1,\,\ldots,\ %
+ {#1}_{#3}\,\EXTENDS\,{#2}_{#3}}}
+
+% For consistency, we may as well use this whenever possible.
+\newcommand{\TypeParametersStd}{\TypeParameters{X}{B}{s}}
+
+% Used to specify comma separated lists of pairs of symbols
+% separated by \EXTENDS{}, as needed for type parameter declarations.
+% Parameters: Type parameter name, bound name, number of type parameters.
+\newcommand{\FTTypeParameters}[3]{\ensuremath{%
+ {#1}_1\FunctionTypeExtends{#2}_1,\,\ldots,\ %
+ {#1}_{#3}\FunctionTypeExtends{#2}_{#3}}}
+
+% Used to specify function types: Same syntax as in source.
+% Arguments: Return type, formal parameter declarations.
+\newcommand{\FunctionTypeSimple}[2]{\code{\ensuremath{#1}\ \FUNCTION({#2})}}
+
+% Used to specify function types: Same syntax as in source.
+% Arguments: Return type, spacer, type parameter name, bound name,
+% number of type parameters, formal parameter declarations.
+\newcommand{\FunctionType}[6]{\leavevmode\par\noindent\code{%
+ \ensuremath{#1}{#2}\FUNCTION<\FTTypeParameters{#3}{#4}{#5}>({#6})}}
+
+% Used to specify function types with positional optionals:
+% Arguments: Return type, spacer, type parameter name, bound name,
+% number of type parameters, parameter type, number of required parameters,
+% number of optional parameters.
+\newcommand{\FunctionTypePositional}[8]{%
+ \FunctionType{#1}{#2}{#3}{#4}{#5}{\List{#6}{1}{#7},\ %
+ [\List{#6}{{#7}+1}{{#7}+{#8}}]}}
+
+% Used to specify function types with named parameters:
+% Arguments: Return type, spacer, type parameter name, bound name,
+% number of type parameters, parameter type, number of required parameters,
+% name of optional parameters, number of optional parameters.
+\newcommand{\FunctionTypeNamed}[9]{%
+ \FunctionType{#1}{#2}{#3}{#4}{#5}{\List{#6}{1}{#7},\ %
+ \{\PairList{#6}{#8}{{#7}+1}{{#7}+{#9}}\}}}
+
+% Used to specify function types with no optional parameters:
+% Arguments: Return type, spacer, type parameter name, bound name,
+% number of type parameters, parameter type,
+% number of parameters (all required).
+\newcommand{\FunctionTypeAllRequired}[7]{%
+ \FunctionType{#1}{#2}{#3}{#4}{#5}{\List{#6}{1}{#7}}}
+
+\newcommand{\FunctionTypePositionalStd}[1]{%
+ \FunctionTypePositional{#1}{ }{X}{B}{s}{T}{n}{k}}
+
+\newcommand{\FunctionTypeNamedStd}[1]{%
+ \FunctionTypeNamed{#1}{ }{X}{B}{s}{T}{n}{x}{k}}
+
+\newcommand{\FunctionTypeAllRequiredStd}[1]{%
+ \FunctionTypeAllRequired{#1}{ }{X}{B}{s}{T}{n}}
+
+\newcommand{\FunctionTypePositionalStdCr}[1]{%
+ \FunctionTypePositional{#1}{\\}{X}{B}{s}{T}{n}{k}}
+
+\newcommand{\FunctionTypeNamedStdCr}[1]{%
+ \FunctionTypeNamed{#1}{\\}{X}{B}{s}{T}{n}{x}{k}}
+
+\newcommand{\FunctionTypeAllRequiredStdCr}[1]{%
+ \FunctionTypeAllRequired{#1}{\\}{X}{B}{s}{T}{n}}
+
+\newcommand{\MoreSignatureSpecificSymbol}{\ensuremath{\preceq}}
+\newcommand{\NotMoreSignatureSpecificSymbol}{\ensuremath{\not\preceq}}
+\newcommand{\LessSignatureSpecificSymbol}{\ensuremath{\succeq}}
+
+\newcommand{\MoreSignatureSpecific}[2]{%
+ \ensuremath{{#1}\MoreSignatureSpecificSymbol{#2}}}
+\newcommand{\NotMoreSignatureSpecific}[2]{%
+ \ensuremath{{#1}\NotMoreSignatureSpecificSymbol{#2}}}
+
% ----------------------------------------------------------------------
% Support for hash valued Location Markers
@@ -140,7 +254,8 @@
% insert location marker showing hash value of following paragraph
\newcommand{\LMHash}[1]{\leavevmode\marginpar{\quad%
- \raisebox{0.5ex}{\miniscule{\color{LMdim}#1}}\vspace{-2\baselineskip}}}
+ \raisebox{0.5ex}{\miniscule{\color{LMdim}#1}}\vspace{-2\baselineskip}}%
+ \color{normativeColor}}
% support convenient renewcommand
\let\OriginalLMHash\LMHash
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index ecc249e..ffc6d8e 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -1,12 +1,13 @@
\documentclass[makeidx]{article}
\usepackage{xspace}
\usepackage{epsfig}
-\usepackage{color}
+\usepackage{xcolor}
\usepackage{syntax}
\usepackage{dart}
\usepackage{hyperref}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
+\usepackage[fleqn]{amsmath}
\usepackage{makeidx}
\makeindex
\title{Dart Programming Language Specification\\
@@ -73,6 +74,18 @@
% - Specify that super-bounded generic type alias applications must trigger
% a well-boundedness check on all types occurring in the denoted type.
% - Corrected corner case of rules for generation of noSuchMethod forwarders.
+% - Integrate feature specification on parameters that are
+% covariant-by-declaration.
+% - Integrate feature specification on parameters that are
+% covariant-by-class.
+% - Correct section 'Type of a function', allowing for adjustments needed
+% for rules related to covariant parameters.
+% - Specified the dynamic type of function objects in several contexts, such
+% that the special treatment of covariant parameters can be mentioned.
+% - Specified what it means for an override relation to be correct, thus
+% adding the parts that are not captured by a function type subtype check.
+% - Introduced the notion of member signatures, specified that they are the
+% kind of entity that a class interface contains.
%
% 2.0
% - Don't allow functions as assert test values.
@@ -287,7 +300,7 @@
An example would be:
}
-\begin{grammar}
+\begin{grammar}\color{commentaryColor}
<aProduction> ::= <anAlternative>
\alt <anotherAlternative>
\alt <oneThing> <after> <another>
@@ -710,7 +723,7 @@
\begin{grammar}
<variableDeclaration> ::= <declaredIdentifier> (`,' <identifier>)*
-<declaredIdentifier> ::= <metadata> <finalConstVarOrType> <identifier>
+<declaredIdentifier> ::= <metadata> \COVARIANT{}? <finalConstVarOrType> <identifier>
<finalConstVarOrType> ::= \FINAL{} <type>?
\alt \CONST{} <type>?
@@ -728,17 +741,14 @@
\end{grammar}
\LMHash{}%
-A variable declaration that contains one or more terms of the form
-\syntax{<identifier>}
-(\commentary{i.e., a declaration that declares two or more variables})
+A \synt{variableDeclaration} that declares two or more variables
is equivalent to multiple variable declarations declaring
the same set of variable names in the same order,
with the same type and modifiers.
\LMHash{}%
-An \syntax{<initializedVariableDeclaration>} that contains one or more terms of the form
-\syntax{<initializedIdentifier>}
-(\commentary{that is, a declaration that declares two or more initialized variables})
+An \synt{initializedVariableDeclaration}
+that declares two or more variables
is equivalent to multiple variable declarations declaring
the same set of variable names, in the same order,
with the same initialization, type, and modifiers.
@@ -755,6 +765,14 @@
}
\LMHash{}%
+It is possible for a variable declaration to include the modifier \COVARIANT{}.
+The effect of doing this with an instance variable is described elsewhere
+(\ref{instanceVariables}).
+It is a compile-time error for the declaration of
+a variable which is not an instance variable
+to include the modifier \COVARIANT{}.
+
+\LMHash{}%
In a variable declaration of one of the forms
\code{$N$ $v$;}
\code{$N$ $v$ = $e$;}
@@ -769,7 +787,7 @@
\commentary{
In an expression of the form \code{$e$.\id} it is possible that
$e$ has static type \DYNAMIC{} and \id{} cannot be associated with
-any declaration named \id{} at compile-time,
+any specific declaration named \id{} at compile-time,
but in this situation \id{} is still a referencing identifier.
}
@@ -813,7 +831,8 @@
%% then we treat `var x;` as if it had been `T x;`.
\LMHash{}%
-The following rules apply to all static and instance variables.
+The following rules on implicitly induced getters and setters
+apply to all static and instance variables.
\LMHash{}%
A variable declaration of one of the forms
@@ -1259,8 +1278,8 @@
<functionFormalParameter> ::= \gnewline{}
<metadata> \COVARIANT{}? <returnType>? <identifier> <formalParameterPart>
-<simpleFormalParameter> ::= \gnewline{}
- <metadata> \COVARIANT{}? <finalConstVarOrType>? <identifier>
+<simpleFormalParameter> ::= <declaredIdentifier>
+ \alt <metadata> \COVARIANT{}? <identifier>
<fieldFormalParameter> ::= \gnewline{}
<metadata> <finalConstVarOrType>? \THIS{} `.' <identifier> \gnewline{}
@@ -1268,12 +1287,15 @@
\end{grammar}
\LMHash{}%
-It is possible to include the modifier \COVARIANT{} in some forms of parameter declarations.
-This modifier has no effect.
+It is possible to include the modifier \COVARIANT{}
+in some forms of parameter declarations.
+The effect of doing this is described in a separate section
+(\ref{covariantParameters}).
-\rationale{
-The modifier \COVARIANT{} is used in strong mode.
-The modifier is allowed here even though it has no effect, such that source code can be used in both contexts.
+\commentary{
+Note that the non-terminal \synt{normalFormalParameter} is also used
+in the grammar rules for optional parameters,
+which means that such parameters can also be covariant.
}
\LMHash{}%
@@ -1314,72 +1336,281 @@
}
+\subsubsection{Covariant Parameters}
+\LMLabel{covariantParameters}
+
+\LMHash{}%
+Dart allows formal parameters of instance methods,
+including setters and operators,
+to be declared \COVARIANT{}.
+\commentary{
+The syntax for doing this is specified in an earlier section (\ref{requiredFormals}).
+}
+
+\LMHash{}%
+It is a compile-time error if the modifier \COVARIANT{} occurs
+in the declaration of a formal parameter of a function
+which is not an instance method, an instance setter, or an operator.
+
+\commentary{
+As specified below, a parameter can also be covariant for other reasons.
+The overall effect of having a covariant parameter $p$
+in the signature of a given method $m$
+is to allow the type of $p$ to be overridden covariantly,
+which means that the type required at run time for a given actual argument
+may be a proper subtype of the type which is known at compile time
+at the call site.
+}
+
+\rationale{
+This mechanism allows developers to explicitly request that
+a compile-time guarantee which is otherwise supported
+(namely: that an actual argument whose static type satisfies the requirement
+will also do so at run time)
+is replaced by dynamic type checks.
+In return for accepting these dynamic type checks,
+developers can use covariant parameters to express software designs
+where the dynamic type checks are known (or at least trusted) to succeed,
+based on reasoning that the static type analysis does not capture.
+}
+
+\LMHash{}%
+Let $m$ be a method signature with formal type parameters
+\List{X}{1}{s},
+positional formal parameters \List{p}{1}{n},
+and named formal parameters \List{q}{1}{k}.
+Let $m'$ be a method signature with formal type parameters
+\List{X'\!}{1}{s},
+positional formal parameters \List{p'\!}{1}{n'},
+and named formal parameters \List{q'\!}{1}{k'}.
+%
+Assume that $j \in 1 .. n'$, and $j \leq n$;
+we say that $p'_j$ is the parameter in $m'$ that
+\IndexCustom{corresponds}{parameter corresponds to parameter}
+to the formal parameter $p_j$ in $m$.
+Assume that $j \in 1 .. k'$ and $l \in 1 .. k$;
+we say that $q'_j$ is the parameter in $m'$ that
+\NoIndex{corresponds} to the formal parameter
+$q_l$ in $m$ if $q'_j = q_l$.
+%
+Similarly, we say that the formal type parameter
+$X'_j$ from $m'$
+\NoIndex{corresponds} to the formal type parameter
+$X_j$ from $m$, for all $j \in 1 .. s$.
+
+\commentary{
+This includes the case where $m$ respectively $m'$ has
+optional positional parameters,
+in which case $k = 0$ respectively $k' = 0$ must hold,
+but we can have $n \not= n'$.
+The case where the numbers of formal type parameters differ is not relevant.
+}
+
+% Being covariant is a property of a parameter of the interface of a class;
+% this means that we only talk about the originating keyword \COVARIANT{}
+% and the class that contains the relevant declaration when we detect for
+% the first time that a given parameter is covariant. From that point and on
+% it is "carried" along the subtype links associated with class interfaces,
+% such that we can get it inductively from an indirect superinterface just
+% by checking whether the direct superinterfaces "have" a method signature
+% with the relevant name and a corresponding parameter, and then checking
+% that parameter. The same approach is applicable for covariant-by-class.
+
+\LMHash{}%
+Let $C$ be a class that declares a method $m$ which has
+a parameter $p$ whose declaration has the modifier \COVARIANT{};
+in this case we say that the parameter $p$ is
+\IndexCustom{covariant-by-declaration}{parameter!covariant-by-declaration}.
+%
+In this case the interface of $C$ has the method signature $m$,
+and that signature has the parameter $p$;
+we also say that the parameter $p$ in this method signature is
+\NoIndex{covariant-by-declaration}.
+%
+Finally, the parameter $p$ of the method signature $m$
+of the interface of a class $C$ is
+\NoIndex{covariant-by-declaration}
+if a direct superinterface of $C$
+has an accessible method signature $m'$ with the same name as $m$,
+which has a parameter $p'$ that corresponds to $p$,
+such that $p'$ is covariant-by-declaration.
+
+\LMHash{}%
+Assume that $C$ is a generic class with formal type parameter declarations
+\code{$X_1\ \EXTENDS\ B_1 \ldots,\ X_s\ \EXTENDS\ B_s$},
+let $m$ be a declaration of an instance method in $C$
+(which can be a method, a setter, or an operator),
+let $p$ be a parameter declared by $m$, and
+let $T$ be the declared type of $p$.
+%
+The parameter $p$ is
+\IndexCustom{covariant-by-class}{parameter!covariant-by-class}
+if, for any $j \in 1 .. s$,
+$X_j$ occurs in a covariant or an invariant position in $T$.
+%
+In this case the interface of $C$ also has the method signature $m$,
+and that signature has the parameter $p$;
+we also say that the parameter $p$ in this method signature is
+\NoIndex{covariant-by-class}.
+Finally, the parameter $p$ of the method signature $m$
+of the interface of the class $C$ is
+\NoIndex{covariant-by-class}
+if a direct superinterface of $C$
+has an accessible method signature $m'$ with the same name as $m$,
+which has a parameter $p'$ that corresponds to $p$,
+such that $p'$ is covariant-by-class.
+
+\LMHash{}%
+A formal parameter $p$ is
+\IndexCustom{covariant}{parameter!covariant}
+if $p$ is covariant-by-declaration or $p$ is covariant-by-class.
+
+\commentary{
+It is possible for a parameter to be simultaneously
+covariant-by-declaration and covariant-by-class.
+Note that a parameter may be
+covariant-by-declaration or covariant-by-class
+based on a declaration in any direct or indirect superinterface,
+including any superclass:
+The definitions above propagate these properties
+to an interface from each of its direct superinterfaces,
+but they will in turn receive the property from their direct superinterfaces,
+and so on.
+}
+
+
\subsection{Type of a Function}
\LMLabel{typeOfAFunction}
\LMHash{}%
-If a function declaration does not declare a return type explicitly, its return type is \DYNAMIC{} (\ref{typeDynamic}),
-unless it is a constructor function, in which case its return type is the immediately enclosing class,
-or it is a setter or operator \code{[]=}, in which case its return type is \VOID{}.
+This section specifies the static type which is ascribed to
+the function denoted by a function declaration,
+and the dynamic type of the corresponding function object.
+
+\LMHash{}%
+In this specification,
+the notation used to denote the type of a function follows
+the syntax of the language, except that \EXTENDS{} is abbreviated to
+\FunctionTypeExtends.
+This means that every function type is of one of the forms
+\FunctionTypePositionalStd{T_0}
+\FunctionTypeNamedStd{T_0}
+
+\noindent
+where $T_0$ is the return type,
+$X_j$ are the formal type parameters with bounds $B_j$, $j \in 1 .. s$,
+$T_j$ are the formal parameter types for $j \in 1 .. n + k$.
+Non-generic function types are covered by the case $s = 0$,
+where the type parameter declaration list
+\code{<\ldots{}>}
+as a whole is omitted.
+%
+Similarly, the optional brackets \code{[]} and \code{\{\}} are omitted
+when there are no optional parameters.
+
+% We promise that the two forms always get the same treatment for k=0.
+\commentary{
+Both forms with optionals cover function types with no optionals when $k = 0$,
+and every rule in this specification is such that
+any of the two forms may be used without ambiguity
+to determine the treatment of function types with no optionals.
+}
+
+\LMHash{}%
+If a function declaration does not declare a return type explicitly,
+its return type is \DYNAMIC{} (\ref{typeDynamic}),
+unless it is a constructor,
+in which case it is not considered to have a return type,
+or it is a setter or operator \code{[]=},
+in which case its return type is \VOID{}.
\LMHash{}%
A function declaration may declare formal type parameters.
-The type of the function includes the names of the type parameters and their upper bounds.
+The type of the function includes the names of the type parameters
+and for each type parameter the upper bound,
+which is considered to be the built-in class \code{Object} if no bound is specified.
When consistent renaming of type parameters can make two function types identical,
they are considered to be the same type.
\commentary{
-It is convenient to include the type parameter names in function types because they are needed in order to express such things as relations among different type parameters, and F-bounds.
-However, we do not wish to distinguish two function types if they have the same structure and only differ in the choice of names.
+It is convenient to include the formal type parameter names in function types
+because they are needed in order to express such things as relations among
+different type parameters, F-bounds, and the types of formal parameters.
+However, we do not wish to distinguish between two function types if they have
+the same structure and only differ in the choice of names.
This treatment of names is also known as alpha-equivalence.
}
\LMHash{}%
In the following three paragraphs,
-if the number $m$ of formal type parameters is zero then the type parameter list in the function type should be omitted.
+if the number $m$ of formal type parameters is zero then
+the type parameter list in the function type is omitted.
\LMHash{}%
Let $F$ be a function with
-formal type parameters $X_1\ B_1, \ldots,\ X_m\ B_m$,
-required formal parameters $T_1\ p_1, \ldots,\ T_n\ p_n$,
-return type $T_0$
+type parameters \TypeParametersStd,
+required formal parameter types \List{T}{1}{n},
+return type $T_0$,
and no optional parameters.
-Then the type of $F$ is
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n$) $ \rightarrow T_0$}.
+Then the static type of $F$ is
+\FunctionTypeAllRequiredStd{T_0}.
\LMHash{}%
Let $F$ be a function with
-formal type parameters $X_1\ B_1, \ldots,\ X_m\ B_m$,
-required formal parameters $T_1\ p_1, \ldots,\ T_n\ p_n$,
+type parameters \TypeParametersStd,
+required formal parameter types \List{T}{1}{n},
return type $T_0$
-and positional optional parameters $T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}$.
-Then the type of $F$ is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}$]) $ \rightarrow T_0$}.
+and positional optional parameter types \List{T}{n+1}{n+k}.
+Then the static type of $F$ is
+\FunctionTypePositionalStd{T_0}.
\LMHash{}%
Let $F$ be a function with
-formal type parameters $X_1\ B_1, \ldots,\ X_m\ B_m$,
-required formal parameters $T_1\ p_1, \ldots,\ T_n\ p_n$,
-return type $T_0$
-and named optional parameters $T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}$.
-Then the type of $F$ is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}$\}) $ \rightarrow T_0$}.
+type parameters \TypeParametersStd,
+required formal parameter types \List{T}{1}{n},
+return type $T_0$,
+and named parameters \PairList{T}{x}{n+1}{n+k}.
+Then the static type of $F$ is
+\FunctionTypeNamedStd{T_0}.
\LMHash{}%
-The run-time type of a function object always implements the class \FUNCTION{}.
-
+Let $T$ be the static type of a function declaration $F$.
+Let $u$ be the run-time type of a function object $o$ obtained by
+function closurization
+(\ref{functionClosurization})
+or instance method closurization
+(\ref{ordinaryMemberClosurization})
+applied to $F$,
+and let $t$ be the actual type corresponding to $T$
+at the occasion where $o$ was created
+(\ref{actualTypeOfADeclaration}).
+\commentary{$T$ may contain free type variables, but $t$ contains their actual values.}
+The following must then hold:
+$u$ is a class that implements the built-in class \FUNCTION{};
+$u$ is a subtype of $t$;
+and $u$ is not a subtype of any function type which is a proper subtype of $t$.
\commentary{
-One cannot assume, based on the above, that given a function \code{f}, \code{f.runtimeType} will actually be \FUNCTION{}, or that any two distinct function objects necessarily have the same run-time type.
+If we had omitted the last requirement then
+\code{f \IS{} int\,\FUNCTION([int])}
+could evaluate to \TRUE{} with the declaration
+\code{void f()\,\{\}},
+e.g., by letting $u$ be \code{Null}.
}
\rationale{
-It is up to the implementation to choose an appropriate representation for function objects.
-For example, consider that a function object produced via property extraction treats equality differently from other function objects, and is therefore likely a different class.
-Implementations may also use different classes for function objects based on arity and or type.
-Arity may be implicitly affected by whether a function is an instance method (with an implicit receiver parameter) or not.
-The variations are manifold, and so this specification only guarantees that function objects are instances of some class that implements \FUNCTION{}.
+It is up to the implementation to choose
+an appropriate representation for function objects.
+For example, consider that
+a function object produced via property extraction
+treats equality differently from other function objects,
+and is therefore likely a different class.
+Implementations may also use different classes for function objects
+based on arity and or type.
+Arity may be implicitly affected by whether a function is
+an instance method (with an implicit receiver parameter) or not.
+The variations are manifold and, e.g.,
+one cannot assume that any two distinct function objects
+will necessarily have the same run-time type.
}
@@ -1431,7 +1662,6 @@
<methodSignature> ::= <constructorSignature> <initializers>?
\alt <factoryConstructorSignature>
-% This doesn't work: `static @override foo() => 42`, but `functionSignature` starts with metadata. https://github.com/dart-lang/sdk/issues/29614
\alt \STATIC{}? <functionSignature>
\alt \STATIC{}? <getterSignature>
\alt \STATIC{}? <setterSignature>
@@ -1444,10 +1674,8 @@
\alt ((\EXTERNAL{} \STATIC{}?))? <getterSignature>
\alt ((\EXTERNAL{} \STATIC{}?))? <setterSignature>
\alt \EXTERNAL{}? <operatorSignature>
-% This doesn't work: `static @override foo() => 42`, but `functionSignature` starts with metadata. https://github.com/dart-lang/sdk/issues/29614
\alt ((\EXTERNAL{} \STATIC{}?))? <functionSignature>
\alt \STATIC{} (\FINAL{} | \CONST{}) <type>? <staticFinalDeclarationList>
-% \CONST{} type? staticFinalDeclarationList;
\alt \FINAL{} <type>? <initializedIdentifierList>
\alt (\STATIC{} | \COVARIANT{})? (\VAR{} | <type>) <initializedIdentifierList>
@@ -1459,12 +1687,8 @@
\LMHash{}%
It is possible to include the modifier \COVARIANT{} in some forms of declarations.
-This modifier has no effect.
-
-\rationale{
-The modifier \COVARIANT{} is used in strong mode.
-The modifier is allowed here even though it has no effect, such that source code can be used in both contexts.
-}
+The effect of doing this is described elsewhere
+(\ref{covariantParameters}).
\LMHash{}%
A class has constructors, instance members and static members.
@@ -1510,13 +1734,57 @@
\rationale{
We want different behavior for concrete classes and abstract classes.
-If $A$ is intended to be abstract, we want the static checker to warn about any attempt to instantiate $A$, and we do not want the checker to complain about unimplemented methods in $A$.
-In contrast, if $A$ is intended to be concrete, the checker should warn about all unimplemented methods, but allow clients to instantiate it freely.
+If $A$ is intended to be abstract,
+we want the static checker to warn about any attempt to instantiate $A$,
+and we do not want the checker to complain about unimplemented methods in $A$.
+In contrast, if $A$ is intended to be concrete,
+the checker should warn about all unimplemented methods,
+but allow clients to instantiate it freely.
+}
+
+\commentary{
+The interface of a class $C$ is
+an implicit interface that declares instance member signatures
+that correspond to the instance members declared by $C$,
+and whose direct superinterfaces are
+the direct superinterfaces of $C$
+(\ref{interfaces}, \ref{superinterfaces}).
}
\LMHash{}%
-The \Index{interface of a class} $C$ is an implicit interface that declares instance members that correspond to the instance members declared by $C$, and whose direct superinterfaces are the direct superinterfaces of $C$ (\ref{superinterfaces}).
-When a class name appears as a type, that name denotes the interface of the class.
+When a class name appears as a type,
+that name denotes the interface of the class.
+
+\LMHash{}%
+% The use of 'concrete member' below may seem redundant, because a class
+% does not inherit abstract members from its superclass, but this
+% underscores the fact that even when an abstract declaration of $m$ is
+% declared in $C$, $C$ does not "have" $m$.
+A concrete class must fully implement its interface:
+Let $C$ be a concrete class with interface $I$.
+Assume that $I$ has an accessible member signature $m$.
+It is a compile-time error if $C$ does not have
+a concrete accessible member with the same name as $m$,
+unless $C$ has a non-trivial \code{noSuchMethod}
+(\ref{theMethodNoSuchMethod}).
+It is a compile-time error if $C$ has
+a concrete accessible member with the same name as $m$,
+with a method signature $m'$ which is not a correct override of $m$
+(\ref{correctMemberOverrides}),
+unless that concrete member is a \code{noSuchMethod} forwarder
+(\ref{theMethodNoSuchMethod}).
+
+\commentary{
+In particular, it is an error for a class to be concrete even if it inherits
+a member implementation for every member signature in its interface,
+unless each of them has parameters and types such that they satisfy
+the corresponding member signature.
+But when there is a non-trivial \code{noSuchMethod} it is allowed
+to leave some members unimplemented,
+and it is allowed to to have a \code{noSuchMethod} forwarder which does not
+satisfy the class interface
+(in which case it will be overridden by another \code{noSuchMethod} forwarder).
+}
% making an exception for the setters generated for final fields is tempting but problematic.
% If a super type defines a setter, it will be overridden yet have no impact on the interface.
@@ -1569,28 +1837,73 @@
\LMLabel{instanceMethods}
\LMHash{}%
-Instance methods are functions (\ref{functions}) whose declarations are immediately contained within a class declaration and that are not declared \STATIC{}.
-The instance methods of a class $C$ are those instance methods declared by $C$ and the instance methods inherited by $C$ from its superclass.
+\IndexCustom{Instance methods}{method!instance}
+are functions (\ref{functions})
+whose declarations are immediately contained within a class declaration
+and that are not declared \STATIC{}.
+The \Index{instance methods of a class} $C$ are the instance methods declared by $C$
+and the instance methods inherited by $C$ from its superclass
+(\ref{inheritanceAndOverriding}).
\LMHash{}%
-It is a compile-time error if an instance method $m_1$ overrides (\ref{inheritanceAndOverriding}) an instance member $m_2$ and $m_1$ has a greater number of required parameters than $m_2$.
-It is a compile-time error if an instance method $m_1$ overrides an instance member $m_2$ and $m_1$ has fewer positional parameters than $m_2$.
-It is a compile-time error if an instance method $m_1$ overrides an instance member $m_2$ and $m_1$ does not declare all the named parameters declared by $m_2$.
-
-\LMHash{}%
-%% TODO(eernst): We need to use the concept of 'correctly overrides' rather than 'is a subtype of', e.g., to treat `void` correctly.
-It is a compile-time error if an instance method $m_1$ overrides an instance member $m_2$ and the type of $m_1$ is not a subtype of the type of $m_2$.
-It is a static warning if
-an instance method $m_1$ overrides an instance member $m_2$,
-the signature of $m_2$ explicitly specifies a default value
-for a formal parameter $p$, and
-the signature of $m_1$ implies a different default value for $p$.
+Consider a class $C$.
+It is a compile-time error if an instance method declaration in $C$ has
+a member signature $m$
+(\ref{interfaces})
+% Note that $m'$ is accessible, due to the definition of 'overrides'.
+which overrides a member signature $m'$
+from a direct superinterface of $C$
+(\ref{interfaceInheritanceAndOverriding}),
+unless this is a correct member override
+(\ref{correctMemberOverrides}).
\commentary{
-A method declaration may conflict with other declarations
+This is not the only kind of conflict that may exist:
+An instance member declaration $D$ may conflict with another declaration $D'$,
+even in the case where they do not have the same name
+or they are not the same kind of declaration.
+E.g., $D$ could be an instance getter and $D'$ a static setter
(\ref{classMemberConflicts}).
}
+\LMHash{}%
+For each parameter $p$ of $m$ where \COVARIANT{} is present,
+it is a compile-time error if there exists
+a direct or indirect superinterface $J$ of $C$ which has
+an accessible method signature $m''$ with the same name as $m$,
+such that $m''$ has a parameter $p''$ that corresponds to $p$
+(\ref{covariantParameters}),
+unless the type of $p$ is assignable to the type of $p''$.
+
+\commentary{
+This means that
+a parameter which is covariant-by-declaration can have a type
+which is a supertype or a subtype of the type of
+a corresponding parameter in a superinterface,
+but the two types cannot be unrelated.
+Note that this requirement must be satisfied
+for each direct or indirect superinterface separately,
+because assignability is not transitive.
+}
+
+\rationale{
+The superinterface may be the statically known type of the receiver,
+so this means that we relax the potential typing relationship
+between the statically known type of a parameter and the
+type which is actually required at run time
+to the assignability relationship,
+rather than the strict supertype relationship
+which applies to a parameter which is not covariant.
+It should be noted that it is not statically known
+at the call site whether any given parameter is covariant,
+because the covariance could be introduced in
+a proper subtype of the statically known type of the receiver.
+We chose to give priority to flexibility rather than safety here,
+because the whole point covariant parameters is that developers
+can make the choice to increase the flexibility
+in a trade-off where some static type safety is lost.
+}
+
\subsubsection{Operators}
\LMLabel{operators}
@@ -2027,23 +2340,25 @@
A getter definition that is prefixed with the \STATIC{} modifier defines a static getter.
Otherwise, it defines an instance getter.
The name of the getter is given by the identifier in the definition.
-The effect of a static getter declaration in class $C$ is to add an instance getter with the same name and signature to the \code{Type} object for class $C$ that forwards (\ref{functionDeclarations}) to the static getter.
\LMHash{}%
-The instance getters of a class $C$ are those instance getters declared by $C$, either implicitly or explicitly, and the instance getters inherited by $C$ from its superclass.
-The static getters of a class $C$ are those static getters declared by $C$.
+The \Index{instance getters of a class} $C$ are
+those instance getters declared by $C$,
+either implicitly or explicitly,
+and the instance getters inherited by $C$ from its superclass.
+The \Index{static getters of a class} $C$ are
+those static getters declared by $C$.
\commentary{
A getter declaration may conflict with other declarations
(\ref{classMemberConflicts}).
In particular, a getter can never override a method,
and a method can never override a getter or an instance variable.
+The rules for when a getter correctly overrides another member
+are given elsewhere
+(\ref{correctMemberOverrides}).
}
-\LMHash{}%
-It is a compile-time error if a getter $m_1$ overrides (\ref{inheritanceAndOverriding}) a getter $m_2$
-and the return type of $m_1$ is not a subtype of the return type of $m_2$.
-
\subsection{Setters}
\LMLabel{setters}
@@ -2063,33 +2378,39 @@
A setter definition that is prefixed with the \STATIC{} modifier defines a static setter.
Otherwise, it defines an instance setter.
The name of a setter is obtained by appending the string `=' to the identifier given in its signature.
-The effect of a static setter declaration in class $C$ is to add an instance setter with the same name and signature to the \code{Type} object for class $C$ that forwards (\ref{functionDeclarations}) to the static setter.
\commentary{
Hence, a setter name can never conflict with, override or be overridden by a getter or method.
}
\LMHash{}%
-The instance setters of a class $C$ are those instance setters declared by $C$ either implicitly or explicitly, and the instance setters inherited by $C$ from its superclass.
-The static setters of a class $C$ are those static setters declared by $C$.
+The \Index{instance setters of a class} $C$ are
+those instance setters declared by $C$
+either implicitly or explicitly,
+and the instance setters inherited by $C$ from its superclass.
+The \Index{static setters of a class} $C$ are
+those static setters declared by $C$,
+either implicitly or explicitly.
\LMHash{}%
-It is a compile-time error if a setter's formal parameter list does not consist of exactly one required formal parameter $p$.
+It is a compile-time error if a setter's formal parameter list
+does not consist of exactly one required formal parameter $p$.
\rationale{
We could enforce this via the grammar, but we'd have to specify the evaluation rules in that case.
}
\LMHash{}%
It is a static warning if a setter declares a return type other than \VOID{}.
-It is a compile-time error if a setter $m_1$ overrides (\ref{inheritanceAndOverriding}) a setter $m_2$
-and the parameter type of $m_1$ is not a supertype of the parameter type of $m_2$.
It is a static warning if a class has
-a setter named $v=$ with argument type $T$ and
+a setter named \code{$v$=} with argument type $T$ and
a getter named $v$ with return type $S$,
and $S$ may not be assigned to $T$.
\commentary{
-A setter declaration may conflict with other declarations
+The rules for when a setter correctly overrides another member
+are given elsewhere
+(\ref{correctMemberOverrides}).
+A setter declaration may conflict with other declarations as well
(\ref{classMemberConflicts}).
}
@@ -2110,14 +2431,15 @@
is an instance method, getter or setter that is not abstract.
\rationale{
-Earlier versions of Dart required that abstract members be identified by prefixing them with the modifier \ABSTRACT{}.
-The elimination of this requirement is motivated by the desire to use abstract classes as interfaces.
-Every Dart class induces an implicit interface.
-
-Using an abstract class instead of an interface has important advantages.
-An abstract class can provide default implementations; it can also provide static methods, obviating the need for service classes such as \code{Collections} or \code{Lists}, whose entire purpose is to group utilities related to a given type.
-
-Eliminating the requirement for an explicit modifier on members makes abstract classes more concise, making abstract classes an attractive substitute for interface declarations.
+Abstract instance members are useful because of their interplay with classes.
+Every Dart class induces an implicit interface,
+and Dart does not support specifying interfaces explicitly.
+Using an abstract class instead of a traditional interface
+has important advantages.
+An abstract class can provide default implementations.
+It can also provide static methods,
+obviating the need for service classes such as \code{Collections} or \code{Lists},
+whose entire purpose is to group utilities related to a given type.
}
\commentary{
@@ -2133,22 +2455,12 @@
}
\rationale{
-The purpose of an abstract method is to provide a declaration for purposes such as type checking and reflection.
-In classes used as mixins, it is often useful to introduce such declarations for methods that the mixin expects will be provided by the superclass the mixin is applied to.
+The purpose of an abstract method is to provide a declaration
+for purposes such as type checking and reflection.
+In mixins, it is often useful to introduce such declarations for methods that
+the mixin expects will be provided by the superclass the mixin is applied to.
}
-\LMHash{}%
-%% TODO(eernst): This is semi-redundant: We should define what it means for
-%% a class to be 'fully implemented' and require once and for all that it is
-%% a compile-time error if a concrete class is not fully implemented. That
-%% is very nearly what line 2706++ already says. This will then be commentary,
-%% just focusing on the case where a concrete $C$ _declares_ an abstract $m$.
-It is a compile-time error if an abstract member $m$ is declared or inherited in a concrete class $C$ unless:
-\begin{itemize}
-\item $m$ overrides a concrete member, or
-\item $C$ has a concrete \code{noSuchMethod()} method distinct from the one declared in class \code{Object}.
-\end{itemize}
-
\rationale{
We wish to detect if one declares a concrete class with abstract members.
However, code like the following should work:
@@ -2177,8 +2489,13 @@
\LMLabel{instanceVariables}
\LMHash{}%
-Instance variables are variables whose declarations are immediately contained within a class declaration and that are not declared \STATIC{}.
-The instance variables of a class $C$ are those instance variables declared by $C$ and the instance variables inherited by $C$ from its superclass.
+\IndexCustom{Instance variables}{variables!instance}
+are variables whose declarations
+are immediately contained within a class declaration
+and that are not declared \STATIC{}.
+The \Index{instance variables of a class} $C$ are
+the instance variables declared by $C$
+and the instance variables inherited by $C$ from its superclass.
\LMHash{}%
It is a compile-time error if an instance variable is declared to be constant.
@@ -2195,6 +2512,23 @@
An instance getter for it can always be defined manually if desired.
}
+\LMHash{}%
+It is possible for the declaration of an instance variable
+to include the modifier \COVARIANT{}
+(\ref{variables}).
+The effect of this is that the formal parameter of
+the corresponding implicitly induced setter
+is considered to be covariant-by-declaration
+(\ref{covariantParameters}).
+
+\commentary{
+The modifier \COVARIANT{} on an instance variable has no other effects.
+In particular, the return type of the implicitly induced getter
+can already be overridden covariantly without \COVARIANT{},
+and it can never be overridden to a supertype or an unrelated type,
+regardless of whether the modifier \COVARIANT{} is present.
+}
+
\subsection{Constructors}
\LMLabel{constructors}
@@ -2282,6 +2616,7 @@
\LMHash{}%
Initializing formals are executed during the execution of generative constructors detailed below.
Executing an initializing formal \code{\THIS{}.\id} causes the instance variable \id{} of the immediately surrounding class to be assigned the value of the corresponding actual parameter,
+%% TODO(eernst): This should be a compile-time error -- check, revise if true!
unless \id{} is a final variable that has already been initialized, in which case a run-time error occurs.
\commentary{
@@ -2687,13 +3022,13 @@
$T$ is a type name, and \id{} is an identifier,
then consider a declaration of a redirecting factory constructor $k$ of one of the forms
-\begin{dartCode}
+\begin{normativeDartCode}
$\ConstMetavar$ \FACTORY{}
$N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $[$T_{n+1}\ x_{n+1}$=$d_1, \ldots,\ T_{n+k}\ x_{n+k}$=$d_k$]) = $R$;
\\
$\ConstMetavar$ \FACTORY{}
$N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $\{$T_{n+1}\ x_{n+1}$=$d_1, \ldots,\ T_{n+k}\ x_{n+k}$=$d_k$\}) = $R$;
-\end{dartCode}
+\end{normativeDartCode}
\noindent
where $R$ is of one of the forms
@@ -2946,16 +3281,16 @@
are functions, other than getters or setters, whose declarations are immediately contained within a class declaration and that are declared \STATIC{}.
The static methods of a class $C$ are those static methods declared by $C$.
-\LMHash{}%
-The effect of a static method declaration in class $C$ is to add an instance method with the same name and signature to the \code{Type} object for class $C$ that forwards (\ref{functionDeclarations}) to the static method.
-
\rationale{
Inheritance of static methods has little utility in Dart.
Static methods cannot be overridden.
-Any required static function can be obtained from its declaring library, and there is no need to bring it into scope via inheritance.
-Experience shows that developers are confused by the idea of inherited methods that are not instance methods.
+Any required static function can be obtained from its declaring library,
+and there is no need to bring it into scope via inheritance.
+Experience shows that developers are confused by
+the idea of inherited methods that are not instance methods.
-Of course, the entire notion of static methods is debatable, but it is retained here because so many programmers are familiar with it.
+Of course, the entire notion of static methods is debatable,
+but it is retained here because so many programmers are familiar with it.
Dart static methods may be seen as functions of the enclosing library.
}
@@ -3067,7 +3402,7 @@
Let $C = S_0$ be a class declared in library $L$, and
let $\{S_1, \ldots, S_k\}$ be the set of all superclasses of $C$,
where $S_i$ is the superclass of $S_{i-1}$ for $i \in 1 .. k$.
-\commentary{This means that $S_k$ is the built-in class \code{Object}.}
+\commentary{$S_k$ is the built-in class \code{Object}.}
Let $C$ declare a concrete member $m$, and
let $m'$ be a concrete member of $S_j, j \in 1 .. k$, that has the same name as $m$,
such that $m'$ is accessible to $L$.
@@ -3081,47 +3416,21 @@
}
\rationale{
-Again, a local definition of overriding would be preferable, but fails to account for library privacy.
-}
-
-\LMHash{}%
-Whether an override is legal or not is described elsewhere in this specification (see \ref{instanceMethods}, \ref{getters} and \ref{setters}).
-
-\commentary{
-For example getters may not legally override methods and vice versa.
-Setters never override methods or getters, and vice versa, because their names always differ.
-}
-
-\rationale{
-It is nevertheless convenient to define the override relation between members in this way, so that we can concisely describe the illegal cases.
+Again, a local definition of overriding would be preferable,
+but fails to account for library privacy.
}
\commentary{
-Note that instance variables do not participate in the override relation, but the getters and setters they induce do.
-Also, getters don't override setters and vice versa.
-Finally, static members never override anything.
+Whether an override is legal or not is specified relative to
+all direct superinterfaces, not just the interface of the superclass,
+and that is described elsewhere
+(\ref{instanceMethods}).
+Static members never override anything,
+but they may participate in some conflicts
+involving declarations in superinterfaces
+(\ref{classMemberConflicts}).
}
-\LMHash{}%
-Let $C$ be a concrete class
-whose interface has an accessible member $m$ named \id{}.
-It is a compile-time error if $C$ does not have
-a concrete member $m'$ named \id{} which is a correct override of $m$,
-unless $C$ has a concrete method named \code{noSuchMethod}
-which is different from the one in the built-in class \code{Object},
-and $C$ does not have a concrete member named \id.
-
-\commentary{
-So it is an error even if $C$ does have a concrete member $m'$ named \id{}
-if $m'$ is an \emph{incorrect} override of $m$,
-also when $C$ has a \code{noSuchMethod} which is not from \code{Object}.
-Note that it is allowed to let inaccessible methods remain unimplemented;
-invocations of such methods will be redirected to \code{noSuchMethod}.
-}
-
-%% TODO(eernst): Why don't we just get rid of this list entirely?
-%% It's 'for convenience', but that's not otherwise a priority in this
-%% document, it is more important that it is correct and consistent.
\commentary{
For convenience, here is a summary of the relevant rules,
using `error' to denote compile-time errors.
@@ -3152,26 +3461,9 @@
they override each other.
This may or may not be legal.
\item \label{typeSigAssignable}
- %% TODO(eernst): This is commentary, but we may need to adjust it
- %% to say 'correctly overrides'.
If two members override each other,
- it is an error if their type signatures are not assignable to each other
- (\ref{instanceMethods}, \ref{getters}, \ref{setters})
- %% TODO(eernst): Revisit relative to the new subtyping.md rules.
- (and since these are function types, this means the same as
- "subtypes of each other").
-\item \label{requiredParams}
- If two members override each other,
- it is an error if the overriding member has
- more required parameters than the overridden one (\ref{instanceMethods}).
-\item \label{optionalPositionals}
- If two members override each other,
- it is an error if the overriding member has
- fewer positional parameters than the overridden one (\ref{instanceMethods}).
-\item \label{namedParams}
- If two members override each other,
- it is an error if the overriding member does not have
- all the named parameters that the overridden one has (\ref{instanceMethods}).
+ it is an error unless it is a correct override
+ (\ref{correctMemberOverrides}).
\item Setters, getters and operators never have
optional parameters of any kind;
it's an error (\ref{operators}, \ref{getters}, \ref{setters}).
@@ -3187,38 +3479,31 @@
it has no body and is not labeled \EXTERNAL{}
(\ref{abstractInstanceMembers}, \ref{externalFunctions}).
\item A class is abstract if{}f it is explicitly labeled \ABSTRACT{}.
-\item It is an error if a concrete class has an abstract member
- (declared or inherited), and there is no \code{noSuchMethod}.
+\item It is an error if a concrete class does not implement some member
+ of its interface, and there is no non-trivial \code{noSuchMethod}
+ (\ref{classes}).
\item It is an error to call a non-factory constructor of an abstract class
using an instance creation expression (\ref{instanceCreation}),
such a constructor may only be invoked from another constructor
using a super invocation (\ref{superInvocation}).
\item If a class defines an instance member named $m$,
- and any of its superinterfaces have a member named $m$,
+ and any of its superinterfaces have a member signature named $m$,
the interface of the class contains the $m$ from the class itself.
-\item
- %% TODO(eernst): This needs to be updated when we introduce the
- %% new override/conflict rules.
- An interface inherits all members of its superinterfaces
+\item An interface inherits all members of its superinterfaces
that are not overridden and not members of multiple superinterfaces.
-\item
- %% TODO(eernst): This must be rewritten when we introduce the new
- %% override/conflict rules.
- If multiple superinterfaces of an interface
- define a member with the same name $m$,
+\item If multiple superinterfaces of an interface
+ define a member with the same name as $m$,
then at most one member is inherited.
- %% TODO(eernst): Switch to use 'correctly overrides' terminology.
That member (if it exists) is the one whose type is a subtype
of all the others.
- If there is no such member, then an error occurs
+ If there is no such member, an error occurs
(\ref{interfaceInheritanceAndOverriding}).
\item Rule \ref{typeSigAssignable} applies to interfaces as well as classes
(\ref{interfaceInheritanceAndOverriding}).
\item It is an error if a concrete class does not have an implementation
for a method in its interface
- unless it has a concrete \code{noSuchMethod} method
- (\ref{superinterfaces})
- distinct from the one in class \code{Object}.
+ unless it has a non-trivial \code{noSuchMethod}
+ (\ref{theMethodNoSuchMethod}).
\item The identifier of a named constructor cannot be
the same as the name of a static member declared in the same class
(\ref{classMemberConflicts}).
@@ -3228,11 +3513,12 @@
\subsection{Superinterfaces}
\LMLabel{superinterfaces}
-% what about rules about classes that fail to implement their interfaces?
\LMHash{}%
-A class has a set of direct superinterfaces.
-This set includes the interface of its superclass and the interfaces specified in the \IMPLEMENTS{} clause of the class.
+A class has a set of \Index{direct superinterfaces}.
+This set contains the interface of its superclass
+and the interfaces of the classes specified in
+the \IMPLEMENTS{} clause of the class.
\begin{grammar}
<interfaces> ::= \IMPLEMENTS{} <typeList>
@@ -3263,38 +3549,11 @@
\LMHash{}%
It is a compile-time error if the interface of a class $C$ is a superinterface of itself.
-\LMHash{}%
-Let $C$ be a concrete class that does not have a concrete \code{noSuchMethod()} method distinct from the one declared in class \code{Object}.
-%% TODO(eernst): Adjust to use 'correctly overrides' terminology.
-It is a compile-time error if the implicit interface of $C$ has an accessible instance member $m$ of type $F$,
-and $C$ does not declare or inherit a corresponding concrete instance member $m$ of type $F'$ such that $F' <: F$.
-
\commentary{
A class does not inherit members from its superinterfaces.
However, its implicit interface does.
}
-\rationale{
-We choose to raise these compile-time errors only for concrete classes;
-an abstract class might legitimately be designed with the expectation that concrete subclasses will implement part of the interface.
-We also disable these errors if a concrete \code{noSuchMethod()} declaration is present or inherited from any class other than \code{Object},
-unless a concrete member $m$ is declared or inherited.
-The point is that there is an error to disable,
-so the signature of the concrete $m$ is not a correct override of the signature in the class interface.
-Otherwise, when all such errors have been disabled,
-the supported interface is going to be implemented via \code{noSuchMethod()}
-and no actual declarations of the implemented interface's members are needed.
-This allows proxy classes for specific types to be implemented without provoking errors.
-}
-
-\LMHash{}%
-%% TODO(eernst): Switch to use 'correctly overrides' terminology.
-It is a compile-time error if the implicit interface of a class $C$ has an instance member $m$ of type $F$ and $C$ declares or inherits a corresponding instance member $m$ of type $F'$ if $F'$ is not a subtype of $F$.
-
-\rationale{
-However, if a class does explicitly declare a member that conflicts with its superinterface, this always yields an error.
-}
-
\subsection{Class Member Conflicts}
\LMLabel{classMemberConflicts}
@@ -3325,18 +3584,397 @@
\LMLabel{interfaces}
\LMHash{}%
-An \Index{interface} defines how one may interact with an object.
-An interface has methods, getters and setters and a set of superinterfaces.
+This section introduces the notion of interfaces.
+We define the notion of member signatures first,
+because that concept is needed in the definition of interfaces.
+
+% We need a separate concept of instance member signatures,
+% such that we can obtain a clean treatment of how to compute
+% the interface of a class and the common interface of a set
+% of superinterfaces, e.g., the superinterfaces of a class or
+% the common interface represented by an `on` clause in a
+% `mixin`. For instance, we do not want to specify each time
+% we check for conflicts that the body doesn't matter, or
+% that the metadata doesn't matter, the interface of a class
+% should simply never contain a body of any member in the
+% first place. Also the clear separation of a syntactic
+% declaration and a member signature provides a well-defined
+% occasion to introduce transformations, e.g., to replace
+% some parameter types by others, which is needed for the
+% specification of a correct override relation.
+
+\LMHash{}%
+A \Index{member signature} $s$
+can be derived from a class instance member declaration $D$.
+It contains the same information as $D$,
+except that $s$ omits the body, if any;
+it contains the return type and parameter types
+even if they are implicit in $D$;
+it omits the names of positional parameters;
+it omits the modifier \FINAL{} from each parameter, if any;
+it omits metadata
+(\ref{metadata});
+and it omits information about whether the member is
+\EXTERNAL{}, \ASYNC{}, \ASYNC*, or \SYNC*.
+It makes no difference whether $D$ is given as explicit syntax
+or it is induced implicitly, e.g., by a variable declaration.
+Finally, if $s$ has formal parameters,
+each of them has the modifier \COVARIANT{}
+(\ref{requiredFormals})
+if and only if that parameter is covariant-by-declaration
+(\ref{covariantParameters}).
+
+\LMHash{}%
+We use a syntax similar to that of an abstract member declaration
+to specify member signatures.
+The difference is that the names of positional parameters are omitted.
+This syntax is only used for the purposes of specification.
+
+\rationale{
+Member signatures are synthetic entities, that is,
+they are not supported as concrete syntax in a Dart program,
+they are computed entities used during static analysis.
+However, it is useful to be able to indicate the
+properties of a member signature in this specification
+via a syntactic representation.
+A member signature makes it explicit
+whether a parameter is covariant-by-declaration,
+but it remains implicit whether it is covariant-by-class
+(\ref{covariantParameters}).
+The reason for this is that the rule for determining whether
+a given override relation is correct
+(\ref{correctMemberOverrides})
+depends on the former and not on the latter.
+}
+
+\LMHash{}%
+Let $m$ be a method signature of the form
+
+\noindent
+\code{$T_0$ \id<\TypeParametersStd>(}
+
+\noindent
+\code{\qquad\qquad\List{\COVARIANT{}?\ T}{1}{n},}
+
+\noindent
+\code{\qquad\qquad[\PairList{\COVARIANT{}?\ T}{= d}{n+1}{n+k}])}.
+
+\noindent
+The \IndexCustom{function type of}{method signature!function type}
+$m$ is then
+
+\noindent
+\FunctionTypePositionalStd{T_0}.
+
+\LMHash{}%
+Let $m$ be a method signature of the form
+
+\noindent
+\code{$T_0$ \id<\TypeParametersStd>(}
+
+\noindent
+\code{\qquad\qquad\List{\COVARIANT{}?\ T}{1}{n},}
+
+\noindent
+\code{\qquad\qquad\{\TripleList{\COVARIANT{}?\ T}{x}{= d}{n+1}{n+k}\})}.
+
+\noindent
+The \NoIndex{function type of} $m$ is then
+
+\noindent
+\FunctionTypeNamedStd{T_0}.
+
+\LMHash{}%
+Let $m$ be a setter signature of the form
+\code{\VOID\ \SET\ \id(\COVARIANT?\ $T$ $p$)}.
+The \NoIndex{function type of} $m$ is then
+\FunctionTypeSimple{\VOID}{$T$}.
+
+\LMHash{}%
+The function type of a member signature remains unchanged if
+some or all default values are omitted.
+
+\commentary{
+We do not specify the function type of a getter signature.
+For such signatures we will instead directly refer to the return type.
+}
+
+\LMHash{}%
+An \Index{interface} is a synthetic entity that defines
+how one may interact with an object.
+An interface has method, getter and setter signatures,
+and a set of superinterfaces,
+which are again interfaces.
+Each interface is the implicit interface of a class,
+in which case we call it a
+\IndexCustom{class interface}{interface!class},
+or a combination of several other interfaces,
+in which case we call it a
+\IndexCustom{combined interface}{interface!combined}.
+
+\LMHash{}%
+Let $C$ be a class.
+The \Index{class interface} $I$ of $C$ is the interface that declares
+a member signature derived from
+each instance member declared by $C$.
+The \Index{direct superinterfaces} of $I$ are the direct superinterfaces of $C$
+(\ref{superinterfaces}).
+
+\commentary{
+We say that the class interface 'declares' these member signatures,
+such that we can say that an interface 'declares' or 'has' a member,
+just like we do for classes.
+Note that a member signature $s$ of the interface of class $C$
+may have a parameter $p$ with modifier \COVARIANT{},
+even though $s$ was derived from a declaration $D$ in $C$
+and the parameter corresponding to $p$ in $D$ does not
+have that modifier.
+This is because $p$ may have ``inherited''
+the property of being covariant-by-declaration
+from one of its superinterfaces
+(\ref{covariantParameters}).
+}
+
+\LMHash{}%
+%% TODO(eernst): 'list of interfaces' --> 'set of interfaces' if we
+%% switch to use a total order on top types for interface specificity.
+The \Index{combined interface} $I$ of a list of interfaces \List{I}{1}{k}
+is the interface that declares the set of member signatures $M$,
+where $M$ is determined as specified below.
+The \Index{direct superinterfaces} of $I$ is the set \List{I}{1}{k}.
+
+\LMHash{}%
+Let $M_0$ be the set of all member signatures declared by \List{I}{1}{k}.
+$M$ is then the smallest set satisfying the following:
+
+\begin{itemize}
+\item For each name \id{} and library $L$ such that $M_0$ contains
+ a member signature named \id{} which is accessible to $L$,
+ let $m$ be the combined member signature named \id{}
+ from \List{I}{1}{k} with respect to $L$.
+ It is a compile-time error
+ if the computation of this combined member signature failed.
+ Otherwise, $M$ contains $m$.
+\end{itemize}
+
+\rationale{
+Interfaces must be able to contain inaccessible member signatures,
+because they may be accessible from the interfaces associated with
+declarations of subtypes.
+}
+
+\commentary{%
+For instance, class $C$ in library $L$ may declare a private member named
+\code{\_foo},
+a class $D$ in a different library $L_2$ may extend $C$,
+and a class $E$ in library $L$ may extend $D$;
+$E$ may then declare a member that overrides \code{\_foo} from $C$,
+and that override relation must be checked based on the interface of $D$.
+So we cannot allow the interface of $D$
+to ``forget'' inaccessible members like \code{\_foo}.
+
+For conflicts the situation is even more demanding:
+Classes $C_1$ and $C_2$ in library $L$ may declare private members
+\code{String \_foo(int i)} and \code{int get \_foo},
+and a subtype $D_{12}$ in a different library $L_2$ may have
+an \IMPLEMENTS{} clause listing both $C_1$ and $C_2$.
+In that case we must report a conflict even though the conflicting
+declarations are not accessible to $L_2$,
+because those member signatures are then noSuchMethod forwarded
+(\ref{theMethodNoSuchMethod}),
+and an invocation of \code{\_foo} on an instance of $D$ in $L$
+must return an `int` according to the first member signature,
+and it must return a function object according to the second one,
+and an invocation of \code{\_foo(42)}
+must return a \code{String} with the first member signature, and it must fail
+(at compile time or, for a dynamic invocation, run time) with the second.
+}
+
+\rationale{%
+It may not be possible to satisfy such constraints simultaneously,
+and it will inevitably be a complex semantics,
+so we have chosen to make it an error.
+It is unfortunate that the addition of a private declaration
+in one library may break existing code in a different library.
+But it should be noted that the conflicts can be detected locally
+in the library where the private declarations exist,
+because they only arise for private members with
+the same name and incompatible signatures.
+Renaming that private member to anything not used in that library
+will eliminate the conflict and will not break any clients.
+}
+
+
+\subsection{Combined Member Signatures}
+\LMLabel{combinedMemberSignatures}
+
+\LMHash{}%
+This section specifies how to compute a member signature which will
+appropriately stand for a prioritized set of several member signatures,
+taken from a given list of interfaces.
+
+\commentary{
+In general, a combined member signature has a type which is
+a subtype of all the types given for that member.
+This is needed in order to ensure that the type of
+a member \id{} of a class $C$ is well-defined,
+even in the case where $C$ inherits
+several different declarations of \id{}
+and does not override \id{}.
+In case of failure, it serves to specify the situations
+where a developer must add a declaration in order to resolve an ambiguity.
+The member signatures are prioritized in the sense that we will select
+a member signature from the interface with the lowest possible index
+in the case where several member signatures are equally suitable
+to be chosen as the combined member signature.
+That is, ``the first interface wins''.
+}
+
+\LMHash{}%
+For the purposes of computing a combined member signature,
+we need a special notion of
+\IndexCustom{equality}{member signature equality}
+of member signatures.
+Two member signatures $m_1$ and $m_2$ are equal
+if{}f they have the same name,
+are accessible to the same set of libraries,
+have the same same return type (for getters),
+or the same function type and the same occurrences of \COVARIANT{}
+(for methods and setters).
+
+\commentary{
+In particular, private methods from different libraries are never equal.
+Top types differ as well.
+For instance,
+\FunctionTypeSimple{\DYNAMIC}{} and \FunctionTypeSimple{\code{Object}}{}
+are not equal, even though they are subtypes of each other.
+We need this distinction because management of top type discrepancies is
+one of the purposes of computing a combined interface.
+}
+
+\LMHash{}%
+Now we define combined member signatures.
+Let \id{} be an identifier, $L$ a library,
+\List{I}{1}{k} a list of interfaces,
+and $M_0$ the set of
+all member signatures from \List{I}{1}{k} named \id{}
+and accessible to $L$.
+The
+\IndexCustom{combined member signature
+ named \id{} from \List{I}{1}{k} with respect to $L$}{%
+ combined member signature}
+is the member signature which is obtained as follows:
+
+\LMHash{}%
+If $M_0$ is empty, computation of the combined member signature failed.
+
+\LMHash{}%
+If $M_0$ contains exactly one member signature $m'$,
+the combined member signature is $m'$.
+
+\LMHash{}%
+Otherwise, $M_0$ contains more than one member signature \List{m}{1}{q}.
+
+\LMHash{}%
+\Case{Failing mixtures}
+If $M_0$ contains at least one getter signature
+and at least one non-getter signature,
+the computation of the combined member signature failed.
+
+\LMHash{}%
+\Case{Getters}
+If $M_0$ contains getter signatures only,
+the computation of the combined member signature proceeds as described below
+for methods and setters,
+except that it uses the return type of the getter signature
+where methods and setters use the function type of the member signature.
+
+
+\LMHash{}%
+\Case{Methods and setters}
+In this case $M_0$ consists of setter signatures only,
+or method signatures only,
+because the name \id{} in the former case always end in \syntax{`='},
+which is never true in the latter case.
+
+\LMHash{}%
+Determine whether there exists a non-empty set $N \subseteq 1 .. q$ such that
+for each $i \in N$,
+the function type of $m_i$ is a subtype of
+the function type of $m_j$ for each $j \in 1 .. q$.
+%
+If no such set exists, the computation of the combined member signature failed.
+\commentary{%
+A useful intuition about this situation is that
+the given member signatures do not agree on
+which type is suitable for the member named \id.
+Otherwise we have a set of member signatures which are ``most specific''
+in the sense that their function types are subtypes of them all.
+}
+
+{ % Scope for N_min, M_min, N_firstMin.
+
+\def\Nall{\ensuremath{N_{\mbox{\scriptsize{}all}}}}
+\def\Mall{\ensuremath{M_{\mbox{\scriptsize{}all}}}}
+\def\MallFirst{\ensuremath{M_{\mbox{\scriptsize{}first}}}}
+
+\LMHash{}%
+Otherwise, when a set $N$ as specified above exists,
+let \Nall{} be the greatest set satisfying the requirement on $N$,
+and let $\Mall{} = \{ m_i\;|\;i \in \Nall\}$.
+\commentary{
+That is, \Mall{} contains all member signatures named \id{}
+with the most specific type.
+Dart subtyping is a partial pre-order,
+which ensures that such a greatest set of least elements exists,
+if any non-empty set of least elements exist.
+We can have several such signatures because member signatures
+can be such that they are not equal,
+and yet their function types are subtypes of each other.
+We need to compute one member signature from \Mall{},
+and we do that by using the ordering of the given interfaces.
+}
+
+\LMHash{}%
+Let $j \in 1 .. k$ be the smallest number such that
+$\MallFirst{} = \Mall{} \cap I_j$ is non-empty.
+Let $m_i$ be the single element that \MallFirst{} contains.
+\commentary{
+This set contains exactly one element because it is non-empty
+and no interface contains more than one member signature named \id.
+In other words, we choose $m_i$ as the member signature from
+the first possible interface
+among the most specific member signatures \Mall.
+}
+}
+
+\LMHash{}
+The combined member signature is then $m'$,
+which is obtained from $m_i$ by adding the modifier \COVARIANT{}
+to each parameter $p$ (if it is not already present)
+when there exists a $j \in 1 .. q$
+such that the parameter corresponding to $p$
+(\ref{covariantParameters})
+has the modifier \COVARIANT{}.
+\commentary{
+In other words,
+each parameter in the combined member signature is marked covariant
+if any of the corresponding parameters are marked covariant,
+not just among the most specific signatures,
+but among \emph{all} signatures named \id{} (which are accessible to $L$)
+in the given list of interfaces.
+}
\subsection{Superinterfaces}
\LMLabel{interfaceSuperinterfaces}
\LMHash{}%
-An interface has a set of direct superinterfaces.
-
-\LMHash{}%
-An interface $J$ is a superinterface of an interface $I$ if{}f either $J$ is a direct superinterface of $I$ or $J$ is a superinterface of a direct superinterface of $I$.
+An interface has a set of direct superinterfaces
+(\ref{interfaces}).
+An interface $J$ is a \Index{superinterface} of an interface $I$
+if{}f either $J$ is a direct superinterface of $I$
+or $J$ is a superinterface of a direct superinterface of $I$.
\subsubsection{Inheritance and Overriding}
@@ -3344,58 +3982,111 @@
\LMHash{}%
Let $J$ be an interface and $K$ be a library.
-We define $inherited(J, K)$ to be the set of members $m$ such that all of the following hold:
+We define $\inherited{J, K}$ to be the set of member signatures $m$
+such that all of the following hold:
\begin{itemize}
\item $m$ is accessible to $K$ and
\item $A$ is a direct superinterface of $J$ and either
\begin{itemize}
- \item $A$ declares a member $m$ or
- \item $m$ is a member of $inherited(A, K)$.
+ \item $A$ declares a member signature $m$ or
+ \item $m$ is a member of $\inherited{A, K}$.
\end{itemize}
\item $m$ is not overridden by $J$.
\end{itemize}
\LMHash{}%
-Furthermore, we define $overrides(J, K)$ to be the set of members $m'$ such that all of the following hold:
+Furthermore, we define $\overrides{J, K}$ to be
+the set of member signatures $m'$
+such that all of the following hold:
\begin{itemize}
-\item $J$ is the implicit interface of a class $C$.
-\item $C$ declares a member $m$.
+\item $J$ is the interface of a class $C$.
+\item $C$ declares a member signature $m$.
\item $m'$ has the same name as $m$.
\item $m'$ is accessible to $K$.
\item $A$ is a direct superinterface of $J$ and either
\begin{itemize}
- \item $A$ declares a member $m'$ or
+ \item $A$ declares a member signature $m'$ or
\item $m'$ is a member of $inherited(A, K)$.
\end{itemize}
\end{itemize}
\LMHash{}%
-Let $I$ be the implicit interface of a class $C$ declared in library $L$.
-$I$ \Index{inherits} all members of $inherited(I, L)$ and $I$ \Index{overrides} $m'$ if $m' \in overrides(I, L)$.
+Let $I$ be the interface of a class $C$ declared in library $L$.
+$I$ \Index{inherits} all members of $\inherited{I, L}$
+and $I$ \Index{overrides} $m'$ if $m' \in \overrides{I, L}$.
\LMHash{}%
-All the compile-time errors pertaining to the overriding of instance members given in section \ref{classes} above hold for overriding between interfaces as well.
+All the compile-time errors pertaining to the overriding of instance members
+given in section~\ref{classes} hold for overriding between interfaces as well.
\LMHash{}%
-It is a compile-time error if $m$ is a method and $m'$ is a getter, or if $m$ is a getter and $m'$ is a method.
+If the above rule would cause multiple member signatures
+with the same name \id{} to be inherited then
+exactly one member is inherited, namely
+the combined member signature named \id{},
+from the direct superinterfaces
+%% TODO(eernst): This is only well-defined when $J$ is a class interface.
+in the textual order that they are declared,
+with respect to $L$
+(\ref{combinedMemberSignatures}).
-%Let $I = S_0$ be the implicit interface of a class $C$ declared in library $L$, and let $\{S_1, \ldots, S_k\}$ be the set of all superinterfaces of $I$.
-%Let $I$ be the implicit interface of a class $C$. $I$ inherits any instance members of its superinterfaces that are not overridden by members declared in $C$.
-
-% tighten definition? do we need chain as for classes? Definition for interface override?
+\subsubsection{Correct Member Overrides}
+\LMLabel{correctMemberOverrides}
\LMHash{}%
-However, if the above rules would cause multiple members $m_1, \ldots, m_k$ with the same name $n$ to be inherited (because identically named members existed in several superinterfaces) then at most one member is inherited.
+Let $m$ and $m'$ be member signatures with the same name \id.
+Then $m$ is a \Index{correct override} of $m'$
+if{}f the following criteria are all satisfied:
-\LMHash{}%
-If some but not all of the $m_i, 1 \le i \le k$ are getters, a compile-time error occurs.
+\begin{itemize}
+\item
+ $m$ and $m'$ are both methods, both getters, or both setters.
+ % We cannot have a setter and a method, say, because they cannot have
+ % the same name. However, we must _allow_ $m$ and $m'$ to be two setters.
+\item
+ If $m$ and $m'$ are both methods or both setters:
+ Let $F$ be the function type of $m$
+ except that the parameter type is the built-in class \code{Object}
+ for each parameter of $m$ which has the modifier \COVARIANT{}.
+ Let $F'$ be the function type of $m'$.
+ $F$ must then be a subtype of $F'$.
-\LMHash{}%
-%% TODO(eernst): Adjust to use 'correctly overrides' terminology.
-Otherwise, if the static types $T_1, \ldots, T_k$ of the members $m_1, \ldots, m_k$ are not identical then there must be an $x \in 1 .. k$ such that $T_x <: T_i$ for all $i \in 1 .. k$,
-or a compile-time error occurs.
-The member that is inherited is $m_x$, if it exists.
+ \commentary{%
+ The subtype requirement ensures that argument list shapes
+ that are admissible for an invocation of a method with signature $m'$
+ are also admissible for an invocation of a method with signature $m$.
+ For instance, $m'$ may accept 2 or 3 positional arguments,
+ and $m$ may accept 1, 2, 3, or 4 positional arguments, but not vice versa.
+ This is a built-in property of the function type subtype rules.
+ %
+ Note that a member signature differs from
+ an underlying syntactic declaration $D$ in a class $C$.
+ In particular,
+ a parameter in a member signature has the modifier \COVARIANT{}
+ if and only if the parameter is covariant-by-declaration
+ (\ref{covariantParameters}),
+ and that may be the case due to declarations in a supertype of $C$,
+ so that modifier need not be present in $D$.
+ %
+ There is an additional potential compile-time error associated with
+ a parameter which is covariant-by-declaration
+ (\ref{instanceMethods}).
+ But we cannot cover that here as a property of member overrides,
+ because it is concerned with declarations in all superinterfaces,
+ indirect as well as direct.
+ }
+\item
+ If $m$ and $m'$ are both methods,
+ $p$ is an optional parameter of $m$,
+ $p'$ is the parameter of $m'$ corresponding to $p$,
+ $p$ has default value $d$ and $p'$ has default value $d'$,
+ then $d$ and $d'$ must be identical,
+ or a compile-time warning occurs.
+\item
+ If $m$ and $m'$ are both getters:
+ The return type of $m$ must be a subtype of the return type of $m'$.
+\end{itemize}
\section{Mixins}
@@ -3462,9 +4153,9 @@
For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, $\ldots$, $T_{k}$ $a_{k}$)} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
-\begin{dartCode}
+\begin{normativeDartCode}
$C_q$($T_{1}$ $a_{1}$, \ldots, $T_{k}$ $a_{k}$): $\SUPER_q$($a_{1}$, $\ldots$, $a_{k}$);
-\end{dartCode}
+\end{normativeDartCode}
\noindent
where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$,
@@ -3476,10 +4167,10 @@
\LMHash{}%
For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, [$T_{k+1}$ $a_{k+1}$ = $d_1$, \ldots , $T_{k+p}$ $a_{k+p}$ = $d_p$])} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
-\begin{dartCode}
+\begin{normativeDartCode}
$C_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, [$T_{k+1}$ $a_{k+1}$ = $d'_{1}$, \ldots , $T_{k+p}$ $a_{k+p}$ = $d'_p$])
: $\SUPER_q$($a_{1}$, \ldots , $a_{k}$, $a_{k+1}$, \ldots, $a_p$);
-\end{dartCode}
+\end{normativeDartCode}
\noindent
where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$,
@@ -3494,10 +4185,10 @@
\LMHash{}%
For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, \{$T_{k+1}$ $a_{k+1}$ = $d_1$, \ldots , $T_{k+n}$ $a_{k+n}$ = $d_n$\})} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
-\begin{dartCode}
+\begin{normativeDartCode}
$C_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, \{$T_{k+1}$ $a_{k+1}$ = $d'_1$, \ldots , $T_{k+n}$ $a_{k+n}$ = $d'_n$\})
: $\SUPER_q$($a_{1}$, \ldots , $a_{k}$, $a_{k+1}$: $a_{k+1}$, \ldots, $a_p$: $a_p$);
-\end{dartCode}
+\end{normativeDartCode}
\noindent
where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$
@@ -3563,17 +4254,17 @@
to \code{$S$<$V_1, \ldots, V_{k_S}$>} for the name $C$ is equivalent to
-\begin{dartCode}
+\begin{normativeDartCode}
\ABSTRACT{} \CLASS{} $C<T_1, \ldots, T_{k_{M_1}}, U_1, \ldots, U_{k_{M_2}}, V_1, \ldots, V_{k_S}> = $
$Id_2<U_1, \ldots, U_{k_{M_2}}, V_1 \ldots V_{k_S}>$ \WITH{} $M_1 <T_1, \ldots, T_{k_{M_1}}>$;
-\end{dartCode}
+\end{normativeDartCode}
where $Id_2$ denotes
-\begin{dartCode}
+\begin{normativeDartCode}
\ABSTRACT{} \CLASS{} $Id_2<U_1, \ldots, U_{k_{M_2}}, V_1, \ldots, V_{k_S}> =$
$S<V_1, \ldots, V_{k_S}>$ \WITH{} $M_2<U_1, \ldots, U_{k_{M_2}}>$;
-\end{dartCode}
+\end{normativeDartCode}
and $Id_2$ is a unique identifier that does not exist anywhere in the program.
@@ -3610,7 +4301,7 @@
\code{$m$ \ENUM{} $E$ \{$m_0\,\,\id_0, \ldots,\ m_{n-1}\,\,\id_{n-1}$\}}
has the same effect as a class declaration
-\begin{dartCode}
+\begin{normativeDartCode}
$m$ \CLASS{} $E$ \{
\FINAL{} int index;
\CONST{} $E$(\THIS{}.index);
@@ -3620,7 +4311,7 @@
\STATIC{} \CONST{} List<$E$> values = const <$E$>[\id$_0, \ldots, $ \id$_{n-1}$];
String toString() => \{ 0: `$E$.\id$_0$', $\ldots$, n-1: `$E$.\id$_{n-1}$'\}[index]
\}
-\end{dartCode}
+\end{normativeDartCode}
\commentary{
It is also a compile-time error to subclass, mix-in or implement an enum or to explicitly instantiate an enum.
@@ -5419,64 +6110,33 @@
\LMLabel{functionExpressions}
\LMHash{}%
-%% TODO(eernst): A function literal is a syntactic construct, and we may use
-%% function closurization to obtain a corresponding function object.
A \IndexCustom{function literal}{literal!function}
-is an object that encapsulates an executable unit of code.
+is an anonymous declaration and an expression
+that encapsulates an executable unit of code.
\begin{grammar}
<functionExpression> ::= <formalParameterPart> <functionBody>
\end{grammar}
-%% TODO[inference]: The static and dynamic type of a function literal
-%% interacts with inference: If a type-from-context $T$ exists and the
-%% function literal can be given a type which is a subtype of $T$, we may
-%% end up typing both the function as a whole and the body of the function
-%% very differently than we would in a situation where no type-from-context
-%% exists. So the rules below must be changed to be the default case (where
-%% no type-from-context is available, or it is `Object` or some other
-%% non-constraing type, and other cases where the type-from-context is
-%% actually used to select the function literal signature must be described
-%% specifically for each relevant type of situation.
+\LMHash{}%
+The grammar does not allow a function literal to declare a return type,
+but it is possible for a function literal to have a
+\IndexCustom{declared return type}{literal!function!declared return type},
+because it can be obtained by means of type inference.
+Such a return type is included
+when we refer to the declared return type of a function.
+
+\commentary{%
+Type inference will be specified in a future version of this document.
+Currently we consider type inference to be a phase that has completed,
+and this document specifies the meaning of Dart programs
+where inferred types have already been added.
+}
\LMHash{}%
-The class of a function literal implements the built-in class \FUNCTION{}.
-
-\LMHash{}%
-The static type of a function literal of the form
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
-
-\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$]) => $e$}
-
-\noindent
-is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow T_0$},
-
-\noindent
-%% TODO[inference]: The static type of the function literal may come from context.
-where $T_0$ is the static type of $e$.
-
-\LMHash{}%
-The static type of a function literal of the form
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
-
-\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$]) \ASYNC{} => $e$}
-
-\noindent
-is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
-
-\code{($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ Future<\flatten{T_0}>},
-
-\noindent
-where $T_0$ is the static type of $e$.
-
-\LMHash{}%
-In the previous two paragraphs, the type argument lists are omitted in the case where $m = 0$, and \flatten{T} is defined as follows:
+We define the auxiliary function
+\IndexCustom{\flatten{T}}{flatten(t)@\emph{flatten}$(T)$},
+which is used below and in other sections, as follows:
\begin{itemize}
\item If $T$ is \code{FutureOr<$S$>} for some $S$ then $\flatten{T} = S$.
@@ -5484,10 +6144,10 @@
\item Otherwise if
\code{$T <:$ Future}
then let $S$ be a type such that
-\code{$T <<$ Future<$S$>}
+\code{$T <:$ Future<$S$>}
and for all $R$, if
-\code{$T <<$ Future<$R$>}
-then $S << R$.
+\code{$T <:$ Future<$R$>}
+then $S <: R$.
\rationale{
This ensures that
@@ -5505,139 +6165,210 @@
\end{itemize}
\LMHash{}%
+\Case{Positional, arrow}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
+\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$]) => $e$}
+
+\noindent
+is
+\FunctionTypePositionalStd{T_0},
+
+\noindent
+%% TODO[inference]: The static type of the function literal may come from context.
+where $T_0$ is the static type of $e$.
+
+\LMHash{}%
+\Case{Positional, arrow, future}
+The static type of a function literal of the form
+
+\noindent
+\code{<\TypeParametersStd>}
+
+\noindent
+\code{($T_1\ a_1, \ldots,\ T_n\ a_n,$ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$]) \ASYNC{} => $e$}
+
+\noindent
+is
+\FunctionTypePositionalStdCr{\code{Future<\flatten{T_0}>}},
+
+\noindent
+where $T_0$ is the static type of $e$.
+
+\LMHash{}%
+\Case{Named, arrow}
+The static type of a function literal of the form
+
+\noindent
+\code{<\TypeParametersStd>}
+
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) => $e$}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow T_0$},
+\FunctionTypeNamedStd{T_0},
\noindent
where $T_0$ is the static type of $e$.
\LMHash{}%
+\Case{Named, arrow, future}
The static type of a function literal of the form
-\code{<$X_1 B_1, \ldots,\ X_m B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) \ASYNC{} => $e$}
\noindent
is
-
-\code{<$X_1 B_1, \ldots,\ X_m B_m$>}
-
-\code{($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow$ Future<\flatten{T_0}>},
+\FunctionTypeNamedStdCr{\code{Future<\flatten{T_0}>}},
\noindent
where $T_0$ is the static type of $e$.
\LMHash{}%
+\Case{Positional, block}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParameters{X}{B}{S}>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k}= d_k$]) \{ $s$ \}}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ \DYNAMIC{}}.
+\FunctionTypePositionalStdCr{\DYNAMIC}
\LMHash{}%
+\Case{Positional, block, future}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$]) \ASYNC{} \{ $s$ \}}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ Future}.
+%% TODO(eernst): Adjust to take type inference into account.
+\FunctionTypePositionalStdCr{\code{Future}}.
\LMHash{}%
+\Case{Positional, block, stream}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k}= d_k$]) \ASYNC*{} \{ $s$ \}}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ Stream}.
+%% TODO(eernst): Adjust to take type inference into account.
+\FunctionTypePositionalStdCr{\code{Stream}}.
\LMHash{}%
+\Case{Positional, block, iterable}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k}= d_k$]) \SYNC*{} \{ $s$ \}}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ Iterable}.
+%% TODO(eernst): Adjust to take type inference into account.
+\FunctionTypePositionalStdCr{\code{Iterable}}.
\LMHash{}%
+\Case{Named, block}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k}= d_k$]) \{ $s$ \}}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ \DYNAMIC{}}.
+%% TODO(eernst): Adjust to take type inference into account.
+\FunctionTypePositionalStdCr{\DYNAMIC}.
\LMHash{}%
+\Case{Named, block, future}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) \ASYNC{} \{ $s$ \}}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow$ Future}.
+%% TODO(eernst): Adjust to take type inference into account.
+\FunctionTypeNamedStdCr{\code{Future}}.
\LMHash{}%
+\Case{Named, block, stream}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) \ASYNC*{} \{ $s$ \}}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow$ Stream}.
+%% TODO(eernst): Adjust to take type inference into account.
+\FunctionTypeNamedStdCr{\code{Stream}}.
\LMHash{}%
+\Case{Named, block, iterable}
The static type of a function literal of the form
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
+\noindent
+\code{<\TypeParametersStd>}
+\noindent
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) \SYNC*{} \{ $s$ \}}
\noindent
is
-
-\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow$ Iterable}.
+%% TODO(eernst): Adjust to take type inference into account.
+\FunctionTypeNamedStdCr{\code{Iterable}}.
\LMHash{}%
In all of the above cases,
the type argument lists are omitted when $m=0$,
-and whenever $T_i, 1 \le i \le n+k$, is not specified,
+and whenever $T_i$ is not specified, $i \in 1 .. n+k$,
it is considered to have been specified as \DYNAMIC{}.
+\LMHash{}%
+Evaluation of a function literal yields a function object $o$.
+
+\commentary{
+The run-time type of $o$ is specified based on
+the static type $T$ of the function literal
+and the binding of type variables occurring in $T$
+at the occasion where the evaluation occurred
+(\ref{typeOfAFunction}).
+}
+
\subsection{This}
\LMLabel{this}
@@ -6403,7 +7134,7 @@
the word `function' is more low-level than `function object',
but `function' still denotes a semantic entity
which is associated with a function declaration,
-even though there may not be corresponding entity in the heap at run time.
+even though there may not be a corresponding entity in the heap at run time.
}
\LMHash{}%
@@ -6425,13 +7156,16 @@
and let $p_{h+1}, \ldots, p_{h+k}$ be the optional parameters of $F$.
Let $S_i$ be the static type of the formal parameters $p_i, i \in 1 .. h+k$,
and for each $q$ let $S_q$ be the type of the parameter named $q$,
-where each parameter type is obtained by replacing $X_j$ by $A_j, j \in 1 .. s$, in the given parameter type annotation.
+where each parameter type is obtained by replacing $X_j$ by $A_j, j \in 1 .. s$,
+in the given parameter type annotation.
Finally, let $T_i$ be the static type of $a_i$.
\commentary{
-We have an actual argument list consisting of $r$ type arguments, $m$ positional arguments, and $l$ named arguments.
-We have a function with $s$ type parameters, $h$ required parameters, and $k$ optional parameters.
-Figure~\ref{fig:argumentsAndParameters} shows how this situation may arise.
+We have an actual argument list consisting of $r$ type arguments,
+$m$ positional arguments, and $l$ named arguments.
+We have a function with $s$ type parameters,
+$h$ required parameters, and $k$ optional parameters.
+Figure~\ref{fig:argumentsAndParameters} shows how this situation arises.
}
% View on declaration:
@@ -6518,6 +7252,32 @@
It is a compile-time error if $T_j$ may not be assigned to $S_j, j \in 1 .. m$.
It is a compile-time error if $T_{m+j}$ may not be assigned to $S_{q_j}, j \in 1 .. l$.
+\commentary{
+Consider the case where the function invocation in focus here is
+an instance method invocation.
+In that case, for each actual argument,
+the corresponding parameter may be covariant.
+However, the above assignability requirements apply equally
+both when the parameter is covariant and when it is not.
+}
+
+\rationale{
+Parameter covariance in an instance method invocation can be introduced by
+a subtype of the statically known receiver type,
+which means that any attempt to flag a given actual argument as dangerous
+due to the dynamic type check that it will be subjected to
+will be incomplete:
+some actual arguments can be subjected to such a dynamic type check
+even though this is not known statically at the call site.
+This is not surprising for a mechanism like parameter covariance which is
+designed for the very purpose of allowing developers to explicitly request
+that this specific kind of compile-time safety is violated.
+The point is that this mechanism postpones the enforcement of
+the underlying invariant to run time,
+and in return allows some useful program designs
+that would otherwise be rejected at compile-time.
+}
+
\LMHash{}%
For the dynamic semantics,
let $f$ be a function with $s$ type parameters and $h$ required parameters;
@@ -6764,14 +7524,26 @@
\LMHash{}%
Function closurization applied to a function declaration $f$
amounts to the creation of a function object $o$
-which is an instance of a class whose interface is a subtype of the actual type
+which is an instance of a class $C$ whose interface is
+a subtype of the actual type $F$
(\ref{actualTypeOfADeclaration})
corresponding to the signature in the function declaration $f$,
using the current bindings of type variables, if any.
+There does not exist a function type $F'$ which is a proper subtype of $F$
+such that $C$ is a subtype of $F'$.
If $f$ denotes a static method or top-level function,
-the corresponding class does not override the \code{==} operator
+class $C$ does not override the \code{==} operator
inherited from the \code{Object} class.
-%
+
+\commentary{
+In other words, $C$ has the freedom to be a proper subtype of
+the function type that we can read off of the declaration of $f$
+because it may need to be a specific internal platform defined class,
+but $C$ does not have the freedom to be a subtype of
+a different and more special function type, and it cannot be \code{Null}.
+}
+
+\LMHash{}%
An invocation of $o$ with a given argument list will bind actuals to formals
in the same way as an invocation of $f$
(\ref{bindingActualsToFormals}),
@@ -6949,13 +7721,10 @@
\LMHash{}%
Let $T$ be the static type of $e$.
-It is a compile-time error if $T$ does not have an accessible (\ref{privacy}) instance member named $m$, unless either:
+It is a compile-time error if $T$ does not have an accessible
+(\ref{privacy})
+instance member named $m$, unless either:
\begin{itemize}
-\item
-%% TODO(eernst): This is metaclass stuff, should be deleted.
-$T$ is \code{Type}, $e$ is a constant type literal,
-and the class corresponding to $e$ has a static getter named $m$.
-Or
\item $T$ is \DYNAMIC{}.
Or
\item $T$ is \FUNCTION{} and $m$ is \CALL.
@@ -7006,30 +7775,24 @@
\LMHash{}%
First, the expression $e$ is evaluated to a value $o$.
-Let $f$ be the result of looking up (\ref{lookup}) method $m$ in $o$ with respect to the current library $L$.
-
-\LMHash{}%
-%% TODO(eernst): This is metaclass stuff, should be deleted.
-If method lookup succeeded,
-but $o$ is an instance of \code{Type} and $e$ is not a constant type literal,
-then if $m$ is a method that forwards (\ref{functionDeclarations}) to a static method,
-method lookup is considered to have failed.
+Let $f$ be the result of looking up
+(\ref{lookup})
+method $m$ in $o$ with respect to the current library $L$.
\LMHash{}%
If the method lookup succeeded,
-the binding of actual arguments to formal parameters is performed as specified in Section~\ref{bindingActualsToFormals}.
-The body of $f$ is then executed with respect to the bindings that resulted from the evaluation of the argument list,
+the binding of actual arguments to formal parameters is performed
+as specified in Section~\ref{bindingActualsToFormals}.
+The body of $f$ is then executed with respect to the bindings
+that resulted from the evaluation of the argument list,
and with \THIS{} bound to $o$.
The value of $i$ is the value returned by the execution of $f$'s body.
\LMHash{}%
If the method lookup failed,
-then let $g$ be the result of looking up getter (\ref{lookup}) $m$ in $o$ with respect to $L$.
-%% TODO(eernst): This is metaclass stuff, should be deleted.
-If getter lookup succeeded,
-but $o$ is an instance of \code{Type} and $e$ is not a constant type literal,
-then if $g$ is a getter that forwards to a static getter,
-getter lookup is considered to have failed.
+then let $g$ be the result of looking up getter
+(\ref{lookup})
+$m$ in $o$ with respect to $L$.
\LMHash{}%
If the getter lookup succeeded then invoke the getter $o.m$
@@ -7217,77 +7980,152 @@
A property extraction can be either:
\begin{enumerate}
\item An instance method closurization,
-which converts a method into a function object
-(\ref{ordinaryMemberClosurization}).
-Or
-\item A getter invocation, which returns the result of invoking of a getter method
-(\ref{getterAccessAndMethodExtraction}).
+ which converts a method into a function object
+ (\ref{ordinaryMemberClosurization}).
+ Or
+\item A getter invocation, which returns
+ the result of invoking of a getter method
+ (\ref{getterAccessAndMethodExtraction}).
\end{enumerate}
\commentary{
-Function objects derived from members via closurization are colloquially known as tear-offs.
+Function objects derived from members via closurization
+are colloquially known as tear-offs.
}
Property extraction can be either conditional or unconditional.
\LMHash{}%
-Evaluation of a \IndexCustom{conditional property extraction expression}{%
+\Case{Conditional}
+Consider a \IndexCustom{conditional property extraction expression}{%
property extraction!conditional}
-$e$ of the form \code{$e_1$?.\id} proceeds as follows:
+$i$ of the form \code{$e$?.\id}.
\LMHash{}%
-If $e_1$ is a type literal, $e$ is equivalent to \code{$e_1$.$m$}.
+If $e$ is a type literal, $i$ is equivalent to \code{$e$.\id}.
\LMHash{}%
-Otherwise evaluate $e_1$ to an object $o$.
-If $o$ is the null object, $e$ evaluates to the null object (\ref{null}).
+Otherwise, the static type of $i$ is the same as
+the static type of \code{$e$.\id}.
+Let $T$ be the static type of $e$,
+and let $y$ be a fresh variable of type $T$.
+Except for errors inside $e$ and references to the name $y$,
+exactly the same compile-time errors that would be caused by \code{$y$.\id}
+are also generated in the case of \code{$e$?.\id}.
+
+\LMHash{}%
+Evaluation of a conditional property extraction expression $i$
+of the form \code{$e$?.\id} proceeds as follows:
+
+\LMHash{}%
+If $e$ is a type literal,
+evaluation of $i$ amounts to evaluation of \code{$e$.\id}.
+
+\LMHash{}%
+Otherwise evaluate $e$ to an object $o$.
+If $o$ is the null object, $i$ evaluates to the null object (\ref{null}).
Otherwise let $x$ be a fresh variable bound to $o$
and evaluate \code{$x$.\id} to a value $r$.
-Then $e$ evaluates to $r$.
-
-The static type of $e$ is the same as the static type of \code{$e_1$.\id}.
-Let $T$ be the static type of $e_1$ and let $y$ be a fresh variable of type $T$.
-Exactly the same compile-time errors that would be caused by \code{$y$.\id} are also generated in the case of \code{$e_1$?.\id}.
+Then $i$ evaluates to $r$.
\LMHash{}%
-\IndexCustom{Unconditional property extraction}{%
+\Case{Unconditional}
+Let \id{} be an identifier;
+an \IndexCustom{unconditional property extraction}{%
property extraction!unconditional}
-has one of two syntactic forms:
-$e.m$ (\ref{getterAccessAndMethodExtraction}) or
-$\SUPER.m$ (\ref{superGetterAccessAndMethodClosurization}),
-where $e$ is an expression and $m$ is an identifier.
+may be of the form \code{$e$.\id} where $e$ is an expression
+(\ref{getterAccessAndMethodExtraction}),
+or of the form \code{\SUPER.\id}
+(\ref{superGetterAccessAndMethodClosurization}).
\subsubsection{Getter Access and Method Extraction}
\LMLabel{getterAccessAndMethodExtraction}
\LMHash{}%
-Evaluation of a property extraction $i$ of the form $e.m$ proceeds as follows:
+Consider an unconditional property extraction $i$
+(\ref{propertyExtraction})
+of the form \code{$e$.\id}.
+It is a compile-time error if \id{} is a member of class \code{Object}
+and $e$ is either a prefix object (\ref{imports})
+or a type literal.
+
+\commentary{
+It may seem obvious that it is an error to use prefix object,
+but more surprising that it also applies to a type literal.
+In particular, we cannot use \code{int.toString}
+to obtain a function object for the \code{toString} method of the
+\code{Type} object for \code{int}.
+But we can use \code{(int).toString}:
+$e$ is then not a type literal, but a parenthesized expression.
+}
+
+\rationale{
+This is a pragmatic trade-off.
+The ability to tear off instance methods on instances of \code{Type}
+was considered less useful,
+and it was considered more useful to insist on the simple rule that
+a method tear-off on a type literal is \emph{always} a tear-off
+of a static method on the denoted class.
+}
+
+\LMHash{}%
+Let $T$ be the static type of $e$.
+It is a compile-time error if $T$ does not have a method or getter named \id{}
+unless $T$ is \DYNAMIC{},
+or $T$ is \FUNCTION{} and \id{} is \code{call}.
+The static type of $i$ is:
+
+\begin{itemize}
+\item The declared return type of \code{$T$.\id},
+ if $T$ has an accessible instance getter named \id{}.
+\item The function type of the method signature \code{$T$.\id},
+ if $T$ has an accessible instance method named \id{}.
+\item The type \DYNAMIC{} otherwise.
+ \commentary{This only occurs when $T$ is \DYNAMIC{} or \FUNCTION.}
+\end{itemize}
+
+\commentary{
+Note that the type of a method tear-off ignores
+whether any given parameter is covariant.
+However, the dynamic type of a function object
+thus obtained does take parameter covariance into account.
+}
+
+\LMHash{}%
+Evaluation of a property extraction $i$ of the form \code{$e$.\id} proceeds as follows:
\LMHash{}%
First, the expression $e$ is evaluated to an object $o$.
-Let $f$ be the result of looking up (\ref{lookup}) method (\ref{instanceMethods}) $m$ in $o$ with respect to the current library $L$.
-%% TODO(eernst): This is metaclass stuff, should be deleted.
-If $o$ is an instance of \code{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards (\ref{functionDeclarations}) to a static method, method lookup fails.
-If method lookup succeeds then $i$ evaluates to the closurization of method $f$ on object $o$ (\ref{ordinaryMemberClosurization}).
+Let $f$ be the result of looking up (\ref{lookup}) method
+(\ref{instanceMethods})
+\id{} in $o$ with respect to the current library $L$.
+If method lookup succeeds then $i$ evaluates to
+the closurization of method $f$ on object $o$
+(\ref{ordinaryMemberClosurization}).
\commentary{
Note that $f$ is never an abstract method, because method lookup skips abstract methods.
-Hence, if $m$ refers to an abstract method, we will continue to the next step.
-However, since methods and getters never override each other, getter lookup will necessarily fail as well, and \code{noSuchMethod()} will ultimately be invoked.
+If the method lookup failed, e.g.,
+because there is an abstract declaration of \id, but no concrete declaration,
+we will continue to the next step.
+However, since methods and getters never override each other,
+getter lookup will necessarily fail as well,
+and \code{noSuchMethod()} will ultimately be invoked.
The regrettable implication is that the error will refer to a missing getter rather than an attempt to closurize an abstract method.
}
\LMHash{}%
Otherwise, $i$ is a getter invocation.
-Let $f$ be the result of looking up (\ref{lookup}) getter (\ref{getters}) $m$ in $o$ with respect to $L$.
-%% TODO(eernst): This is metaclass stuff, should be deleted.
-If $o$ is an instance of \code{Type} but $e$ is not a constant type literal, then if $f$ is a getter that forwards to a static getter, getter lookup fails.
+Let $f$ be the result of looking up (\ref{lookup}) getter
+(\ref{getters})
+\id{} in $o$ with respect to $L$.
Otherwise, the body of $f$ is executed with \THIS{} bound to $o$.
The value of $i$ is the result returned by the call to the getter function.
\LMHash{}%
-If the getter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that:
+If the getter lookup has failed,
+then a new instance $im$ of the predefined class \code{Invocation} is created, such that:
\begin{itemize}
\item \code{$im$.isGetter} evaluates to \code{\TRUE{}}.
\item \code{$im$.memberName} evaluates to the symbol \code{m}.
@@ -7310,82 +8148,75 @@
when the static type of $e$ is \DYNAMIC{}.
}
-\LMHash{}%
-It is a compile-time error if $m$ is a member of class \code{Object} and $e$ is either a prefix object (\ref{imports}) or a constant type literal.
-
-\commentary{
-This precludes \code{int.toString} but not \code{(int).toString} because in the latter case, $e$ is a parenthesized expression.
-}
-
-\LMHash{}%
-Let $T$ be the static type of $e$.
-It is a compile-time error if $T$ does not have a method or getter named $m$,
-%% TODO(eernst): This is metaclass stuff, should be deleted.
-unless $T$ is \code{Type},
-$e$ is a constant type literal,
-and the class corresponding to $e$ has a static method or getter named $m$.
-
-\LMHash{}%
-The static type of $i$ is:
-\begin{itemize}
-\item The declared return type of \code{$T$.$m$}, if $T$ has an accessible instance getter named $m$.
-\item
-%% TODO(eernst): This is metaclass stuff, should be deleted.
-The declared return type of $m$, if $T$ is \code{Type},
-$e$ is a constant type literal
-and the class corresponding to $e$ declares an accessible static getter named $m$.
-\item The static type of function \code{$T$.$m$} if $T$ has an accessible instance method named $m$.
-\item
-%% TODO(eernst): This is metaclass stuff, should be deleted.
-The static type of function $m$, if $T$ is \code{Type},
-$e$ is a constant type literal
-and the class corresponding to $e$ declares an accessible static method named $m$.
-\item The type \DYNAMIC{} otherwise.
-\end{itemize}
-
\subsubsection{Super Getter Access and Method Closurization}
\LMLabel{superGetterAccessAndMethodClosurization}
\LMHash{}%
+Consider a property extraction $i$ of the form \code{\SUPER.\id}.
+
+\LMHash{}%
+Let $S$ be the superclass of the immediately enclosing class.
+It is a compile-time error if $S$ does not have
+an accessible instance method or getter named \id.
+The static type of $i$ is:
+
+\begin{itemize}
+\item The declared return type of \code{$S$.\id},
+ if $S$ has an accessible instance getter named \id.
+\item The function type of the method signature \code{$S$.\id},
+ if $S$ has an accessible instance method named \id.
+\item The type \DYNAMIC{} otherwise.
+ \commentary{This only occurs when $T$ is \DYNAMIC{} or \FUNCTION.}
+\end{itemize}
+
+\commentary{
+Note that the type of a method tear-off ignores
+whether any given parameter is covariant.
+However, the dynamic type of a function object
+thus obtained does take parameter covariance into account.
+}
+
+\LMHash{}%
Evaluation of a property extraction $i$ of the form $\SUPER.m$ proceeds as follows:
\LMHash{}%
-Let $g$ be the method currently executing, and let $C$ be the class in which $g$ was looked up.
-Let $S_{dynamic}$ be the superclass of $C$.
-Let $f$ be the result of looking up method $m$ in $S_{dynamic}$ with respect to the current library $L$.
-If method lookup succeeds then $i$ evaluates to the closurization of method $f$ with respect to superclass $S_{dynamic}$ (\ref{superClosurization}).
+Let $g$ be the method implementation currently executing,
+and let $C$ be the class in which $g$ is declared.
+Let $S$ be the superclass of $C$.
+Let $f$ be the result of looking up method \id{} in $S$
+with respect to the current library $L$.
+If method lookup succeeds then $i$ evaluates to
+the closurization of method $f$
+with respect to superclass $S$
+(\ref{superClosurization}).
\LMHash{}%
Otherwise, $i$ is a getter invocation.
-Let $f$ be the result of looking up getter $m$ in $S_{dynamic}$ with respect to $L$.
+Let $f$ be the result of looking up
+getter \id{} in $S$ with respect to $L$.
The body of $f$ is executed with \THIS{} bound to the current value of \THIS{}.
The value of $i$ is the result returned by the call to the getter function.
\commentary{
The getter lookup will not fail, because it is a compile-time error to have
-a super property extraction of a member $m$ when the superclass $S_{dynamic}$
-does not have a concrete member named $m$.
+a super property extraction of a member \id{} when the superclass $S$
+does not have a concrete member named \id.
}
-\LMHash{}%
-Let $S_{static}$ be the superclass of the immediately enclosing class.
-It is a compile-time error if $S_{static}$ does not have an accessible instance method or getter named $m$.
-
-The static type of $i$ is:
-\begin{itemize}
-\item The declared return type of $S_{static}.m$, if $S_{static}$ has an accessible instance getter named $m$.
-\item The static type of function $S_{static}.m$, if $S_{static}$ has an accessible instance method named $m$.
-\item The type \DYNAMIC{} otherwise.
-\end{itemize}
-
\subsubsection{Ordinary Member Closurization}
\LMLabel{ordinaryMemberClosurization}
+\LMHash{}%
+This section specifies the dynamic semantics of
+ordinary member closurizations.
+
\commentary{
Note that the non-generic case is covered implicitly using $s = 0$,
-in which case the type parameter declarations are omitted (\ref{generics}).
+in which case the type parameter declaration lists
+and the actual type argument lists passed in invocations
+are omitted (\ref{generics}).
}
\LMHash{}%
@@ -7404,26 +8235,30 @@
%\item $(a) \{\RETURN{}$ $u[a];$\} if $f$ is named \code{[]}.
%\item $(a, b) \{\RETURN{}$ $u[a] = b;$\} if $f$ is named \code{[]=}.
\item
-\begin{dartCode}
-<$X_1\ \EXTENDS\ B'_1, \ldots,\ X_s\ \EXTENDS\ B'_s$>
-($T_1\ r_1, \ldots,\ T_n\ r_n,\ $\{$T_{n+1}\ p_1 = d_1, \ldots,\ T_{n+k}\ p_k = d_k$\}) =>
- $u.m$<$X_1, \ldots,\ X_s$>($r_1, \ldots,\ r_n,\ p_1$: $p_1, \ldots,\ p_k$: $p_k$);
-\end{dartCode}
-if $f$ is named $m$ and has type parameter declarations
-$X_1\ \EXTENDS\ B_1$, \ldots,\ $X_s\ \EXTENDS\ B_s$,
-required parameters $r_1, \ldots, r_n$,
-and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+\begin{normativeDartCode}
+<\TypeParameters{X}{B'}{s}>
+($\PairList{T}{p}{1}{n},\ $\{$T_{n+1}\ p_{n+1} = d_1, \ldots,\ T_{n+k}\ p_{n+k} = d_k$\}) =>
+\quad$u$.$m$<\List{X}{1}{s}>($\List{p}{1}{n},\ p_{n+1}$: $p_{n+1}, \ldots,\ p_{n+k}$: $p_{n+k}$);
+\end{normativeDartCode}
+where $f$ is an instance method named $m$
+which has type parameter declarations
+\TypeParametersStd{},
+required parameters \List{p}{1}{n},
+and named parameters \List{p}{n+1}{n+k} with defaults \List{d}{1}{k},
+using \code{null} for parameters whose default value is not specified.
\item
-\begin{dartCode}
-<$X_1\ \EXTENDS\ B'_1, \ldots,\ X_s\ \EXTENDS\ B'_s$>
-($T_1\ r_1, \ldots,\ T_n\ r_n,\ $[$T_{n+1}\ p_1 = d_1, \ldots,\ T_{n+k}\ p_k = d_k$]) =>
- $u.m$<$X_1, \ldots,\ X_s$>($r_1, \ldots,\ r_n,\ p_1, \ldots,\ p_k$);
-\end{dartCode}
-if $f$ is named $m$ and has type parameter declarations
-$X_1\ \EXTENDS\ B_1$, \ldots,\ $X_s\ \EXTENDS\ B_s$,
-required parameters $r_1, \ldots, r_n$,
+\begin{normativeDartCode}
+<\TypeParameters{X}{B'}{s}>
+($\PairList{T}{p}{1}{n},\ $[$T_{n+1}\ p_{n+1} = d_1, \ldots,\ T_{n+k}\ p_{n+k} = d_k$]) =>
+\quad$u$.$m$<\List{X}{1}{s}>(\List{p}{1}{n+k});
+\end{normativeDartCode}
+where $f$ is an instance method named $m$
+which has type parameter declarations
+\TypeParametersStd{},
+required parameters \List{p}{1}{n},
and optional positional parameters
-$p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+\List{p}{n+1}{n+k} with defaults \List{d}{1}{k},
+using \code{null} for parameters whose default value is not specified.
\end{itemize}
\LMHash{}%
@@ -7434,23 +8269,14 @@
Then $B'_j = [t'_1/X'_1, \ldots, t'_{s'}/X'_{s'}]B_j, j \in 1 .. s$.
\commentary{
-That is, we replace the formal type parameters of the enclosing class, if any, by the corresponding actual type arguments.
+That is, we replace the formal type parameters of the enclosing class, if any,
+by the corresponding actual type arguments.
}
-%% TODO: We should specify tear-offs by means of their (static and dynamice)
-%% semantics, not via syntactic sugar, because the syntactic sugar causes
-%% weird phenomena like `a type annotation that denotes the same type as`
-%% etc.
-
-%% TODO[covariant-parameters]: When adding a specification of covariant
-%% parameters we will need to indicate that the dynamic parameter type is
-%% `Object` for such a parameter, and that the static type of the function
-%% as a whole will be taken from the statically known type of the receiver
-%% of the tear-off invocation.
-
\LMHash{}%
The parameter types $T_j, j \in 1 .. n+k$, are determined as follows:
-Let the method declaration $D$ be the implementation of $m$ which is invoked by the expression in the body.
+Let the method declaration $D$ be the implementation of $m$
+which is invoked by the expression in the body.
Let $T$ be the class that contains $D$.
\commentary{
@@ -7458,8 +8284,24 @@
}
\LMHash{}%
+For each parameter $p_j$, $j \in 1 .. n+k$, if $p_j$ is covariant
+(\ref{covariantParameters})
+then $T_j$ is the built-in class \code{Object}.
+
+\commentary{
+This is concerned with the dynamic type of the function object obtained by
+the member closurization.
+The static type of the expression that gives rise to the member closurization
+is specified elsewhere
+(\ref{propertyExtraction},
+\ref{getterAccessAndMethodExtraction}).
+Note that for the static type it is ignored whether a parameter is covariant.
+}
+
+\LMHash{}%
If $T$ is a non-generic class then for $j \in 1 .. n+k$,
-$T_j$ is a type annotation that denotes the same type as that which is denoted by the type annotation on the corresponding parameter declaration in $D$.
+$T_j$ is a type annotation that denotes the same type as that
+which is denoted by the type annotation on the corresponding parameter declaration in $D$.
If that parameter declaration has no type annotation then $T_j$ is \DYNAMIC{}.
\LMHash{}%
@@ -7479,11 +8321,6 @@
obtained by closurization of $m$ on $o_1$ respectively $o_2$.
Then \code{$c_1$ == $c_2$} evaluates to true if and only if $o_1$ and $o_2$ is the same object.
-%% TODO(eernst): This being a comment, it's presumably spelled out somewhere
-%% else. Find it and check that it does actually say that it is an error
-%% except when the type of $e$ is \DYNAMIC{}.
-%\item The static type of the property extraction is the static type of function \code{$T$.$m$}, where $T$ is the static type of $e$, if \code{$T$.$m$} is defined. Otherwise the static type of $e.m$ is \DYNAMIC{}.
-
\commentary{
% Spell out the consequences for `==` and for `identical`, for the receivers
% and for the closurizations.
@@ -7505,6 +8342,10 @@
\subsubsection{Super Closurization}
\LMLabel{superClosurization}
+\LMHash{}%
+This section specifies the dynamic semantics of
+super closurizations.
+
\commentary{
Note that the non-generic case is covered implicitly using $s = 0$,
in which case the type parameter declarations are omitted (\ref{generics}).
@@ -7533,25 +8374,28 @@
%\item $(a) \{\RETURN{}$ $\SUPER[a];$\} if $f$ is named \code{[]}.
%\item $(a, b) \{\RETURN{}$ $\SUPER[a] = b;$\} if $f$ is named \code{[]=}.
\item
-\begin{dartCode}
-<$X_1\ \EXTENDS\ B'_1, \ldots,\ X_s\ \EXTENDS\ B'_s$>
-($T_1\ r_1, \ldots,\ T_n\ r_n,\ $\{$T_{n+1}\ p_1 = d_1, \ldots,\ T_{n+k}\ p_k = d_k$\}) =>
- \SUPER$.m$<$X_1, \ldots,\ X_s$>($r_1, \ldots,\ r_n,\ p_1$: $p_1, \ldots,\ p_k$: $p_k$);
-\end{dartCode}
-if $f$ is named $m$ and has type parameter declarations
-$X_1\ \EXTENDS\ B_1$, \ldots,\ $X_s\ \EXTENDS\ B_s$,
-required parameters $r_1, \ldots, r_n$,
-and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+\begin{normativeDartCode}
+<\TypeParameters{X}{B'}{s}>
+($\PairList{T}{p}{1}{n},\ $\{$T_{n+1}\ p_{n+1} = d_1, \ldots,\ T_{n+k}\ p_{n+k} = d_k$\}) =>
+\quad\SUPER$.m$<\List{X}{1}{s}>($\List{p}{1}{n},\ p_{n+1}$: $p_{n+1}, \ldots,\ p_{n+k}$: $p_{n+k}$);
+\end{normativeDartCode}
+where $f$ is an instance method named $m$
+which has type parameter declarations
+\TypeParametersStd{},
+required parameters \List{p}{1}{n},
+and named parameters \List{p}{n+1}{n+k} with defaults \List{d}{1}{k}.
\item
-\begin{dartCode}
-<$X_1\ \EXTENDS\ B'_1, \ldots,\ X_s\ \EXTENDS\ B'_s$>
-($T_1\ r_1, \ldots,\ T_n\ r_n,\ $[$T_{n+1}\ p_1 = d_1, \ldots,\ T_{n+k}\ p_k = d_k$]) =>
- \SUPER.$m$<$X_1, \ldots,\ X_s$>($r_1, \ldots,\ r_n,\ p_1, \ldots,\ p_k$);
-\end{dartCode}
-if $f$ is named $m$ and has type parameter declarations
-$X_1\ \EXTENDS\ B_1$, \ldots,\ $X_s\ \EXTENDS\ B_s$,
-required parameters $r_1, \ldots, r_n$,
-and optional positional parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+\begin{normativeDartCode}
+<\TypeParameters{X}{B'}{s}>
+($\PairList{T}{p}{1}{n},\ $[$T_{n+1}\ p_{n+1} = d_1, \ldots,\ T_{n+k}\ p_{n+k} = d_k$]) =>
+\quad\SUPER.$m$<\List{X}{1}{s}>(\List{p}{1}{n+k});
+\end{normativeDartCode}
+where $f$ is an instance method named $m$
+which has type parameter declarations
+\TypeParametersStd{},
+required parameters \List{p}{1}{n},
+and optional positional parameters
+\List{p}{n+1}{n+k} with defaults \List{d}{1}{k}.
\end{itemize}
\commentary{
@@ -7567,28 +8411,36 @@
Then $B'_j = [t'_1/X'_1, \ldots, t'_{s'}/X'_{s'}]B_j, j \in 1 .. s$.
\commentary{
-That is, we replace the formal type parameters of the enclosing class, if any, by the corresponding actual type arguments.
-We need to consider the type arguments with respect to a specific class because it is possible for a class to pass different type arguments to its superclass than the ones it receives itself.
+That is, we replace the formal type parameters of the enclosing class, if any,
+by the corresponding actual type arguments.
+We need to consider the type arguments with respect to a specific class because
+it is possible for a class to pass different type arguments to its superclass
+than the ones it receives itself.
}
-%% TODO: We should specify tear-offs by means of their (static and dynamice)
-%% semantics, not via syntactic sugar, because the syntactic sugar causes
-%% weird phenomena like `a type annotation that denotes the same type as`
-%% etc.
-
-%% TODO[covariant-parameters]: When adding a specification of covariant
-%% parameters we will need to indicate that the dynamic parameter type is
-%% `Object` for such a parameter, and that the static type of the function
-%% as a whole will be taken from the statically known type of the receiver
-%% of the tear-off invocation.
-
\LMHash{}%
The parameter types $T_j, j \in 1 .. n+k$, are determined as follows:
Let the method declaration $D$ be the implementation of $m$ in $S$.
\LMHash{}%
+For each parameter $p_j$, $j \in 1 .. n+k$, if $p_j$ is covariant
+(\ref{covariantParameters})
+then $T_j$ is the built-in class \code{Object}.
+
+\commentary{
+This is concerned with the dynamic type of the function object obtained by
+the super closurization.
+The static type of the expression that gives rise to the super closurization
+is specified elsewhere
+(\ref{propertyExtraction},
+\ref{superGetterAccessAndMethodClosurization}).
+Note that for the static type it is ignored whether a parameter is covariant.
+}
+
+\LMHash{}%
If $S$ is a non-generic class then for $j \in 1 .. n+k$,
-$T_j$ is a type annotation that denotes the same type as that which is denoted by the type annotation on the corresponding parameter declaration in $D$.
+$T_j$ is a type annotation that denotes the same type as that
+which is denoted by the type annotation on the corresponding parameter declaration in $D$.
If that parameter declaration has no type annotation then $T_j$ is \DYNAMIC{}.
\LMHash{}%
@@ -9442,13 +10294,13 @@
and let $n0$ be an identifier that does not occur anywhere in the program.
A for statement of the form \code{\FOR{} ($D$ \id{} \IN{} $e$) $s$} is equivalent to the following code:
-\begin{dartCode}
+\begin{normativeDartCode}
\VAR{} $n0$ = $e$.iterator;
\WHILE{} ($n0$.moveNext()) \{
$D$ \id{} = $n0$.current;
$s$
\}
-\end{dartCode}
+\end{normativeDartCode}
For purposes of static typechecking,
this code is checked under the assumption that $n0$ is declared to be of type $T$,
@@ -9623,24 +10475,24 @@
\LMHash{}%
Given a switch statement of the form
-\begin{dartCode}
+\begin{normativeDartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
$label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
\}
-\end{dartCode}
+\end{normativeDartCode}
or the form
-\begin{dartCode}
+\begin{normativeDartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
\}
-\end{dartCode}
+\end{normativeDartCode}
it is a compile-time error unless the expressions $e_k$ are constant expressions for all $k \in 1 .. n$.
It is a compile-time error if the values of the expressions $e_k$ are not either:
@@ -9684,24 +10536,24 @@
\LMHash{}%
Execution of a switch statement of the form
-\begin{dartCode}
+\begin{normativeDartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
$label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
\}
-\end{dartCode}
+\end{normativeDartCode}
or the form
-\begin{dartCode}
+\begin{normativeDartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
\}
-\end{dartCode}
+\end{normativeDartCode}
proceeds as follows:
@@ -9721,14 +10573,14 @@
\LMHash{}%
Matching of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
-\begin{dartCode}
+\begin{normativeDartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
$label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
\}
-\end{dartCode}
+\end{normativeDartCode}
against the value of a variable \id{} proceeds as follows:
@@ -9743,13 +10595,13 @@
\LMHash{}%
Matching of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
-\begin{dartCode}
+\begin{normativeDartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
\}
-\end{dartCode}
+\end{normativeDartCode}
against the value of a variable \id{} proceeds as follows:
@@ -9813,24 +10665,24 @@
\LMHash{}%
Execution of the case statements $s_h$ of a switch statement
-\begin{dartCode}
+\begin{normativeDartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
\}
-\end{dartCode}
+\end{normativeDartCode}
or a switch statement
-\begin{dartCode}
+\begin{normativeDartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
$label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
\}
-\end{dartCode}
+\end{normativeDartCode}
proceeds as follows:
@@ -9940,13 +10792,13 @@
\LMHash{}%
Execution of a \TRY{} statement $s$ of the form:
-\begin{dartCode}
+\begin{normativeDartCode}
\TRY{} $b$
\ON{} $T_1$ \CATCH{} ($e_1$, $t_1$) $c_1$
\ldots{}
\ON{} $T_n$ \CATCH{} ($e_n$, $t_n$) $c_n$
\FINALLY{} $f$
-\end{dartCode}
+\end{normativeDartCode}
proceeds as follows:
\LMHash{}%
@@ -9971,11 +10823,11 @@
\LMHash{}%
Matching an exception object $e$ and stack trace $t$ against a (potentially empty) sequence of \ON{}-\CATCH{} clauses of the form
-\begin{dartCode}
+\begin{normativeDartCode}
\ON{} $T_1$ \CATCH{} ($e_1$, $st_1$) \{ $s_1$ \}
\ldots
\ON{} $T_n$ \CATCH{} ($e_n$, $st_n$) \{ $s_n$ \}
-\end{dartCode}
+\end{normativeDartCode}
proceeds as follows:
\LMHash{}%
@@ -9991,11 +10843,11 @@
\LMHash{}%
Otherwise, if the first clause did not match $e$, $e$ and $t$ are recursively matched against the remaining \ON{}-\CATCH{} clauses:
-\begin{dartCode}
+\begin{normativeDartCode}
\ON{} $T_2$ \CATCH{} ($e_2$, $t_2$) \{ $s_2$ \}
\ldots
\ON{} $T_n$ \CATCH{} ($e_n$, $t_n$) \{ $s_n$ \}
-\end{dartCode}
+\end{normativeDartCode}
\subsection{Return}
@@ -11325,7 +12177,7 @@
\LMLabel{interfaceTypes}
\LMHash{}%
-The implicit interface of class $I$ is a direct supertype of the implicit interface of class $J$ if{}f:
+The interface of class $I$ is a direct supertype of the interface of class $J$ if{}f:
\begin{itemize}
\item $I$ is \code{Object}, and $J$ has no \EXTENDS{} clause.
\item $I$ is listed in the \EXTENDS{} clause of $J$.
diff --git a/docs/language/informal/covariant-from-class.md b/docs/language/informal/covariant-from-class.md
index 2cdb696..06d54bf 100644
--- a/docs/language/informal/covariant-from-class.md
+++ b/docs/language/informal/covariant-from-class.md
@@ -2,7 +2,8 @@
**Owner**: eernst@
-**Status**: Implemented.
+**Status**: This document is now background material.
+For normative text, please consult the language specification.
**Version**: 0.6 (2018-06-01)
diff --git a/docs/language/informal/covariant-overrides.md b/docs/language/informal/covariant-overrides.md
index f0f415e..dc0b83b 100644
--- a/docs/language/informal/covariant-overrides.md
+++ b/docs/language/informal/covariant-overrides.md
@@ -2,7 +2,8 @@
**Owner**: rnystrom@, eernst@.
-**Status**: Implemented.
+**Status**: This document is now background material.
+For normative text, please consult the language specification.
**Version**: 1.1 (Oct 10, 2017).
diff --git a/docs/language/informal/int64.md b/docs/language/informal/int64.md
index 20d89ab..f0b4a6d 100644
--- a/docs/language/informal/int64.md
+++ b/docs/language/informal/int64.md
@@ -5,7 +5,7 @@
**Version**: 2017-09-26.
-**Status**: Implemented.
+**Status**: Background material, the normative source is now the language specification.
This document discusses Dart's plan to switch the `int` type so that it represents 64-bit integers instead of bigints. It is part of our continued effort of changing the integer type to fixed size ([issue]).
diff --git a/docs/language/informal/interface-conflicts.md b/docs/language/informal/interface-conflicts.md
index cd1d7f3..ebc21f2 100644
--- a/docs/language/informal/interface-conflicts.md
+++ b/docs/language/informal/interface-conflicts.md
@@ -2,7 +2,11 @@
**Owner**: eernst@
-**Status**: Under discussion.
+**Status**: Background material, normative text is now in dartLangSpec.tex.
+Note that the rules have changed, which means that
+**this document cannot be used as a reference**, it can only be
+used to get an overview of the ideas; please refer to the language
+specification for all technical details.
**Version**: 0.3 (2018-04-24)
diff --git a/pkg/analyzer/lib/dart/analysis/session.dart b/pkg/analyzer/lib/dart/analysis/session.dart
index 1760f2a..b945ed6 100644
--- a/pkg/analyzer/lib/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/dart/analysis/session.dart
@@ -91,6 +91,21 @@
*/
Future<ResolveResult> getResolvedAst(String path);
+ /// Return a future that will complete with information about the results of
+ /// resolving all of the files in the library with the given absolute,
+ /// normalized [path].
+ ///
+ /// Throw [ArgumentError] if the given [path] is not the defining compilation
+ /// unit for a library (that is, is a part of a library).
+ Future<ResolvedLibraryResult> getResolvedLibrary(String path);
+
+ /// Return a future that will complete with information about the results of
+ /// resolving all of the files in the library with the library [element].
+ ///
+ /// Throw [ArgumentError] if the [element] was not produced by this session.
+ Future<ResolvedLibraryResult> getResolvedLibraryByElement(
+ LibraryElement element);
+
/**
* Return a future that will complete with the source kind of the file with
* the given absolute, normalized [path]. If the path does not represent a
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 000fcae..6f2d3ec 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -8,6 +8,7 @@
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/analysis/results.dart' as results;
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart'
@@ -24,6 +25,7 @@
import 'package:analyzer/src/dart/analysis/library_analyzer.dart';
import 'package:analyzer/src/dart/analysis/library_context.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
+import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/dart/analysis/search.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/analysis/status.dart';
@@ -187,6 +189,13 @@
final _requestedFiles = <String, List<Completer<AnalysisResult>>>{};
/**
+ * The mapping from the files for which analysis was requested using
+ * [getResolvedLibrary] to the [Completer]s to report the result.
+ */
+ final _requestedLibraries =
+ <String, List<Completer<ResolvedLibraryResult>>>{};
+
+ /**
* The task that discovers available files. If this field is not `null`,
* and the task is not completed, it should be performed and completed
* before any name searching task.
@@ -468,6 +477,9 @@
if (_requestedFiles.isNotEmpty) {
return AnalysisDriverPriority.interactive;
}
+ if (_requestedLibraries.isNotEmpty) {
+ return AnalysisDriverPriority.interactive;
+ }
if (_discoverAvailableFilesTask != null &&
!_discoverAvailableFilesTask.isCompleted) {
return AnalysisDriverPriority.interactive;
@@ -725,6 +737,83 @@
return unitResult.element.library;
}
+ /**
+ * Return a [Future] that completes with a [ResolvedLibraryResult] for the
+ * Dart library file with the given [path]. If the file is not a Dart file
+ * or cannot be analyzed, the [Future] completes with `null`.
+ *
+ * Throw [ArgumentError] if the given [path] is not the defining compilation
+ * unit for a library (that is, is a part of a library).
+ *
+ * The [path] must be absolute and normalized.
+ *
+ * The [path] can be any file - explicitly or implicitly analyzed, or neither.
+ *
+ * Invocation of this method causes the analysis state to transition to
+ * "analyzing" (if it is not in that state already), the driver will produce
+ * the resolution result for it, which is consistent with the current file
+ * state (including new states of the files previously reported using
+ * [changeFile]), prior to the next time the analysis state transitions
+ * to "idle".
+ */
+ Future<ResolvedLibraryResult> getResolvedLibrary(String path) {
+ _throwIfNotAbsolutePath(path);
+ if (!_fsState.hasUri(path)) {
+ return new Future.value();
+ }
+
+ FileState file = _fsState.getFileForPath(path);
+
+ if (file.isExternalLibrary) {
+ return Future.value(
+ ResolvedLibraryResultImpl.external(currentSession, file.uri),
+ );
+ }
+
+ if (file.isPart) {
+ throw ArgumentError('Is a part: $path');
+ }
+
+ // Schedule analysis.
+ var completer = new Completer<ResolvedLibraryResult>();
+ _requestedLibraries
+ .putIfAbsent(path, () => <Completer<ResolvedLibraryResult>>[])
+ .add(completer);
+ _scheduler.notify(this);
+ return completer.future;
+ }
+
+ /**
+ * Return a [Future] that completes with a [ResolvedLibraryResult] for the
+ * Dart library file with the given [uri].
+ *
+ * Throw [ArgumentError] if the given [uri] is not the defining compilation
+ * unit for a library (that is, is a part of a library).
+ *
+ * Invocation of this method causes the analysis state to transition to
+ * "analyzing" (if it is not in that state already), the driver will produce
+ * the resolution result for it, which is consistent with the current file
+ * state (including new states of the files previously reported using
+ * [changeFile]), prior to the next time the analysis state transitions
+ * to "idle".
+ */
+ Future<ResolvedLibraryResult> getResolvedLibraryByUri(Uri uri) {
+ FileState file = _fsState.getFileForUri(uri);
+
+ if (file.isExternalLibrary) {
+ return Future.value(
+ ResolvedLibraryResultImpl.external(currentSession, file.uri),
+ );
+ }
+
+ if (file.isPart) {
+ throw ArgumentError('Is a part: $uri');
+ }
+
+ // The file is a local file, we can get the result.
+ return getResolvedLibrary(file.path);
+ }
+
ApiSignature getResolvedUnitKeyByPath(String path) {
_throwIfNotAbsolutePath(path);
ApiSignature signature = getUnitKeyByPath(path);
@@ -959,6 +1048,22 @@
return;
}
+ // Analyze a requested library.
+ if (_requestedLibraries.isNotEmpty) {
+ String path = _requestedLibraries.keys.first;
+ try {
+ var result = _computeResolvedLibrary(path);
+ _requestedLibraries.remove(path).forEach((completer) {
+ completer.complete(result);
+ });
+ } catch (exception, stackTrace) {
+ _requestedLibraries.remove(path).forEach((completer) {
+ completer.completeError(exception, stackTrace);
+ });
+ }
+ return;
+ }
+
// Process an index request.
if (_indexRequestedFiles.isNotEmpty) {
String path = _indexRequestedFiles.keys.first;
@@ -1256,7 +1361,7 @@
if (!_fsState.getFileForUri(Uri.parse('dart:async')).exists) {
return _newMissingDartLibraryResult(file, 'dart:async');
}
- libraryContext = await _createLibraryContext(library);
+ libraryContext = _createLibraryContext(library);
LibraryAnalyzer analyzer = new LibraryAnalyzer(
analysisOptions,
@@ -1267,7 +1372,7 @@
libraryContext.resynthesizer,
library,
_resourceProvider);
- Map<FileState, UnitAnalysisResult> results = await analyzer.analyze();
+ Map<FileState, UnitAnalysisResult> results = analyzer.analyze();
List<int> bytes;
CompilationUnit resolvedUnit;
@@ -1319,6 +1424,62 @@
return analysisResult._index;
}
+ /**
+ * Return the newly computed resolution result of the library with the
+ * given [path].
+ */
+ ResolvedLibraryResultImpl _computeResolvedLibrary(String path) {
+ FileState library = _fsState.getFileForPath(path);
+
+ return _logger.run('Compute resolved library $path', () {
+ _testView.numOfAnalyzedLibraries++;
+ var libraryContext = _createLibraryContext(library);
+
+ LibraryAnalyzer analyzer = new LibraryAnalyzer(
+ analysisOptions,
+ declaredVariables,
+ sourceFactory,
+ libraryContext.isLibraryUri,
+ libraryContext.analysisContext,
+ libraryContext.resynthesizer,
+ library,
+ _resourceProvider);
+ Map<FileState, UnitAnalysisResult> unitResults = analyzer.analyze();
+ var resolvedUnits = <ResolvedUnitResult>[];
+
+ for (var unitFile in unitResults.keys) {
+ if (unitFile.path != null) {
+ var unitResult = unitResults[unitFile];
+ resolvedUnits.add(
+ new AnalysisResult(
+ this,
+ _sourceFactory,
+ unitFile.path,
+ unitFile.uri,
+ unitFile.exists,
+ unitFile.content,
+ unitFile.lineInfo,
+ unitFile.isPart,
+ null,
+ unitResult.unit,
+ unitResult.errors,
+ null,
+ ),
+ );
+ }
+ }
+
+ return new ResolvedLibraryResultImpl(
+ currentSession,
+ library.path,
+ library.uri,
+ resolvedUnits.first.libraryElement,
+ libraryContext.analysisContext.typeProvider,
+ resolvedUnits,
+ );
+ });
+ }
+
Future<UnitElementResult> _computeUnitElement(String path,
{bool asIsIfPartWithoutLibrary: false}) async {
// TODO(brianwilkerson) Determine whether this await is necessary.
@@ -1335,7 +1496,7 @@
}
}
- LibraryContext libraryContext = await _createLibraryContext(library);
+ LibraryContext libraryContext = _createLibraryContext(library);
try {
CompilationUnitElement element =
libraryContext.computeUnitElement(library.source, file.source);
@@ -1389,9 +1550,7 @@
/**
* Return the context in which the [library] should be analyzed.
*/
- Future<LibraryContext> _createLibraryContext(FileState library) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
+ LibraryContext _createLibraryContext(FileState library) {
_testView.numOfCreatedLibraryContexts++;
return new LibraryContext.forSingleLibrary(
library,
@@ -1955,7 +2114,7 @@
FileState library = driver.fsState.getFileForPath(libraryPath);
// TODO(brianwilkerson) Determine whether this await is necessary.
await null;
- LibraryContext libraryContext = await driver._createLibraryContext(library);
+ LibraryContext libraryContext = driver._createLibraryContext(library);
try {
return libraryContext.store;
} finally {
@@ -1975,7 +2134,7 @@
* Every result is independent, and is not guaranteed to be consistent with
* any previously returned result, even inside of the same library.
*/
-class AnalysisResult extends FileResult implements results.ResolveResult {
+class AnalysisResult extends FileResult implements results.ResolvedUnitResult {
static final _UNCHANGED = new AnalysisResult(
null, null, null, null, null, null, null, null, null, null, null, null);
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index f9da8aa..e627abb 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -214,10 +214,25 @@
List<FileState> get importedFiles => _importedFiles;
/**
+ * Return `true` if the file is a stub created for a library in the provided
+ * external summary store.
+ */
+ bool get isExternalLibrary {
+ return _fsState.externalSummaries != null &&
+ _fsState.externalSummaries.linkedMap.containsKey(uriStr);
+ }
+
+ /**
* Return `true` if the file does not have a `library` directive, and has a
* `part of` directive, so is probably a part.
*/
- bool get isPart => _unlinked.libraryNameOffset == 0 && _unlinked.isPartOf;
+ bool get isPart {
+ if (_fsState.externalSummaries != null &&
+ _fsState.externalSummaries.unlinkedMap.containsKey(uriStr)) {
+ return !_fsState.externalSummaries.linkedMap.containsKey(uriStr);
+ }
+ return _unlinked.libraryNameOffset == 0 && _unlinked.isPartOf;
+ }
/**
* Return `true` if the file is the "unresolved" file, which does not have
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index bce1a66..dfc67fe 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'dart:async';
-
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
@@ -94,10 +92,8 @@
/**
* Compute analysis results for all units of the library.
*/
- Future<Map<FileState, UnitAnalysisResult>> analyze() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
- return PerformanceStatistics.analysis.makeCurrentWhileAsync(() async {
+ Map<FileState, UnitAnalysisResult> analyze() {
+ return PerformanceStatistics.analysis.makeCurrentWhile(() {
return analyzeSync();
});
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index 2f1eb6c..2b9ac07 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -144,9 +144,6 @@
final LibraryElement element;
@override
- final ResultState state = ResultState.VALID;
-
- @override
final TypeProvider typeProvider;
@override
@@ -156,8 +153,23 @@
this.element, this.typeProvider, this.units)
: super(session, path, uri);
+ ResolvedLibraryResultImpl.external(AnalysisSession session, Uri uri)
+ : this(session, null, uri, null, null, null);
+
+ @override
+ ResultState get state {
+ if (path == null) {
+ return ResultState.NOT_A_FILE;
+ }
+ return ResultState.VALID;
+ }
+
@override
ElementDeclarationResult getElementDeclaration(Element element) {
+ if (state != ResultState.VALID) {
+ throw StateError('The result is not valid: $state');
+ }
+
var elementPath = element.source.fullName;
var unitResult = units.firstWhere(
(r) => r.path == elementPath,
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index 982f3bb..b44d556 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -130,6 +130,20 @@
}
@override
+ Future<ResolvedLibraryResult> getResolvedLibrary(String path) {
+ _checkConsistency();
+ return _driver.getResolvedLibrary(path);
+ }
+
+ @override
+ Future<ResolvedLibraryResult> getResolvedLibraryByElement(
+ LibraryElement element) {
+ _checkConsistency();
+ _checkElementOfThisSession(element);
+ return _driver.getResolvedLibraryByUri(element.source.uri);
+ }
+
+ @override
Future<SourceKind> getSourceKind(String path) {
_checkConsistency();
return _driver.getSourceKind(path);
@@ -163,4 +177,13 @@
throw new InconsistentAnalysisException();
}
}
+
+ void _checkElementOfThisSession(Element element) {
+ // TODO(scheglov) Requires 2.2 implementation
+// if (element.session != this) {
+// throw new ArgumentError(
+// '(${element.runtimeType}) $element was not produced by '
+// 'this session.');
+// }
+ }
}
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 2c718d9..650778f 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -892,7 +892,7 @@
constKeyword, typeArguments, leftBracket, entries, rightBracket));
}
- void endLiteralMapEntry(Token colon, Token endToken) {
+ void handleLiteralMapEntry(Token colon, Token endToken) {
assert(optional(':', colon));
debugEvent("LiteralMapEntry");
diff --git a/pkg/analyzer/lib/src/summary/expr_builder.dart b/pkg/analyzer/lib/src/summary/expr_builder.dart
index 85053fe..66112ea 100644
--- a/pkg/analyzer/lib/src/summary/expr_builder.dart
+++ b/pkg/analyzer/lib/src/summary/expr_builder.dart
@@ -711,7 +711,12 @@
for (int i = 0; i < count; i++) {
elements.insert(0, _pop());
}
- _push(AstTestFactory.listLiteral2(Keyword.CONST, typeArguments, elements));
+ var typeArg = typeArguments == null
+ ? resynthesizer.typeProvider.dynamicType
+ : typeArguments.arguments[0].type;
+ var staticType = resynthesizer.typeProvider.listType.instantiate([typeArg]);
+ _push(AstTestFactory.listLiteral2(Keyword.CONST, typeArguments, elements)
+ ..staticType = staticType);
}
void _pushLocalFunctionReference() {
@@ -770,7 +775,16 @@
Expression key = _pop();
entries.insert(0, AstTestFactory.mapLiteralEntry2(key, value));
}
- _push(AstTestFactory.mapLiteral(Keyword.CONST, typeArguments, entries));
+ var keyType = typeArguments == null
+ ? resynthesizer.typeProvider.dynamicType
+ : typeArguments.arguments[0].type;
+ var valueType = typeArguments == null
+ ? resynthesizer.typeProvider.dynamicType
+ : typeArguments.arguments[1].type;
+ var staticType =
+ resynthesizer.typeProvider.mapType.instantiate([keyType, valueType]);
+ _push(AstTestFactory.mapLiteral(Keyword.CONST, typeArguments, entries)
+ ..staticType = staticType);
}
void _pushPrefix(TokenType operator) {
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 7fea9c5..2add257 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -257,7 +257,10 @@
if (libraryMap == null) {
getLibraryElement(libraryUri);
libraryMap = _resynthesizedUnits[libraryUri];
- assert(libraryMap != null);
+ if (libraryMap == null) {
+ throw new StateError(
+ 'Unable to find library `$libraryUri` in a summary file.');
+ }
}
CompilationUnitElementImpl unitElement = libraryMap[unitUri];
// Fill elements in the unit map.
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index d224d7f..8d275c0 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -3731,6 +3731,52 @@
verify([source]);
}
+ test_issue_35320_lists() async {
+ addNamedSource('/lib.dart', '''
+const x = const <String>['a'];
+''');
+ Source source = addSource('''
+import 'lib.dart';
+const y = const <String>['b'];
+int f(v) {
+ switch(v) {
+ case x:
+ return 0;
+ case y:
+ return 1;
+ default:
+ return 2;
+ }
+}
+''');
+ await computeAnalysisResult(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ test_issue_35320_maps() async {
+ addNamedSource('/lib.dart', '''
+const x = const <String, String>{'a': 'b'};
+''');
+ Source source = addSource('''
+import 'lib.dart';
+const y = const <String, String>{'c': 'd'};
+int f(v) {
+ switch(v) {
+ case x:
+ return 0;
+ case y:
+ return 1;
+ default:
+ return 2;
+ }
+}
+''');
+ await computeAnalysisResult(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
test_listElementTypeNotAssignable() async {
Source source = addSource(r'''
var v1 = <int> [42];
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index a39d370..f692d58 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -341,12 +341,6 @@
}
@override
- void beginLiteralMapEntry(Token token) {
- super.beginLiteralMapEntry(token);
- begin('LiteralMapEntry');
- }
-
- @override
void beginLiteralString(Token token) {
super.beginLiteralString(token);
begin('LiteralString');
@@ -849,12 +843,6 @@
}
@override
- void endLiteralMapEntry(Token colon, Token endToken) {
- end('LiteralMapEntry');
- super.endLiteralMapEntry(colon, endToken);
- }
-
- @override
void endLiteralString(int interpolationCount, Token endToken) {
end('LiteralString');
super.endLiteralString(interpolationCount, endToken);
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 1bcac17..2e121cc 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -48,7 +48,56 @@
@reflectiveTest
class ClassMemberParserTest_Fasta extends FastaParserTestCase
- with ClassMemberParserTestMixin {}
+ with ClassMemberParserTestMixin {
+ void test_parseClassMember_operator_gtgtgt() {
+ final sourceText = 'class C { bool operator >>>(other) => false; }';
+
+ // ---------------------------------------------------
+ // TODO(danrubel): Replace this section with a call to parseCompilationUnit
+ // once '>>>' token support is enabled permanently.
+
+ var source = new StringSource(sourceText, 'parser_test_StringSource.dart');
+ GatheringErrorListener errorListener =
+ new GatheringErrorListener(checkRanges: true);
+
+ // Scan tokens
+ StringScanner scanner = new StringScanner(sourceText, includeComments: true)
+ ..enableGtGtGt = true;
+ Token tokens = scanner.tokenize();
+ expect(scanner.hasErrors, isFalse);
+
+ // Run parser
+ ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
+ fasta.Parser parser = new fasta.Parser(null);
+ AstBuilder astBuilder = new AstBuilder(errorReporter, source.uri, true);
+ parser.listener = astBuilder;
+ astBuilder.parser = parser;
+ parser.parseUnit(tokens);
+
+ CompilationUnitImpl unit = astBuilder.pop();
+ expect(unit, isNotNull);
+ unit.localDeclarations = astBuilder.localDeclarations;
+ errorListener.assertNoErrors();
+
+ // ---------------------------------------------------
+
+ ClassDeclaration declaration = unit.declarations[0];
+ ClassMember member = declaration.members[0];
+ expect(member, isNotNull);
+ expect(member, new TypeMatcher<MethodDeclaration>());
+ MethodDeclaration method = member;
+ expect(method.documentationComment, isNull);
+ expect(method.externalKeyword, isNull);
+ expect(method.modifierKeyword, isNull);
+ expect(method.propertyKeyword, isNull);
+ expect(method.returnType, isNotNull);
+ expect(method.name.name, '>>>');
+ expect(method.operatorKeyword, isNotNull);
+ expect(method.typeParameters, isNull);
+ expect(method.parameters, isNotNull);
+ expect(method.body, isNotNull);
+ }
+}
/**
* Tests of the fasta parser based on [ComplexParserTestMixin].
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index feb577a..473e17f 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -6919,6 +6919,15 @@
expect(literal.rightBracket, isNotNull);
}
+ void test_parseMapLiteral_multiple_trailing_comma() {
+ MapLiteral literal = parseMapLiteral(null, null, "{'a' : b, 'x' : y,}");
+ expect(literal, isNotNull);
+ assertNoErrors();
+ expect(literal.leftBracket, isNotNull);
+ expect(literal.entries, hasLength(2));
+ expect(literal.rightBracket, isNotNull);
+ }
+
void test_parseMapLiteral_single() {
MapLiteral literal = parseMapLiteral(null, null, "{'x' : y}");
expect(literal, isNotNull);
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 1afe213..0345738 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -4,6 +4,7 @@
import 'dart:async';
+import 'package:analyzer/dart/analysis/results.dart' as results;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -1572,6 +1573,89 @@
expect(coreLibrary.getType('Object'), isNotNull);
}
+ test_getResolvedLibrary_external() async {
+ var a1 = _p('/aaa/lib/a1.dart');
+ var a2 = _p('/aaa/lib/a2.dart');
+
+ var a1UriStr = 'package:aaa/a1.dart';
+ var a2UriStr = 'package:aaa/a2.dart';
+
+ provider.newFile(a1, "part 'a2.dart'; class A {}");
+ provider.newFile(a2, "part of 'a1.dart';");
+
+ // Build the store with the library.
+ var store = await createAnalysisDriver().test.getSummaryStore(a1);
+ expect(store.unlinkedMap.keys, contains(a1UriStr));
+ expect(store.unlinkedMap.keys, contains(a2UriStr));
+ expect(store.linkedMap.keys, contains(a1UriStr));
+
+ var driver = createAnalysisDriver(externalSummaries: store);
+ var libraryElement = await driver.getLibraryByUri(a1UriStr);
+ var classA = libraryElement.library.getType('A');
+
+ var resolvedLibrary = await driver.getResolvedLibrary(a1);
+ expect(resolvedLibrary, isNotNull);
+ expect(resolvedLibrary.state, results.ResultState.NOT_A_FILE);
+ expect(() {
+ resolvedLibrary.getElementDeclaration(classA);
+ }, throwsStateError);
+
+ // It is an error to ask for a library when we know that it is a part.
+ expect(() async {
+ await driver.getResolvedLibrary(a2);
+ }, throwsArgumentError);
+ }
+
+ test_getResolvedLibraryByUri_external() async {
+ var a1 = _p('/aaa/lib/a1.dart');
+ var a2 = _p('/aaa/lib/a2.dart');
+
+ var a1UriStr = 'package:aaa/a1.dart';
+ var a2UriStr = 'package:aaa/a2.dart';
+
+ var a1Uri = Uri.parse(a1UriStr);
+ var a2Uri = Uri.parse(a2UriStr);
+
+ provider.newFile(a1, "part 'a2.dart'; class A {}");
+ provider.newFile(a2, "part of 'a1.dart';");
+
+ // Build the store with the library.
+ var store = await createAnalysisDriver().test.getSummaryStore(a1);
+ expect(store.unlinkedMap.keys, contains(a1UriStr));
+ expect(store.unlinkedMap.keys, contains(a2UriStr));
+ expect(store.linkedMap.keys, contains(a1UriStr));
+
+ var driver = createAnalysisDriver(externalSummaries: store);
+ var libraryElement = await driver.getLibraryByUri(a1UriStr);
+ var classA = libraryElement.library.getType('A');
+
+ {
+ var resolvedLibrary = await driver.getResolvedLibraryByUri(a1Uri);
+ expect(resolvedLibrary, isNotNull);
+ expect(resolvedLibrary.state, results.ResultState.NOT_A_FILE);
+ expect(() {
+ resolvedLibrary.getElementDeclaration(classA);
+ }, throwsStateError);
+ }
+
+ // We can also get the result from the session.
+ {
+ var session = driver.currentSession;
+ var resolvedLibrary =
+ await session.getResolvedLibraryByElement(libraryElement);
+ expect(resolvedLibrary, isNotNull);
+ expect(resolvedLibrary.state, results.ResultState.NOT_A_FILE);
+ expect(() {
+ resolvedLibrary.getElementDeclaration(classA);
+ }, throwsStateError);
+ }
+
+ // It is an error to ask for a library when we know that it is a part.
+ expect(() async {
+ await driver.getResolvedLibraryByUri(a2Uri);
+ }, throwsArgumentError);
+ }
+
test_getResult() async {
String content = 'int f() => 42;';
addTestFile(content, priority: true);
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index 0c00794..a5b9b87 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -2,23 +2,18 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'dart:async';
-
-import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/dart/analysis/analysis_context.dart';
+import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
-import 'package:analyzer/src/dart/analysis/top_level_declaration.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/engine.dart'
- show AnalysisOptions, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import '../../context/mock_sdk.dart';
+
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AnalysisSessionImplTest);
@@ -26,214 +21,281 @@
}
@reflectiveTest
-class AnalysisSessionImplTest {
- MockAnalysisDriver driver;
+class AnalysisSessionImplTest with ResourceProviderMixin {
+ AnalysisContextCollection contextCollection;
+ AnalysisContext context;
AnalysisSessionImpl session;
+ String testContextPath;
+ String aaaContextPath;
+ String bbbContextPath;
+
+ String testPath;
+
void setUp() {
- driver = new MockAnalysisDriver();
- session = new AnalysisSessionImpl(driver);
- driver.currentSession = session;
+ MockSdk(resourceProvider: resourceProvider);
+
+ testContextPath = newFolder('/home/test').path;
+ aaaContextPath = newFolder('/home/aaa').path;
+ bbbContextPath = newFolder('/home/bbb').path;
+
+ newFile('/home/test/.packages', content: r'''
+test:lib/
+''');
+
+ contextCollection = AnalysisContextCollectionImpl(
+ includedPaths: [testContextPath, aaaContextPath, bbbContextPath],
+ resourceProvider: resourceProvider,
+ sdkPath: convertPath(sdkRoot),
+ );
+ context = contextCollection.contextFor(testContextPath);
+ session = context.currentSession;
+
+ testPath = convertPath('/home/test/lib/test.dart');
}
test_getErrors() async {
- ErrorsResult result = new ErrorsResult(null, null, null, null, null, null);
- driver.errorsResult = result;
- expect(await session.getErrors('path'), result);
+ newFile(testPath, content: 'class C {');
+ var errorsResult = await session.getErrors(testPath);
+ expect(errorsResult.session, session);
+ expect(errorsResult.path, testPath);
+ expect(errorsResult.errors, isNotEmpty);
}
test_getLibraryByUri() async {
- String uri = 'uri';
+ newFile(testPath, content: r'''
+class A {}
+class B {}
+''');
- var source = new _SourceMock(Uri.parse(uri));
- var unit = new CompilationUnitElementImpl()
- ..librarySource = source
- ..source = source;
- var library = new LibraryElementImpl(null, null, null, null)
- ..definingCompilationUnit = unit;
-
- driver.libraryMap[uri] = library;
- expect(await session.getLibraryByUri(uri), library);
+ var library = await session.getLibraryByUri('package:test/test.dart');
+ expect(library.getType('A'), isNotNull);
+ expect(library.getType('B'), isNotNull);
+ expect(library.getType('C'), isNull);
}
- test_getParsedAst() async {
- ParseResult result =
- new ParseResult(null, null, null, null, null, null, null, null);
- driver.parseResult = result;
- expect(await session.getParsedAst('path'), result);
+ test_getParsedAstSync() async {
+ newFile(testPath, content: r'''
+class A {}
+class B {}
+''');
+
+ var unitResult = session.getParsedAstSync(testPath);
+ expect(unitResult.session, session);
+ expect(unitResult.path, testPath);
+ expect(unitResult.uri, Uri.parse('package:test/test.dart'));
+ expect(unitResult.unit.declarations, hasLength(2));
}
test_getResolvedAst() async {
- AnalysisResult result = new AnalysisResult(driver, null, null, null, null,
- null, null, null, null, null, null, null);
- driver.result = result;
- expect(await session.getResolvedAst('path'), result);
+ newFile(testPath, content: r'''
+class A {}
+class B {}
+''');
+
+ var unitResult = await session.getResolvedAst(testPath);
+ expect(unitResult.session, session);
+ expect(unitResult.path, testPath);
+ expect(unitResult.uri, Uri.parse('package:test/test.dart'));
+ expect(unitResult.unit.declarations, hasLength(2));
+ expect(unitResult.typeProvider, isNotNull);
+ expect(unitResult.libraryElement, isNotNull);
+ }
+
+ test_getResolvedLibrary() async {
+ var a = convertPath('/home/test/lib/a.dart');
+ var b = convertPath('/home/test/lib/b.dart');
+
+ var aContent = r'''
+part 'b.dart';
+
+class A /*a*/ {}
+''';
+ newFile(a, content: aContent);
+
+ var bContent = r'''
+part of 'a.dart';
+
+class B /*b*/ {}
+class B2 extends X {}
+''';
+ newFile(b, content: bContent);
+
+ var resolvedLibrary = await session.getResolvedLibrary(a);
+ expect(resolvedLibrary.session, session);
+ expect(resolvedLibrary.path, a);
+ expect(resolvedLibrary.uri, Uri.parse('package:test/a.dart'));
+
+ var typeProvider = resolvedLibrary.typeProvider;
+ expect(typeProvider.intType.element.name, 'int');
+
+ var libraryElement = resolvedLibrary.element;
+ expect(libraryElement, isNotNull);
+
+ var aClass = libraryElement.getType('A');
+ expect(aClass, isNotNull);
+
+ var bClass = libraryElement.getType('B');
+ expect(bClass, isNotNull);
+
+ var aUnitResult = resolvedLibrary.units[0];
+ expect(aUnitResult.path, a);
+ expect(aUnitResult.uri, Uri.parse('package:test/a.dart'));
+ expect(aUnitResult.content, aContent);
+ expect(aUnitResult.unit, isNotNull);
+ expect(aUnitResult.unit.directives, hasLength(1));
+ expect(aUnitResult.unit.declarations, hasLength(1));
+ expect(aUnitResult.errors, isEmpty);
+
+ var bUnitResult = resolvedLibrary.units[1];
+ expect(bUnitResult.path, b);
+ expect(bUnitResult.uri, Uri.parse('package:test/b.dart'));
+ expect(bUnitResult.content, bContent);
+ expect(bUnitResult.unit, isNotNull);
+ expect(bUnitResult.unit.directives, hasLength(1));
+ expect(bUnitResult.unit.declarations, hasLength(2));
+ expect(bUnitResult.errors, isNotEmpty);
+
+ var aDeclaration = resolvedLibrary.getElementDeclaration(aClass);
+ ClassDeclaration aNode = aDeclaration.node;
+ expect(aNode.name.name, 'A');
+ expect(aNode.offset, 16);
+ expect(aNode.length, 16);
+ expect(aNode.name.staticElement.name, 'A');
+
+ var bDeclaration = resolvedLibrary.getElementDeclaration(bClass);
+ ClassDeclaration bNode = bDeclaration.node;
+ expect(bNode.name.name, 'B');
+ expect(bNode.offset, 19);
+ expect(bNode.length, 16);
+ expect(bNode.name.staticElement.name, 'B');
+ }
+
+ test_getResolvedLibrary_getElementDeclaration_notThisLibrary() async {
+ newFile(testPath, content: '');
+
+ var resolvedLibrary = await session.getResolvedLibrary(testPath);
+
+ expect(() {
+ var intClass = resolvedLibrary.typeProvider.intType.element;
+ resolvedLibrary.getElementDeclaration(intClass);
+ }, throwsArgumentError);
+ }
+
+ test_getResolvedLibrary_getElementDeclaration_synthetic() async {
+ newFile(testPath, content: r'''
+int foo = 0;
+''');
+
+ var resolvedLibrary = await session.getResolvedLibrary(testPath);
+ var unitElement = resolvedLibrary.element.definingCompilationUnit;
+
+ var fooElement = unitElement.topLevelVariables[0];
+ expect(fooElement.name, 'foo');
+
+ // We can get the variable element declaration.
+ var fooDeclaration = resolvedLibrary.getElementDeclaration(fooElement);
+ VariableDeclaration fooNode = fooDeclaration.node;
+ expect(fooNode.name.name, 'foo');
+ expect(fooNode.offset, 4);
+ expect(fooNode.length, 7);
+ expect(fooNode.name.staticElement.name, 'foo');
+
+ // Synthetic elements don't have nodes.
+ expect(resolvedLibrary.getElementDeclaration(fooElement.getter), isNull);
+ expect(resolvedLibrary.getElementDeclaration(fooElement.setter), isNull);
+ }
+
+ test_getResolvedLibrary_invalidPartUri() async {
+ newFile(testPath, content: r'''
+part 'a.dart';
+part ':[invalid uri].dart';
+part 'c.dart';
+''');
+
+ var resolvedLibrary = await session.getResolvedLibrary(testPath);
+
+ expect(resolvedLibrary.units, hasLength(3));
+ expect(
+ resolvedLibrary.units[0].path,
+ convertPath('/home/test/lib/test.dart'),
+ );
+ expect(
+ resolvedLibrary.units[1].path,
+ convertPath('/home/test/lib/a.dart'),
+ );
+ expect(
+ resolvedLibrary.units[2].path,
+ convertPath('/home/test/lib/c.dart'),
+ );
+ }
+
+ test_getResolvedLibrary_notLibrary() async {
+ newFile(testPath, content: 'part of "a.dart";');
+
+ expect(() {
+ session.getResolvedLibrary(testPath);
+ }, throwsArgumentError);
+ }
+
+ test_getResolvedLibraryByElement() async {
+ newFile(testPath, content: '');
+
+ var element = await session.getLibraryByUri('package:test/test.dart');
+
+ var resolvedLibrary = await session.getResolvedLibraryByElement(element);
+ expect(resolvedLibrary.session, session);
+ expect(resolvedLibrary.path, testPath);
+ expect(resolvedLibrary.uri, Uri.parse('package:test/test.dart'));
+ expect(resolvedLibrary.units, hasLength(1));
+ expect(resolvedLibrary.units[0].unit.declaredElement, isNotNull);
}
test_getSourceKind() async {
- SourceKind kind = SourceKind.LIBRARY;
- driver.sourceKind = kind;
- expect(await session.getSourceKind('path'), kind);
+ newFile(testPath, content: 'class C {}');
+
+ var kind = await session.getSourceKind(testPath);
+ expect(kind, SourceKind.LIBRARY);
}
- test_getTopLevelDeclarations() async {
- List<TopLevelDeclarationInSource> declarations = [];
- driver.topLevelDeclarations = declarations;
- expect(await session.getTopLevelDeclarations('path'), declarations);
+ test_getSourceKind_part() async {
+ newFile(testPath, content: 'part of "a.dart";');
+
+ var kind = await session.getSourceKind(testPath);
+ expect(kind, SourceKind.PART);
}
test_getUnitElement() async {
- UnitElementResult result =
- new UnitElementResult(null, null, null, null, null);
- driver.unitElementResult = result;
- expect(await session.getUnitElement('path'), result);
+ newFile(testPath, content: r'''
+class A {}
+class B {}
+''');
+
+ var unitResult = await session.getUnitElement(testPath);
+ expect(unitResult.session, session);
+ expect(unitResult.path, testPath);
+ expect(unitResult.uri, Uri.parse('package:test/test.dart'));
+ expect(unitResult.element.types, hasLength(2));
+
+ var signature = await session.getUnitElementSignature(testPath);
+ expect(unitResult.signature, signature);
}
- test_getUnitElementSignature() async {
- String signature = 'xyzzy';
- driver.unitElementSignature = signature;
- expect(await session.getUnitElementSignature('path'), signature);
- }
-
- test_resourceProvider() {
- ResourceProvider resourceProvider = new MemoryResourceProvider();
- driver.resourceProvider = resourceProvider;
+ test_resourceProvider() async {
expect(session.resourceProvider, resourceProvider);
}
- test_sourceFactory() {
- SourceFactory sourceFactory = new SourceFactory([]);
- driver.sourceFactory = sourceFactory;
- expect(session.sourceFactory, sourceFactory);
- }
-
test_typeProvider() async {
- _initializeSDK();
- expect(await session.typeProvider, isNotNull);
+ var typeProvider = await session.typeProvider;
+ expect(typeProvider.intType.element.name, 'int');
}
test_typeSystem() async {
- _initializeSDK();
- expect(await session.typeSystem, isNotNull);
- }
-
- void _initializeSDK() {
- CompilationUnitElementImpl newUnit(String name) {
- CompilationUnitElementImpl unit = new CompilationUnitElementImpl();
- unit.accessors = [];
- unit.enums = [];
- unit.functions = [];
- unit.typeAliases = [];
- return unit;
- }
-
- ClassElementImpl newClass(String name) {
- TypeParameterElementImpl param = new TypeParameterElementImpl('E', 0);
- param.type = new TypeParameterTypeImpl(param);
- ClassElementImpl element = new ClassElementImpl(name, 0);
- element.typeParameters = [param];
- return element;
- }
-
- {
- CompilationUnitElementImpl coreUnit = newUnit('dart.core');
- coreUnit.types = <ClassElement>[newClass('Iterable')];
- LibraryElementImpl core = new LibraryElementImpl(null, null, null, null);
- core.definingCompilationUnit = coreUnit;
- driver.libraryMap['dart:core'] = core;
- }
- {
- CompilationUnitElementImpl asyncUnit = newUnit('dart.async');
- asyncUnit.types = <ClassElement>[
- newClass('Future'),
- newClass('FutureOr'),
- newClass('Stream')
- ];
- LibraryElementImpl async = new LibraryElementImpl(null, null, null, null);
- async.definingCompilationUnit = asyncUnit;
- driver.libraryMap['dart:async'] = async;
- }
- }
-}
-
-class MockAnalysisDriver implements AnalysisDriver {
- @override
- AnalysisSession currentSession;
-
- ErrorsResult errorsResult;
- Map<String, LibraryElement> libraryMap = <String, LibraryElement>{};
- ParseResult parseResult;
- ResourceProvider resourceProvider;
- AnalysisResult result;
- SourceFactory sourceFactory;
- SourceKind sourceKind;
- List<TopLevelDeclarationInSource> topLevelDeclarations;
- UnitElementResult unitElementResult;
- String unitElementSignature;
-
- AnalysisOptions get analysisOptions => new AnalysisOptionsImpl();
-
- @override
- Future<ErrorsResult> getErrors(String path) async {
- return errorsResult;
- }
-
- @override
- Future<LibraryElement> getLibraryByUri(String uri) async {
- return libraryMap[uri];
- }
-
- @override
- Future<AnalysisResult> getResult(String path,
- {bool sendCachedToStream: false}) async {
- return result;
- }
-
- @override
- Future<SourceKind> getSourceKind(String path) async {
- return sourceKind;
- }
-
- @override
- Future<List<TopLevelDeclarationInSource>> getTopLevelNameDeclarations(
- String name) async {
- return topLevelDeclarations;
- }
-
- @override
- Future<UnitElementResult> getUnitElement(String path) async {
- return unitElementResult;
- }
-
- @override
- Future<String> getUnitElementSignature(String path) async {
- return unitElementSignature;
- }
-
- @override
- dynamic noSuchMethod(Invocation invocation) {
- fail('Unexpected invocation of ${invocation.memberName}');
- }
-
- @override
- Future<ParseResult> parseFile(String path) async {
- return parseResult;
- }
-
- @override
- ParseResult parseFileSync(String path) {
- return parseResult;
- }
-}
-
-class _SourceMock implements Source {
- @override
- final Uri uri;
-
- _SourceMock(this.uri);
-
- @override
- noSuchMethod(Invocation invocation) {
- throw new StateError('Unexpected invocation of ${invocation.memberName}');
+ var typeSystem = await session.typeSystem;
+ var typeProvider = typeSystem.typeProvider;
+ expect(
+ typeSystem.isSubtypeOf(typeProvider.intType, typeProvider.numType),
+ isTrue,
+ );
}
}
diff --git a/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart b/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
index 492f026..cf48c96 100644
--- a/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/missing_code_test.dart
@@ -212,6 +212,14 @@
''');
}
+ void test_comma_missing() {
+ testRecovery('''
+f(int a int b) { }
+''', [ParserErrorCode.EXPECTED_TOKEN], '''
+f(int a, int b) { }
+''');
+ }
+
void test_equalEqual() {
testBinaryExpression('==');
}
diff --git a/pkg/compiler/lib/compiler_new.dart b/pkg/compiler/lib/compiler_new.dart
index d7de722..918c627 100644
--- a/pkg/compiler/lib/compiler_new.dart
+++ b/pkg/compiler/lib/compiler_new.dart
@@ -72,9 +72,11 @@
/// A source map for a JavaScript output.
sourceMap,
- /// Additional information requested by the user, such dump info or a deferred
- /// map.
- info,
+ /// Dump info output.
+ dumpInfo,
+
+ /// Deferred map output.
+ deferredMap,
/// Implementation specific output used for debugging the compiler.
debug,
@@ -188,6 +190,6 @@
return new CompilationResult(compiler,
isSuccess: success,
kernelInitializedCompilerState:
- compiler.libraryLoader.initializedCompilerState);
+ compiler.kernelLoader.initializedCompilerState);
});
}
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 82ab539..982a2de 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -34,6 +34,10 @@
// Experimentally try to force part-file functions to be seen as IIFEs.
static const String experimentStartupFunctions = '--experiment-code-2';
+ // Add instrumentation to log every method call.
+ static const String experimentCallInstrumentation =
+ '--experiment-call-instrumentation';
+
static const String fastStartup = '--fast-startup';
static const String fatalWarnings = '--fatal-warnings';
static const String generateCodeWithCompileTimeErrors =
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 0a8a1b1..4922314 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -11,10 +11,9 @@
import 'constants/values.dart';
import 'elements/entities.dart';
import 'elements/types.dart';
-import 'js_backend/backend.dart' show JavaScriptBackend;
import 'js_backend/constant_system_javascript.dart';
import 'js_backend/native_data.dart' show NativeBasicData;
-import 'native/native.dart';
+import 'kernel/dart2js_target.dart';
import 'types/abstract_value_domain.dart';
import 'universe/selector.dart' show Selector;
@@ -1416,17 +1415,7 @@
FunctionEntity get boolConversionCheck =>
_findHelperFunction('boolConversionCheck');
- FunctionEntity get _consoleTraceHelper =>
- _findHelperFunction('consoleTraceHelper');
-
- FunctionEntity get _postTraceHelper => _findHelperFunction('postTraceHelper');
-
- FunctionEntity _traceHelper;
- FunctionEntity get traceHelper {
- return _traceHelper ??= JavaScriptBackend.TRACE_METHOD == 'console'
- ? _consoleTraceHelper
- : _postTraceHelper;
- }
+ FunctionEntity get traceHelper => _findHelperFunction('traceHelper');
FunctionEntity get closureFromTearOff =>
_findHelperFunction('closureFromTearOff');
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index a98f635..c4effda 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -32,7 +32,7 @@
import 'js_backend/inferred_data.dart';
import 'js_model/js_strategy.dart';
import 'kernel/kernel_strategy.dart';
-import 'library_loader.dart' show LibraryLoaderTask, LoadedLibraries;
+import 'kernel/loader.dart' show KernelLoaderTask, KernelResult;
import 'null_compiler_output.dart' show NullCompilerOutput;
import 'options.dart' show CompilerOptions, DiagnosticOptions;
import 'serialization/task.dart';
@@ -101,7 +101,7 @@
Entity get currentElement => _reporter.currentElement;
List<CompilerTask> tasks;
- LibraryLoaderTask libraryLoader;
+ KernelLoaderTask kernelLoader;
GlobalTypeInferenceTask globalInference;
JavaScriptBackend backend;
CodegenWorldBuilder _codegenWorldBuilder;
@@ -168,8 +168,8 @@
enqueuer = backend.makeEnqueuer();
tasks = [
- libraryLoader =
- new LibraryLoaderTask(options, provider, reporter, measurer),
+ kernelLoader =
+ new KernelLoaderTask(options, provider, reporter, measurer),
kernelFrontEndTask,
globalInference = new GlobalTypeInferenceTask(this),
constants = backend.constantCompilerTask,
@@ -226,30 +226,6 @@
});
});
- /// This method is called when all new libraries loaded through
- /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
- /// have been computed.
- ///
- /// [loadedLibraries] contains the newly loaded libraries.
- void processLoadedLibraries(LoadedLibraries loadedLibraries) {
- frontendStrategy.registerLoadedLibraries(loadedLibraries);
- loadedLibraries.forEachLibrary((Uri uri) {
- LibraryEntity library =
- frontendStrategy.elementEnvironment.lookupLibrary(uri);
- backend.setAnnotations(library);
- });
-
- // TODO(efortuna, sigmund): These validation steps should be done in the
- // front end for the Kernel path since Kernel doesn't have the notion of
- // imports (everything has already been resolved). (See
- // https://github.com/dart-lang/sdk/issues/29368)
- if (loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
- reporter.reportWarningMessage(NO_LOCATION_SPANNABLE,
- MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_WITH_CFE);
- }
- backend.onLibrariesLoaded(frontendStrategy.commonElements, loadedLibraries);
- }
-
Future runInternal(Uri uri) async {
// TODO(ahe): This prevents memory leaks when invoking the compiler
// multiple times. Implement a better mechanism where we can store
@@ -274,16 +250,30 @@
await serializationTask.deserialize();
generateJavaScriptCode(results);
} else {
- LoadedLibraries loadedLibraries = await libraryLoader.loadLibraries(uri);
- // Note: libraries may be null because of errors trying to find files or
- // parse-time errors (when using `package:front_end` as a loader).
- if (loadedLibraries == null) return;
+ KernelResult result = await kernelLoader.load(uri);
+ if (result == null) return;
if (compilationFailed && !options.generateCodeWithCompileTimeErrors) {
return;
}
- _mainLibraryUri = loadedLibraries.rootLibraryUri;
- processLoadedLibraries(loadedLibraries);
- await compileLoadedLibraries(loadedLibraries);
+ _mainLibraryUri = result.rootLibraryUri;
+
+ frontendStrategy.registerLoadedLibraries(result);
+ for (Uri uri in result.libraries) {
+ LibraryEntity library =
+ frontendStrategy.elementEnvironment.lookupLibrary(uri);
+ backend.setAnnotations(library);
+ }
+
+ // TODO(efortuna, sigmund): These validation steps should be done in the
+ // front end for the Kernel path since Kernel doesn't have the notion of
+ // imports (everything has already been resolved). (See
+ // https://github.com/dart-lang/sdk/issues/29368)
+ if (result.libraries.contains(Uris.dart_mirrors)) {
+ reporter.reportWarningMessage(NO_LOCATION_SPANNABLE,
+ MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_WITH_CFE);
+ }
+
+ await compileFromKernel(result.rootLibraryUri, result.libraries);
}
}
@@ -303,7 +293,7 @@
return resolutionEnqueuer;
}
- JClosedWorld computeClosedWorld(LoadedLibraries loadedLibraries) {
+ JClosedWorld computeClosedWorld(Uri rootLibraryUri, Iterable<Uri> libraries) {
ResolutionEnqueuer resolutionEnqueuer = startResolution();
for (LibraryEntity library
in frontendStrategy.elementEnvironment.libraries) {
@@ -321,7 +311,7 @@
// compile-time constants that are metadata. This means adding
// something to the resolution queue. So we cannot wait with
// this until after the resolution queue is processed.
- deferredLoadTask.beforeResolution(loadedLibraries);
+ deferredLoadTask.beforeResolution(rootLibraryUri, libraries);
impactStrategy = backend.createImpactStrategy(
supportDeferredLoad: deferredLoadTask.isProgramSplit,
supportDumpInfo: options.dumpInfo);
@@ -395,10 +385,9 @@
checkQueue(codegenEnqueuer);
}
- /// Performs the compilation when all libraries have been loaded.
- void compileLoadedLibraries(LoadedLibraries loadedLibraries) {
- selfTask.measureSubtask("Compiler.compileLoadedLibraries", () {
- JClosedWorld closedWorld = computeClosedWorld(loadedLibraries);
+ void compileFromKernel(Uri rootLibraryUri, Iterable<Uri> libraries) {
+ selfTask.measureSubtask("Compiler.compileFromKernel", () {
+ JClosedWorld closedWorld = computeClosedWorld(rootLibraryUri, libraries);
if (closedWorld != null) {
GlobalTypeInferenceResults globalInferenceResults =
performGlobalTypeInference(closedWorld);
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 7468875..b97806b 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -408,6 +408,7 @@
new OptionHandler(Flags.experimentLocalNames, passThrough),
new OptionHandler(Flags.experimentStartupFunctions, passThrough),
+ new OptionHandler(Flags.experimentCallInstrumentation, passThrough),
// The following three options must come last.
new OptionHandler('-D.+=.*', addInEnvironment),
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index a7e2e97..d1cc893 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -20,7 +20,6 @@
import 'elements/types.dart';
import 'elements/entities.dart';
import 'kernel/kelements.dart' show KLocalFunction;
-import 'library_loader.dart';
import 'serialization/serialization.dart';
import 'options.dart';
import 'universe/use.dart';
@@ -785,15 +784,15 @@
/// Frees up strategy-specific temporary data.
void cleanup() {}
- void beforeResolution(LoadedLibraries loadedLibraries) {
- for (Uri uri in loadedLibraries.libraries) {
+ void beforeResolution(Uri rootLibraryUri, Iterable<Uri> libraries) {
+ for (Uri uri in libraries) {
LibraryEntity library = elementEnvironment.lookupLibrary(uri);
reporter.withCurrentElement(library, () {
checkForDeferredErrorCases(library);
for (ImportEntity import in elementEnvironment.getImports(library)) {
if (import.isDeferred) {
- _deferredImportDescriptions[import] = new ImportDescription(
- import, library, loadedLibraries.rootLibraryUri);
+ _deferredImportDescriptions[import] =
+ new ImportDescription(import, library, rootLibraryUri);
isProgramSplit = true;
}
}
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index f9f6392..7c14077 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -113,14 +113,6 @@
_globalInferenceResults.resultOfParameter(e);
FieldInfo visitField(FieldEntity field, {ClassEntity containingClass}) {
- var isInInstantiatedClass = false;
- if (containingClass != null) {
- isInInstantiatedClass =
- closedWorld.classHierarchy.isInstantiated(containingClass);
- }
- if (!isInInstantiatedClass && !_hasBeenResolved(field)) {
- return null;
- }
AbstractValue inferredType = _resultOfMember(field).type;
// If a field has an empty inferred type it is never used.
if (inferredType == null ||
@@ -147,7 +139,7 @@
codegenWorldBuilder.getConstantFieldInitializer(field)];
}
- if (JavaScriptBackend.TRACE_METHOD == 'post') {
+ if (compiler.options.experimentCallInstrumentation) {
// We use field.hashCode because it is globally unique and it is
// available while we are doing codegen.
info.coverageId = '${field.hashCode}';
@@ -160,12 +152,6 @@
return info;
}
- bool _hasBeenResolved(MemberEntity entity) {
- return compiler.globalInference.typesInferrerInternal.inferrer.types
- .memberTypeInformations
- .containsKey(entity);
- }
-
ClassInfo visitClass(ClassEntity clazz) {
// Omit class if it is not needed.
ClassInfo classInfo = new ClassInfo(
@@ -312,7 +298,7 @@
int closureSize = _addClosureInfo(info, function);
size += closureSize;
- if (JavaScriptBackend.TRACE_METHOD == 'post') {
+ if (compiler.options.experimentCallInstrumentation) {
// We use function.hashCode because it is globally unique and it is
// available while we are doing codegen.
info.coverageId = '${function.hashCode}';
@@ -556,9 +542,10 @@
compiler.outputProvider.createOutputSink(
compiler.options.outputUri.pathSegments.last,
'info.json',
- OutputType.info)
+ OutputType.dumpInfo)
..add(jsonBuffer.toString())
..close();
+ BasicInfo.resetIds();
});
}
diff --git a/pkg/compiler/lib/src/frontend_strategy.dart b/pkg/compiler/lib/src/frontend_strategy.dart
index 3743e66..1508076 100644
--- a/pkg/compiler/lib/src/frontend_strategy.dart
+++ b/pkg/compiler/lib/src/frontend_strategy.dart
@@ -18,7 +18,7 @@
import 'js_backend/native_data.dart';
import 'js_backend/no_such_method_registry.dart';
import 'js_backend/runtime_types.dart';
-import 'library_loader.dart';
+import 'kernel/loader.dart';
import 'native/enqueue.dart' show NativeResolutionEnqueuer;
import 'native/resolver.dart';
import 'universe/class_hierarchy.dart';
@@ -30,7 +30,7 @@
/// the resolved element model.
abstract class FrontendStrategy {
/// Registers a set of loaded libraries with this strategy.
- void registerLoadedLibraries(LoadedLibraries loadedLibraries);
+ void registerLoadedLibraries(KernelResult result);
/// Returns the [ElementEnvironment] for the element model used in this
/// strategy.
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 7c2d111..3009a68 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -49,6 +49,7 @@
final bool _inGenerativeConstructor;
LocalsHandler _locals;
+ FieldInitializationScope _fieldScope;
final SideEffectsBuilder _sideEffectsBuilder;
final Map<JumpTarget, List<LocalsHandler>> _breaksFor =
<JumpTarget, List<LocalsHandler>>{};
@@ -70,7 +71,9 @@
KernelTypeGraphBuilder(this._options, this._closedWorld, this._inferrer,
this._analyzedMember, this._analyzedNode, this._localsMap,
- [this._locals, Map<Local, FieldEntity> capturedAndBoxed])
+ [this._locals,
+ this._fieldScope,
+ Map<Local, FieldEntity> capturedAndBoxed])
: this._types = _inferrer.types,
this._memberData = _inferrer.dataOfMember(_analyzedMember),
// TODO(johnniwinther): Should side effects also be tracked for field
@@ -85,9 +88,9 @@
: <Local, FieldEntity>{} {
if (_locals != null) return;
- FieldInitializationScope fieldScope =
+ _fieldScope =
_inGenerativeConstructor ? new FieldInitializationScope() : null;
- _locals = new LocalsHandler(_analyzedNode, fieldScope);
+ _locals = new LocalsHandler(_analyzedNode);
}
JsToElementMap get _elementMap => _closedWorld.elementMap;
@@ -99,12 +102,12 @@
bool get inLoop => _loopLevel > 0;
bool get _isThisExposed {
- return _inGenerativeConstructor ? _locals.fieldScope.isThisExposed : true;
+ return _inGenerativeConstructor ? _fieldScope.isThisExposed : true;
}
void _markThisAsExposed() {
if (_inGenerativeConstructor) {
- _locals.fieldScope.isThisExposed = true;
+ _fieldScope.isThisExposed = true;
}
}
@@ -141,7 +144,7 @@
if (!selector.isSetter &&
_isInClassOrSubclass(field) &&
field.isAssignable &&
- _locals.fieldScope.readField(field) == null &&
+ _fieldScope.readField(field) == null &&
getFieldInitializer(_elementMap, field) == null) {
// If the field is being used before this constructor
// actually had a chance to initialize it, say it can be
@@ -198,7 +201,7 @@
void initializationIsIndefinite() {
if (_inGenerativeConstructor) {
- _locals.fieldScope.isIndefinite = true;
+ _fieldScope.isIndefinite = true;
}
}
@@ -257,7 +260,7 @@
_elementMap.elementEnvironment.forEachLocalClassMember(cls,
(MemberEntity member) {
if (member.isField && member.isInstanceMember && member.isAssignable) {
- TypeInformation type = _locals.fieldScope.readField(member);
+ TypeInformation type = _fieldScope.readField(member);
MemberDefinition definition = _elementMap.getMemberDefinition(member);
assert(definition.kind == MemberKind.regular);
ir.Field node = definition.node;
@@ -291,7 +294,7 @@
visitFieldInitializer(ir.FieldInitializer node) {
TypeInformation rhsType = visit(node.value);
FieldEntity field = _elementMap.getField(node.field);
- _locals.updateField(field, rhsType);
+ _fieldScope.updateField(field, rhsType);
_inferrer.recordTypeOfField(field, rhsType);
return null;
}
@@ -455,17 +458,26 @@
List<IsCheck> negativeTests = <IsCheck>[];
bool simpleCondition =
handleCondition(node.condition, positiveTests, negativeTests);
- LocalsHandler saved = _locals;
- _locals = new LocalsHandler.from(_locals, node);
- _updateIsChecks(positiveTests, negativeTests);
+ LocalsHandler localsBefore = _locals;
+ FieldInitializationScope fieldScopeBefore = _fieldScope;
- LocalsHandler thenLocals = _locals;
- _locals = new LocalsHandler.from(saved, node);
+ _locals = new LocalsHandler.from(localsBefore, node);
+ _updateIsChecks(positiveTests, negativeTests);
+ LocalsHandler localsAfterCondition = _locals;
+ FieldInitializationScope fieldScopeAfterThen = _fieldScope;
+
+ _locals = new LocalsHandler.from(localsBefore, node);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
if (simpleCondition) _updateIsChecks(negativeTests, positiveTests);
visit(node.message);
- _locals.seenReturnOrThrow = true;
- saved.mergeDiamondFlow(_inferrer, thenLocals, _locals);
- _locals = saved;
+
+ LocalsHandler localsAfterMessage = _locals;
+ FieldInitializationScope fieldScopeAfterMessage = _fieldScope;
+ localsAfterMessage.seenReturnOrThrow = true;
+ _locals = localsBefore.mergeDiamondFlow(
+ _inferrer, localsAfterCondition, localsAfterMessage);
+ _fieldScope = fieldScopeBefore?.mergeDiamondFlow(
+ _inferrer, fieldScopeAfterThen, fieldScopeAfterMessage);
return null;
}
@@ -525,18 +537,24 @@
do {
changed = false;
for (ir.SwitchCase switchCase in node.cases) {
- LocalsHandler saved = _locals;
- _locals = new LocalsHandler.from(_locals, switchCase);
+ LocalsHandler localsBeforeCase = _locals;
+ FieldInitializationScope fieldScopeBeforeCase = _fieldScope;
+ _locals = new LocalsHandler.from(localsBeforeCase, switchCase);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBeforeCase);
visit(switchCase);
- changed = saved.mergeAll(_inferrer, [_locals]) || changed;
- _locals = saved;
+ LocalsHandler localsAfterCase = _locals;
+ changed = localsBeforeCase.mergeAll(_inferrer, [localsAfterCase]) ||
+ changed;
+ _locals = localsBeforeCase;
+ _fieldScope = fieldScopeBeforeCase;
}
} while (changed);
_locals.endLoop(_inferrer, node);
continueTargets.forEach(_clearBreaksAndContinues);
} else {
- LocalsHandler saved = _locals;
+ LocalsHandler localsBeforeCase = _locals;
+ FieldInitializationScope fieldScopeBeforeCase = _fieldScope;
List<LocalsHandler> localsToMerge = <LocalsHandler>[];
bool hasDefaultCase = false;
@@ -544,13 +562,14 @@
if (switchCase.isDefault) {
hasDefaultCase = true;
}
- _locals = new LocalsHandler.from(saved, switchCase);
+ _locals = new LocalsHandler.from(localsBeforeCase, switchCase);
visit(switchCase);
localsToMerge.add(_locals);
}
- saved.mergeAfterBreaks(_inferrer, localsToMerge,
+ localsBeforeCase.mergeAfterBreaks(_inferrer, localsToMerge,
keepOwnLocals: !hasDefaultCase);
- _locals = saved;
+ _locals = localsBeforeCase;
+ _fieldScope = fieldScopeBeforeCase;
}
_clearBreaksAndContinues(jumpTarget);
return null;
@@ -1012,22 +1031,24 @@
TypeInformation handleLoop(ir.Node node, JumpTarget target, void logic()) {
_loopLevel++;
bool changed = false;
- LocalsHandler saved = _locals;
- saved.startLoop(_inferrer, node);
+ LocalsHandler localsBefore = _locals;
+ FieldInitializationScope fieldScopeBefore = _fieldScope;
+ localsBefore.startLoop(_inferrer, node);
do {
// Setup (and clear in case of multiple iterations of the loop)
// the lists of breaks and continues seen in the loop.
_setupBreaksAndContinues(target);
- _locals = new LocalsHandler.from(saved, node);
+ _locals = new LocalsHandler.from(localsBefore, node);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
logic();
- changed = saved.mergeAll(_inferrer, _getLoopBackEdges(target));
+ changed = localsBefore.mergeAll(_inferrer, _getLoopBackEdges(target));
} while (changed);
_loopLevel--;
- saved.endLoop(_inferrer, node);
+ localsBefore.endLoop(_inferrer, node);
bool keepOwnLocals = node is! ir.DoStatement;
- saved.mergeAfterBreaks(_inferrer, _getBreaks(target),
+ _locals = localsBefore.mergeAfterBreaks(_inferrer, _getBreaks(target),
keepOwnLocals: keepOwnLocals);
- _locals = saved;
+ _fieldScope = fieldScopeBefore;
_clearBreaksAndContinues(target);
return null;
}
@@ -1293,7 +1314,7 @@
MemberEntity single = targets.first;
if (single.isField) {
FieldEntity field = single;
- _locals.updateField(field, rhsType);
+ _fieldScope.updateField(field, rhsType);
}
}
}
@@ -1378,18 +1399,28 @@
List<IsCheck> negativeTests = <IsCheck>[];
bool simpleCondition =
handleCondition(node.condition, positiveTests, negativeTests);
- LocalsHandler saved = _locals;
- _locals = new LocalsHandler.from(_locals, node);
+ LocalsHandler localsBefore = _locals;
+ FieldInitializationScope fieldScopeBefore = _fieldScope;
+ _locals = new LocalsHandler.from(localsBefore, node);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
_updateIsChecks(positiveTests, negativeTests);
visit(node.then);
- LocalsHandler thenLocals = _locals;
- _locals = new LocalsHandler.from(saved, node);
+
+ LocalsHandler localsAfterThen = _locals;
+ FieldInitializationScope fieldScopeAfterThen = _fieldScope;
+ _locals = new LocalsHandler.from(localsBefore, node);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
if (simpleCondition) {
_updateIsChecks(negativeTests, positiveTests);
}
visit(node.otherwise);
- saved.mergeDiamondFlow(_inferrer, thenLocals, _locals);
- _locals = saved;
+ LocalsHandler localsAfterElse = _locals;
+ FieldInitializationScope fieldScopeAfterElse = _fieldScope;
+
+ _locals = localsBefore.mergeDiamondFlow(
+ _inferrer, localsAfterThen, localsAfterElse);
+ _fieldScope = fieldScopeBefore?.mergeDiamondFlow(
+ _inferrer, fieldScopeAfterThen, fieldScopeAfterElse);
return null;
}
@@ -1425,9 +1456,12 @@
_negativeIsChecks = <IsCheck>[];
}
visit(node.left, conditionContext: _accumulateIsChecks);
- LocalsHandler saved = _locals;
- _locals = new LocalsHandler.from(_locals, node);
+ LocalsHandler localsBefore = _locals;
+ FieldInitializationScope fieldScopeBefore = _fieldScope;
+ _locals = new LocalsHandler.from(localsBefore, node);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
_updateIsChecks(_positiveIsChecks, _negativeIsChecks);
+
LocalsHandler narrowed;
if (oldAccumulateIsChecks) {
narrowed = new LocalsHandler.topLevelCopyOf(_locals);
@@ -1439,14 +1473,18 @@
visit(node.right, conditionContext: _accumulateIsChecks);
if (oldAccumulateIsChecks) {
bool invalidatedInRightHandSide(IsCheck check) {
- return narrowed.locals[check.local] != _locals.locals[check.local];
+ TypeInformation narrowedType =
+ narrowed.use(_inferrer, _capturedAndBoxed, check.local);
+ TypeInformation currentType =
+ _locals.use(_inferrer, _capturedAndBoxed, check.local);
+ return narrowedType != currentType;
}
_positiveIsChecks.removeWhere(invalidatedInRightHandSide);
_negativeIsChecks.removeWhere(invalidatedInRightHandSide);
}
- saved.mergeDiamondFlow(_inferrer, _locals, null);
- _locals = saved;
+ _locals = localsBefore.mergeFlow(_inferrer, _locals);
+ _fieldScope = fieldScopeBefore;
return _types.boolType;
} else if (node.operator == '||') {
_conditionIsSimple = false;
@@ -1454,14 +1492,16 @@
List<IsCheck> negativeIsChecks = <IsCheck>[];
bool isSimple =
handleCondition(node.left, positiveIsChecks, negativeIsChecks);
- LocalsHandler saved = _locals;
+ LocalsHandler localsBefore = _locals;
+ FieldInitializationScope fieldScopeBefore = _fieldScope;
_locals = new LocalsHandler.from(_locals, node);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
if (isSimple) {
_updateIsChecks(negativeIsChecks, positiveIsChecks);
}
visit(node.right, conditionContext: false);
- saved.mergeDiamondFlow(_inferrer, _locals, null);
- _locals = saved;
+ _locals = localsBefore.mergeFlow(_inferrer, _locals);
+ _fieldScope = fieldScopeBefore;
return _types.boolType;
}
failedAt(CURRENT_ELEMENT_SPANNABLE,
@@ -1475,16 +1515,24 @@
List<IsCheck> negativeTests = <IsCheck>[];
bool simpleCondition =
handleCondition(node.condition, positiveTests, negativeTests);
- LocalsHandler saved = _locals;
- _locals = new LocalsHandler.from(_locals, node);
+ LocalsHandler localsBefore = _locals;
+ _locals = new LocalsHandler.from(localsBefore, node);
+ FieldInitializationScope fieldScopeBefore = _fieldScope;
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
_updateIsChecks(positiveTests, negativeTests);
TypeInformation firstType = visit(node.then);
- LocalsHandler thenLocals = _locals;
- _locals = new LocalsHandler.from(saved, node);
+ LocalsHandler localsAfterThen = _locals;
+ FieldInitializationScope fieldScopeAfterThen = _fieldScope;
+ _locals = new LocalsHandler.from(localsBefore, node);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
if (simpleCondition) _updateIsChecks(negativeTests, positiveTests);
TypeInformation secondType = visit(node.otherwise);
- saved.mergeDiamondFlow(_inferrer, thenLocals, _locals);
- _locals = saved;
+ LocalsHandler localsAfterElse = _locals;
+ FieldInitializationScope fieldScopeAfterElse = _fieldScope;
+ _locals = localsBefore.mergeDiamondFlow(
+ _inferrer, localsAfterThen, localsAfterElse);
+ _fieldScope = fieldScopeBefore?.mergeDiamondFlow(
+ _inferrer, fieldScopeAfterThen, fieldScopeAfterElse);
return _types.allocateDiamondPhi(firstType, secondType);
}
@@ -1508,9 +1556,12 @@
if (variable == info.thisLocal) {
_inferrer.recordTypeOfField(field, thisType);
}
+ TypeInformation localType =
+ _locals.use(_inferrer, _capturedAndBoxed, variable);
// The type is null for type parameters.
- if (_locals.locals[variable] == null) return;
- _inferrer.recordTypeOfField(field, _locals.locals[variable]);
+ if (localType != null) {
+ _inferrer.recordTypeOfField(field, localType);
+ }
}
_capturedVariables.add(variable);
});
@@ -1531,6 +1582,8 @@
// method, like for example the types of local variables.
LocalsHandler closureLocals =
new LocalsHandler.from(_locals, node, useOtherTryBlock: false);
+ FieldInitializationScope closureFieldScope =
+ new FieldInitializationScope.from(_fieldScope);
KernelTypeGraphBuilder visitor = new KernelTypeGraphBuilder(
_options,
_closedWorld,
@@ -1539,6 +1592,7 @@
functionNode,
_localsMap,
closureLocals,
+ closureFieldScope,
_capturedAndBoxed);
visitor.run();
_inferrer.recordReturnType(info.callMethod, visitor._returnType);
@@ -1601,32 +1655,41 @@
@override
visitTryCatch(ir.TryCatch node) {
- LocalsHandler saved = _locals;
- _locals = new LocalsHandler.from(_locals, node,
+ LocalsHandler localsBefore = _locals;
+ FieldInitializationScope fieldScopeBefore = _fieldScope;
+ _locals = new LocalsHandler.from(localsBefore, node,
isTry: true, useOtherTryBlock: false);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
initializationIsIndefinite();
visit(node.body);
- saved.mergeDiamondFlow(_inferrer, _locals, null);
- _locals = saved;
+ LocalsHandler localsAfterBody = _locals;
+ _locals = localsBefore.mergeFlow(_inferrer, localsAfterBody);
+ _fieldScope = fieldScopeBefore;
for (ir.Catch catchBlock in node.catches) {
- saved = _locals;
- _locals = new LocalsHandler.from(_locals, catchBlock);
+ LocalsHandler localsBeforeCatch = _locals;
+ FieldInitializationScope fieldScopeBeforeCatch = _fieldScope;
+ _locals = new LocalsHandler.from(localsBeforeCatch, catchBlock);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBeforeCatch);
visit(catchBlock);
- saved.mergeDiamondFlow(_inferrer, _locals, null);
- _locals = saved;
+ LocalsHandler localsAfterCatch = _locals;
+ _locals = localsBeforeCatch.mergeFlow(_inferrer, localsAfterCatch);
+ _fieldScope = fieldScopeBeforeCatch;
}
return null;
}
@override
visitTryFinally(ir.TryFinally node) {
- LocalsHandler saved = _locals;
- _locals = new LocalsHandler.from(_locals, node,
+ LocalsHandler localsBefore = _locals;
+ FieldInitializationScope fieldScopeBefore = _fieldScope;
+ _locals = new LocalsHandler.from(localsBefore, node,
isTry: true, useOtherTryBlock: false);
+ _fieldScope = new FieldInitializationScope.from(fieldScopeBefore);
initializationIsIndefinite();
visit(node.body);
- saved.mergeDiamondFlow(_inferrer, _locals, null);
- _locals = saved;
+ LocalsHandler localsAfterBody = _locals;
+ _locals = localsBefore.mergeFlow(_inferrer, localsAfterBody);
+ _fieldScope = fieldScopeBefore;
visit(node.finalizer);
return null;
}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 835c405..896f862 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -19,7 +19,7 @@
import '../js_model/element_map.dart';
import '../js_model/js_world.dart';
import '../js_model/locals.dart';
-import '../native/behavior.dart' as native;
+import '../native/behavior.dart';
import '../options.dart';
import '../serialization/serialization.dart';
import '../types/abstract_value_domain.dart';
@@ -216,8 +216,8 @@
TypeInformation typeOfParameter(Local element);
/// Returns the type for [nativeBehavior]. See documentation on
- /// [native.NativeBehavior].
- TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior);
+ /// [NativeBehavior].
+ TypeInformation typeOfNativeBehavior(NativeBehavior nativeBehavior);
bool returnsListElementType(Selector selector, AbstractValue mask);
@@ -346,14 +346,14 @@
}
}
- TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior) {
+ TypeInformation typeOfNativeBehavior(NativeBehavior nativeBehavior) {
if (nativeBehavior == null) return types.dynamicType;
List typesReturned = nativeBehavior.typesReturned;
if (typesReturned.isEmpty) return types.dynamicType;
TypeInformation returnType;
for (var type in typesReturned) {
TypeInformation mappedType;
- if (type == native.SpecialType.JsObject) {
+ if (type == SpecialType.JsObject) {
mappedType = types.nonNullExact(commonElements.objectClass);
} else if (type == commonElements.stringType) {
mappedType = types.stringType;
diff --git a/pkg/compiler/lib/src/inferrer/locals_handler.dart b/pkg/compiler/lib/src/inferrer/locals_handler.dart
index a0ad009..2ebc446 100644
--- a/pkg/compiler/lib/src/inferrer/locals_handler.dart
+++ b/pkg/compiler/lib/src/inferrer/locals_handler.dart
@@ -144,15 +144,19 @@
fields?.forEach(f);
}
- void mergeDiamondFlow(InferrerEngine inferrer,
+ /// Returns the join between [thenScope] and [elseScope] which models the
+ /// flow through either [thenScope] or [elseScope].
+ FieldInitializationScope mergeDiamondFlow(InferrerEngine inferrer,
FieldInitializationScope thenScope, FieldInitializationScope elseScope) {
+ assert(elseScope != null);
+
// Quick bailout check. If [isThisExposed] or [isIndefinite] is true, we
// know the code following won'TypeInformation do anything.
- if (isThisExposed) return;
- if (isIndefinite) return;
+ if (isThisExposed) return this;
+ if (isIndefinite) return this;
FieldInitializationScope otherScope =
- (elseScope == null || elseScope.fields == null) ? this : elseScope;
+ elseScope.fields == null ? this : elseScope;
thenScope.forEach((FieldEntity field, TypeInformation type) {
TypeInformation otherType = otherScope.readField(field);
@@ -162,6 +166,7 @@
isThisExposed = thenScope.isThisExposed || elseScope.isThisExposed;
isIndefinite = thenScope.isIndefinite || elseScope.isIndefinite;
+ return this;
}
}
@@ -245,9 +250,8 @@
* Placeholder for inferred types of local variables.
*/
class LocalsHandler {
- final VariableScope locals;
- final FieldInitializationScope fieldScope;
- LocalsHandler tryBlock;
+ final VariableScope _locals;
+ LocalsHandler _tryBlock;
bool seenReturnOrThrow = false;
bool seenBreakOrContinue = false;
@@ -255,31 +259,28 @@
return seenReturnOrThrow || seenBreakOrContinue;
}
- bool get inTryBlock => tryBlock != null;
+ bool get inTryBlock => _tryBlock != null;
- LocalsHandler.internal(
- ir.Node block, this.fieldScope, this.locals, this.tryBlock);
+ LocalsHandler.internal(ir.Node block, this._locals, this._tryBlock);
- LocalsHandler(ir.Node block, [this.fieldScope])
- : locals = new VariableScope(block, isTry: false),
- tryBlock = null;
+ LocalsHandler(ir.Node block)
+ : _locals = new VariableScope(block, isTry: false),
+ _tryBlock = null;
LocalsHandler.from(LocalsHandler other, ir.Node block,
{bool isTry: false, bool useOtherTryBlock: true})
- : locals = new VariableScope(block, isTry: isTry, parent: other.locals),
- fieldScope = new FieldInitializationScope.from(other.fieldScope) {
- tryBlock = useOtherTryBlock ? other.tryBlock : this;
+ : _locals =
+ new VariableScope(block, isTry: isTry, parent: other._locals) {
+ _tryBlock = useOtherTryBlock ? other._tryBlock : this;
}
LocalsHandler.deepCopyOf(LocalsHandler other)
- : locals = new VariableScope.deepCopyOf(other.locals),
- fieldScope = new FieldInitializationScope.from(other.fieldScope),
- tryBlock = other.tryBlock;
+ : _locals = new VariableScope.deepCopyOf(other._locals),
+ _tryBlock = other._tryBlock;
LocalsHandler.topLevelCopyOf(LocalsHandler other)
- : locals = new VariableScope.topLevelCopyOf(other.locals),
- fieldScope = new FieldInitializationScope.from(other.fieldScope),
- tryBlock = other.tryBlock;
+ : _locals = new VariableScope.topLevelCopyOf(other._locals),
+ _tryBlock = other._tryBlock;
TypeInformation use(InferrerEngine inferrer,
Map<Local, FieldEntity> capturedAndBoxed, Local local) {
@@ -287,32 +288,14 @@
if (field != null) {
return inferrer.typeOfMember(field);
} else {
- return locals[local];
+ return _locals[local];
}
}
void update(InferrerEngine inferrer, Map<Local, FieldEntity> capturedAndBoxed,
- Local local, TypeInformation type, ir.Node node, DartType staticType,
- {bool isSetIfNull: false}) {
+ Local local, TypeInformation type, ir.Node node, DartType staticType) {
assert(type != null);
- if (!inferrer.options.assignmentCheckPolicy.isIgnored) {
- type = inferrer.types.narrowType(type, staticType);
- }
- updateLocal() {
- TypeInformation currentType = locals[local];
-
- if (isSetIfNull && currentType != null) {
- // If-null assignments may return either the new or the original value
- // narrowed to non-null.
- type = inferrer.types.addPhiInput(
- local,
- inferrer.types.allocatePhi(
- locals.block, local, inferrer.types.narrowNotNull(currentType),
- isTry: locals.isTry),
- type);
- }
- locals[local] = type;
- }
+ type = inferrer.types.narrowType(type, staticType);
FieldEntity field = capturedAndBoxed[local];
if (field != null) {
@@ -323,94 +306,98 @@
// potential types after we have left it. We update the parent
// of the try block so that, at exit of the try block, we get
// the right phi for it.
- TypeInformation existing = tryBlock.locals.parent[local];
+ TypeInformation existing = _tryBlock._locals.parent[local];
if (existing != null) {
TypeInformation phiType = inferrer.types.allocatePhi(
- tryBlock.locals.block, local, existing,
- isTry: tryBlock.locals.isTry);
+ _tryBlock._locals.block, local, existing,
+ isTry: _tryBlock._locals.isTry);
TypeInformation inputType =
inferrer.types.addPhiInput(local, phiType, type);
- tryBlock.locals.parent[local] = inputType;
+ _tryBlock._locals.parent[local] = inputType;
}
// Update the current handler unconditionally with the new
// type.
- updateLocal();
+ _locals[local] = type;
} else {
- updateLocal();
+ _locals[local] = type;
}
}
void narrow(InferrerEngine inferrer, Map<Local, FieldEntity> capturedAndBoxed,
- Local local, DartType type, ir.Node node,
- {bool isSetIfNull: false}) {
+ Local local, DartType type, ir.Node node) {
TypeInformation existing = use(inferrer, capturedAndBoxed, local);
TypeInformation newType =
inferrer.types.narrowType(existing, type, isNullable: false);
- update(inferrer, capturedAndBoxed, local, newType, node, type,
- isSetIfNull: isSetIfNull);
+ update(inferrer, capturedAndBoxed, local, newType, node, type);
}
- void mergeDiamondFlow(InferrerEngine inferrer, LocalsHandler thenBranch,
- LocalsHandler elseBranch) {
- if (fieldScope != null && elseBranch != null) {
- fieldScope.mergeDiamondFlow(
- inferrer, thenBranch.fieldScope, elseBranch.fieldScope);
- }
- seenReturnOrThrow = thenBranch.seenReturnOrThrow &&
- elseBranch != null &&
- elseBranch.seenReturnOrThrow;
- seenBreakOrContinue = thenBranch.seenBreakOrContinue &&
- elseBranch != null &&
- elseBranch.seenBreakOrContinue;
- if (aborts) return;
+ /// Returns the join between this locals handler and [other] which models the
+ /// flow through either this or [other].
+ LocalsHandler mergeFlow(InferrerEngine inferrer, LocalsHandler other) {
+ seenReturnOrThrow = false;
+ seenBreakOrContinue = false;
- void mergeOneBranch(LocalsHandler other) {
- other.locals.forEachOwnLocal((Local local, TypeInformation type) {
- TypeInformation myType = locals[local];
+ if (other.aborts) {
+ return this;
+ } else {
+ other._locals.forEachOwnLocal((Local local, TypeInformation type) {
+ TypeInformation myType = _locals[local];
if (myType == null) return; // Variable is only defined in [other].
if (type == myType) return;
- locals[local] = inferrer.types.allocateDiamondPhi(myType, type);
+ _locals[local] = inferrer.types.allocateDiamondPhi(myType, type);
});
}
+ return this;
+ }
+
+ /// Returns the join between [thenBranch] and [elseBranch] which models the
+ /// flow through either [thenBranch] or [elseBranch].
+ LocalsHandler mergeDiamondFlow(InferrerEngine inferrer,
+ LocalsHandler thenBranch, LocalsHandler elseBranch) {
+ assert(elseBranch != null);
+ seenReturnOrThrow =
+ thenBranch.seenReturnOrThrow && elseBranch.seenReturnOrThrow;
+ seenBreakOrContinue =
+ thenBranch.seenBreakOrContinue && elseBranch.seenBreakOrContinue;
+ if (aborts) return this;
void inPlaceUpdateOneBranch(LocalsHandler other) {
- other.locals.forEachOwnLocal((Local local, TypeInformation type) {
- TypeInformation myType = locals[local];
+ other._locals.forEachOwnLocal((Local local, TypeInformation type) {
+ TypeInformation myType = _locals[local];
if (myType == null) return; // Variable is only defined in [other].
if (type == myType) return;
- locals[local] = type;
+ _locals[local] = type;
});
}
if (thenBranch.aborts) {
- if (elseBranch == null) return;
inPlaceUpdateOneBranch(elseBranch);
- } else if (elseBranch == null) {
- mergeOneBranch(thenBranch);
} else if (elseBranch.aborts) {
inPlaceUpdateOneBranch(thenBranch);
} else {
void mergeLocal(Local local) {
- TypeInformation myType = locals[local];
+ TypeInformation myType = _locals[local];
if (myType == null) return;
- TypeInformation elseType = elseBranch.locals[local];
- TypeInformation thenType = thenBranch.locals[local];
+ TypeInformation elseType = elseBranch._locals[local];
+ TypeInformation thenType = thenBranch._locals[local];
if (thenType == elseType) {
- locals[local] = thenType;
+ _locals[local] = thenType;
} else {
- locals[local] = inferrer.types.allocateDiamondPhi(thenType, elseType);
+ _locals[local] =
+ inferrer.types.allocateDiamondPhi(thenType, elseType);
}
}
- thenBranch.locals.forEachOwnLocal((Local local, _) {
+ thenBranch._locals.forEachOwnLocal((Local local, _) {
mergeLocal(local);
});
- elseBranch.locals.forEachOwnLocal((Local local, _) {
+ elseBranch._locals.forEachOwnLocal((Local local, _) {
// Discard locals we already processed when iterating over
// [thenBranch]'s locals.
- if (!thenBranch.locals.updates(local)) mergeLocal(local);
+ if (!thenBranch._locals.updates(local)) mergeLocal(local);
});
}
+ return this;
}
/**
@@ -443,39 +430,41 @@
* where [:this:] is the [LocalsHandler] for the paths through the
* labeled statement that do not break out.
*/
- void mergeAfterBreaks(InferrerEngine inferrer, List<LocalsHandler> handlers,
+ LocalsHandler mergeAfterBreaks(
+ InferrerEngine inferrer, List<LocalsHandler> handlers,
{bool keepOwnLocals: true}) {
- ir.Node level = locals.block;
+ ir.Node level = _locals.block;
// Use a separate locals handler to perform the merge in, so that Phi
// creation does not invalidate previous type knowledge while we might
// still look it up.
LocalsHandler merged =
- new LocalsHandler.from(this, level, isTry: locals.isTry);
+ new LocalsHandler.from(this, level, isTry: _locals.isTry);
Set<Local> seenLocals = new Setlet<Local>();
bool allBranchesAbort = true;
// Merge all other handlers.
for (LocalsHandler handler in handlers) {
allBranchesAbort = allBranchesAbort && handler.seenReturnOrThrow;
- merged.mergeHandler(inferrer, handler, seenLocals);
+ merged._mergeHandler(inferrer, handler, seenLocals);
}
// If we want to keep own locals, we merge [seenLocals] from [this] into
// [merged] to update the Phi nodes with original values.
if (keepOwnLocals && !seenReturnOrThrow) {
for (Local variable in seenLocals) {
- TypeInformation originalType = locals[variable];
+ TypeInformation originalType = _locals[variable];
if (originalType != null) {
- merged.locals[variable] = inferrer.types
- .addPhiInput(variable, merged.locals[variable], originalType);
+ merged._locals[variable] = inferrer.types
+ .addPhiInput(variable, merged._locals[variable], originalType);
}
}
}
// Clean up Phi nodes with single input and store back result into
// actual locals handler.
- merged.locals.forEachOwnLocal((Local variable, TypeInformation type) {
- locals[variable] = inferrer.types.simplifyPhi(level, variable, type);
+ merged._locals.forEachOwnLocal((Local variable, TypeInformation type) {
+ _locals[variable] = inferrer.types.simplifyPhi(level, variable, type);
});
seenReturnOrThrow =
allBranchesAbort && (!keepOwnLocals || seenReturnOrThrow);
+ return this;
}
/**
@@ -484,24 +473,24 @@
* unless the local is already present in the set [seen]. This effectively
* overwrites the current type knowledge in this handler.
*/
- bool mergeHandler(InferrerEngine inferrer, LocalsHandler other,
+ bool _mergeHandler(InferrerEngine inferrer, LocalsHandler other,
[Set<Local> seen]) {
if (other.seenReturnOrThrow) return false;
bool changed = false;
- other.locals.forEachLocalUntilNode(locals.block, (local, otherType) {
- TypeInformation myType = locals[local];
+ other._locals.forEachLocalUntilNode(_locals.block, (local, otherType) {
+ TypeInformation myType = _locals[local];
if (myType == null) return;
TypeInformation newType;
if (seen != null && !seen.contains(local)) {
newType = inferrer.types
- .allocatePhi(locals.block, local, otherType, isTry: locals.isTry);
+ .allocatePhi(_locals.block, local, otherType, isTry: _locals.isTry);
seen.add(local);
} else {
newType = inferrer.types.addPhiInput(local, myType, otherType);
}
if (newType != myType) {
changed = true;
- locals[local] = newType;
+ _locals[local] = newType;
}
});
return changed;
@@ -515,39 +504,35 @@
bool changed = false;
assert(!seenReturnOrThrow);
handlers.forEach((other) {
- changed = mergeHandler(inferrer, other) || changed;
+ changed = _mergeHandler(inferrer, other) || changed;
});
return changed;
}
void startLoop(InferrerEngine inferrer, ir.Node loop) {
- locals.forEachLocal((Local variable, TypeInformation type) {
+ _locals.forEachLocal((Local variable, TypeInformation type) {
TypeInformation newType =
inferrer.types.allocateLoopPhi(loop, variable, type, isTry: false);
if (newType != type) {
- locals[variable] = newType;
+ _locals[variable] = newType;
}
});
}
void endLoop(InferrerEngine inferrer, ir.Node loop) {
- locals.forEachLocal((Local variable, TypeInformation type) {
+ _locals.forEachLocal((Local variable, TypeInformation type) {
TypeInformation newType =
inferrer.types.simplifyPhi(loop, variable, type);
if (newType != type) {
- locals[variable] = newType;
+ _locals[variable] = newType;
}
});
}
- void updateField(FieldEntity element, TypeInformation type) {
- fieldScope.updateField(element, type);
- }
-
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('LocalsHandler(');
- sb.write('locals=$locals');
+ sb.write('locals=$_locals');
sb.write(')');
return sb.toString();
}
diff --git a/pkg/compiler/lib/src/ir/static_type.dart b/pkg/compiler/lib/src/ir/static_type.dart
index 669b6c6..78e4277 100644
--- a/pkg/compiler/lib/src/ir/static_type.dart
+++ b/pkg/compiler/lib/src/ir/static_type.dart
@@ -7,8 +7,23 @@
import 'package:kernel/core_types.dart' as ir;
import 'package:kernel/type_algebra.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
+import 'scope.dart';
import 'static_type_base.dart';
+/// Enum values for how the target of a static type should be interpreted.
+enum ClassRelation {
+ /// The target is any subtype of the static type.
+ subtype,
+
+ /// The target is a subclass or mixin application of the static type.
+ ///
+ /// This corresponds to accessing a member through a this expression.
+ thisExpression,
+
+ /// The target is an exact instance of the static type.
+ exact,
+}
+
/// Visitor that computes and caches the static type of expression while
/// visiting the full tree at expression level.
///
@@ -26,6 +41,8 @@
Map<ir.Expression, ir.DartType> get staticTypeCacheForTesting => _cache;
+ VariableScopeModel get variableScopeModel => null;
+
@override
ir.DartType defaultNode(ir.Node node) =>
throw UnsupportedError('Unhandled node $node (${node.runtimeType})');
@@ -90,6 +107,10 @@
ir.DartType _computePropertyGetType(
ir.PropertyGet node, ir.DartType receiverType) {
ir.Member interfaceTarget = node.interfaceTarget;
+ if (interfaceTarget == null && receiverType is ir.InterfaceType) {
+ interfaceTarget = node.interfaceTarget = typeEnvironment.hierarchy
+ .getInterfaceMember(receiverType.classNode, node.name);
+ }
if (interfaceTarget != null) {
ir.Class superclass = interfaceTarget.enclosingClass;
receiverType = getTypeAsInstanceOf(receiverType, superclass);
@@ -126,6 +147,10 @@
ir.DartType visitPropertySet(ir.PropertySet node) {
ir.DartType receiverType = visitNode(node.receiver);
ir.DartType valueType = super.visitPropertySet(node);
+ if (node.interfaceTarget == null && receiverType is ir.InterfaceType) {
+ node.interfaceTarget = typeEnvironment.hierarchy
+ .getInterfaceMember(receiverType.classNode, node.name, setter: true);
+ }
receiverType = _narrowInstanceReceiver(node.interfaceTarget, receiverType);
handlePropertySet(node, receiverType, valueType);
return valueType;
@@ -219,6 +244,75 @@
return receiverType;
}
+ /// Returns `true` if [member] can be called with the structure of
+ /// [arguments].
+ bool _isApplicable(ir.Arguments arguments, ir.Member member) {
+ /// Returns `true` if [arguments] are applicable to the function type
+ /// structure.
+ bool isFunctionTypeApplicable(
+ int typeParameterCount,
+ int requiredParameterCount,
+ int positionalParameterCount,
+ Iterable<String> Function() getNamedParameters) {
+ if (arguments.types.isNotEmpty &&
+ arguments.types.length != typeParameterCount) {
+ return false;
+ }
+ if (arguments.positional.length < requiredParameterCount) {
+ return false;
+ }
+ if (arguments.positional.length > positionalParameterCount) {
+ return false;
+ }
+ Iterable<String> namedParameters = getNamedParameters();
+ if (arguments.named.length > namedParameters.length) {
+ return false;
+ }
+ if (arguments.named.isNotEmpty) {
+ for (ir.NamedExpression namedArguments in arguments.named) {
+ if (!namedParameters.contains(namedArguments.name)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /// Returns `true` if [arguments] are applicable to a value of the static
+ /// [type].
+ bool isTypeApplicable(ir.DartType type) {
+ if (type is ir.DynamicType) return true;
+ if (type == typeEnvironment.rawFunctionType) return true;
+ if (type is ir.FunctionType) {
+ return isFunctionTypeApplicable(
+ type.typeParameters.length,
+ type.requiredParameterCount,
+ type.positionalParameters.length,
+ () => type.namedParameters.map((p) => p.name).toSet());
+ }
+ return false;
+ }
+
+ if (member is ir.Procedure) {
+ if (member.kind == ir.ProcedureKind.Setter ||
+ member.kind == ir.ProcedureKind.Factory) {
+ return false;
+ } else if (member.kind == ir.ProcedureKind.Getter) {
+ return isTypeApplicable(member.getterType);
+ } else if (member.kind == ir.ProcedureKind.Method ||
+ member.kind == ir.ProcedureKind.Operator) {
+ return isFunctionTypeApplicable(
+ member.function.typeParameters.length,
+ member.function.requiredParameterCount,
+ member.function.positionalParameters.length,
+ () => member.function.namedParameters.map((p) => p.name).toSet());
+ }
+ } else if (member is ir.Field) {
+ return isTypeApplicable(member.type);
+ }
+ return false;
+ }
+
/// Computes the result type of the method invocation [node] on a receiver of
/// type [receiverType].
///
@@ -236,6 +330,13 @@
node.arguments.named.isEmpty) {
interfaceTarget = node.interfaceTarget = objectEquals;
}
+ if (interfaceTarget == null && receiverType is ir.InterfaceType) {
+ ir.Member member = typeEnvironment.hierarchy
+ .getInterfaceMember(receiverType.classNode, node.name);
+ if (_isApplicable(node.arguments, member)) {
+ interfaceTarget = node.interfaceTarget = member;
+ }
+ }
if (interfaceTarget != null) {
if (isSpecialCasedBinaryOperator(interfaceTarget)) {
ir.DartType argumentType = argumentTypes.positional[0];
@@ -247,8 +348,21 @@
ir.DartType getterType = ir.Substitution.fromInterfaceType(receiverType)
.substituteType(interfaceTarget.getterType);
if (getterType is ir.FunctionType) {
+ List<ir.DartType> typeArguments = node.arguments.types;
+ if (interfaceTarget is ir.Procedure &&
+ interfaceTarget.function.typeParameters.isNotEmpty &&
+ typeArguments.isEmpty) {
+ // If this was a dynamic call the invocation does not have the
+ // inferred default type arguments so we need to create them here
+ // to perform a valid substitution.
+ ir.Substitution substitution =
+ ir.Substitution.fromInterfaceType(receiverType);
+ typeArguments = interfaceTarget.function.typeParameters
+ .map((t) => substitution.substituteType(t.defaultType))
+ .toList();
+ }
return ir.Substitution.fromPairs(
- getterType.typeParameters, node.arguments.types)
+ getterType.typeParameters, typeArguments)
.substituteType(getterType.returnType);
} else {
return const ir.DynamicType();
@@ -817,7 +931,12 @@
@override
Null visitVariableDeclaration(ir.VariableDeclaration node) {
- visitNode(node.initializer);
+ ir.DartType type = visitNode(node.initializer);
+ if (node.initializer != null &&
+ variableScopeModel != null &&
+ variableScopeModel.isEffectivelyFinal(node)) {
+ node.type = type;
+ }
handleVariableDeclaration(node);
}
}
diff --git a/pkg/compiler/lib/src/js_backend/annotations.dart b/pkg/compiler/lib/src/js_backend/annotations.dart
index 025f6d8..bd195e7 100644
--- a/pkg/compiler/lib/src/js_backend/annotations.dart
+++ b/pkg/compiler/lib/src/js_backend/annotations.dart
@@ -9,7 +9,7 @@
import '../diagnostics/diagnostic_listener.dart';
import '../diagnostics/messages.dart';
import '../elements/entities.dart';
-import '../native/native.dart' as native;
+import '../kernel/dart2js_target.dart';
import '../serialization/serialization.dart';
/// Returns `true` if parameter and returns types should be trusted for
@@ -69,7 +69,7 @@
FunctionEntity method = element;
LibraryEntity library = element.library;
bool platformAnnotationsAllowed = library.canonicalUri.scheme == 'dart' ||
- native.maybeEnableNative(library.canonicalUri);
+ maybeEnableNative(library.canonicalUri);
bool hasNoThrows = false;
bool hasNoSideEffects = false;
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 9190a79..360666b 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -26,8 +26,8 @@
import '../js/rewrite_async.dart';
import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
import '../js_emitter/sorter.dart' show Sorter;
-import '../library_loader.dart' show LoadedLibraries;
-import '../native/native.dart' as native;
+import '../kernel/dart2js_target.dart';
+import '../native/enqueue.dart';
import '../ssa/ssa.dart' show SsaFunctionCompiler;
import '../tracer.dart';
import '../types/types.dart';
@@ -318,14 +318,6 @@
final Map<MemberEntity, jsAst.Expression> generatedCode =
<MemberEntity, jsAst.Expression>{};
- /// If [true], the compiler will emit code that logs whenever a method is
- /// called. When TRACE_METHOD is 'console' this will be logged
- /// directly in the JavaScript console. When TRACE_METHOD is 'post' the
- /// information will be sent to a server via a POST request.
- static const String TRACE_METHOD = const String.fromEnvironment('traceCalls');
- static const bool TRACE_CALLS =
- TRACE_METHOD == 'post' || TRACE_METHOD == 'console';
-
Namer _namer;
Namer get namer {
@@ -388,8 +380,8 @@
final SuperMemberData superMemberData = new SuperMemberData();
- native.NativeResolutionEnqueuer _nativeResolutionEnqueuer;
- native.NativeCodegenEnqueuer _nativeCodegenEnqueuer;
+ NativeResolutionEnqueuer _nativeResolutionEnqueuer;
+ NativeCodegenEnqueuer _nativeCodegenEnqueuer;
Tracer tracer;
@@ -550,7 +542,7 @@
compiler.frontendStrategy.createRuntimeTypesNeedBuilder();
BackendImpacts impacts =
new BackendImpacts(compiler.options, commonElements);
- _nativeResolutionEnqueuer = new native.NativeResolutionEnqueuer(
+ _nativeResolutionEnqueuer = new NativeResolutionEnqueuer(
compiler.options,
elementEnvironment,
commonElements,
@@ -633,7 +625,7 @@
commonElements,
elementEnvironment,
closedWorld.nativeData);
- _nativeCodegenEnqueuer = new native.NativeCodegenEnqueuer(
+ _nativeCodegenEnqueuer = new NativeCodegenEnqueuer(
compiler.options,
elementEnvironment,
commonElements,
@@ -703,10 +695,10 @@
return worldImpact;
}
- native.NativeResolutionEnqueuer get nativeResolutionEnqueuerForTesting =>
+ NativeResolutionEnqueuer get nativeResolutionEnqueuerForTesting =>
_nativeResolutionEnqueuer;
- native.NativeEnqueuer get nativeCodegenEnqueuer => _nativeCodegenEnqueuer;
+ NativeEnqueuer get nativeCodegenEnqueuer => _nativeCodegenEnqueuer;
/**
* Unit test hook that returns code of an element as a String.
@@ -750,7 +742,7 @@
void setAnnotations(LibraryEntity library) {
AnnotationProcessor processor =
compiler.frontendStrategy.annotationProcesser;
- if (native.maybeEnableNative(library.canonicalUri)) {
+ if (maybeEnableNative(library.canonicalUri)) {
processor.extractNativeAnnotations(library);
}
processor.extractJsInteropAnnotations(library);
@@ -760,18 +752,6 @@
}
}
- /// This method is called when all new libraries loaded through
- /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
- /// have been computed.
- void onLibrariesLoaded(
- CommonElements commonElements, LoadedLibraries loadedLibraries) {
- if (loadedLibraries.containsLibrary(Uris.dart_core)) {
- assert(loadedLibraries.containsLibrary(Uris.dart_core));
- assert(loadedLibraries.containsLibrary(Uris.dart__interceptors));
- assert(loadedLibraries.containsLibrary(Uris.dart__js_helper));
- }
- }
-
/// Called when the compiler starts running the codegen enqueuer. The
/// [WorldImpact] of enabled backend features is returned.
WorldImpact onCodegenStart(JClosedWorld closedWorld,
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index 282086e..73b9075 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -16,7 +16,7 @@
import '../elements/entities.dart';
import '../elements/types.dart';
import '../native/enqueue.dart';
-import '../native/native.dart' as native;
+import '../native/behavior.dart';
import '../options.dart';
import '../universe/feature.dart';
import '../universe/use.dart'
@@ -286,7 +286,7 @@
}
}
- for (native.NativeBehavior behavior in worldImpact.nativeData) {
+ for (NativeBehavior behavior in worldImpact.nativeData) {
_nativeResolutionEnqueuer.registerNativeBehavior(
transformed, behavior, worldImpact);
}
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index aef92595..8f18ffb 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -18,7 +18,6 @@
import '../universe/world_impact.dart'
show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
import 'allocator_analysis.dart';
-import 'backend.dart';
import 'backend_impact.dart';
import 'backend_usage.dart';
import 'checked_mode_helpers.dart';
@@ -429,7 +428,7 @@
_registerBackendImpact(impactBuilder, _impacts.getRuntimeTypeArgument);
}
- if (JavaScriptBackend.TRACE_CALLS) {
+ if (_options.experimentCallInstrumentation) {
_registerBackendImpact(impactBuilder, _impacts.traceHelper);
}
_registerBackendImpact(impactBuilder, _impacts.assertUnreachable);
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index 19fecf5..9da5325 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -1718,7 +1718,7 @@
mapping.addAll(_closedWorld.outputUnitData
.computeDeferredMap(compiler.options, _elementEnvironment));
compiler.outputProvider.createOutputSink(
- compiler.options.deferredMapUri.path, '', OutputType.info)
+ compiler.options.deferredMapUri.path, '', OutputType.deferredMap)
..add(const JsonEncoder.withIndent(" ").convert(mapping))
..close();
}
diff --git a/pkg/compiler/lib/src/js_emitter/headers.dart b/pkg/compiler/lib/src/js_emitter/headers.dart
index ad9e783..9af8ea1 100644
--- a/pkg/compiler/lib/src/js_emitter/headers.dart
+++ b/pkg/compiler/lib/src/js_emitter/headers.dart
@@ -33,6 +33,11 @@
// successCallback. If it fails to do so, it should call errorCallback with
// an error.
//
+// dartCallInstrumentation(id, qualifiedName):
+// if this function is defined, it will be called at each entry of a
+// method or constructor. Used only when compiling programs with
+// --experiment-call-instrumentation.
+//
// defaultPackagesBase:
// Override the location where `package:` uris are resolved from. By default
// they are resolved under "packages/" from the current window location.
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index a5e2a7c..5201c75 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -412,7 +412,7 @@
omittedUnits:
omittedFragments.map((fragemnt) => fragemnt.outputUnit).toSet()));
compiler.outputProvider.createOutputSink(
- compiler.options.deferredMapUri.path, '', OutputType.info)
+ compiler.options.deferredMapUri.path, '', OutputType.deferredMap)
..add(const JsonEncoder.withIndent(" ").convert(mapping))
..close();
}
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index 5d1215e..a342420 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -18,7 +18,7 @@
import '../js_emitter/code_emitter_task.dart';
import '../js_model/closure.dart' show JRecordField;
import '../js_model/elements.dart' show JGeneratorBody;
-import '../native/native.dart' as native;
+import '../native/behavior.dart';
import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
import '../types/abstract_value_domain.dart';
@@ -92,16 +92,15 @@
Name getName(ir.Name name);
/// Computes the [native.NativeBehavior] for a call to the [JS] function.
- native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
+ NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
/// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
/// function.
- native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
- ir.StaticInvocation node);
+ NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node);
/// Computes the [native.NativeBehavior] for a call to the
/// [JS_EMBEDDED_GLOBAL] function.
- native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+ NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
ir.StaticInvocation node);
/// Returns the [js.Name] for the `JsGetName` [constant] value.
@@ -220,7 +219,7 @@
/// Returns the returned type annotation in the [nativeBehavior].
AbstractValue typeFromNativeBehavior(
- native.NativeBehavior nativeBehavior, JClosedWorld closedWorld);
+ NativeBehavior nativeBehavior, JClosedWorld closedWorld);
}
/// Map from kernel IR nodes to local entities.
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index acd6671..07c24f3 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -41,7 +41,7 @@
import '../kernel/element_map_impl.dart';
import '../kernel/env.dart';
import '../kernel/kelements.dart';
-import '../native/native.dart' as native;
+import '../native/behavior.dart';
import '../options.dart';
import '../ordered_typeset.dart';
import '../serialization/serialization.dart';
@@ -87,6 +87,7 @@
static const String typedefDataTag = 'typedef-data';
static const String memberDataTag = 'member-data';
static const String typeVariableDataTag = 'type-variable-data';
+ static const String nestedClosuresTag = 'nested-closures';
final CompilerOptions options;
final DiagnosticReporter reporter;
@@ -333,7 +334,10 @@
JClassEnv env = new JClassEnv.readFromDataSource(source);
JClassData data = new JClassData.readFromDataSource(source);
classMap[env.cls] = classes.registerByIndex(index, cls, data, env);
- libraries.getEnv(cls.library).registerClass(cls.name, env);
+ if (cls is! JRecord && cls is! JClosureClass) {
+ // Synthesized classes are not part of the library environment.
+ libraries.getEnv(cls.library).registerClass(cls.name, env);
+ }
assert(index == cls.classIndex);
});
source.end(classDataTag);
@@ -376,6 +380,12 @@
assert(index == typeVariable.typeVariableIndex);
});
source.end(typeVariableDataTag);
+
+ source.begin(nestedClosuresTag);
+ _nestedClosureMap.addAll(
+ source.readMemberMap(() => source.readMembers<IndexedFunction>()));
+ source.end(nestedClosuresTag);
+
source.end(tag);
}
@@ -457,6 +467,10 @@
});
sink.end(typeVariableDataTag);
+ sink.begin(nestedClosuresTag);
+ sink.writeMemberMap(_nestedClosureMap, sink.writeMembers);
+ sink.end(nestedClosuresTag);
+
sink.end(tag);
}
@@ -1146,16 +1160,16 @@
/// Looks up [typeName] for use in the spec-string of a `JS` call.
// TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
// the `ForeignResolver`.
- native.TypeLookup typeLookup({bool resolveAsRaw: true}) {
+ TypeLookup typeLookup({bool resolveAsRaw: true}) {
return resolveAsRaw
? (_cachedTypeLookupRaw ??= _typeLookup(resolveAsRaw: true))
: (_cachedTypeLookupFull ??= _typeLookup(resolveAsRaw: false));
}
- native.TypeLookup _cachedTypeLookupRaw;
- native.TypeLookup _cachedTypeLookupFull;
+ TypeLookup _cachedTypeLookupRaw;
+ TypeLookup _cachedTypeLookupFull;
- native.TypeLookup _typeLookup({bool resolveAsRaw: true}) {
+ TypeLookup _typeLookup({bool resolveAsRaw: true}) {
bool cachedMayLookupInMain;
bool mayLookupInMain() {
var mainUri = elementEnvironment.mainLibrary.canonicalUri;
@@ -1220,28 +1234,28 @@
/// Computes the [native.NativeBehavior] for a call to the [JS] function.
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
+ NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
if (node.arguments.positional.length < 2 ||
node.arguments.named.isNotEmpty) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
String codeString = _getStringArgument(node, 1);
if (codeString == null) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
- return native.NativeBehavior.ofJsCall(
+ return NativeBehavior.ofJsCall(
specString,
codeString,
typeLookup(resolveAsRaw: true),
@@ -1250,28 +1264,27 @@
commonElements);
}
- /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
+ /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN]
/// function.
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
- ir.StaticInvocation node) {
+ NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) {
if (node.arguments.positional.length < 1) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
if (node.arguments.positional.length < 2) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
- return native.NativeBehavior.ofJsBuiltinCall(
+ return NativeBehavior.ofJsBuiltinCall(
specString,
typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
@@ -1279,34 +1292,34 @@
commonElements);
}
- /// Computes the [native.NativeBehavior] for a call to the
+ /// Computes the [NativeBehavior] for a call to the
/// [JS_EMBEDDED_GLOBAL] function.
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+ NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
ir.StaticInvocation node) {
if (node.arguments.positional.length < 1) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"JS embedded global expression has no type.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
if (node.arguments.positional.length < 2) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
if (node.arguments.positional.length > 2 ||
node.arguments.named.isNotEmpty) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"JS embedded global has more than 2 arguments.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
- return native.NativeBehavior.ofJsEmbeddedGlobalCall(
+ return NativeBehavior.ofJsEmbeddedGlobalCall(
specString,
typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
@@ -2397,8 +2410,8 @@
}
}
-/// [native.BehaviorBuilder] for kernel based elements.
-class JsBehaviorBuilder extends native.BehaviorBuilder {
+/// [BehaviorBuilder] for kernel based elements.
+class JsBehaviorBuilder extends BehaviorBuilder {
final ElementEnvironment elementEnvironment;
final CommonElements commonElements;
final DiagnosticReporter reporter;
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index 2187722..9ab34db 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -2,15 +2,44 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// TODO(johnniwinther): Add a test that ensure that this library doesn't depend
+// on the dart2js internals.
library compiler.src.kernel.dart2js_target;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/core_types.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/target/targets.dart';
+import 'invocation_mirror_constants.dart';
-import '../native/native.dart' show maybeEnableNative;
-import '../universe/selector.dart';
+const Iterable<String> _allowedDartSchemePaths = const <String>[
+ 'async',
+ 'html',
+ 'html_common',
+ 'indexed_db',
+ 'js',
+ 'js_util',
+ 'svg',
+ '_native_typed_data',
+ 'web_audio',
+ 'web_gl',
+ 'web_sql'
+];
+
+bool maybeEnableNative(Uri uri) {
+ bool allowedTestLibrary() {
+ String scriptName = uri.path;
+ return scriptName.contains('tests/compiler/dart2js_native') ||
+ scriptName.contains('tests/compiler/dart2js_extra');
+ }
+
+ bool allowedDartLibrary() {
+ if (uri.scheme != 'dart') return false;
+ return _allowedDartSchemePaths.contains(uri.path);
+ }
+
+ return allowedTestLibrary() || allowedDartLibrary();
+}
/// A kernel [Target] to configure the Dart Front End for dart2js.
class Dart2jsTarget extends Target {
@@ -59,13 +88,13 @@
bool isSuper) {
int kind;
if (name.startsWith('get:')) {
- kind = Selector.invocationMirrorGetterKind;
+ kind = invocationMirrorGetterKind;
name = name.substring(4);
} else if (name.startsWith('set:')) {
- kind = Selector.invocationMirrorSetterKind;
+ kind = invocationMirrorSetterKind;
name = name.substring(4);
} else {
- kind = Selector.invocationMirrorMethodKind;
+ kind = invocationMirrorMethodKind;
}
return new ir.StaticInvocation(
coreTypes.index
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index 5edfd7d..9533b15 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -13,7 +13,7 @@
import '../js/js.dart' as js;
import '../js_backend/namer.dart';
import '../js_backend/native_data.dart';
-import '../native/native.dart' as native;
+import '../native/behavior.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
@@ -86,17 +86,16 @@
/// Returns the [Name] corresponding to [name].
Name getName(ir.Name name);
- /// Computes the [native.NativeBehavior] for a call to the [JS] function.
- native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
+ /// Computes the [NativeBehavior] for a call to the [JS] function.
+ NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
- /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
+ /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN]
/// function.
- native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
- ir.StaticInvocation node);
+ NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node);
- /// Computes the [native.NativeBehavior] for a call to the
+ /// Computes the [NativeBehavior] for a call to the
/// [JS_EMBEDDED_GLOBAL] function.
- native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+ NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
ir.StaticInvocation node);
/// Returns the [js.Name] for the `JsGetName` [constant] value.
@@ -147,15 +146,15 @@
bool isNativeClass(ir.Class node);
/// Computes the native behavior for reading the native [field].
- native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
+ NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
{bool isJsInterop});
/// Computes the native behavior for writing to the native [field].
- native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field);
+ NativeBehavior getNativeBehaviorForFieldStore(ir.Field field);
/// Computes the native behavior for calling the function or constructor
/// [member].
- native.NativeBehavior getNativeBehaviorForMethod(ir.Member member,
+ NativeBehavior getNativeBehaviorForMethod(ir.Member member,
{bool isJsInterop});
/// Compute the kind of foreign helper function called by [node], if any.
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 981f998..ec2f758 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -41,7 +41,8 @@
import '../js_backend/native_data.dart';
import '../js_backend/no_such_method_registry.dart';
import '../js_model/locals.dart';
-import '../native/native.dart' as native;
+import '../kernel/dart2js_target.dart';
+import '../native/behavior.dart';
import '../native/resolver.dart';
import '../options.dart';
import '../ordered_typeset.dart';
@@ -104,7 +105,7 @@
final Map<ir.Field, IndexedField> fieldMap = {};
final Map<ir.TreeNode, Local> localFunctionMap = {};
- native.BehaviorBuilder _nativeBehaviorBuilder;
+ BehaviorBuilder _nativeBehaviorBuilder;
FrontendStrategy _frontendStrategy;
Map<KMember, Map<ir.TreeNode, ir.DartType>> staticTypeCacheForTesting;
@@ -817,18 +818,18 @@
}
/// Looks up [typeName] for use in the spec-string of a `JS` call.
- // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
+ // TODO(johnniwinther): Use this in [NativeBehavior] instead of calling
// the `ForeignResolver`.
- native.TypeLookup typeLookup({bool resolveAsRaw: true}) {
+ TypeLookup typeLookup({bool resolveAsRaw: true}) {
return resolveAsRaw
? (_cachedTypeLookupRaw ??= _typeLookup(resolveAsRaw: true))
: (_cachedTypeLookupFull ??= _typeLookup(resolveAsRaw: false));
}
- native.TypeLookup _cachedTypeLookupRaw;
- native.TypeLookup _cachedTypeLookupFull;
+ TypeLookup _cachedTypeLookupRaw;
+ TypeLookup _cachedTypeLookupFull;
- native.TypeLookup _typeLookup({bool resolveAsRaw: true}) {
+ TypeLookup _typeLookup({bool resolveAsRaw: true}) {
bool cachedMayLookupInMain;
bool mayLookupInMain() {
var mainUri = elementEnvironment.mainLibrary.canonicalUri;
@@ -891,30 +892,30 @@
return node.arguments.positional[index].accept(new Stringifier());
}
- /// Computes the [native.NativeBehavior] for a call to the [JS] function.
+ /// Computes the [NativeBehavior] for a call to the [JS] function.
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
+ NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
if (node.arguments.positional.length < 2 ||
node.arguments.named.isNotEmpty) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
String codeString = _getStringArgument(node, 1);
if (codeString == null) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
- return native.NativeBehavior.ofJsCall(
+ return NativeBehavior.ofJsCall(
specString,
codeString,
typeLookup(resolveAsRaw: true),
@@ -923,28 +924,27 @@
commonElements);
}
- /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
+ /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN]
/// function.
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
- ir.StaticInvocation node) {
+ NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) {
if (node.arguments.positional.length < 1) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
if (node.arguments.positional.length < 2) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
- return native.NativeBehavior.ofJsBuiltinCall(
+ return NativeBehavior.ofJsBuiltinCall(
specString,
typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
@@ -952,34 +952,34 @@
commonElements);
}
- /// Computes the [native.NativeBehavior] for a call to the
+ /// Computes the [NativeBehavior] for a call to the
/// [JS_EMBEDDED_GLOBAL] function.
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+ NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
ir.StaticInvocation node) {
if (node.arguments.positional.length < 1) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"JS embedded global expression has no type.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
if (node.arguments.positional.length < 2) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
if (node.arguments.positional.length > 2 ||
node.arguments.named.isNotEmpty) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"JS embedded global has more than 2 arguments.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
- return new native.NativeBehavior();
+ return new NativeBehavior();
}
- return native.NativeBehavior.ofJsEmbeddedGlobalCall(
+ return NativeBehavior.ofJsEmbeddedGlobalCall(
specString,
typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
@@ -1332,14 +1332,15 @@
env.addComponent(component);
}
- native.BehaviorBuilder get nativeBehaviorBuilder =>
+ BehaviorBuilder get nativeBehaviorBuilder =>
_nativeBehaviorBuilder ??= new KernelBehaviorBuilder(elementEnvironment,
commonElements, nativeBasicData, reporter, options);
- ResolutionImpact computeWorldImpact(KMember member) {
+ ResolutionImpact computeWorldImpact(
+ KMember member, VariableScopeModel variableScopeModel) {
ir.Member node = members.getData(member).node;
- KernelImpactBuilder builder =
- new KernelImpactBuilder(this, member, reporter, options);
+ KernelImpactBuilder builder = new KernelImpactBuilder(
+ this, member, reporter, options, variableScopeModel);
node.accept(builder);
if (retainDataForTesting) {
staticTypeCacheForTesting ??= {};
@@ -1504,7 +1505,7 @@
/// Computes the native behavior for reading the native [field].
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
+ NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
{bool isJsInterop}) {
DartType type = getDartType(field.type);
List<ConstantValue> metadata = getMetadata(field.annotations);
@@ -1515,14 +1516,14 @@
/// Computes the native behavior for writing to the native [field].
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
+ NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
DartType type = getDartType(field.type);
return nativeBehaviorBuilder.buildFieldStoreBehavior(type);
}
/// Computes the native behavior for calling [member].
// TODO(johnniwinther): Cache this for later use.
- native.NativeBehavior getNativeBehaviorForMethod(ir.Member member,
+ NativeBehavior getNativeBehaviorForMethod(ir.Member member,
{bool isJsInterop}) {
DartType type;
if (member is ir.Procedure) {
@@ -1890,8 +1891,8 @@
}
}
-/// [native.BehaviorBuilder] for kernel based elements.
-class KernelBehaviorBuilder extends native.BehaviorBuilder {
+/// [BehaviorBuilder] for kernel based elements.
+class KernelBehaviorBuilder extends BehaviorBuilder {
final ElementEnvironment elementEnvironment;
final CommonElements commonElements;
final DiagnosticReporter reporter;
@@ -1997,14 +1998,13 @@
CommonElements get commonElements => elementMap.commonElements;
@override
- native.NativeBehavior computeNativeFieldStoreBehavior(
- covariant KField field) {
+ NativeBehavior computeNativeFieldStoreBehavior(covariant KField field) {
ir.Field node = elementMap.getMemberNode(field);
return elementMap.getNativeBehaviorForFieldStore(node);
}
@override
- native.NativeBehavior computeNativeFieldLoadBehavior(covariant KField field,
+ NativeBehavior computeNativeFieldLoadBehavior(covariant KField field,
{bool isJsInterop}) {
ir.Field node = elementMap.getMemberNode(field);
return elementMap.getNativeBehaviorForFieldLoad(node,
@@ -2012,8 +2012,7 @@
}
@override
- native.NativeBehavior computeNativeMethodBehavior(
- covariant KFunction function,
+ NativeBehavior computeNativeMethodBehavior(covariant KFunction function,
{bool isJsInterop}) {
ir.Member node = elementMap.getMemberNode(function);
return elementMap.getNativeBehaviorForMethod(node,
@@ -2022,7 +2021,7 @@
@override
bool isNativeMethod(covariant KFunction function) {
- if (!native.maybeEnableNative(function.library.canonicalUri)) return false;
+ if (!maybeEnableNative(function.library.canonicalUri)) return false;
ir.Member node = elementMap.getMemberNode(function);
return node.annotations.any((ir.Expression expression) {
return expression is ir.ConstructorInvocation &&
diff --git a/pkg/compiler/lib/src/kernel/invocation_mirror_constants.dart b/pkg/compiler/lib/src/kernel/invocation_mirror_constants.dart
new file mode 100644
index 0000000..246429e
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/invocation_mirror_constants.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+const int invocationMirrorMethodKind = 0;
+const int invocationMirrorGetterKind = 1;
+const int invocationMirrorSetterKind = 2;
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index 09d6756..f6bcf24 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -14,6 +14,7 @@
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
+import '../ir/scope.dart';
import '../ir/static_type.dart';
import '../ir/util.dart';
import '../js_backend/native_data.dart';
@@ -33,9 +34,10 @@
final DiagnosticReporter reporter;
final CompilerOptions _options;
final MemberEntity currentMember;
+ final VariableScopeModel variableScopeModel;
- KernelImpactBuilder(
- this.elementMap, this.currentMember, this.reporter, this._options)
+ KernelImpactBuilder(this.elementMap, this.currentMember, this.reporter,
+ this._options, this.variableScopeModel)
: this.impactBuilder =
new ResolutionWorldImpactBuilder('${currentMember}'),
super(elementMap.typeEnvironment);
@@ -505,7 +507,7 @@
ir.DartType returnType) {
Selector selector = elementMap.getSelector(node);
List<DartType> typeArguments = _getTypeArguments(node.arguments);
- var receiver = node.receiver;
+ ir.Expression receiver = node.receiver;
if (receiver is ir.VariableGet &&
receiver.variable.isFinal &&
receiver.variable.parent is ir.FunctionDeclaration) {
@@ -521,6 +523,9 @@
impactBuilder.registerDynamicUse(
new ConstrainedDynamicUse(selector, null, typeArguments));
} else {
+ ClassRelation relation = receiver is ir.ThisExpression
+ ? ClassRelation.thisExpression
+ : ClassRelation.subtype;
DartType receiverDartType = elementMap.getDartType(receiverType);
ir.Member interfaceTarget = node.interfaceTarget;
@@ -536,8 +541,8 @@
} else {
Object constraint;
if (receiverDartType is InterfaceType) {
- constraint = new StrongModeConstraint(
- commonElements, _nativeBasicData, receiverDartType.element);
+ constraint = new StrongModeConstraint(commonElements,
+ _nativeBasicData, receiverDartType.element, relation);
}
if (interfaceTarget is ir.Field ||
@@ -573,8 +578,11 @@
Object constraint;
DartType receiverDartType = elementMap.getDartType(receiverType);
if (receiverDartType is InterfaceType) {
+ ClassRelation relation = node.receiver is ir.ThisExpression
+ ? ClassRelation.thisExpression
+ : ClassRelation.subtype;
constraint = new StrongModeConstraint(
- commonElements, _nativeBasicData, receiverDartType.element);
+ commonElements, _nativeBasicData, receiverDartType.element, relation);
}
impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
new Selector.getter(elementMap.getName(node.name)),
@@ -612,8 +620,11 @@
Object constraint;
DartType receiverDartType = elementMap.getDartType(receiverType);
if (receiverDartType is InterfaceType) {
+ ClassRelation relation = node.receiver is ir.ThisExpression
+ ? ClassRelation.thisExpression
+ : ClassRelation.subtype;
constraint = new StrongModeConstraint(
- commonElements, _nativeBasicData, receiverDartType.element);
+ commonElements, _nativeBasicData, receiverDartType.element, relation);
}
impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
new Selector.setter(elementMap.getName(node.name)),
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 8eb8e55..31c810f 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -25,7 +25,6 @@
import '../js_backend/native_data.dart';
import '../js_backend/no_such_method_registry.dart';
import '../js_backend/runtime_types.dart';
-import '../library_loader.dart';
import '../native/enqueue.dart' show NativeResolutionEnqueuer;
import '../native/resolver.dart';
import '../options.dart';
@@ -36,6 +35,7 @@
import 'deferred_load.dart';
import 'element_map.dart';
import 'element_map_impl.dart';
+import 'loader.dart';
/// Front end strategy that loads '.dill' files and builds a resolved element
/// model from kernel IR nodes.
@@ -57,8 +57,8 @@
}
@override
- void registerLoadedLibraries(LoadedLibraries loadedLibraries) {
- _elementMap.addComponent(loadedLibraries.component);
+ void registerLoadedLibraries(KernelResult kernelResult) {
+ _elementMap.addComponent(kernelResult.component);
}
@override
@@ -204,7 +204,7 @@
WorldImpact run() {
return _compilerTask.measure(() {
_nativeMemberResolver.resolveNativeMember(element);
- _compilerTask.measureSubtask('closures', () {
+ ScopeModel scopeModel = _compilerTask.measureSubtask('closures', () {
ScopeModel scopeModel = _elementMap.computeScopeModel(element);
if (scopeModel?.closureScopeModel != null) {
closureModels[element] = scopeModel.closureScopeModel;
@@ -212,7 +212,8 @@
return scopeModel;
});
return _compilerTask.measureSubtask('worldImpact', () {
- ResolutionImpact impact = _elementMap.computeWorldImpact(element);
+ ResolutionImpact impact = _elementMap.computeWorldImpact(
+ element, scopeModel?.variableScopeModel);
WorldImpact worldImpact =
_impactTransformer.transformResolutionImpact(impact);
if (impactCache != null) {
diff --git a/pkg/compiler/lib/src/kernel/kernel_world.dart b/pkg/compiler/lib/src/kernel/kernel_world.dart
index 563fc9c..af7cde7 100644
--- a/pkg/compiler/lib/src/kernel/kernel_world.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_world.dart
@@ -16,7 +16,6 @@
import '../js_backend/runtime_types.dart';
import '../options.dart';
import '../universe/class_hierarchy.dart';
-import '../universe/class_set.dart';
import '../universe/resolution_world_builder.dart';
import '../world.dart';
@@ -74,12 +73,9 @@
this.processedMembers,
this.mixinUses,
this.typesImplementedBySubclasses,
- Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes,
- Map<ClassEntity, ClassSet> classSets,
+ this.classHierarchy,
this.annotationsData})
- : _implementedClasses = implementedClasses,
- classHierarchy = new ClassHierarchyImpl(
- commonElements, classHierarchyNodes, classSets) {
+ : _implementedClasses = implementedClasses {
_rtiNeed = rtiNeedBuilder.computeRuntimeTypesNeed(
resolutionWorldBuilder, this, options);
}
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/kernel/loader.dart
similarity index 68%
rename from pkg/compiler/lib/src/library_loader.dart
rename to pkg/compiler/lib/src/kernel/loader.dart
index e9baa28..6abde20 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/kernel/loader.dart
@@ -14,21 +14,20 @@
import 'package:kernel/kernel.dart' hide LibraryDependency, Combinator;
import 'package:kernel/target/targets.dart';
-import '../compiler_new.dart' as api;
-import 'kernel/front_end_adapter.dart';
-import 'kernel/dart2js_target.dart' show Dart2jsTarget;
+import '../../compiler_new.dart' as api;
+import '../common/tasks.dart' show CompilerTask, Measurer;
+import '../common.dart';
+import '../options.dart';
-import 'common/tasks.dart' show CompilerTask, Measurer;
-import 'common.dart';
-import 'options.dart';
+import 'front_end_adapter.dart';
+import 'dart2js_target.dart' show Dart2jsTarget;
-/// A loader that builds a kernel IR representation of the component.
+/// A task that produces the kernel IR representation of the application.
///
/// It supports loading both .dart source files or pre-compiled .dill files.
-/// When given .dart source files, it invokes the shared frontend
-/// (`package:front_end`) to produce the corresponding kernel IR representation.
-// TODO(sigmund): move this class to a new file under src/kernel/.
-class LibraryLoaderTask extends CompilerTask {
+/// When given .dart source files, it invokes the common front-end (CFE)
+/// to produce the corresponding kernel IR representation.
+class KernelLoaderTask extends CompilerTask {
final DiagnosticReporter _reporter;
final api.CompilerInput _compilerInput;
@@ -44,15 +43,15 @@
/// This is used for testing.
bool forceSerialization = false;
- LibraryLoaderTask(
+ KernelLoaderTask(
this._options, this._compilerInput, this._reporter, Measurer measurer)
: initializedCompilerState = _options.kernelInitializedCompilerState,
super(measurer);
- String get name => 'Library loader';
+ String get name => 'kernel loader';
/// Loads an entire Kernel [Component] from a file on disk.
- Future<LoadedLibraries> loadLibraries(Uri resolvedUri) {
+ Future<KernelResult> load(Uri resolvedUri) {
return measure(() async {
var isDill = resolvedUri.path.endsWith('.dill');
ir.Component component;
@@ -85,12 +84,11 @@
component = new ir.Component();
new BinaryBuilder(data).readComponent(component);
}
- return _createLoadedLibraries(component);
+ return _toResult(component);
});
}
- // Only visible for unit testing.
- LoadedLibraries _createLoadedLibraries(ir.Component component) {
+ KernelResult _toResult(ir.Component component) {
Uri rootLibraryUri = null;
Iterable<ir.Library> libraries = component.libraries;
if (component.mainMethod != null) {
@@ -119,38 +117,27 @@
libraries = libraries.where(seen.contains);
}
- return new LoadedLibraries(component, rootLibraryUri,
+ return new KernelResult(component, rootLibraryUri,
libraries.map((lib) => lib.importUri).toList());
}
}
-/// Information on the set libraries loaded as a result of a call to
-/// [LibraryLoader.loadLibrary].
-class LoadedLibraries {
- final ir.Component _component;
- final Uri _rootLibraryUri;
- final List<Uri> _libraries;
+/// Result of invoking the CFE to produce the kernel IR.
+class KernelResult {
+ final ir.Component component;
- LoadedLibraries(this._component, this._rootLibraryUri, this._libraries) {
+ /// The [Uri] of the root library containing main.
+ final Uri rootLibraryUri;
+
+ /// Returns the [Uri]s of all libraries that have been loaded that are
+ /// reachable from the [rootLibraryUri].
+ ///
+ /// Note that [component] may contain some libraries that are excluded here.
+ final Iterable<Uri> libraries;
+
+ KernelResult(this.component, this.rootLibraryUri, this.libraries) {
assert(rootLibraryUri != null);
}
- /// Returns the root component for the loaded libraries.
- ir.Component get component => _component;
-
- /// The [Uri] of the root library.
- Uri get rootLibraryUri => _rootLibraryUri;
-
- /// Returns the [Uri]s of all libraries that have been loaded.
- Iterable<Uri> get libraries => _libraries;
-
- /// Returns `true` if a library with canonical [uri] was loaded in this bulk.
- bool containsLibrary(Uri uri) {
- return _libraries.contains(uri);
- }
-
- /// Applies all library [Uri]s in this bulk to [f].
- void forEachLibrary(f(Uri Uri)) => _libraries.forEach(f);
-
- String toString() => 'root=$_rootLibraryUri,libraries=${_libraries}';
+ String toString() => 'root=$rootLibraryUri,libraries=${libraries}';
}
diff --git a/pkg/compiler/lib/src/native/native.dart b/pkg/compiler/lib/src/native/native.dart
deleted file mode 100644
index ae0ce99..0000000
--- a/pkg/compiler/lib/src/native/native.dart
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library native;
-
-export 'behavior.dart';
-export 'enqueue.dart';
-export 'js.dart';
-
-const Iterable<String> _allowedDartSchemePaths = const <String>[
- 'async',
- 'html',
- 'html_common',
- 'indexed_db',
- 'js',
- 'js_util',
- 'svg',
- '_native_typed_data',
- 'web_audio',
- 'web_gl',
- 'web_sql'
-];
-
-bool maybeEnableNative(Uri uri) {
- bool allowedTestLibrary() {
- String scriptName = uri.path;
- return scriptName.contains('tests/compiler/dart2js_native') ||
- scriptName.contains('tests/compiler/dart2js_extra');
- }
-
- bool allowedDartLibary() {
- if (uri.scheme != 'dart') return false;
- return _allowedDartSchemePaths.contains(uri.path);
- }
-
- return allowedTestLibrary() || allowedDartLibary();
-}
diff --git a/pkg/compiler/lib/src/old_to_new_api.dart b/pkg/compiler/lib/src/old_to_new_api.dart
index c7ab17f..808e242 100644
--- a/pkg/compiler/lib/src/old_to_new_api.dart
+++ b/pkg/compiler/lib/src/old_to_new_api.dart
@@ -71,7 +71,8 @@
OutputSink createOutputSink(String name, String extension, OutputType type) {
if (_outputProvider != null) {
switch (type) {
- case OutputType.info:
+ case OutputType.dumpInfo:
+ case OutputType.deferredMap:
if (extension == '') {
// Needed to make Pub generate the same output name.
extension = 'deferred_map';
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 4513395..0c05a18 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -241,6 +241,12 @@
/// Experimental part file function generation.
bool experimentStartupFunctions = false;
+ /// Experimental instrumentation to investigate code bloat.
+ ///
+ /// If [true], the compiler will emit code that logs whenever a method is
+ /// called.
+ bool experimentCallInstrumentation = false;
+
/// The path to the file that contains the profiled allocations.
///
/// The file must contain the Map that was produced by using
@@ -298,6 +304,8 @@
..experimentLocalNames = _hasOption(options, Flags.experimentLocalNames)
..experimentStartupFunctions =
_hasOption(options, Flags.experimentStartupFunctions)
+ ..experimentCallInstrumentation =
+ _hasOption(options, Flags.experimentCallInstrumentation)
..generateCodeWithCompileTimeErrors =
_hasOption(options, Flags.generateCodeWithCompileTimeErrors)
..generateSourceMap = !_hasOption(options, Flags.noSourceMaps)
@@ -422,18 +430,13 @@
/// Whether the type assertion should be emitted and checked.
final bool isEmitted;
- /// Whether the type assertion should be ignored.
- final bool isIgnored;
-
- const CheckPolicy(
- {this.isTrusted: false, this.isEmitted: false, this.isIgnored: false});
+ const CheckPolicy({this.isTrusted: false, this.isEmitted: false});
static const trusted = const CheckPolicy(isTrusted: true);
static const checked = const CheckPolicy(isEmitted: true);
- static const ignored = const CheckPolicy(isIgnored: true);
String toString() => 'CheckPolicy(isTrusted=$isTrusted,'
- 'isEmitted=$isEmitted,isIgnored=$isIgnored)';
+ 'isEmitted=$isEmitted)';
}
String _extractStringOption(
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index 986b990..f6551af 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -352,7 +352,8 @@
case OutputType.jsPart:
uri = out.resolve('$name.$extension');
break;
- case OutputType.info:
+ case OutputType.dumpInfo:
+ case OutputType.deferredMap:
if (name == '') {
name = out.pathSegments.last;
}
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 25993e7..d9a0664 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -32,7 +32,9 @@
import '../js_model/elements.dart' show JGeneratorBody;
import '../js_model/element_map.dart';
import '../js_model/js_strategy.dart';
-import '../native/native.dart' as native;
+import '../kernel/invocation_mirror_constants.dart';
+import '../native/behavior.dart';
+import '../native/js.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
@@ -1326,7 +1328,6 @@
if (functionNode != null) {
_potentiallyAddFunctionParameterTypeChecks(functionNode, checks);
}
- _insertTraceCall(member);
_insertCoverageCall(member);
}
@@ -2485,7 +2486,7 @@
js.Template code = js.js.parseForeignJS('#');
push(new HForeignCode(code, abstractValueDomain.boolType,
[localsHandler.readLocal(switchTarget)],
- nativeBehavior: native.NativeBehavior.PURE));
+ nativeBehavior: NativeBehavior.PURE));
}
handleIf(
@@ -3395,7 +3396,7 @@
lengthInput = conversion;
}
js.Template code = js.js.parseForeignJS('new Array(#)');
- var behavior = new native.NativeBehavior();
+ var behavior = new NativeBehavior();
var expectedType =
_elementMap.getDartType(invocation.getStaticType(null));
@@ -3418,9 +3419,8 @@
HForeignCode foreign = new HForeignCode(
code, resultType, <HInstruction>[lengthInput],
nativeBehavior: behavior,
- throwBehavior: canThrow
- ? native.NativeThrowBehavior.MAY
- : native.NativeThrowBehavior.NEVER)
+ throwBehavior:
+ canThrow ? NativeThrowBehavior.MAY : NativeThrowBehavior.NEVER)
..sourceInformation = sourceInformation;
push(foreign);
// TODO(redemption): Global type analysis tracing may have determined that
@@ -3431,7 +3431,7 @@
// We set the instruction as [canThrow] to avoid it being dead code.
// We need a finer grained side effect.
add(new HForeignCode(code, abstractValueDomain.nullType, [stack.last],
- throwBehavior: native.NativeThrowBehavior.MAY));
+ throwBehavior: NativeThrowBehavior.MAY));
}
} else if (isGrowableListConstructorCall) {
push(buildLiteralList(<HInstruction>[]));
@@ -3613,13 +3613,13 @@
Name memberName = new Name(name, _currentFrame.member.library);
Selector selector;
switch (kindLiteral.value) {
- case Selector.invocationMirrorGetterKind:
+ case invocationMirrorGetterKind:
selector = new Selector.getter(memberName);
break;
- case Selector.invocationMirrorSetterKind:
+ case invocationMirrorSetterKind:
selector = new Selector.setter(memberName);
break;
- case Selector.invocationMirrorMethodKind:
+ case invocationMirrorMethodKind:
if (memberName == Names.INDEX_NAME) {
selector = new Selector.index();
} else if (memberName == Names.INDEX_SET_NAME) {
@@ -3812,7 +3812,7 @@
.staticFunctionAccess(_elementMap.getMethod(staticTarget))),
abstractValueDomain.dynamicType,
<HInstruction>[],
- nativeBehavior: native.NativeBehavior.PURE,
+ nativeBehavior: NativeBehavior.PURE,
foreignFunction: _elementMap.getMethod(staticTarget)));
return;
}
@@ -3844,8 +3844,7 @@
sideEffects.setAllSideEffects();
push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"),
abstractValueDomain.dynamicType, inputs,
- nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
- effects: sideEffects));
+ nativeBehavior: NativeBehavior.CHANGES_OTHER, effects: sideEffects));
}
void handleForeignJsGetStaticState(ir.StaticInvocation invocation) {
@@ -3858,7 +3857,7 @@
push(new HForeignCode(js.js.parseForeignJS(namer.staticStateHolder),
abstractValueDomain.dynamicType, <HInstruction>[],
- nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
+ nativeBehavior: NativeBehavior.DEPENDS_OTHER));
}
void handleForeignJsGetName(ir.StaticInvocation invocation) {
@@ -3900,7 +3899,7 @@
js.Template expr = js.js.expressionTemplateYielding(
emitter.generateEmbeddedGlobalAccess(globalName));
- native.NativeBehavior nativeBehavior =
+ NativeBehavior nativeBehavior =
_elementMap.getNativeBehaviorForJsEmbeddedGlobalCall(invocation);
assert(
nativeBehavior != null,
@@ -3947,7 +3946,7 @@
inputs.add(pop());
}
- native.NativeBehavior nativeBehavior =
+ NativeBehavior nativeBehavior =
_elementMap.getNativeBehaviorForJsBuiltinCall(invocation);
assert(
nativeBehavior != null,
@@ -4038,7 +4037,7 @@
return;
}
- native.NativeBehavior nativeBehavior =
+ NativeBehavior nativeBehavior =
_elementMap.getNativeBehaviorForJsCall(invocation);
assert(
nativeBehavior != null,
@@ -4063,7 +4062,7 @@
return;
}
- if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) {
+ if (HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) {
reporter.reportErrorMessage(
_elementMap.getSpannable(targetElement, invocation),
MessageKind.JS_PLACEHOLDER_CAPTURE);
@@ -4257,8 +4256,7 @@
var codeTemplate =
new js.Template(null, js.objectLiteral(parameterNameMap));
- var nativeBehavior = new native.NativeBehavior()
- ..codeTemplate = codeTemplate;
+ var nativeBehavior = new NativeBehavior()..codeTemplate = codeTemplate;
if (options.trustJSInteropTypeAnnotations) {
InterfaceType thisType = _elementMap.elementEnvironment
.getThisType(constructor.enclosingClass);
@@ -4283,8 +4281,7 @@
arguments = arguments.where((arg) => arg != null).toList();
var inputs = <HInstruction>[target]..addAll(arguments);
- var nativeBehavior = new native.NativeBehavior()
- ..sideEffects.setAllSideEffects();
+ var nativeBehavior = new NativeBehavior()..sideEffects.setAllSideEffects();
DartType type = element is ConstructorEntity
? _elementMap.elementEnvironment.getThisType(element.enclosingClass)
@@ -5377,7 +5374,6 @@
_elementMap.elementEnvironment.getFunctionType(function).returnType;
stack = <HInstruction>[];
- _insertTraceCall(function);
_insertCoverageCall(function);
}
@@ -5521,35 +5517,20 @@
return _allInlinedFunctionsCalledOnce && _isFunctionCalledOnce(element);
}
- void _insertTraceCall(MemberEntity element) {
- if (JavaScriptBackend.TRACE_METHOD == 'console') {
- if (element == commonElements.traceHelper) return;
- n(e) => e == null ? '' : e.name;
- String name = "${n(element.library)}:${n(element.enclosingClass)}."
- "${n(element)}";
- HConstant nameConstant = graph.addConstantString(name, closedWorld);
- add(new HInvokeStatic(
- commonElements.traceHelper,
- <HInstruction>[nameConstant],
- abstractValueDomain.dynamicType,
- const <DartType>[]));
- }
- }
-
void _insertCoverageCall(MemberEntity element) {
- if (JavaScriptBackend.TRACE_METHOD == 'post') {
- if (element == commonElements.traceHelper) return;
- // TODO(sigmund): create a better uuid for elements.
- HConstant idConstant =
- graph.addConstantInt(element.hashCode, closedWorld);
- HConstant nameConstant =
- graph.addConstantString(element.name, closedWorld);
- add(new HInvokeStatic(
- commonElements.traceHelper,
- <HInstruction>[idConstant, nameConstant],
- abstractValueDomain.dynamicType,
- const <DartType>[]));
- }
+ if (!options.experimentCallInstrumentation) return;
+ if (element == commonElements.traceHelper) return;
+ // TODO(sigmund): create a better uuid for elements.
+ HConstant idConstant = graph.addConstantInt(element.hashCode, closedWorld);
+ n(e) => e == null ? '' : e.name;
+ String name = "${n(element.library)}:${n(element.enclosingClass)}."
+ "${n(element)}";
+ HConstant nameConstant = graph.addConstantString(name, closedWorld);
+ add(new HInvokeStatic(
+ commonElements.traceHelper,
+ <HInstruction>[idConstant, nameConstant],
+ abstractValueDomain.dynamicType,
+ const <DartType>[]));
}
}
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index bcfe386..c6f57d2 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -27,7 +27,8 @@
import '../js_backend/runtime_types.dart';
import '../js_emitter/code_emitter_task.dart';
import '../js_model/elements.dart' show JGeneratorBody;
-import '../native/native.dart' as native;
+import '../native/behavior.dart';
+import '../native/enqueue.dart';
import '../options.dart';
import '../types/abstract_value_domain.dart';
import '../universe/call_structure.dart' show CallStructure;
@@ -157,7 +158,7 @@
final CompilerOptions _options;
final CodeEmitterTask _emitter;
- final native.NativeCodegenEnqueuer _nativeEnqueuer;
+ final NativeCodegenEnqueuer _nativeEnqueuer;
final CheckedModeHelpers _checkedModeHelpers;
final OneShotInterceptorData _oneShotInterceptorData;
final RuntimeTypesSubstitutions _rtiSubstitutions;
@@ -2215,7 +2216,7 @@
}
void registerForeignTypes(HForeign node) {
- native.NativeBehavior nativeBehavior = node.nativeBehavior;
+ NativeBehavior nativeBehavior = node.nativeBehavior;
if (nativeBehavior == null) return;
_nativeEnqueuer.registerNativeBehavior(
_registry.worldImpact, nativeBehavior, node);
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index b3c93c2..222f33d 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -16,7 +16,7 @@
import '../io/source_information.dart';
import '../js/js.dart' as js;
import '../js_backend/js_backend.dart';
-import '../native/native.dart' as native;
+import '../native/behavior.dart';
import '../types/abstract_value_domain.dart';
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
@@ -2055,7 +2055,7 @@
HForeign(AbstractValue type, List<HInstruction> inputs) : super(inputs, type);
bool get isStatement => false;
- native.NativeBehavior get nativeBehavior => null;
+ NativeBehavior get nativeBehavior => null;
bool canThrow(AbstractValueDomain domain) {
return sideEffects.hasSideEffects() || sideEffects.dependsOnSomething();
@@ -2065,15 +2065,15 @@
class HForeignCode extends HForeign {
final js.Template codeTemplate;
final bool isStatement;
- final native.NativeBehavior nativeBehavior;
- native.NativeThrowBehavior throwBehavior;
+ final NativeBehavior nativeBehavior;
+ NativeThrowBehavior throwBehavior;
final FunctionEntity foreignFunction;
HForeignCode(this.codeTemplate, AbstractValue type, List<HInstruction> inputs,
{this.isStatement: false,
SideEffects effects,
- native.NativeBehavior nativeBehavior,
- native.NativeThrowBehavior throwBehavior,
+ NativeBehavior nativeBehavior,
+ NativeThrowBehavior throwBehavior,
this.foreignFunction})
: this.nativeBehavior = nativeBehavior,
this.throwBehavior = throwBehavior,
@@ -2084,7 +2084,7 @@
}
if (this.throwBehavior == null) {
this.throwBehavior = (nativeBehavior == null)
- ? native.NativeThrowBehavior.MAY
+ ? NativeThrowBehavior.MAY
: nativeBehavior.throwBehavior;
}
assert(this.throwBehavior != null);
@@ -2095,12 +2095,8 @@
}
}
- HForeignCode.statement(
- js.Template codeTemplate,
- List<HInstruction> inputs,
- SideEffects effects,
- native.NativeBehavior nativeBehavior,
- AbstractValue type)
+ HForeignCode.statement(js.Template codeTemplate, List<HInstruction> inputs,
+ SideEffects effects, NativeBehavior nativeBehavior, AbstractValue type)
: this(codeTemplate, type, inputs,
isStatement: true,
effects: effects,
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 67455a8..e4b5eab 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -16,7 +16,7 @@
import '../js_backend/backend.dart';
import '../js_backend/native_data.dart' show NativeData;
import '../js_backend/runtime_types.dart';
-import '../native/native.dart' as native;
+import '../native/behavior.dart';
import '../options.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
@@ -770,8 +770,7 @@
// Strengthen instruction type from annotations to help optimize
// dependent instructions.
- native.NativeBehavior nativeBehavior =
- _nativeData.getNativeMethodBehavior(method);
+ NativeBehavior nativeBehavior = _nativeData.getNativeMethodBehavior(method);
AbstractValue returnType =
AbstractValueFactory.fromNativeBehavior(nativeBehavior, _closedWorld);
HInvokeDynamicMethod result = new HInvokeDynamicMethod(
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index 39fd61c..8519ee9 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.dart
@@ -4,7 +4,7 @@
import '../common_elements.dart' show CommonElements;
import '../elements/entities.dart';
-import '../native/native.dart' as native;
+import '../native/behavior.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
@@ -36,7 +36,7 @@
}
static AbstractValue fromNativeBehavior(
- native.NativeBehavior nativeBehavior, JClosedWorld closedWorld) {
+ NativeBehavior nativeBehavior, JClosedWorld closedWorld) {
AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
var typesReturned = nativeBehavior.typesReturned;
if (typesReturned.isEmpty) return abstractValueDomain.dynamicType;
@@ -46,7 +46,7 @@
// [type] is either an instance of [DartType] or special objects
// like [native.SpecialType.JsObject].
AbstractValue fromNativeType(dynamic type) {
- if (type == native.SpecialType.JsObject) {
+ if (type == SpecialType.JsObject) {
return abstractValueDomain
.createNonNullExact(commonElements.objectClass);
} else if (type.isVoid) {
diff --git a/pkg/compiler/lib/src/universe/class_hierarchy.dart b/pkg/compiler/lib/src/universe/class_hierarchy.dart
index 7032550..181714f 100644
--- a/pkg/compiler/lib/src/universe/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/universe/class_hierarchy.dart
@@ -571,9 +571,9 @@
class ClassHierarchyBuilder {
// We keep track of subtype and subclass relationships in four
// distinct sets to make class hierarchy analysis faster.
- final Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes =
+ final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes =
<ClassEntity, ClassHierarchyNode>{};
- final Map<ClassEntity, ClassSet> classSets = <ClassEntity, ClassSet>{};
+ final Map<ClassEntity, ClassSet> _classSets = <ClassEntity, ClassSet>{};
final Map<ClassEntity, Set<ClassEntity>> mixinUses =
new Map<ClassEntity, Set<ClassEntity>>();
@@ -582,12 +582,22 @@
ClassHierarchyBuilder(this._commonElements, this._classQueries);
+ ClassHierarchy close() {
+ assert(
+ _classHierarchyNodes.length == _classSets.length,
+ "ClassHierarchyNode/ClassSet mismatch: "
+ "${_classHierarchyNodes} vs "
+ "${_classSets}");
+ return new ClassHierarchyImpl(
+ _commonElements, _classHierarchyNodes, _classSets);
+ }
+
void registerClass(ClassEntity cls) {
_ensureClassSet(_classQueries.getDeclaration(cls));
}
ClassHierarchyNode _ensureClassHierarchyNode(ClassEntity cls) {
- return classHierarchyNodes.putIfAbsent(cls, () {
+ return _classHierarchyNodes.putIfAbsent(cls, () {
ClassHierarchyNode parentNode;
ClassEntity superclass = _classQueries.getSuperClass(cls);
if (superclass != null) {
@@ -599,7 +609,7 @@
}
ClassSet _ensureClassSet(ClassEntity cls) {
- return classSets.putIfAbsent(cls, () {
+ return _classSets.putIfAbsent(cls, () {
ClassHierarchyNode node = _ensureClassHierarchyNode(cls);
ClassSet classSet = new ClassSet(node);
@@ -665,55 +675,170 @@
}
bool _isSubtypeOf(ClassEntity x, ClassEntity y) {
- assert(
- classSets.containsKey(x), "ClassSet for $x has not been computed yet.");
- ClassSet classSet = classSets[y];
+ assert(_classSets.containsKey(x),
+ "ClassSet for $x has not been computed yet.");
+ ClassSet classSet = _classSets[y];
assert(classSet != null,
- failedAt(y, "No ClassSet for $y (${y.runtimeType}): ${classSets}"));
- ClassHierarchyNode classHierarchyNode = classHierarchyNodes[x];
+ failedAt(y, "No ClassSet for $y (${y.runtimeType}): ${_classSets}"));
+ ClassHierarchyNode classHierarchyNode = _classHierarchyNodes[x];
assert(classHierarchyNode != null,
failedAt(x, "No ClassHierarchyNode for $x"));
return classSet.hasSubtype(classHierarchyNode);
}
- Map<ClassEntity, _InheritedCache> _inheritedCacheMap = {};
+ /// Returns `true` if a dynamic access on an instance of [exactClass] can
+ /// target a member declared in [memberHoldingClass].
+ bool isInheritedInExactClass(
+ ClassEntity memberHoldingClass, ClassEntity exactClass) {
+ ClassHierarchyNode exactClassNode = _classHierarchyNodes[exactClass];
+ if (!exactClassNode.isAbstractlyInstantiated &&
+ !exactClassNode.isDirectlyInstantiated) {
+ // No instances of [thisClass] are live.
+ return false;
+ }
+ ClassSet memberHoldingClassSet = _classSets[memberHoldingClass];
+ if (memberHoldingClassSet.hasSubclass(exactClassNode)) {
+ /// A member from a super class can be accessed.
+ return true;
+ }
+ for (ClassHierarchyNode mixinApplication
+ in memberHoldingClassSet.mixinApplicationNodes) {
+ if (mixinApplication.hasSubclass(exactClassNode)) {
+ /// A member from a mixed in class can be accessed.
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Map<ClassEntity, _InheritedInThisClassCache> _inheritedInThisClassCacheMap =
+ {};
+
+ /// Returns `true` if a `this` expression in [thisClass] can target a member
+ /// declared in [memberHoldingClass].
+ bool isInheritedInThisClass(
+ ClassEntity memberHoldingClass, ClassEntity thisClass) {
+ _InheritedInThisClassCache cache =
+ _inheritedInThisClassCacheMap[memberHoldingClass] ??=
+ new _InheritedInThisClassCache();
+ return cache.isInheritedInThisClassOf(this, memberHoldingClass, thisClass);
+ }
+
+ Map<ClassEntity, _InheritedInSubtypeCache> _inheritedInSubtypeCacheMap = {};
bool isInheritedInSubtypeOf(ClassEntity x, ClassEntity y) {
- _InheritedCache cache = _inheritedCacheMap[x] ??= new _InheritedCache();
+ _InheritedInSubtypeCache cache =
+ _inheritedInSubtypeCacheMap[x] ??= new _InheritedInSubtypeCache();
return cache.isInheritedInSubtypeOf(this, x, y);
}
}
+/// Cache used for computing when a member of a given class, the so-called
+/// member holding class, can be inherited into a live class.
+class _InheritedInThisClassCache {
+ /// Set of classes that inherits members from the member holding class.
+ Set<ClassEntity> _inheritingClasses;
+
+ /// Cache for liveness computation for a `this` expressions of a given class.
+ Map<ClassEntity, _LiveSet> _map;
+
+ /// Returns `true` if members of [memberHoldingClass] can be inherited into
+ /// a live class that can be the target of a `this` expression in [thisClass].
+ bool isInheritedInThisClassOf(ClassHierarchyBuilder builder,
+ ClassEntity memberHoldingClass, ClassEntity thisClass) {
+ _LiveSet set;
+ if (_map == null) {
+ _map = {};
+ } else {
+ set = _map[thisClass];
+ }
+ if (set == null) {
+ set = _map[thisClass] = _computeInheritingInThisClassSet(
+ builder, memberHoldingClass, thisClass);
+ }
+ return set.hasLiveClass(builder);
+ }
+
+ _LiveSet _computeInheritingInThisClassSet(ClassHierarchyBuilder builder,
+ ClassEntity memberHoldingClass, ClassEntity thisClass) {
+ ClassHierarchyNode memberHoldingClassNode =
+ builder._classHierarchyNodes[memberHoldingClass];
+
+ if (_inheritingClasses == null) {
+ _inheritingClasses = new Set<ClassEntity>();
+ _inheritingClasses.addAll(memberHoldingClassNode
+ .subclassesByMask(ClassHierarchyNode.ALL, strict: false));
+ for (ClassHierarchyNode mixinApplication
+ in builder._classSets[memberHoldingClass].mixinApplicationNodes) {
+ _inheritingClasses.addAll(mixinApplication
+ .subclassesByMask(ClassHierarchyNode.ALL, strict: false));
+ }
+ }
+
+ Set<ClassEntity> validatingSet = new Set<ClassEntity>();
+
+ void processHierarchy(ClassHierarchyNode mixerNode) {
+ for (ClassEntity inheritingClass in _inheritingClasses) {
+ ClassHierarchyNode inheritingClassNode =
+ builder._classHierarchyNodes[inheritingClass];
+ if (!validatingSet.contains(mixerNode.cls) &&
+ inheritingClassNode.hasSubclass(mixerNode)) {
+ // If [mixerNode.cls] is live then a `this` expression can target
+ // members inherited from [memberHoldingClass] into [inheritingClass].
+ validatingSet.add(mixerNode.cls);
+ }
+ if (mixerNode.hasSubclass(inheritingClassNode)) {
+ // If [inheritingClass] is live then a `this` expression can target
+ // members inherited from [memberHoldingClass] into `inheritingClass`
+ // into a subclass of [mixerNode.cls].
+ validatingSet.add(inheritingClass);
+ }
+ }
+ }
+
+ ClassSet thisClassSet = builder._classSets[thisClass];
+
+ processHierarchy(thisClassSet.node);
+
+ for (ClassHierarchyNode mixinApplication
+ in thisClassSet.mixinApplicationNodes) {
+ processHierarchy(mixinApplication);
+ }
+
+ return new _LiveSet(validatingSet);
+ }
+}
+
/// A cache object used for [ClassHierarchyBuilder.isInheritedInSubtypeOf].
-class _InheritedCache {
- Map<ClassEntity, _InheritingSet> _map;
+class _InheritedInSubtypeCache {
+ Map<ClassEntity, _LiveSet> _map;
/// Returns whether a live class currently known to inherit from [x] and
/// implement [y].
bool isInheritedInSubtypeOf(
ClassHierarchyBuilder builder, ClassEntity x, ClassEntity y) {
- _InheritingSet set;
+ _LiveSet set;
if (_map == null) {
_map = {};
} else {
set = _map[y];
}
if (set == null) {
- set = _map[y] = _computeInheritingSet(builder, x, y);
+ set = _map[y] = _computeInheritingInSubtypeSet(builder, x, y);
}
return set.hasLiveClass(builder);
}
- /// Creates an [_InheritingSet] of classes that inherit members of a class [x]
+ /// Creates an [_LiveSet] of classes that inherit members of a class [x]
/// while implementing class [y].
- _InheritingSet _computeInheritingSet(
+ _LiveSet _computeInheritingInSubtypeSet(
ClassHierarchyBuilder builder, ClassEntity x, ClassEntity y) {
- ClassSet classSet = builder.classSets[x];
+ ClassSet classSet = builder._classSets[x];
assert(
classSet != null,
failedAt(
- x, "No ClassSet for $x (${x.runtimeType}): ${builder.classSets}"));
+ x, "No ClassSet for $x (${x.runtimeType}): ${builder._classSets}"));
Set<ClassEntity> classes = new Set<ClassEntity>();
@@ -740,16 +865,16 @@
subclassImplements(mixinApplication, strict: false);
}
- return new _InheritingSet(classes);
+ return new _LiveSet(classes);
}
}
-/// A set of classes that inherit members of a class 'x' while implementing
-/// class 'y'.
+/// A set of potentially live classes.
///
-/// The set is used [ClassHierarchyBuilder.isInheritedInSubtypeOf] to determine
+/// The set is used [ClassHierarchyBuilder.isInheritedInSubtypeOf] and
+/// [ClassHierarchyBuilder.isInheritedInThisClassOf] to determine
/// when members of a class is live.
-class _InheritingSet {
+class _LiveSet {
/// If `true` the set of classes is known to contain a live class. In this
/// case [_classes] is `null`. If `false` the set of classes is empty and
/// therefore known never to contain live classes. In this case [_classes]
@@ -758,7 +883,7 @@
bool _result;
Set<ClassEntity> _classes;
- _InheritingSet(Set<ClassEntity> classes)
+ _LiveSet(Set<ClassEntity> classes)
: _result = classes.isEmpty ? false : null,
_classes = classes.isNotEmpty ? classes : null;
@@ -777,7 +902,7 @@
bool hasLiveClass(ClassHierarchyBuilder builder) {
if (_result != null) return _result;
for (ClassEntity cls in _classes) {
- if (builder.classHierarchyNodes[cls].isInstantiated) {
+ if (builder._classHierarchyNodes[cls].isInstantiated) {
// We now know this set contains a live class and done need to remember
// that set of classes anymore.
_result = true;
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index 85d96a2..fa29bf7 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -612,10 +612,16 @@
return true;
}
+ /// Returns an [Iterable] of the classes that implement [cls] directly or
+ /// through supertypes.
+ ///
+ /// A class that implements [cls] through its superclasses is not included in
+ /// the iterable.
Iterable<ClassHierarchyNode> get subtypeNodes {
return _subtypes ?? const <ClassHierarchyNode>[];
}
+ /// Returns an [Iterable] of the classes that mix in [cls] directly.
Iterable<ClassHierarchyNode> get mixinApplicationNodes {
return _mixinApplications ?? const <ClassHierarchyNode>[];
}
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index 88cee2e..e396467 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -8,6 +8,7 @@
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
+import '../ir/static_type.dart';
import '../js_backend/annotations.dart';
import '../js_backend/allocator_analysis.dart' show KAllocatorAnalysis;
import '../js_backend/backend_usage.dart'
@@ -970,11 +971,28 @@
_classHierarchyBuilder.registerClass(cls);
}
- bool isInheritedInSubtypeOf(MemberEntity member, ClassEntity type) {
+ @override
+ bool isInheritedIn(
+ MemberEntity member, ClassEntity type, ClassRelation relation) {
// TODO(johnniwinther): Use the [member] itself to avoid enqueueing members
// that are overridden.
- return _classHierarchyBuilder.isInheritedInSubtypeOf(
- member.enclosingClass, type);
+ return isInheritedInClass(member.enclosingClass, type, relation);
+ }
+
+ bool isInheritedInClass(ClassEntity memberHoldingClass, ClassEntity type,
+ ClassRelation relation) {
+ switch (relation) {
+ case ClassRelation.exact:
+ return _classHierarchyBuilder.isInheritedInExactClass(
+ memberHoldingClass, type);
+ case ClassRelation.thisExpression:
+ return _classHierarchyBuilder.isInheritedInThisClass(
+ memberHoldingClass, type);
+ case ClassRelation.subtype:
+ return _classHierarchyBuilder.isInheritedInSubtypeOf(
+ memberHoldingClass, type);
+ }
+ throw new UnsupportedError("Unexpected ClassRelation $relation.");
}
@override
@@ -1000,12 +1018,6 @@
BackendUsage backendUsage = _backendUsageBuilder.close();
_closed = true;
- assert(
- _classHierarchyBuilder.classHierarchyNodes.length ==
- _classHierarchyBuilder.classSets.length,
- "ClassHierarchyNode/ClassSet mismatch: "
- "${_classHierarchyBuilder.classHierarchyNodes} vs "
- "${_classHierarchyBuilder.classSets}");
AnnotationsData annotationsData = processAnnotations(
reporter, _commonElements, _elementEnvironment, _processedMembers);
@@ -1029,8 +1041,7 @@
processedMembers: _processedMembers,
mixinUses: _classHierarchyBuilder.mixinUses,
typesImplementedBySubclasses: typesImplementedBySubclasses,
- classHierarchyNodes: _classHierarchyBuilder.classHierarchyNodes,
- classSets: _classHierarchyBuilder.classSets,
+ classHierarchy: _classHierarchyBuilder.close(),
annotationsData: annotationsData);
if (retainDataForTesting) {
_closedWorldCache = closedWorld;
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index acc7100..42cac09 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -10,6 +10,7 @@
import '../elements/entity_utils.dart' as utils;
import '../elements/names.dart';
import '../elements/operators.dart';
+import '../kernel/invocation_mirror_constants.dart';
import '../serialization/serialization.dart';
import '../util/util.dart' show Hashing;
import 'call_structure.dart' show CallStructure;
@@ -237,10 +238,6 @@
*/
String get invocationMirrorMemberName => isSetter ? '$name=' : name;
- static const int invocationMirrorMethodKind = 0;
- static const int invocationMirrorGetterKind = 1;
- static const int invocationMirrorSetterKind = 2;
-
int get invocationMirrorKind {
int kind = invocationMirrorMethodKind;
if (isGetter) {
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 5e7b719..a5e2b41 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -46,6 +46,11 @@
if (receiverConstraint != null) {
var constraint = receiverConstraint;
if (constraint is StrongModeConstraint) {
+ if (constraint.isThis) {
+ sb.write('<');
+ } else if (constraint.isExact) {
+ sb.write('=');
+ }
sb.write(constraint.cls.name);
} else {
sb.write(constraint);
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index 31838fc..9eb4560 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -7,6 +7,7 @@
import '../common_elements.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
+import '../ir/static_type.dart';
import '../js_backend/native_data.dart' show NativeBasicData;
import '../world.dart' show World, JClosedWorld, OpenWorld;
import 'selector.dart' show Selector;
@@ -158,34 +159,42 @@
class StrongModeConstraint {
final ClassEntity cls;
+ final ClassRelation relation;
factory StrongModeConstraint(CommonElements commonElements,
- NativeBasicData nativeBasicData, ClassEntity cls) {
+ NativeBasicData nativeBasicData, ClassEntity cls,
+ [ClassRelation relation = ClassRelation.subtype]) {
if (nativeBasicData.isJsInteropClass(cls)) {
// We can not tell js-interop classes apart, so we just assume the
// receiver could be any js-interop class.
cls = commonElements.jsJavaScriptObjectClass;
+ relation = ClassRelation.subtype;
}
- return new StrongModeConstraint.internal(cls);
+ return new StrongModeConstraint.internal(cls, relation);
}
- const StrongModeConstraint.internal(this.cls);
+ const StrongModeConstraint.internal(this.cls, this.relation);
bool needsNoSuchMethodHandling(Selector selector, World world) => true;
bool canHit(MemberEntity element, Selector selector, OpenWorld world) {
- return world.isInheritedInSubtypeOf(element, cls);
+ return world.isInheritedIn(element, cls, relation);
}
- bool operator ==(other) {
+ bool get isExact => relation == ClassRelation.exact;
+
+ bool get isThis => relation == ClassRelation.thisExpression;
+
+ bool operator ==(Object other) {
if (identical(this, other)) return true;
- if (other is! StrongModeConstraint) return false;
- return cls == other.cls;
+ return other is StrongModeConstraint &&
+ cls == other.cls &&
+ relation == other.relation;
}
int get hashCode => cls.hashCode * 13;
- String toString() => 'StrongModeConstraint($cls)';
+ String toString() => 'StrongModeConstraint($cls,$relation)';
}
/// The [WorldBuilder] is an auxiliary class used in the process of computing
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 01ba8f9..6a0fd25 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -17,6 +17,7 @@
import 'diagnostics/diagnostic_listener.dart';
import 'elements/entities.dart';
import 'elements/types.dart';
+import 'ir/static_type.dart';
import 'js_backend/annotations.dart';
import 'js_backend/allocator_analysis.dart'
show JAllocatorAnalysis, KAllocatorAnalysis;
@@ -225,10 +226,11 @@
/// abstract class I { m(); }
/// abstract class J implements A { }
///
- /// Here `A.m` is inherited into `A`, `B`, and `C`. Becausec `B` and
- /// `C` implement `I`, `isInheritedInSubtypeOf(A.M, I)` is true, but
- /// `isInheritedInSubtypeOf(A.M, J)` is false.
- bool isInheritedInSubtypeOf(MemberEntity member, ClassEntity type);
+ /// Here `A.m` is inherited into `A`, `B`, and `C`. Because `B` and
+ /// `C` implement `I`, `isInheritedInSubtypeOf(A.m, I)` is true, but
+ /// `isInheritedInSubtypeOf(A.m, J)` is false.
+ bool isInheritedIn(
+ MemberEntity member, ClassEntity type, ClassRelation relation);
}
abstract class KClosedWorld {
diff --git a/pkg/dev_compiler/bin/dartdevc.dart b/pkg/dev_compiler/bin/dartdevc.dart
index 28b950d..10b1dd6 100755
--- a/pkg/dev_compiler/bin/dartdevc.dart
+++ b/pkg/dev_compiler/bin/dartdevc.dart
@@ -38,7 +38,6 @@
class _CompilerWorker extends AsyncWorkerLoop {
/// The original args supplied to the executable.
final ParsedArguments _startupArgs;
- CompilerResult _result;
_CompilerWorker(this._startupArgs, AsyncWorkerConnection workerConnection)
: super(connection: workerConnection);
@@ -47,13 +46,12 @@
Future<WorkResponse> performRequest(WorkRequest request) async {
var args = _startupArgs.merge(request.arguments);
var output = StringBuffer();
- _result = await runZoned(() => compile(args, previousResult: _result),
- zoneSpecification:
- ZoneSpecification(print: (self, parent, zone, message) {
+ var result = await runZoned(() => compile(args), zoneSpecification:
+ ZoneSpecification(print: (self, parent, zone, message) {
output.writeln(message.toString());
}));
return WorkResponse()
- ..exitCode = _result.success ? 0 : 1
+ ..exitCode = result.success ? 0 : 1
..output = output.toString();
}
}
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index e247077..32f7d96 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -65,7 +65,7 @@
// expressions (which result in JS.Expression) and statements
// (which result in (JS.Statement).
class CodeGenerator extends Object
- with NullableTypeInference, SharedCompiler<LibraryElement>
+ with NullableTypeInference, SharedCompiler<LibraryElement, ClassElement>
implements AstVisitor<JS.Node> {
final SummaryDataStore summaryData;
@@ -1318,8 +1318,8 @@
ctorBody
.add(_emitSuperConstructorCall(className, ctor.name, jsParams));
}
- body.add(_addConstructorToClass(
- className, ctor.name, JS.Fun(jsParams, JS.Block(ctorBody))));
+ body.add(_addConstructorToClass(classElem, className, ctor.name,
+ JS.Fun(jsParams, JS.Block(ctorBody))));
}
}
@@ -1879,7 +1879,7 @@
}
addConstructor(String name, JS.Expression jsCtor) {
- body.add(_addConstructorToClass(className, name, jsCtor));
+ body.add(_addConstructorToClass(classElem, className, name, jsCtor));
}
if (classElem.isEnum) {
@@ -1943,12 +1943,31 @@
c.isSynthetic && c.name != '' || c.isFactory || c.isExternal);
}
- JS.Statement _addConstructorToClass(
- JS.Expression className, String name, JS.Expression jsCtor) {
- jsCtor = defineValueOnClass(className, _constructorName(name), jsCtor);
+ JS.Statement _addConstructorToClass(ClassElement c, JS.Expression className,
+ String name, JS.Expression jsCtor) {
+ jsCtor = defineValueOnClass(c, className, _constructorName(name), jsCtor);
return js.statement('#.prototype = #.prototype;', [jsCtor, className]);
}
+ @override
+ bool superclassHasStatic(ClassElement c, String name) {
+ // Note: because we're only considering statics, we can ignore mixins.
+ // We're only trying to find conflicts due to JS inheriting statics.
+ var library = c.library;
+ while (true) {
+ var supertype = c.supertype;
+ if (supertype == null) return false;
+ c = supertype.element;
+ for (var members in [c.methods, c.accessors]) {
+ for (var m in members) {
+ if (m.isStatic && m.name == name && m.isAccessibleIn(library)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
/// Emits static fields for a class, and initialize them eagerly if possible,
/// otherwise define them as lazy properties.
void _emitStaticFields(ClassElement classElem,
@@ -1957,7 +1976,7 @@
// Emit enum static fields
var type = classElem.type;
void addField(FieldElement e, JS.Expression value) {
- body.add(defineValueOnClass(_emitStaticClassName(classElem),
+ body.add(defineValueOnClass(classElem, _emitStaticClassName(classElem),
_declareMemberName(e.getter), value)
.toStatement());
}
@@ -2252,8 +2271,8 @@
var parameters = element.parameters
.map((p) => ParameterElementImpl.synthetic(
p.name,
- // ignore: deprecated_member_use
_isCovariant(p) ? objectClass.type : p.type,
+ // ignore: deprecated_member_use
p.parameterKind))
.toList();
diff --git a/pkg/dev_compiler/lib/src/analyzer/driver.dart b/pkg/dev_compiler/lib/src/analyzer/driver.dart
index f3cca4f..63d1223 100644
--- a/pkg/dev_compiler/lib/src/analyzer/driver.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/driver.dart
@@ -216,14 +216,6 @@
prepareUnlinkedUnit(sourcesToProcess.removeFirst());
}
- /// Gets the URIs to link.
- ///
- /// Unlike analyzer_cli, this only includes library URIs, not all
- /// compilation units. This appears to be what [summary_link.link] wants as
- /// input. If all units are passed in, the resulting summary has extra data
- /// in the linkedLibraries list, which appears to be unnecessary.
- var unlinkedUris = Set<String>.from(summaryData.uriToSummaryPath.keys)
- ..addAll(libraryUris);
var declaredVariables = DeclaredVariables.fromMap(
Map.of(options.declaredVariables)..addAll(sdkLibraryVariables));
@@ -232,7 +224,7 @@
/// TODO(jmesserly): can we pass in `getAst` to reuse existing ASTs we
/// created when we did `file.parse()` in [prepareUnlinkedUnit]?
var linkResult = summary_link.link(
- unlinkedUris,
+ libraryUris.toSet(),
(uri) => summaryData.linkedMap[uri],
(uri) => summaryData.unlinkedMap[uri] ?? uriToUnit[uri],
declaredVariables.get);
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index ddb903c..2112e0f 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -466,7 +466,11 @@
var arg = args[i];
var isLastArg = i == len - 1;
if (isLastArg && arg.startsWith('@')) {
- newArgs.addAll(_readLines(arg.substring(1)));
+ var extra = _readLines(arg.substring(1)).toList();
+ if (extra.remove('--kernel') || extra.remove('-k')) {
+ isKernel = true;
+ }
+ newArgs.addAll(extra);
} else if (arg == '--persistent_worker') {
isWorker = true;
} else if (isLastArg && arg == '--batch') {
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
index f9b5c0c..a39888c 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
@@ -13,7 +13,7 @@
///
/// This class should only implement functionality that depends purely on JS
/// classes, rather than on Analyzer/Kernel types.
-abstract class SharedCompiler<Library> {
+abstract class SharedCompiler<Library, Class> {
/// When inside a `[]=` operator, this will be a non-null value that should be
/// returned by any `return;` statement.
///
@@ -141,21 +141,26 @@
});
}
- /// Emits an expression to set the property [name] on the class [className],
+ /// Emits an expression to set the property [nameExpr] on the class [className],
/// with [value].
///
/// This will use `className.name = value` if possible, otherwise it will use
/// `dart.defineValue(className, name, value)`. This is required when
/// `Function.prototype` already defins a getters with the same name.
- JS.Expression defineValueOnClass(
- JS.Expression className, JS.Expression name, JS.Expression value) {
- var args = [className, name, value];
- if (name is JS.LiteralString &&
- JS.isFunctionPrototypeGetter(name.valueWithoutQuotes)) {
- return runtimeCall('defineValue(#, #, #)', args);
+ JS.Expression defineValueOnClass(Class c, JS.Expression className,
+ JS.Expression nameExpr, JS.Expression value) {
+ var args = [className, nameExpr, value];
+ if (nameExpr is JS.LiteralString) {
+ var name = nameExpr.valueWithoutQuotes;
+ if (JS.isFunctionPrototypeGetter(name) || superclassHasStatic(c, name)) {
+ return runtimeCall('defineValue(#, #, #)', args);
+ }
}
return js.call('#.# = #', args);
}
+
+ /// Whether any superclass of [c] defines a static [name].
+ bool superclassHasStatic(Class c, String name);
}
/// Whether a variable with [name] is referenced in the [node].
diff --git a/pkg/dev_compiler/lib/src/js_ast/builder.dart b/pkg/dev_compiler/lib/src/js_ast/builder.dart
index 6520afc..d81f7e3 100644
--- a/pkg/dev_compiler/lib/src/js_ast/builder.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/builder.dart
@@ -663,7 +663,7 @@
void getToken() {
skippedNewline = false;
- for (;;) {
+ while (true) {
if (position >= src.length) break;
int code = src.codeUnitAt(position);
// Skip '//' and '/*' style comments.
@@ -990,7 +990,7 @@
expectCategory(LPAREN);
if (!acceptCategory(RPAREN)) {
- for (;;) {
+ while (true) {
if (acceptCategory(ELLIPSIS)) {
params.add(RestParameter(parseParameter()));
expectCategory(RPAREN);
@@ -1039,7 +1039,7 @@
Expression parseObjectInitializer() {
List<Property> properties = <Property>[];
- for (;;) {
+ while (true) {
if (acceptCategory(RBRACE)) break;
// Limited subset of ES6 object initializers.
//
diff --git a/pkg/dev_compiler/lib/src/js_ast/printer.dart b/pkg/dev_compiler/lib/src/js_ast/printer.dart
index 56f032c..bdd29bd 100644
--- a/pkg/dev_compiler/lib/src/js_ast/printer.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/printer.dart
@@ -402,7 +402,7 @@
newInForInit: true, newAtStatementBegin: false);
out(" of");
pendingSpace = true;
- visitNestedExpression(loop.iterable, EXPRESSION,
+ visitNestedExpression(loop.iterable, ASSIGNMENT,
newInForInit: false, newAtStatementBegin: false);
out(")");
blockBody(loop.body, needsSeparation: false, needsNewline: true);
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 6351180..2617516 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -32,7 +32,7 @@
import 'type_table.dart';
class ProgramCompiler extends Object
- with SharedCompiler<Library>
+ with SharedCompiler<Library, Class>
implements
StatementVisitor<JS.Statement>,
ExpressionVisitor<JS.Expression>,
@@ -773,7 +773,7 @@
ctorBody.add(_emitSuperConstructorCall(className, name, jsParams));
}
body.add(_addConstructorToClass(
- className, name, JS.Fun(jsParams, JS.Block(ctorBody))));
+ c, className, name, JS.Fun(jsParams, JS.Block(ctorBody))));
}
}
@@ -877,7 +877,7 @@
}
addConstructor(String name, JS.Expression jsCtor) {
- body.add(_addConstructorToClass(className, name, jsCtor));
+ body.add(_addConstructorToClass(c, className, name, jsCtor));
}
var fields = c.fields;
@@ -1141,6 +1141,7 @@
for (var f in fields) {
assert(f.isConst);
body.add(defineValueOnClass(
+ c,
classRef,
_emitStaticMemberName(f.name.name),
_visitInitializer(f.initializer, f.annotations))
@@ -1600,11 +1601,28 @@
}
JS.Statement _addConstructorToClass(
- JS.Expression className, String name, JS.Expression jsCtor) {
- jsCtor = defineValueOnClass(className, _constructorName(name), jsCtor);
+ Class c, JS.Expression className, String name, JS.Expression jsCtor) {
+ jsCtor = defineValueOnClass(c, className, _constructorName(name), jsCtor);
return js.statement('#.prototype = #.prototype;', [jsCtor, className]);
}
+ @override
+ bool superclassHasStatic(Class c, String memberName) {
+ // Note: because we're only considering statics, we can ignore mixins.
+ // We're only trying to find conflicts due to JS inheriting statics.
+ var name = Name(memberName, c.enclosingLibrary);
+ while (true) {
+ c = c.superclass;
+ if (c == null) return false;
+ for (var m in c.members) {
+ if (m.name == name &&
+ (m is Procedure && m.isStatic || m is Field && m.isStatic)) {
+ return true;
+ }
+ }
+ }
+ }
+
List<JS.Method> _emitClassMethods(Class c) {
var virtualFields = _classProperties.virtualFields;
diff --git a/pkg/dev_compiler/tool/input_sdk/patch/convert_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/convert_patch.dart
index cfaa3fc..787c677 100644
--- a/pkg/dev_compiler/tool/input_sdk/patch/convert_patch.dart
+++ b/pkg/dev_compiler/tool/input_sdk/patch/convert_patch.dart
@@ -495,3 +495,13 @@
return null;
}();
}
+
+@patch
+int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
+ final to = endIndex;
+ for (var i = from; i < to; i++) {
+ final unit = units[i];
+ if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
+ }
+ return to - from;
+}
diff --git a/pkg/front_end/lib/src/api_prototype/standard_file_system.dart b/pkg/front_end/lib/src/api_prototype/standard_file_system.dart
index 5be815e..bdd78ad 100644
--- a/pkg/front_end/lib/src/api_prototype/standard_file_system.dart
+++ b/pkg/front_end/lib/src/api_prototype/standard_file_system.dart
@@ -63,7 +63,7 @@
Future<List<int>> readAsBytes() async {
try {
CompilerContext.recordDependency(uri);
- return await new io.File.fromUri(uri).readAsBytes();
+ return new io.File.fromUri(uri).readAsBytesSync();
} on io.FileSystemException catch (exception) {
throw _toFileSystemException(exception);
}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
index d033d7d..2a4eb8d 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
@@ -11,6 +11,8 @@
import '../fasta_codes.dart'
show SummaryTemplate, Template, templateDillOutlineSummary;
+import '../compiler_context.dart' show CompilerContext;
+
import '../kernel/kernel_builder.dart' show LibraryBuilder;
import '../loader.dart' show Loader;
@@ -26,9 +28,11 @@
final libraries = <Library>[];
/// Sources for all appended components.
- final Map<Uri, Source> uriToSource = <Uri, Source>{};
+ final Map<Uri, Source> uriToSource;
- DillLoader(TargetImplementation target) : super(target);
+ DillLoader(TargetImplementation target)
+ : uriToSource = CompilerContext.current.uriToSource,
+ super(target);
Template<SummaryTemplate> get outlineSummaryTemplate =>
templateDillOutlineSummary;
diff --git a/pkg/front_end/lib/src/fasta/get_dependencies.dart b/pkg/front_end/lib/src/fasta/get_dependencies.dart
index e4aacb2..abd9879 100644
--- a/pkg/front_end/lib/src/fasta/get_dependencies.dart
+++ b/pkg/front_end/lib/src/fasta/get_dependencies.dart
@@ -49,9 +49,8 @@
var platformComponent = loadComponentFromBytes(bytes);
dillTarget.loader.appendLibraries(platformComponent);
}
- KernelTarget kernelTarget = new KernelTarget(
- fileSystem, false, dillTarget, uriTranslator,
- uriToSource: c.uriToSource);
+ KernelTarget kernelTarget =
+ new KernelTarget(fileSystem, false, dillTarget, uriTranslator);
kernelTarget.setEntryPoints(<Uri>[script]);
await dillTarget.buildOutlines();
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 2565d7e..2ba7eb7 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -81,7 +81,6 @@
Set<Uri> invalidatedUris = new Set<Uri>();
DillTarget dillLoadedData;
- Map<Uri, Source> dillLoadedDataUriToSource = <Uri, Source>{};
List<LibraryBuilder> platformBuilders;
Map<Uri, LibraryBuilder> userBuilders;
final Uri initializeFromDillUri;
@@ -206,7 +205,6 @@
for (Uri uri in new Set<Uri>.from(dillLoadedData.loader.builders.keys)
..removeAll(reusedLibraryUris)) {
dillLoadedData.loader.builders.remove(uri);
- dillLoadedDataUriToSource.remove(uri);
userBuilders?.remove(uri);
}
@@ -234,8 +232,7 @@
c.fileSystem),
false,
dillLoadedData,
- uriTranslator,
- uriToSource: c.uriToSource);
+ uriTranslator);
userCode.loader.hierarchy = hierarchy;
for (LibraryBuilder library in reusedLibraries) {
@@ -265,9 +262,6 @@
List<Library> compiledLibraries =
new List<Library>.from(userCode.loader.libraries);
- Map<Uri, Source> uriToSource =
- new Map<Uri, Source>.from(dillLoadedDataUriToSource);
- uriToSource.addAll(userCode.uriToSource);
Procedure mainMethod = componentWithDill == null
? data.userLoadedUriMain
: componentWithDill.mainMethod;
@@ -287,13 +281,10 @@
userCode = userCodeOld;
}
- Map<Uri, Source> optionalUriToSource = context.options.embedSourceText
- ? uriToSource
- : uriToSource.map((uri, source) => MapEntry<Uri, Source>(
- uri, new Source(source.lineStarts, const <int>[])));
// This is the incremental component.
return context.options.target.configureComponent(new Component(
- libraries: outputLibraries, uriToSource: optionalUriToSource))
+ libraries: outputLibraries,
+ uriToSource: componentWithDill.uriToSource))
..mainMethod = mainMethod;
});
}
@@ -347,7 +338,6 @@
Library lib = builder.target;
removedLibraries.add(lib);
dillLoadedData.loader.builders.remove(uri);
- dillLoadedDataUriToSource.remove(uri);
userBuilders?.remove(uri);
}
}
@@ -387,8 +377,6 @@
if (initializationBytes != null) {
ticker.logMs("Read $initializeFromDillUri");
- Set<Uri> sdkUris = data.component.uriToSource.keys.toSet();
-
// We're going to output all we read here so lazy loading it
// doesn't make sense.
new BinaryBuilder(initializationBytes, disableLazyReading: true)
@@ -412,10 +400,6 @@
bytesLength += initializationBytes.length;
data.userLoadedUriMain = data.component.mainMethod;
data.includeUserLoadedLibraries = true;
- for (Uri uri in data.component.uriToSource.keys) {
- if (sdkUris.contains(uri)) continue;
- dillLoadedDataUriToSource[uri] = data.component.uriToSource[uri];
- }
}
}
return bytesLength;
@@ -622,6 +606,12 @@
for (LibraryPart part in library.target.parts) {
Uri partUri = library.uri.resolve(part.partUri);
Uri fileUri = library.library.fileUri.resolve(part.partUri);
+ if (fileUri.scheme == "package") {
+ // Part was specified via package URI and the resolve above thus
+ // did not go as expected. Translate the package URI to get the
+ // actual file URI.
+ fileUri = uriTranslator.translate(partUri, false);
+ }
if (isInvalidated(partUri, fileUri)) {
invalidatedImportUris.add(partUri);
builders[partUri] = library;
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 3358be6..8d44dc6 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -2328,7 +2328,7 @@
}
@override
- void endLiteralMapEntry(Token colon, Token endToken) {
+ void handleLiteralMapEntry(Token colon, Token endToken) {
debugEvent("LiteralMapEntry");
Expression value = popForValue();
Expression key = popForValue();
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_api.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_api.dart
index fd26c01..87fbc5b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_api.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_api.dart
@@ -5,8 +5,7 @@
/// This library exports all API from Kernel that can be used throughout fasta.
library fasta.kernel_api;
-export 'package:kernel/type_algebra.dart'
- show Substitution, instantiateToBounds, substitute;
+export 'package:kernel/type_algebra.dart' show Substitution, substitute;
export 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -20,6 +19,8 @@
export 'package:kernel/type_environment.dart' show TypeEnvironment;
+export 'package:kernel/src/bounds_checks.dart' show instantiateToBounds;
+
import 'package:kernel/text/ast_to_text.dart' show NameSystem, Printer;
import 'package:kernel/ast.dart' show Class, Member, Node;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_formal_parameter_builder.dart
index b76dbae..f7b56a8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_formal_parameter_builder.dart
@@ -13,7 +13,8 @@
FormalParameterBuilder,
KernelLibraryBuilder,
KernelTypeBuilder,
- MetadataBuilder;
+ MetadataBuilder,
+ TypeBuilder;
import 'kernel_shadow_ast.dart' show VariableDeclarationJudgment;
@@ -48,6 +49,14 @@
return declaration;
}
+ KernelFormalParameterBuilder clone(List<TypeBuilder> newTypes) {
+ // TODO(dmitryas): It's not clear how [metadata] is used currently, and
+ // how it should be cloned. Consider cloning it instead of reusing it.
+ return new KernelFormalParameterBuilder(metadata, modifiers,
+ type?.clone(newTypes), name, hasThis, parent, charOffset)
+ ..kind = kind;
+ }
+
@override
FormalParameterBuilder forFormalParameterInitializerScope() {
assert(declaration != null);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_builder.dart
index edebe4a..916dc20d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_function_type_builder.dart
@@ -91,18 +91,23 @@
}
KernelFunctionTypeBuilder clone(List<TypeBuilder> newTypes) {
- List<TypeVariableBuilder> clonedTypeVariables =
- new List<TypeVariableBuilder>(typeVariables.length);
- for (int i = 0; i < clonedTypeVariables.length; i++) {
- clonedTypeVariables[i] = typeVariables[i].clone(newTypes);
+ List<TypeVariableBuilder> clonedTypeVariables;
+ if (typeVariables != null) {
+ clonedTypeVariables = new List<TypeVariableBuilder>(typeVariables.length);
+ for (int i = 0; i < clonedTypeVariables.length; i++) {
+ clonedTypeVariables[i] = typeVariables[i].clone(newTypes);
+ }
}
- List<FormalParameterBuilder> clonedFormals =
- new List<FormalParameterBuilder>(formals.length);
- for (int i = 0; i < clonedFormals.length; i++) {
- clonedFormals[i] = formals[i].clone(newTypes);
+ List<FormalParameterBuilder> clonedFormals;
+ if (formals != null) {
+ clonedFormals = new List<FormalParameterBuilder>(formals.length);
+ for (int i = 0; i < clonedFormals.length; i++) {
+ KernelFormalParameterBuilder formal = formals[i];
+ clonedFormals[i] = formal.clone(newTypes);
+ }
}
KernelFunctionTypeBuilder newType = new KernelFunctionTypeBuilder(
- returnType.clone(newTypes), clonedTypeVariables, clonedFormals);
+ returnType?.clone(newTypes), clonedTypeVariables, clonedFormals);
newTypes.add(newType);
return newType;
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
index ffd5b41..7660133 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
@@ -420,16 +420,29 @@
/// Helper function that returns `true` if a type variable with a name
/// from [typeVariableNames] is referenced in [type].
- bool usesTypeVariables(KernelNamedTypeBuilder type) {
- List<KernelTypeBuilder> typeArguments = type.arguments;
- if (typeArguments != null && typeVariables != null) {
- for (KernelTypeBuilder argument in typeArguments) {
- if (typeVariableNames.contains(argument.name)) {
- return true;
- } else if (argument is KernelNamedTypeBuilder) {
- if (usesTypeVariables(argument)) return true;
+ bool usesTypeVariables(KernelTypeBuilder type) {
+ if (type is KernelNamedTypeBuilder) {
+ if (type.declaration is KernelTypeVariableBuilder) {
+ return typeVariableNames.contains(type.declaration.name);
+ }
+
+ List<KernelTypeBuilder> typeArguments = type.arguments;
+ if (typeArguments != null && typeVariables != null) {
+ for (KernelTypeBuilder argument in typeArguments) {
+ if (usesTypeVariables(argument)) {
+ return true;
+ }
}
}
+ } else if (type is KernelFunctionTypeBuilder) {
+ if (type.formals != null) {
+ for (FormalParameterBuilder formal in type.formals) {
+ if (usesTypeVariables(formal.type)) {
+ return true;
+ }
+ }
+ }
+ return usesTypeVariables(type.returnType);
}
return false;
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 1342714..ee564d1 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -133,9 +133,9 @@
KernelTarget(this.fileSystem, this.includeComments, DillTarget dillTarget,
UriTranslator uriTranslator,
- {Map<Uri, Source> uriToSource, MetadataCollector metadataCollector})
+ {MetadataCollector metadataCollector})
: dillTarget = dillTarget,
- uriToSource = uriToSource ?? CompilerContext.current.uriToSource,
+ uriToSource = CompilerContext.current.uriToSource,
metadataCollector = metadataCollector,
super(dillTarget.ticker, uriTranslator, dillTarget.backendTarget) {
loader = createLoader();
@@ -350,7 +350,6 @@
}
this.uriToSource.forEach(copySource);
- dillTarget.loader.uriToSource.forEach(copySource);
Component component = CompilerContext.current.options.target
.configureComponent(new Component(
diff --git a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
index 5e15224..166d266 100644
--- a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
@@ -254,11 +254,6 @@
}
@override
- void beginLiteralMapEntry(Token token) {
- listener?.beginLiteralMapEntry(token);
- }
-
- @override
void beginLiteralString(Token token) {
listener?.beginLiteralString(token);
}
@@ -686,8 +681,8 @@
}
@override
- void endLiteralMapEntry(Token colon, Token endToken) {
- listener?.endLiteralMapEntry(colon, endToken);
+ void handleLiteralMapEntry(Token colon, Token endToken) {
+ listener?.handleLiteralMapEntry(colon, endToken);
}
@override
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
index 9078ced..457928d 100644
--- a/pkg/front_end/lib/src/fasta/parser/listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -678,9 +678,7 @@
logEvent("LibraryName");
}
- void beginLiteralMapEntry(Token token) {}
-
- void endLiteralMapEntry(Token colon, Token endToken) {
+ void handleLiteralMapEntry(Token colon, Token endToken) {
logEvent("LiteralMapEntry");
}
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 2617420..bc96678 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -263,7 +263,15 @@
/// Experimental flag for enabling set literal support.
/// See https://github.com/dart-lang/sdk/issues/35121
- bool parseSetLiterals = false;
+ bool enableSetLiterals = false;
+
+ /// Obsolete experimental flag for enabling set literal support.
+ /// Use enableSetLiterals instead.
+ /// TODO(danrubel): Remove this once this has been merged into the analyzer
+ /// branch and the references to this have been cleaned up.
+ set parseSetLiterals(bool value) {
+ enableSetLiterals = value;
+ }
/// Represents parser state: what asynchronous syntax is allowed in the
/// function being currently parsed. In rare situations, this can be set by
@@ -1208,8 +1216,10 @@
} else if (next.kind == IDENTIFIER_TOKEN &&
next.next.kind == IDENTIFIER_TOKEN) {
// Looks like a missing comma
- Token comma = new SyntheticToken(TokenType.COMMA, next.charOffset);
- token = rewriter.insertToken(token, comma);
+ token = rewriteAndRecover(
+ token,
+ fasta.templateExpectedButGot.withArguments(','),
+ new SyntheticToken(TokenType.COMMA, next.charOffset));
continue;
} else {
token = ensureCloseParen(token, begin);
@@ -4196,9 +4206,9 @@
}
/// This method parses the portion of a set or map literal that starts with
- /// the left curly brace.
+ /// the left curly brace when there are no leading type arguments.
Token parseLiteralSetOrMapSuffix(final Token start, Token constKeyword) {
- if (!parseSetLiterals) {
+ if (!enableSetLiterals) {
// TODO(danrubel): remove this once set literals are permanent
return parseLiteralMapSuffix(start, constKeyword);
}
@@ -4211,30 +4221,29 @@
return rightBrace;
}
- final old = mayParseFunctionExpressions;
+ bool old = mayParseFunctionExpressions;
mayParseFunctionExpressions = true;
- final originalListener = listener;
- listener = new ForwardingListener();
-
- // Skip over the first expression to determine if this is a set or map.
- // TODO(danrubel): Consider removing listener.beginLiteralMapEntry
- // so that the expression could be parsed without lookahead
- // regardless of whether this is a set or map literal.
Token token = parseExpression(leftBrace);
- Token next = token.next;
-
- listener = originalListener;
mayParseFunctionExpressions = old;
- if (optional(',', next) || optional('}', next)) {
- return parseLiteralSetSuffix(start, constKeyword);
- } else if (optional(':', next)) {
- return parseLiteralMapSuffix(start, constKeyword);
+ Token next = token.next;
+ if (optional('}', next)) {
+ listener.handleLiteralSet(1, leftBrace, constKeyword, next);
+ return next;
+ } else if (optional(',', next)) {
+ return parseLiteralSetRest(next, constKeyword, leftBrace);
} else {
- // Recovery: This could be either a literal set or a literal map
// TODO(danrubel): Consider better recovery
- // rather than just assuming this is a malformed literal map.
- return parseLiteralMapSuffix(start, constKeyword);
+ // rather than just assuming this is a literal map.
+ Token colon = ensureColon(next);
+
+ final old = mayParseFunctionExpressions;
+ mayParseFunctionExpressions = true;
+ token = parseExpression(colon);
+ mayParseFunctionExpressions = old;
+
+ listener.handleLiteralMapEntry(colon, token.next);
+ return parseLiteralMapRest(token, constKeyword, leftBrace);
}
}
@@ -4253,27 +4262,42 @@
Token parseLiteralMapSuffix(Token token, Token constKeyword) {
Token beginToken = token = token.next;
assert(optional('{', beginToken));
- int count = 0;
+ if (optional('}', token.next)) {
+ token = token.next;
+ listener.handleLiteralMap(0, beginToken, constKeyword, token);
+ return token;
+ }
+
+ bool old = mayParseFunctionExpressions;
+ mayParseFunctionExpressions = true;
+ token = parseMapLiteralEntry(token);
+ mayParseFunctionExpressions = old;
+
+ return parseLiteralMapRest(token, constKeyword, beginToken);
+ }
+
+ /// Parse a literal map after the first entry.
+ Token parseLiteralMapRest(Token token, Token constKeyword, Token beginToken) {
+ int count = 1;
bool old = mayParseFunctionExpressions;
mayParseFunctionExpressions = true;
while (true) {
- if (optional('}', token.next)) {
- token = token.next;
+ Token next = token.next;
+ Token comma;
+ if (optional(',', next)) {
+ comma = token = next;
+ next = token.next;
+ }
+ if (optional('}', next)) {
+ token = next;
break;
}
- token = parseMapLiteralEntry(token);
- Token next = token.next;
- ++count;
- if (!optional(',', next)) {
- if (optional('}', next)) {
- token = next;
- break;
- }
+ if (comma == null) {
// Recovery
if (looksLikeExpressionStart(next)) {
// If this looks like the start of an expression,
// then report an error, insert the comma, and continue parsing.
- next = rewriteAndRecover(
+ token = rewriteAndRecover(
token,
fasta.templateExpectedButGot.withArguments(','),
new SyntheticToken(TokenType.COMMA, next.offset));
@@ -4285,7 +4309,8 @@
break;
}
}
- token = next;
+ token = parseMapLiteralEntry(token);
+ ++count;
}
assert(optional('}', token));
mayParseFunctionExpressions = old;
@@ -4306,34 +4331,49 @@
/// if not. This is a suffix parser because it is assumed that type arguments
/// have been parsed, or `listener.handleNoTypeArguments` has been executed.
Token parseLiteralSetSuffix(Token token, Token constKeyword) {
- if (!parseSetLiterals) {
+ if (!enableSetLiterals) {
// TODO(danrubel): remove this once set literals are permanent
return parseLiteralMapSuffix(token, constKeyword);
}
Token beginToken = token = token.next;
assert(optional('{', beginToken));
- int count = 0;
+ if (optional('}', token.next)) {
+ token = token.next;
+ listener.handleLiteralSet(0, beginToken, constKeyword, token);
+ return token;
+ }
+
+ bool old = mayParseFunctionExpressions;
+ mayParseFunctionExpressions = true;
+ token = parseExpression(token);
+ mayParseFunctionExpressions = old;
+
+ return parseLiteralSetRest(token, constKeyword, beginToken);
+ }
+
+ /// Parse a literal set after the first expression.
+ Token parseLiteralSetRest(Token token, Token constKeyword, Token beginToken) {
+ int count = 1;
bool old = mayParseFunctionExpressions;
mayParseFunctionExpressions = true;
while (true) {
- if (optional('}', token.next)) {
- token = token.next;
+ Token next = token.next;
+ Token comma;
+ if (optional(',', next)) {
+ comma = token = next;
+ next = token.next;
+ }
+ if (optional('}', next)) {
+ token = next;
break;
}
- token = parseExpression(token);
- Token next = token.next;
- ++count;
- if (!optional(',', next)) {
- if (optional('}', next)) {
- token = next;
- break;
- }
+ if (comma == null) {
// Recovery
if (looksLikeExpressionStart(next)) {
// If this looks like the start of an expression,
// then report an error, insert the comma, and continue parsing.
- next = rewriteAndRecover(
+ token = rewriteAndRecover(
token,
fasta.templateExpectedButGot.withArguments(','),
new SyntheticToken(TokenType.COMMA, next.offset));
@@ -4345,7 +4385,8 @@
break;
}
}
- token = next;
+ token = parseExpression(token);
+ ++count;
}
assert(optional('}', token));
mayParseFunctionExpressions = old;
@@ -4424,14 +4465,13 @@
/// ;
/// ```
Token parseMapLiteralEntry(Token token) {
- listener.beginLiteralMapEntry(token.next);
// Assume the listener rejects non-string keys.
// TODO(brianwilkerson): Change the assumption above by moving error
// checking into the parser, making it possible to recover.
token = parseExpression(token);
Token colon = ensureColon(token);
token = parseExpression(colon);
- listener.endLiteralMapEntry(colon, token.next);
+ listener.handleLiteralMapEntry(colon, token.next);
return token;
}
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info.dart b/pkg/front_end/lib/src/fasta/parser/type_info.dart
index 9e43321..585fedf3 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info.dart
@@ -26,27 +26,27 @@
/// Call this function when the token after [token] must be a type (not void).
/// This function will call the appropriate event methods on the [Parser]'s
/// listener to handle the type, inserting a synthetic type reference if
- /// necessary. This may modify the token stream when parsing `>>` in valid
- /// code or during recovery.
+ /// necessary. This may modify the token stream when parsing `>>` or `>>>`
+ /// in valid code or during recovery.
Token ensureTypeNotVoid(Token token, Parser parser);
/// Call this function when the token after [token] must be a type or void.
/// This function will call the appropriate event methods on the [Parser]'s
/// listener to handle the type, inserting a synthetic type reference if
- /// necessary. This may modify the token stream when parsing `>>` in valid
- /// code or during recovery.
+ /// necessary. This may modify the token stream when parsing `>>` or `>>>`
+ /// in valid code or during recovery.
Token ensureTypeOrVoid(Token token, Parser parser);
/// Call this function to parse an optional type (not void) after [token].
/// This function will call the appropriate event methods on the [Parser]'s
/// listener to handle the type. This may modify the token stream
- /// when parsing `>>` in valid code or during recovery.
+ /// when parsing `>>` or `>>>` in valid code or during recovery.
Token parseTypeNotVoid(Token token, Parser parser);
/// Call this function to parse an optional type or void after [token].
/// This function will call the appropriate event methods on the [Parser]'s
/// listener to handle the type. This may modify the token stream
- /// when parsing `>>` in valid code or during recovery.
+ /// when parsing `>>` or `>>>` in valid code or during recovery.
Token parseType(Token token, Parser parser);
/// Call this function with the [token] before the type to obtain
@@ -76,14 +76,14 @@
/// Call this function to parse optional type arguments after [token].
/// This function will call the appropriate event methods on the [Parser]'s
/// listener to handle the arguments. This may modify the token stream
- /// when parsing `>>` in valid code or during recovery.
+ /// when parsing `>>` or `>>>` in valid code or during recovery.
Token parseArguments(Token token, Parser parser);
/// Call this function to parse optional type parameters
/// (also known as type variables) after [token].
/// This function will call the appropriate event methods on the [Parser]'s
/// listener to handle the parameters. This may modify the token stream
- /// when parsing `>>` in valid code or during recovery.
+ /// when parsing `>>` or `>>>` in valid code or during recovery.
Token parseVariables(Token token, Parser parser);
/// Call this function with the [token] before the type var to obtain
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
index 7f959e9..f46d819 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
@@ -30,6 +30,7 @@
skipMetadata,
splitGtEq,
splitGtFromGtGtEq,
+ splitGtFromGtGtGt,
splitGtGt,
syntheticGt;
@@ -990,16 +991,17 @@
}
}
-/// Return `true` if [token] is one of `>`, `>>`, `>=', or `>>=`.
+/// Return `true` if [token] is one of `>`, `>>`, `>=`, `>>>`, or `>>=`.
bool isCloser(Token token) {
final value = token.stringValue;
return identical(value, '>') ||
identical(value, '>>') ||
identical(value, '>=') ||
+ identical(value, '>>>') ||
identical(value, '>>=');
}
-/// If [beforeCloser].next is one of `>`, `>>`, `>=', or `>>=`,
+/// If [beforeCloser].next is one of `>`, `>>`, `>=`, `>>>`, or `>>=`,
/// then update the token stream and return `true`.
bool parseCloser(Token beforeCloser) {
Token unsplit = beforeCloser.next;
@@ -1015,7 +1017,7 @@
}
/// If [closer] is `>` then return it.
-/// If [closer] is one of `>>`, `>=', or `>>=` then split then token
+/// If [closer] is one of `>>`, `>=`, `>>>`, or `>>=` then split then token
/// and return the leading `>` without updating the token stream.
/// If [closer] is none of the above, then return null;
Token splitCloser(Token closer) {
@@ -1026,6 +1028,8 @@
return splitGtGt(closer);
} else if (identical(value, '>=')) {
return splitGtEq(closer);
+ } else if (identical(value, '>>>')) {
+ return splitGtFromGtGtGt(closer);
} else if (identical(value, '>>=')) {
return splitGtFromGtGtEq(closer);
}
diff --git a/pkg/front_end/lib/src/fasta/parser/util.dart b/pkg/front_end/lib/src/fasta/parser/util.dart
index 50937cb6..e02385f 100644
--- a/pkg/front_end/lib/src/fasta/parser/util.dart
+++ b/pkg/front_end/lib/src/fasta/parser/util.dart
@@ -178,6 +178,18 @@
..next = token.next);
}
+/// Split `>>>` into two separate tokens... `>` followed by `>>`.
+/// Call [Token.setNext] to add the token to the stream.
+Token splitGtFromGtGtGt(Token token) {
+ assert(optional('>>>', token));
+ return new SimpleToken(
+ TokenType.GT, token.charOffset, token.precedingComments)
+ ..setNext(new SimpleToken(TokenType.GT_GT, token.charOffset + 1)
+ // Set next rather than calling Token.setNext
+ // so that the previous token is not set.
+ ..next = token.next);
+}
+
/// Return a synthetic `<` followed by [next].
/// Call [Token.setNext] to add the token to the stream.
Token syntheticGt(Token next) {
diff --git a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
index 55266e8..6ac7640 100644
--- a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
@@ -44,6 +44,11 @@
final bool includeComments;
+ /// Experimental flag for enabling parsing of `>>>`.
+ /// See https://github.com/dart-lang/language/issues/61
+ /// and https://github.com/dart-lang/language/issues/60
+ bool enableGtGtGt = false;
+
/**
* The string offset for the next token that will be created.
*
@@ -638,7 +643,7 @@
}
int tokenizeGreaterThan(int next) {
- // > >= >> >>=
+ // > >= >> >>= >>>
next = advance();
if (identical($EQ, next)) {
appendPrecedenceToken(TokenType.GT_EQ);
@@ -648,6 +653,9 @@
if (identical($EQ, next)) {
appendPrecedenceToken(TokenType.GT_GT_EQ);
return advance();
+ } else if (enableGtGtGt && identical($GT, next)) {
+ appendPrecedenceToken(TokenType.GT_GT_GT);
+ return advance();
} else {
appendGtGt(TokenType.GT_GT);
return next;
diff --git a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
index 3b60139..3778a4c 100644
--- a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
@@ -844,7 +844,7 @@
}
@override
- void endLiteralMapEntry(Token colon, Token endToken) {
+ void handleLiteralMapEntry(Token colon, Token endToken) {
debugEvent("LiteralMapEntry", colon);
state.pop(); // Value.
state.popPushNull("%LiteralMapEntry%", colon); // Key.
diff --git a/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart b/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
index 5e2944d..fbfe897 100644
--- a/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
+++ b/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
@@ -128,7 +128,8 @@
Future<Result<Component>> run(Component component, dynamic context) async {
StringBuffer messages = context.componentToDiagnostics[component];
- Uri uri = component.uriToSource.keys.first;
+ Uri uri = component.uriToSource.keys
+ .firstWhere((uri) => uri != null && uri.scheme == "file");
Library library = component.libraries
.firstWhere((Library library) => library.importUri.scheme != "dart");
Uri base = uri.resolve(".");
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 50223d0..bb76249 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -54,7 +54,9 @@
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/type_algebra.dart'
- show calculateBounds, getFreshTypeParameters, Substitution;
+ show getFreshTypeParameters, Substitution;
+
+import 'package:kernel/src/bounds_checks.dart' show calculateBounds;
import '../../base/instrumentation.dart'
show
diff --git a/pkg/front_end/test/fasta/parser/type_info_test.dart b/pkg/front_end/test/fasta/parser/type_info_test.dart
index f3f7c2c..975eda8 100644
--- a/pkg/front_end/test/fasta/parser/type_info_test.dart
+++ b/pkg/front_end/test/fasta/parser/type_info_test.dart
@@ -2,11 +2,15 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:convert';
+
import 'package:front_end/src/fasta/messages.dart';
import 'package:front_end/src/fasta/parser.dart';
import 'package:front_end/src/fasta/parser/type_info.dart';
import 'package:front_end/src/fasta/parser/type_info_impl.dart';
-import 'package:front_end/src/fasta/scanner.dart';
+import 'package:front_end/src/fasta/scanner.dart' hide scanString;
+import 'package:front_end/src/fasta/scanner/recover.dart'
+ show defaultRecoveryStrategy;
import 'package:front_end/src/scanner/token.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -26,6 +30,35 @@
});
}
+/// TODO(danrubel): Remove this and use scanner.dart scanString
+/// once support for `>>>` is permanently enabled.
+///
+/// Scan/tokenize the given [source].
+/// If [recover] is null, then the [defaultRecoveryStrategy] is used.
+ScannerResult scanString(String source,
+ {bool includeComments: false,
+ bool scanLazyAssignmentOperators: false,
+ Recover recover}) {
+ assert(source != null, 'source must not be null');
+ StringScanner scanner =
+ new StringScanner(source, includeComments: includeComments)
+ ..enableGtGtGt = true;
+ return _tokenizeAndRecover(scanner, recover, source: source);
+}
+
+/// TODO(danrubel): Remove this once support for `>>>` is permanently enabled.
+ScannerResult _tokenizeAndRecover(Scanner scanner, Recover recover,
+ {List<int> bytes, String source}) {
+ Token tokens = scanner.tokenize();
+ if (scanner.hasErrors) {
+ if (bytes == null) bytes = utf8.encode(source);
+ recover ??= defaultRecoveryStrategy;
+ tokens = recover(bytes, tokens, scanner.lineStarts);
+ }
+ return new ScannerResult(
+ tokens, scanner.lineStarts, scanner.hasErrors, scanner.errors);
+}
+
@reflectiveTest
class NoTypeInfoTest {
void test_basic() {
@@ -1250,6 +1283,39 @@
'handleType S',
'endTypeArguments 1 < >'
]);
+ expectComplexTypeArg('<S<T<U>>>', typeArgumentCount: 1, expectedCalls: [
+ 'beginTypeArguments <',
+ 'handleIdentifier S typeReference',
+ 'beginTypeArguments <',
+ 'handleIdentifier T typeReference',
+ 'beginTypeArguments <',
+ 'handleIdentifier U typeReference',
+ 'handleNoTypeArguments >>>',
+ 'handleType U',
+ 'endTypeArguments 1 < >',
+ 'handleType T',
+ 'endTypeArguments 1 < >',
+ 'handleType S',
+ 'endTypeArguments 1 < >'
+ ]);
+ expectComplexTypeArg('<S<T<U,V>>>', typeArgumentCount: 1, expectedCalls: [
+ 'beginTypeArguments <',
+ 'handleIdentifier S typeReference',
+ 'beginTypeArguments <',
+ 'handleIdentifier T typeReference',
+ 'beginTypeArguments <',
+ 'handleIdentifier U typeReference',
+ 'handleNoTypeArguments ,',
+ 'handleType U',
+ 'handleIdentifier V typeReference',
+ 'handleNoTypeArguments >>>',
+ 'handleType V',
+ 'endTypeArguments 2 < >',
+ 'handleType T',
+ 'endTypeArguments 1 < >',
+ 'handleType S',
+ 'endTypeArguments 1 < >'
+ ]);
expectComplexTypeArg('<S<Function()>>',
typeArgumentCount: 1,
expectedCalls: [
@@ -1299,6 +1365,26 @@
'handleType S',
'endTypeArguments 1 < >'
]);
+ expectComplexTypeArg('<S<T<void Function()>>>',
+ typeArgumentCount: 1,
+ expectedCalls: [
+ 'beginTypeArguments <',
+ 'handleIdentifier S typeReference',
+ 'beginTypeArguments <',
+ 'handleIdentifier T typeReference',
+ 'beginTypeArguments <',
+ 'handleNoTypeVariables (',
+ 'beginFunctionType void', // was 'beginFunctionType Function'
+ 'handleVoidKeyword void', // was 'handleNoType <'
+ 'beginFormalParameters ( MemberKind.GeneralizedFunctionType',
+ 'endFormalParameters 0 ( ) MemberKind.GeneralizedFunctionType',
+ 'endFunctionType Function',
+ 'endTypeArguments 1 < >',
+ 'handleType T',
+ 'endTypeArguments 1 < >',
+ 'handleType S',
+ 'endTypeArguments 1 < >'
+ ]);
}
void test_computeTypeArg_complex_recovery() {
@@ -1751,7 +1837,7 @@
'handleIdentifier List typeReference',
'beginTypeArguments <',
'handleIdentifier T typeReference',
- 'handleNoTypeArguments >',
+ 'handleNoTypeArguments >>>',
'handleType T',
'endTypeArguments 1 < >',
'handleType List',
@@ -1760,6 +1846,32 @@
'endTypeVariable > 0 extends',
'endTypeVariables < >'
]);
+ expectComplexTypeParam('<T extends List<Map<S, T>>>',
+ typeArgumentCount: 1,
+ expectedCalls: [
+ 'beginTypeVariables <',
+ 'beginMetadataStar T',
+ 'endMetadataStar 0',
+ 'handleIdentifier T typeVariableDeclaration',
+ 'beginTypeVariable T',
+ 'handleTypeVariablesDefined > 1',
+ 'handleIdentifier List typeReference',
+ 'beginTypeArguments <',
+ 'handleIdentifier Map typeReference',
+ 'beginTypeArguments <',
+ 'handleIdentifier S typeReference',
+ 'handleNoTypeArguments ,',
+ 'handleType S',
+ 'handleIdentifier T typeReference',
+ 'handleNoTypeArguments >>>',
+ 'handleType T',
+ 'endTypeArguments 2 < >',
+ 'handleType Map',
+ 'endTypeArguments 1 < >',
+ 'handleType List',
+ 'endTypeVariable > 0 extends',
+ 'endTypeVariables < >'
+ ]);
}
void test_computeTypeParam_34850() {
diff --git a/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart b/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
index ea0190d..9ae979a 100644
--- a/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
+++ b/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
@@ -6,6 +6,10 @@
import 'dart:io' show Directory, File;
import 'package:expect/expect.dart' show Expect;
+import 'package:front_end/src/compute_platform_binaries_location.dart'
+ show computePlatformBinariesLocation;
+import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
+import 'package:kernel/kernel.dart' show Component;
import 'incremental_load_from_dill_test.dart'
show normalCompile, initializedCompile, checkIsEqual;
@@ -35,6 +39,30 @@
Stopwatch stopwatch = new Stopwatch()..start();
await normalCompile(dart2jsUrl, normalDill);
print("Normal compile took ${stopwatch.elapsedMilliseconds} ms");
+ {
+ // Check that we don't include the source from files from the sdk.
+ final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
+ Uri platformUri = sdkRoot.resolve("vm_platform.dill");
+ Component cSdk = new Component();
+ new BinaryBuilder(new File.fromUri(platformUri).readAsBytesSync(),
+ disableLazyReading: false)
+ .readComponent(cSdk);
+
+ Component c = new Component();
+ new BinaryBuilder(new File.fromUri(normalDill).readAsBytesSync(),
+ disableLazyReading: false)
+ .readComponent(c);
+ for (Uri uri in c.uriToSource.keys) {
+ if (cSdk.uriToSource.containsKey(uri)) {
+ if ((c.uriToSource[uri].source?.length ?? 0) != 0) {
+ throw "Compile contained sources for the sdk $uri";
+ }
+ if ((c.uriToSource[uri].lineStarts?.length ?? 0) != 0) {
+ throw "Compile contained line starts for the sdk $uri";
+ }
+ }
+ }
+ }
// Compile dart2js, initializing from the just-compiled dill,
// a nonexisting file and a dill file that isn't valid.
diff --git a/pkg/front_end/testcases/bug34511.dart b/pkg/front_end/testcases/bug34511.dart
new file mode 100644
index 0000000..d8ad848
--- /dev/null
+++ b/pkg/front_end/testcases/bug34511.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// See http://dartbug.com/34511 for details.
+
+class A<X> {}
+
+class B<Z> extends Object with A<Z Function()> {}
+
+main() {}
diff --git a/pkg/front_end/testcases/bug34511.dart.legacy.expect b/pkg/front_end/testcases/bug34511.dart.legacy.expect
new file mode 100644
index 0000000..ebad4e6
--- /dev/null
+++ b/pkg/front_end/testcases/bug34511.dart.legacy.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ : super core::Object::•()
+ ;
+}
+abstract class _B&Object&A<Z extends core::Object = dynamic> = core::Object with self::A<() → self::_B&Object&A::Z> {
+ synthetic constructor •() → self::_B&Object&A<self::_B&Object&A::Z>
+ : super core::Object::•()
+ ;
+}
+class B<Z extends core::Object = dynamic> extends self::_B&Object&A<self::B::Z> {
+ synthetic constructor •() → self::B<self::B::Z>
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/bug34511.dart.legacy.transformed.expect b/pkg/front_end/testcases/bug34511.dart.legacy.transformed.expect
new file mode 100644
index 0000000..739a1e4
--- /dev/null
+++ b/pkg/front_end/testcases/bug34511.dart.legacy.transformed.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ : super core::Object::•()
+ ;
+}
+abstract class _B&Object&A<Z extends core::Object = dynamic> extends core::Object implements self::A<() → self::_B&Object&A::Z> {
+ synthetic constructor •() → self::_B&Object&A<self::_B&Object&A::Z>
+ : super core::Object::•()
+ ;
+}
+class B<Z extends core::Object = dynamic> extends self::_B&Object&A<self::B::Z> {
+ synthetic constructor •() → self::B<self::B::Z>
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/bug34511.dart.outline.expect b/pkg/front_end/testcases/bug34511.dart.outline.expect
new file mode 100644
index 0000000..0291dc5
--- /dev/null
+++ b/pkg/front_end/testcases/bug34511.dart.outline.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ ;
+}
+abstract class _B&Object&A<Z extends core::Object = dynamic> = core::Object with self::A<() → self::_B&Object&A::Z> {
+ synthetic constructor •() → self::_B&Object&A<self::_B&Object&A::Z>
+ : super core::Object::•()
+ ;
+}
+class B<Z extends core::Object = dynamic> extends self::_B&Object&A<self::B::Z> {
+ synthetic constructor •() → self::B<self::B::Z>
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/bug34511.dart.strong.expect b/pkg/front_end/testcases/bug34511.dart.strong.expect
new file mode 100644
index 0000000..ebad4e6
--- /dev/null
+++ b/pkg/front_end/testcases/bug34511.dart.strong.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ : super core::Object::•()
+ ;
+}
+abstract class _B&Object&A<Z extends core::Object = dynamic> = core::Object with self::A<() → self::_B&Object&A::Z> {
+ synthetic constructor •() → self::_B&Object&A<self::_B&Object&A::Z>
+ : super core::Object::•()
+ ;
+}
+class B<Z extends core::Object = dynamic> extends self::_B&Object&A<self::B::Z> {
+ synthetic constructor •() → self::B<self::B::Z>
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/bug34511.dart.strong.transformed.expect b/pkg/front_end/testcases/bug34511.dart.strong.transformed.expect
new file mode 100644
index 0000000..739a1e4
--- /dev/null
+++ b/pkg/front_end/testcases/bug34511.dart.strong.transformed.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ : super core::Object::•()
+ ;
+}
+abstract class _B&Object&A<Z extends core::Object = dynamic> extends core::Object implements self::A<() → self::_B&Object&A::Z> {
+ synthetic constructor •() → self::_B&Object&A<self::_B&Object&A::Z>
+ : super core::Object::•()
+ ;
+}
+class B<Z extends core::Object = dynamic> extends self::_B&Object&A<self::B::Z> {
+ synthetic constructor •() → self::B<self::B::Z>
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/clone_function_type.dart b/pkg/front_end/testcases/clone_function_type.dart
new file mode 100644
index 0000000..fd1d81e
--- /dev/null
+++ b/pkg/front_end/testcases/clone_function_type.dart
@@ -0,0 +1,258 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// In the classes below the function type is cloned when the anonymous mixin
+// application is desugared into a named mixin application, in order to re-bind
+// the type builders for its subterms.
+
+// The case 'm1' covers function types with some missing parts.
+
+class Am1<X, Y> {}
+
+class Bm1<Z> extends Object with Am1<Function(int), Z> {}
+
+class Cm1<Z> extends Object with Am1<Function(int x), Z> {}
+
+class Dm1<Z> extends Object with Am1<int Function(), Z> {}
+
+class Em1<Z> extends Object with Am1<Function(), Z> {}
+
+// Compile-time error: Named parameters should have names.
+class Fm1<Z> extends Object with Am1<Function({int}), Z> {}
+
+class Gm1<Z> extends Object with Am1<Function({int x}), Z> {}
+
+class Hm1<Z> extends Object with Am1<Function([int]), Z> {}
+
+class Im1<Z> extends Object with Am1<Function([int x]), Z> {}
+
+class Jm1<Z> extends Object with Am1<Function, Z> {}
+
+class Km1<Z> extends Object with Am1<Function(Function Function), Z> {}
+
+class Lm1<Z> extends Object
+ with Am1<Function(Function Function() Function) Function(), Z> {}
+
+class Mm1<Z> = Object with Am1<Function(int), Z>;
+
+class Nm1<Z> = Object with Am1<Function(int x), Z>;
+
+class Om1<Z> = Object with Am1<int Function(), Z>;
+
+class Pm1<Z> = Object with Am1<Function(), Z>;
+
+// Compile-time error: Named parameters should have names.
+class Qm1<Z> = Object with Am1<Function({int}), Z>;
+
+class Rm1<Z> = Object with Am1<Function({int x}), Z>;
+
+class Sm1<Z> = Object with Am1<Function([int]), Z>;
+
+class Tm1<Z> = Object with Am1<Function([int x]), Z>;
+
+class Um1<Z> = Object with Am1<Function, Z>;
+
+class Vm1<Z> = Object with Am1<Function(Function Function), Z>;
+
+class Wm1<Z> = Object
+ with Am1<Function(Function Function() Function) Function(), Z>;
+
+// The case 'm2' covers function types with some missing parts that should be
+// checked against a bound.
+
+class Am2<X extends Function(), Y> {}
+
+// Compile-time error: type argument is not a subtype.
+class Bm2<Z> extends Object with Am2<Function(int), Z> {}
+
+// Compile-time error: type argument is not a subtype.
+class Cm2<Z> extends Object with Am2<Function(int x), Z> {}
+
+class Dm2<Z> extends Object with Am2<int Function(), Z> {}
+
+class Em2<Z> extends Object with Am2<Function(), Z> {}
+
+// Compile-time error: Named parameters should have names.
+class Fm2<Z> extends Object with Am2<Function({int}), Z> {}
+
+class Gm2<Z> extends Object with Am2<Function({int x}), Z> {}
+
+class Hm2<Z> extends Object with Am2<Function([int]), Z> {}
+
+class Im2<Z> extends Object with Am2<Function([int x]), Z> {}
+
+// Compile-time error: type argument is not a subtype.
+class Jm2<Z> extends Object with Am2<Function, Z> {}
+
+// Compile-time error: type argument is not a subtype.
+class Km2<Z> extends Object with Am2<Function(Function Function), Z> {}
+
+class Lm2<Z> extends Object
+ with Am2<Function(Function Function() Function) Function(), Z> {}
+
+// Compile-time error: type argument is not a subtype.
+class Mm2<Z> = Object with Am2<Function(int), Z>;
+
+// Compile-time error: type argument is not a subtype.
+class Nm2<Z> = Object with Am2<Function(int x), Z>;
+
+class Om2<Z> = Object with Am2<int Function(), Z>;
+
+class Pm2<Z> = Object with Am2<Function(), Z>;
+
+// Compile-time error: Named parameters should have names.
+class Qm2<Z> = Object with Am2<Function({int}), Z>;
+
+class Rm2<Z> = Object with Am2<Function({int x}), Z>;
+
+class Sm2<Z> = Object with Am2<Function([int]), Z>;
+
+class Tm2<Z> = Object with Am2<Function([int x]), Z>;
+
+// Compile-time error: type argument is not a subtype.
+class Um2<Z> = Object with Am2<Function, Z>;
+
+// Compile-time error: type argument is not a subtype.
+class Vm2<Z> = Object with Am2<Function(Function Function), Z>;
+
+class Wm2<Z> = Object
+ with Am2<Function(Function Function() Function) Function(), Z>;
+
+// The case 'm3' covers function types with some missing parts defined via
+// typedefs.
+
+typedef TdB = Function(int);
+
+typedef TdC = Function(int x);
+
+typedef TdD = int Function();
+
+typedef TdE = Function();
+
+// Compile-time error: Named parameters should have names.
+typedef TdF = Function({int});
+
+typedef TdG = Function({int x});
+
+typedef TdH = Function([int]);
+
+typedef TdI = Function([int x]);
+
+typedef TdJ = Function(Function Function);
+
+typedef TdK = Function(Function Function() Function) Function();
+
+class Am3<L, Y> {}
+
+class Bm3<Z> extends Object with Am3<TdB, Z> {}
+
+class Cm3<Z> extends Object with Am3<TdC, Z> {}
+
+class Dm3<Z> extends Object with Am3<TdD, Z> {}
+
+class Em3<Z> extends Object with Am3<TdE, Z> {}
+
+class Fm3<Z> extends Object with Am3<TdF, Z> {}
+
+class Gm3<Z> extends Object with Am3<TdG, Z> {}
+
+class Hm3<Z> extends Object with Am3<TdH, Z> {}
+
+class Im3<Z> extends Object with Am3<TdI, Z> {}
+
+class Jm3<Z> extends Object with Am3<TdJ, Z> {}
+
+class Km3<Z> extends Object with Am3<TdK, Z> {}
+
+// In case cloning will not be used in the examples above, here are some
+// examples that should utilize cloning of type builders and that should cover
+// some of the cases above. Here, type variables of the class are cloned for
+// its factories, including the bounds that are type builders.
+
+class Af1<X extends Function(int)> {
+ factory Af1.foo() => null;
+}
+
+class Bf1<X extends Function(int x)> {
+ factory Bf1.foo() => null;
+}
+
+class Cf1<X extends int Function()> {
+ factory Cf1.foo() => null;
+}
+
+class Df1<X extends Function()> {
+ factory Df1.foo() => null;
+}
+
+// Compile-time error: Named parameters should have names.
+class Ef1<X extends Function({int})> {
+ factory Ef1.foo() => null;
+}
+
+class Ff1<X extends Function({int x})> {
+ factory Ff1.foo() => null;
+}
+
+class Gf1<X extends Function([int])> {
+ factory Gf1.foo() => null;
+}
+
+class Hf1<X extends Function([int x])> {
+ factory Hf1.foo() => null;
+}
+
+class If1<X extends Function> {
+ factory If1.foo() => null;
+}
+
+class Jf1<X extends Function(Function Function)> {
+ factory Jf1.foo() => null;
+}
+
+class Kf1<X extends Function(Function Function() Function) Function()> {
+ factory Kf1.foo() => null;
+}
+
+class Bf2<X extends TdB> {
+ factory Bf2.foo() => null;
+}
+
+class Cf2<X extends TdC> {
+ factory Cf2.foo() => null;
+}
+
+class Df2<X extends TdD> {
+ factory Df2.foo() => null;
+}
+
+class Ef2<X extends TdE> {
+ factory Ef2.foo() => null;
+}
+
+class Ff2<X extends TdF> {
+ factory Ff2.foo() => null;
+}
+
+class Gf2<X extends TdG> {
+ factory Gf2.foo() => null;
+}
+
+class Hf2<X extends TdH> {
+ factory Hf2.foo() => null;
+}
+
+class If2<X extends TdI> {
+ factory If2.foo() => null;
+}
+
+class Jf2<X extends TdJ> {
+ factory Jf2.foo() => null;
+}
+
+class Kf2<X extends TdK> {
+ factory Kf2.foo() => null;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/clone_function_type.dart.legacy.expect b/pkg/front_end/testcases/clone_function_type.dart.legacy.expect
new file mode 100644
index 0000000..a1b55e6
--- /dev/null
+++ b/pkg/front_end/testcases/clone_function_type.dart.legacy.expect
@@ -0,0 +1,596 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/clone_function_type.dart:22:51: Error: Expected an identifier, but got '}'.
+// class Fm1<Z> extends Object with Am1<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:46:45: Error: Expected an identifier, but got '}'.
+// class Qm1<Z> = Object with Am1<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:77:51: Error: Expected an identifier, but got '}'.
+// class Fm2<Z> extends Object with Am2<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:105:45: Error: Expected an identifier, but got '}'.
+// class Qm2<Z> = Object with Am2<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:134:28: Error: Expected an identifier, but got '}'.
+// typedef TdF = Function({int});
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:190:34: Error: Expected an identifier, but got '}'.
+// class Ef1<X extends Function({int})> {
+// ^
+
+// Unhandled errors:
+//
+// pkg/front_end/testcases/clone_function_type.dart:22:51: Error: Expected an identifier, but got '}'.
+// class Fm1<Z> extends Object with Am1<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:46:45: Error: Expected an identifier, but got '}'.
+// class Qm1<Z> = Object with Am1<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:77:51: Error: Expected an identifier, but got '}'.
+// class Fm2<Z> extends Object with Am2<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:105:45: Error: Expected an identifier, but got '}'.
+// class Qm2<Z> = Object with Am2<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:134:28: Error: Expected an identifier, but got '}'.
+// typedef TdF = Function({int});
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:190:34: Error: Expected an identifier, but got '}'.
+// class Ef1<X extends Function({int})> {
+// ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef TdB = (core::int) → dynamic;
+typedef TdC = (core::int) → dynamic;
+typedef TdD = () → core::int;
+typedef TdE = () → dynamic;
+typedef TdF = () → dynamic;
+typedef TdG = ({x: core::int}) → dynamic;
+typedef TdH = ([core::int]) → dynamic;
+typedef TdI = ([core::int]) → dynamic;
+typedef TdJ = (core::Function) → dynamic;
+typedef TdK = () → (() → core::Function) → dynamic;
+class Am1<X extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am1<self::Am1::X, self::Am1::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::_Bm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Bm1&Object&Am1<self::_Bm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm1<Z extends core::Object = dynamic> extends self::_Bm1&Object&Am1<self::Bm1::Z> {
+ synthetic constructor •() → self::Bm1<self::Bm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::_Cm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Cm1&Object&Am1<self::_Cm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm1<Z extends core::Object = dynamic> extends self::_Cm1&Object&Am1<self::Cm1::Z> {
+ synthetic constructor •() → self::Cm1<self::Cm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → core::int, self::_Dm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Dm1&Object&Am1<self::_Dm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm1<Z extends core::Object = dynamic> extends self::_Dm1&Object&Am1<self::Dm1::Z> {
+ synthetic constructor •() → self::Dm1<self::Dm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::_Em1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Em1&Object&Am1<self::_Em1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Em1<Z extends core::Object = dynamic> extends self::_Em1&Object&Am1<self::Em1::Z> {
+ synthetic constructor •() → self::Em1<self::Em1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::_Fm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Fm1&Object&Am1<self::_Fm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm1<Z extends core::Object = dynamic> extends self::_Fm1&Object&Am1<self::Fm1::Z> {
+ synthetic constructor •() → self::Fm1<self::Fm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<({x: core::int}) → dynamic, self::_Gm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Gm1&Object&Am1<self::_Gm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm1<Z extends core::Object = dynamic> extends self::_Gm1&Object&Am1<self::Gm1::Z> {
+ synthetic constructor •() → self::Gm1<self::Gm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::_Hm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Hm1&Object&Am1<self::_Hm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm1<Z extends core::Object = dynamic> extends self::_Hm1&Object&Am1<self::Hm1::Z> {
+ synthetic constructor •() → self::Hm1<self::Hm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::_Im1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Im1&Object&Am1<self::_Im1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Im1<Z extends core::Object = dynamic> extends self::_Im1&Object&Am1<self::Im1::Z> {
+ synthetic constructor •() → self::Im1<self::Im1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<core::Function, self::_Jm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Jm1&Object&Am1<self::_Jm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm1<Z extends core::Object = dynamic> extends self::_Jm1&Object&Am1<self::Jm1::Z> {
+ synthetic constructor •() → self::Jm1<self::Jm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::Function) → dynamic, self::_Km1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Km1&Object&Am1<self::_Km1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Km1<Z extends core::Object = dynamic> extends self::_Km1&Object&Am1<self::Km1::Z> {
+ synthetic constructor •() → self::Km1<self::Km1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Lm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → (() → core::Function) → dynamic, self::_Lm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Lm1&Object&Am1<self::_Lm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm1<Z extends core::Object = dynamic> extends self::_Lm1&Object&Am1<self::Lm1::Z> {
+ synthetic constructor •() → self::Lm1<self::Lm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Mm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::Mm1::Z> {
+ synthetic constructor •() → self::Mm1<self::Mm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::Nm1::Z> {
+ synthetic constructor •() → self::Nm1<self::Nm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Om1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → core::int, self::Om1::Z> {
+ synthetic constructor •() → self::Om1<self::Om1::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::Pm1::Z> {
+ synthetic constructor •() → self::Pm1<self::Pm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::Qm1::Z> {
+ synthetic constructor •() → self::Qm1<self::Qm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm1<Z extends core::Object = dynamic> = core::Object with self::Am1<({x: core::int}) → dynamic, self::Rm1::Z> {
+ synthetic constructor •() → self::Rm1<self::Rm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::Sm1::Z> {
+ synthetic constructor •() → self::Sm1<self::Sm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::Tm1::Z> {
+ synthetic constructor •() → self::Tm1<self::Tm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Um1<Z extends core::Object = dynamic> = core::Object with self::Am1<core::Function, self::Um1::Z> {
+ synthetic constructor •() → self::Um1<self::Um1::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::Function) → dynamic, self::Vm1::Z> {
+ synthetic constructor •() → self::Vm1<self::Vm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → (() → core::Function) → dynamic, self::Wm1::Z> {
+ synthetic constructor •() → self::Wm1<self::Wm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Am2<X extends () → dynamic = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am2<self::Am2::X, self::Am2::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::_Bm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Bm2&Object&Am2<self::_Bm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm2<Z extends core::Object = dynamic> extends self::_Bm2&Object&Am2<self::Bm2::Z> {
+ synthetic constructor •() → self::Bm2<self::Bm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::_Cm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Cm2&Object&Am2<self::_Cm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm2<Z extends core::Object = dynamic> extends self::_Cm2&Object&Am2<self::Cm2::Z> {
+ synthetic constructor •() → self::Cm2<self::Cm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → core::int, self::_Dm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Dm2&Object&Am2<self::_Dm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm2<Z extends core::Object = dynamic> extends self::_Dm2&Object&Am2<self::Dm2::Z> {
+ synthetic constructor •() → self::Dm2<self::Dm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::_Em2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Em2&Object&Am2<self::_Em2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Em2<Z extends core::Object = dynamic> extends self::_Em2&Object&Am2<self::Em2::Z> {
+ synthetic constructor •() → self::Em2<self::Em2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::_Fm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Fm2&Object&Am2<self::_Fm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm2<Z extends core::Object = dynamic> extends self::_Fm2&Object&Am2<self::Fm2::Z> {
+ synthetic constructor •() → self::Fm2<self::Fm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<({x: core::int}) → dynamic, self::_Gm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Gm2&Object&Am2<self::_Gm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm2<Z extends core::Object = dynamic> extends self::_Gm2&Object&Am2<self::Gm2::Z> {
+ synthetic constructor •() → self::Gm2<self::Gm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::_Hm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Hm2&Object&Am2<self::_Hm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm2<Z extends core::Object = dynamic> extends self::_Hm2&Object&Am2<self::Hm2::Z> {
+ synthetic constructor •() → self::Hm2<self::Hm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::_Im2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Im2&Object&Am2<self::_Im2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Im2<Z extends core::Object = dynamic> extends self::_Im2&Object&Am2<self::Im2::Z> {
+ synthetic constructor •() → self::Im2<self::Im2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<core::Function, self::_Jm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Jm2&Object&Am2<self::_Jm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm2<Z extends core::Object = dynamic> extends self::_Jm2&Object&Am2<self::Jm2::Z> {
+ synthetic constructor •() → self::Jm2<self::Jm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::Function) → dynamic, self::_Km2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Km2&Object&Am2<self::_Km2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Km2<Z extends core::Object = dynamic> extends self::_Km2&Object&Am2<self::Km2::Z> {
+ synthetic constructor •() → self::Km2<self::Km2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Lm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → (() → core::Function) → dynamic, self::_Lm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Lm2&Object&Am2<self::_Lm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm2<Z extends core::Object = dynamic> extends self::_Lm2&Object&Am2<self::Lm2::Z> {
+ synthetic constructor •() → self::Lm2<self::Lm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Mm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::Mm2::Z> {
+ synthetic constructor •() → self::Mm2<self::Mm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::Nm2::Z> {
+ synthetic constructor •() → self::Nm2<self::Nm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Om2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → core::int, self::Om2::Z> {
+ synthetic constructor •() → self::Om2<self::Om2::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::Pm2::Z> {
+ synthetic constructor •() → self::Pm2<self::Pm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::Qm2::Z> {
+ synthetic constructor •() → self::Qm2<self::Qm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm2<Z extends core::Object = dynamic> = core::Object with self::Am2<({x: core::int}) → dynamic, self::Rm2::Z> {
+ synthetic constructor •() → self::Rm2<self::Rm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::Sm2::Z> {
+ synthetic constructor •() → self::Sm2<self::Sm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::Tm2::Z> {
+ synthetic constructor •() → self::Tm2<self::Tm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Um2<Z extends core::Object = dynamic> = core::Object with self::Am2<core::Function, self::Um2::Z> {
+ synthetic constructor •() → self::Um2<self::Um2::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::Function) → dynamic, self::Vm2::Z> {
+ synthetic constructor •() → self::Vm2<self::Vm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → (() → core::Function) → dynamic, self::Wm2::Z> {
+ synthetic constructor •() → self::Wm2<self::Wm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Am3<L extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am3<self::Am3::L, self::Am3::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::int) → dynamic, self::_Bm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Bm3&Object&Am3<self::_Bm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm3<Z extends core::Object = dynamic> extends self::_Bm3&Object&Am3<self::Bm3::Z> {
+ synthetic constructor •() → self::Bm3<self::Bm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::int) → dynamic, self::_Cm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Cm3&Object&Am3<self::_Cm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm3<Z extends core::Object = dynamic> extends self::_Cm3&Object&Am3<self::Cm3::Z> {
+ synthetic constructor •() → self::Cm3<self::Cm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → core::int, self::_Dm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Dm3&Object&Am3<self::_Dm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm3<Z extends core::Object = dynamic> extends self::_Dm3&Object&Am3<self::Dm3::Z> {
+ synthetic constructor •() → self::Dm3<self::Dm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → dynamic, self::_Em3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Em3&Object&Am3<self::_Em3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Em3<Z extends core::Object = dynamic> extends self::_Em3&Object&Am3<self::Em3::Z> {
+ synthetic constructor •() → self::Em3<self::Em3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → dynamic, self::_Fm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Fm3&Object&Am3<self::_Fm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm3<Z extends core::Object = dynamic> extends self::_Fm3&Object&Am3<self::Fm3::Z> {
+ synthetic constructor •() → self::Fm3<self::Fm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<({x: core::int}) → dynamic, self::_Gm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Gm3&Object&Am3<self::_Gm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm3<Z extends core::Object = dynamic> extends self::_Gm3&Object&Am3<self::Gm3::Z> {
+ synthetic constructor •() → self::Gm3<self::Gm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<([core::int]) → dynamic, self::_Hm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Hm3&Object&Am3<self::_Hm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm3<Z extends core::Object = dynamic> extends self::_Hm3&Object&Am3<self::Hm3::Z> {
+ synthetic constructor •() → self::Hm3<self::Hm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<([core::int]) → dynamic, self::_Im3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Im3&Object&Am3<self::_Im3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Im3<Z extends core::Object = dynamic> extends self::_Im3&Object&Am3<self::Im3::Z> {
+ synthetic constructor •() → self::Im3<self::Im3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::Function) → dynamic, self::_Jm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Jm3&Object&Am3<self::_Jm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm3<Z extends core::Object = dynamic> extends self::_Jm3&Object&Am3<self::Jm3::Z> {
+ synthetic constructor •() → self::Jm3<self::Jm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → (() → core::Function) → dynamic, self::_Km3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Km3&Object&Am3<self::_Km3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Km3<Z extends core::Object = dynamic> extends self::_Km3&Object&Am3<self::Km3::Z> {
+ synthetic constructor •() → self::Km3<self::Km3::Z>
+ : super core::Object::•()
+ ;
+}
+class Af1<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Af1<self::Af1::foo::X>
+ return null;
+}
+class Bf1<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf1<self::Bf1::foo::X>
+ return null;
+}
+class Cf1<X extends () → core::int = dynamic> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Cf1<self::Cf1::foo::X>
+ return null;
+}
+class Df1<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Df1<self::Df1::foo::X>
+ return null;
+}
+class Ef1<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef1<self::Ef1::foo::X>
+ return null;
+}
+class Ff1<X extends ({x: core::int}) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Ff1<self::Ff1::foo::X>
+ return null;
+}
+class Gf1<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Gf1<self::Gf1::foo::X>
+ return null;
+}
+class Hf1<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf1<self::Hf1::foo::X>
+ return null;
+}
+class If1<X extends core::Function = dynamic> extends core::Object {
+ static factory foo<X extends core::Function = dynamic>() → self::If1<self::If1::foo::X>
+ return null;
+}
+class Jf1<X extends (core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf1<self::Jf1::foo::X>
+ return null;
+}
+class Kf1<X extends () → (() → core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf1<self::Kf1::foo::X>
+ return null;
+}
+class Bf2<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf2<self::Bf2::foo::X>
+ return null;
+}
+class Cf2<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Cf2<self::Cf2::foo::X>
+ return null;
+}
+class Df2<X extends () → core::int = dynamic> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Df2<self::Df2::foo::X>
+ return null;
+}
+class Ef2<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef2<self::Ef2::foo::X>
+ return null;
+}
+class Ff2<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ff2<self::Ff2::foo::X>
+ return null;
+}
+class Gf2<X extends ({x: core::int}) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Gf2<self::Gf2::foo::X>
+ return null;
+}
+class Hf2<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf2<self::Hf2::foo::X>
+ return null;
+}
+class If2<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::If2<self::If2::foo::X>
+ return null;
+}
+class Jf2<X extends (core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf2<self::Jf2::foo::X>
+ return null;
+}
+class Kf2<X extends () → (() → core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf2<self::Kf2::foo::X>
+ return null;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/clone_function_type.dart.legacy.transformed.expect b/pkg/front_end/testcases/clone_function_type.dart.legacy.transformed.expect
new file mode 100644
index 0000000..8508c16
--- /dev/null
+++ b/pkg/front_end/testcases/clone_function_type.dart.legacy.transformed.expect
@@ -0,0 +1,570 @@
+// Unhandled errors:
+//
+// pkg/front_end/testcases/clone_function_type.dart:22:51: Error: Expected an identifier, but got '}'.
+// class Fm1<Z> extends Object with Am1<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:46:45: Error: Expected an identifier, but got '}'.
+// class Qm1<Z> = Object with Am1<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:77:51: Error: Expected an identifier, but got '}'.
+// class Fm2<Z> extends Object with Am2<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:105:45: Error: Expected an identifier, but got '}'.
+// class Qm2<Z> = Object with Am2<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:134:28: Error: Expected an identifier, but got '}'.
+// typedef TdF = Function({int});
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:190:34: Error: Expected an identifier, but got '}'.
+// class Ef1<X extends Function({int})> {
+// ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef TdB = (core::int) → dynamic;
+typedef TdC = (core::int) → dynamic;
+typedef TdD = () → core::int;
+typedef TdE = () → dynamic;
+typedef TdF = () → dynamic;
+typedef TdG = ({x: core::int}) → dynamic;
+typedef TdH = ([core::int]) → dynamic;
+typedef TdI = ([core::int]) → dynamic;
+typedef TdJ = (core::Function) → dynamic;
+typedef TdK = () → (() → core::Function) → dynamic;
+class Am1<X extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am1<self::Am1::X, self::Am1::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::int) → dynamic, self::_Bm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Bm1&Object&Am1<self::_Bm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm1<Z extends core::Object = dynamic> extends self::_Bm1&Object&Am1<self::Bm1::Z> {
+ synthetic constructor •() → self::Bm1<self::Bm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::int) → dynamic, self::_Cm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Cm1&Object&Am1<self::_Cm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm1<Z extends core::Object = dynamic> extends self::_Cm1&Object&Am1<self::Cm1::Z> {
+ synthetic constructor •() → self::Cm1<self::Cm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → core::int, self::_Dm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Dm1&Object&Am1<self::_Dm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm1<Z extends core::Object = dynamic> extends self::_Dm1&Object&Am1<self::Dm1::Z> {
+ synthetic constructor •() → self::Dm1<self::Dm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → dynamic, self::_Em1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Em1&Object&Am1<self::_Em1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Em1<Z extends core::Object = dynamic> extends self::_Em1&Object&Am1<self::Em1::Z> {
+ synthetic constructor •() → self::Em1<self::Em1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → dynamic, self::_Fm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Fm1&Object&Am1<self::_Fm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm1<Z extends core::Object = dynamic> extends self::_Fm1&Object&Am1<self::Fm1::Z> {
+ synthetic constructor •() → self::Fm1<self::Fm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<({x: core::int}) → dynamic, self::_Gm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Gm1&Object&Am1<self::_Gm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm1<Z extends core::Object = dynamic> extends self::_Gm1&Object&Am1<self::Gm1::Z> {
+ synthetic constructor •() → self::Gm1<self::Gm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<([core::int]) → dynamic, self::_Hm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Hm1&Object&Am1<self::_Hm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm1<Z extends core::Object = dynamic> extends self::_Hm1&Object&Am1<self::Hm1::Z> {
+ synthetic constructor •() → self::Hm1<self::Hm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<([core::int]) → dynamic, self::_Im1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Im1&Object&Am1<self::_Im1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Im1<Z extends core::Object = dynamic> extends self::_Im1&Object&Am1<self::Im1::Z> {
+ synthetic constructor •() → self::Im1<self::Im1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<core::Function, self::_Jm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Jm1&Object&Am1<self::_Jm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm1<Z extends core::Object = dynamic> extends self::_Jm1&Object&Am1<self::Jm1::Z> {
+ synthetic constructor •() → self::Jm1<self::Jm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::Function) → dynamic, self::_Km1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Km1&Object&Am1<self::_Km1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Km1<Z extends core::Object = dynamic> extends self::_Km1&Object&Am1<self::Km1::Z> {
+ synthetic constructor •() → self::Km1<self::Km1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Lm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → (() → core::Function) → dynamic, self::_Lm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Lm1&Object&Am1<self::_Lm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm1<Z extends core::Object = dynamic> extends self::_Lm1&Object&Am1<self::Lm1::Z> {
+ synthetic constructor •() → self::Lm1<self::Lm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Mm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::int) → dynamic, self::Mm1::Z> {
+ synthetic constructor •() → self::Mm1<self::Mm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::int) → dynamic, self::Nm1::Z> {
+ synthetic constructor •() → self::Nm1<self::Nm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Om1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → core::int, self::Om1::Z> {
+ synthetic constructor •() → self::Om1<self::Om1::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → dynamic, self::Pm1::Z> {
+ synthetic constructor •() → self::Pm1<self::Pm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → dynamic, self::Qm1::Z> {
+ synthetic constructor •() → self::Qm1<self::Qm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<({x: core::int}) → dynamic, self::Rm1::Z> {
+ synthetic constructor •() → self::Rm1<self::Rm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<([core::int]) → dynamic, self::Sm1::Z> {
+ synthetic constructor •() → self::Sm1<self::Sm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<([core::int]) → dynamic, self::Tm1::Z> {
+ synthetic constructor •() → self::Tm1<self::Tm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Um1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<core::Function, self::Um1::Z> {
+ synthetic constructor •() → self::Um1<self::Um1::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::Function) → dynamic, self::Vm1::Z> {
+ synthetic constructor •() → self::Vm1<self::Vm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → (() → core::Function) → dynamic, self::Wm1::Z> {
+ synthetic constructor •() → self::Wm1<self::Wm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Am2<X extends () → dynamic = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am2<self::Am2::X, self::Am2::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::int) → dynamic, self::_Bm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Bm2&Object&Am2<self::_Bm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm2<Z extends core::Object = dynamic> extends self::_Bm2&Object&Am2<self::Bm2::Z> {
+ synthetic constructor •() → self::Bm2<self::Bm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::int) → dynamic, self::_Cm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Cm2&Object&Am2<self::_Cm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm2<Z extends core::Object = dynamic> extends self::_Cm2&Object&Am2<self::Cm2::Z> {
+ synthetic constructor •() → self::Cm2<self::Cm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → core::int, self::_Dm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Dm2&Object&Am2<self::_Dm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm2<Z extends core::Object = dynamic> extends self::_Dm2&Object&Am2<self::Dm2::Z> {
+ synthetic constructor •() → self::Dm2<self::Dm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → dynamic, self::_Em2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Em2&Object&Am2<self::_Em2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Em2<Z extends core::Object = dynamic> extends self::_Em2&Object&Am2<self::Em2::Z> {
+ synthetic constructor •() → self::Em2<self::Em2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → dynamic, self::_Fm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Fm2&Object&Am2<self::_Fm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm2<Z extends core::Object = dynamic> extends self::_Fm2&Object&Am2<self::Fm2::Z> {
+ synthetic constructor •() → self::Fm2<self::Fm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<({x: core::int}) → dynamic, self::_Gm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Gm2&Object&Am2<self::_Gm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm2<Z extends core::Object = dynamic> extends self::_Gm2&Object&Am2<self::Gm2::Z> {
+ synthetic constructor •() → self::Gm2<self::Gm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<([core::int]) → dynamic, self::_Hm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Hm2&Object&Am2<self::_Hm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm2<Z extends core::Object = dynamic> extends self::_Hm2&Object&Am2<self::Hm2::Z> {
+ synthetic constructor •() → self::Hm2<self::Hm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<([core::int]) → dynamic, self::_Im2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Im2&Object&Am2<self::_Im2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Im2<Z extends core::Object = dynamic> extends self::_Im2&Object&Am2<self::Im2::Z> {
+ synthetic constructor •() → self::Im2<self::Im2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<core::Function, self::_Jm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Jm2&Object&Am2<self::_Jm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm2<Z extends core::Object = dynamic> extends self::_Jm2&Object&Am2<self::Jm2::Z> {
+ synthetic constructor •() → self::Jm2<self::Jm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::Function) → dynamic, self::_Km2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Km2&Object&Am2<self::_Km2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Km2<Z extends core::Object = dynamic> extends self::_Km2&Object&Am2<self::Km2::Z> {
+ synthetic constructor •() → self::Km2<self::Km2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Lm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → (() → core::Function) → dynamic, self::_Lm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Lm2&Object&Am2<self::_Lm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm2<Z extends core::Object = dynamic> extends self::_Lm2&Object&Am2<self::Lm2::Z> {
+ synthetic constructor •() → self::Lm2<self::Lm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Mm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::int) → dynamic, self::Mm2::Z> {
+ synthetic constructor •() → self::Mm2<self::Mm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::int) → dynamic, self::Nm2::Z> {
+ synthetic constructor •() → self::Nm2<self::Nm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Om2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → core::int, self::Om2::Z> {
+ synthetic constructor •() → self::Om2<self::Om2::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → dynamic, self::Pm2::Z> {
+ synthetic constructor •() → self::Pm2<self::Pm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → dynamic, self::Qm2::Z> {
+ synthetic constructor •() → self::Qm2<self::Qm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<({x: core::int}) → dynamic, self::Rm2::Z> {
+ synthetic constructor •() → self::Rm2<self::Rm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<([core::int]) → dynamic, self::Sm2::Z> {
+ synthetic constructor •() → self::Sm2<self::Sm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<([core::int]) → dynamic, self::Tm2::Z> {
+ synthetic constructor •() → self::Tm2<self::Tm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Um2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<core::Function, self::Um2::Z> {
+ synthetic constructor •() → self::Um2<self::Um2::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::Function) → dynamic, self::Vm2::Z> {
+ synthetic constructor •() → self::Vm2<self::Vm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → (() → core::Function) → dynamic, self::Wm2::Z> {
+ synthetic constructor •() → self::Wm2<self::Wm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Am3<L extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am3<self::Am3::L, self::Am3::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<(core::int) → dynamic, self::_Bm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Bm3&Object&Am3<self::_Bm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm3<Z extends core::Object = dynamic> extends self::_Bm3&Object&Am3<self::Bm3::Z> {
+ synthetic constructor •() → self::Bm3<self::Bm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<(core::int) → dynamic, self::_Cm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Cm3&Object&Am3<self::_Cm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm3<Z extends core::Object = dynamic> extends self::_Cm3&Object&Am3<self::Cm3::Z> {
+ synthetic constructor •() → self::Cm3<self::Cm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<() → core::int, self::_Dm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Dm3&Object&Am3<self::_Dm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm3<Z extends core::Object = dynamic> extends self::_Dm3&Object&Am3<self::Dm3::Z> {
+ synthetic constructor •() → self::Dm3<self::Dm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<() → dynamic, self::_Em3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Em3&Object&Am3<self::_Em3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Em3<Z extends core::Object = dynamic> extends self::_Em3&Object&Am3<self::Em3::Z> {
+ synthetic constructor •() → self::Em3<self::Em3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<() → dynamic, self::_Fm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Fm3&Object&Am3<self::_Fm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm3<Z extends core::Object = dynamic> extends self::_Fm3&Object&Am3<self::Fm3::Z> {
+ synthetic constructor •() → self::Fm3<self::Fm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<({x: core::int}) → dynamic, self::_Gm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Gm3&Object&Am3<self::_Gm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm3<Z extends core::Object = dynamic> extends self::_Gm3&Object&Am3<self::Gm3::Z> {
+ synthetic constructor •() → self::Gm3<self::Gm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<([core::int]) → dynamic, self::_Hm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Hm3&Object&Am3<self::_Hm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm3<Z extends core::Object = dynamic> extends self::_Hm3&Object&Am3<self::Hm3::Z> {
+ synthetic constructor •() → self::Hm3<self::Hm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<([core::int]) → dynamic, self::_Im3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Im3&Object&Am3<self::_Im3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Im3<Z extends core::Object = dynamic> extends self::_Im3&Object&Am3<self::Im3::Z> {
+ synthetic constructor •() → self::Im3<self::Im3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<(core::Function) → dynamic, self::_Jm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Jm3&Object&Am3<self::_Jm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm3<Z extends core::Object = dynamic> extends self::_Jm3&Object&Am3<self::Jm3::Z> {
+ synthetic constructor •() → self::Jm3<self::Jm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<() → (() → core::Function) → dynamic, self::_Km3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Km3&Object&Am3<self::_Km3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Km3<Z extends core::Object = dynamic> extends self::_Km3&Object&Am3<self::Km3::Z> {
+ synthetic constructor •() → self::Km3<self::Km3::Z>
+ : super core::Object::•()
+ ;
+}
+class Af1<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Af1<self::Af1::foo::X>
+ return null;
+}
+class Bf1<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf1<self::Bf1::foo::X>
+ return null;
+}
+class Cf1<X extends () → core::int = dynamic> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Cf1<self::Cf1::foo::X>
+ return null;
+}
+class Df1<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Df1<self::Df1::foo::X>
+ return null;
+}
+class Ef1<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef1<self::Ef1::foo::X>
+ return null;
+}
+class Ff1<X extends ({x: core::int}) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Ff1<self::Ff1::foo::X>
+ return null;
+}
+class Gf1<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Gf1<self::Gf1::foo::X>
+ return null;
+}
+class Hf1<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf1<self::Hf1::foo::X>
+ return null;
+}
+class If1<X extends core::Function = dynamic> extends core::Object {
+ static factory foo<X extends core::Function = dynamic>() → self::If1<self::If1::foo::X>
+ return null;
+}
+class Jf1<X extends (core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf1<self::Jf1::foo::X>
+ return null;
+}
+class Kf1<X extends () → (() → core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf1<self::Kf1::foo::X>
+ return null;
+}
+class Bf2<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf2<self::Bf2::foo::X>
+ return null;
+}
+class Cf2<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Cf2<self::Cf2::foo::X>
+ return null;
+}
+class Df2<X extends () → core::int = dynamic> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Df2<self::Df2::foo::X>
+ return null;
+}
+class Ef2<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef2<self::Ef2::foo::X>
+ return null;
+}
+class Ff2<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ff2<self::Ff2::foo::X>
+ return null;
+}
+class Gf2<X extends ({x: core::int}) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Gf2<self::Gf2::foo::X>
+ return null;
+}
+class Hf2<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf2<self::Hf2::foo::X>
+ return null;
+}
+class If2<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::If2<self::If2::foo::X>
+ return null;
+}
+class Jf2<X extends (core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf2<self::Jf2::foo::X>
+ return null;
+}
+class Kf2<X extends () → (() → core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf2<self::Kf2::foo::X>
+ return null;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/clone_function_type.dart.outline.expect b/pkg/front_end/testcases/clone_function_type.dart.outline.expect
new file mode 100644
index 0000000..7b8504c
--- /dev/null
+++ b/pkg/front_end/testcases/clone_function_type.dart.outline.expect
@@ -0,0 +1,536 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/clone_function_type.dart:22:51: Error: Expected an identifier, but got '}'.
+// class Fm1<Z> extends Object with Am1<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:46:45: Error: Expected an identifier, but got '}'.
+// class Qm1<Z> = Object with Am1<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:77:51: Error: Expected an identifier, but got '}'.
+// class Fm2<Z> extends Object with Am2<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:105:45: Error: Expected an identifier, but got '}'.
+// class Qm2<Z> = Object with Am2<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:134:28: Error: Expected an identifier, but got '}'.
+// typedef TdF = Function({int});
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:190:34: Error: Expected an identifier, but got '}'.
+// class Ef1<X extends Function({int})> {
+// ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef TdB = (core::int) → dynamic;
+typedef TdC = (core::int) → dynamic;
+typedef TdD = () → core::int;
+typedef TdE = () → dynamic;
+typedef TdF = () → dynamic;
+typedef TdG = ({x: core::int}) → dynamic;
+typedef TdH = ([core::int]) → dynamic;
+typedef TdI = ([core::int]) → dynamic;
+typedef TdJ = (core::Function) → dynamic;
+typedef TdK = () → (() → core::Function) → dynamic;
+class Am1<X extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am1<self::Am1::X, self::Am1::Y>
+ ;
+}
+abstract class _Bm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::_Bm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Bm1&Object&Am1<self::_Bm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm1<Z extends core::Object = dynamic> extends self::_Bm1&Object&Am1<self::Bm1::Z> {
+ synthetic constructor •() → self::Bm1<self::Bm1::Z>
+ ;
+}
+abstract class _Cm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::_Cm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Cm1&Object&Am1<self::_Cm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm1<Z extends core::Object = dynamic> extends self::_Cm1&Object&Am1<self::Cm1::Z> {
+ synthetic constructor •() → self::Cm1<self::Cm1::Z>
+ ;
+}
+abstract class _Dm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → core::int, self::_Dm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Dm1&Object&Am1<self::_Dm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm1<Z extends core::Object = dynamic> extends self::_Dm1&Object&Am1<self::Dm1::Z> {
+ synthetic constructor •() → self::Dm1<self::Dm1::Z>
+ ;
+}
+abstract class _Em1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::_Em1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Em1&Object&Am1<self::_Em1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Em1<Z extends core::Object = dynamic> extends self::_Em1&Object&Am1<self::Em1::Z> {
+ synthetic constructor •() → self::Em1<self::Em1::Z>
+ ;
+}
+abstract class _Fm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::_Fm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Fm1&Object&Am1<self::_Fm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm1<Z extends core::Object = dynamic> extends self::_Fm1&Object&Am1<self::Fm1::Z> {
+ synthetic constructor •() → self::Fm1<self::Fm1::Z>
+ ;
+}
+abstract class _Gm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<({x: core::int}) → dynamic, self::_Gm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Gm1&Object&Am1<self::_Gm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm1<Z extends core::Object = dynamic> extends self::_Gm1&Object&Am1<self::Gm1::Z> {
+ synthetic constructor •() → self::Gm1<self::Gm1::Z>
+ ;
+}
+abstract class _Hm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::_Hm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Hm1&Object&Am1<self::_Hm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm1<Z extends core::Object = dynamic> extends self::_Hm1&Object&Am1<self::Hm1::Z> {
+ synthetic constructor •() → self::Hm1<self::Hm1::Z>
+ ;
+}
+abstract class _Im1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::_Im1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Im1&Object&Am1<self::_Im1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Im1<Z extends core::Object = dynamic> extends self::_Im1&Object&Am1<self::Im1::Z> {
+ synthetic constructor •() → self::Im1<self::Im1::Z>
+ ;
+}
+abstract class _Jm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<core::Function, self::_Jm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Jm1&Object&Am1<self::_Jm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm1<Z extends core::Object = dynamic> extends self::_Jm1&Object&Am1<self::Jm1::Z> {
+ synthetic constructor •() → self::Jm1<self::Jm1::Z>
+ ;
+}
+abstract class _Km1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::Function) → dynamic, self::_Km1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Km1&Object&Am1<self::_Km1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Km1<Z extends core::Object = dynamic> extends self::_Km1&Object&Am1<self::Km1::Z> {
+ synthetic constructor •() → self::Km1<self::Km1::Z>
+ ;
+}
+abstract class _Lm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → (() → core::Function) → dynamic, self::_Lm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Lm1&Object&Am1<self::_Lm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm1<Z extends core::Object = dynamic> extends self::_Lm1&Object&Am1<self::Lm1::Z> {
+ synthetic constructor •() → self::Lm1<self::Lm1::Z>
+ ;
+}
+class Mm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::Mm1::Z> {
+ synthetic constructor •() → self::Mm1<self::Mm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::Nm1::Z> {
+ synthetic constructor •() → self::Nm1<self::Nm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Om1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → core::int, self::Om1::Z> {
+ synthetic constructor •() → self::Om1<self::Om1::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::Pm1::Z> {
+ synthetic constructor •() → self::Pm1<self::Pm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::Qm1::Z> {
+ synthetic constructor •() → self::Qm1<self::Qm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm1<Z extends core::Object = dynamic> = core::Object with self::Am1<({x: core::int}) → dynamic, self::Rm1::Z> {
+ synthetic constructor •() → self::Rm1<self::Rm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::Sm1::Z> {
+ synthetic constructor •() → self::Sm1<self::Sm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::Tm1::Z> {
+ synthetic constructor •() → self::Tm1<self::Tm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Um1<Z extends core::Object = dynamic> = core::Object with self::Am1<core::Function, self::Um1::Z> {
+ synthetic constructor •() → self::Um1<self::Um1::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::Function) → dynamic, self::Vm1::Z> {
+ synthetic constructor •() → self::Vm1<self::Vm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → (() → core::Function) → dynamic, self::Wm1::Z> {
+ synthetic constructor •() → self::Wm1<self::Wm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Am2<X extends () → dynamic = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am2<self::Am2::X, self::Am2::Y>
+ ;
+}
+abstract class _Bm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::_Bm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Bm2&Object&Am2<self::_Bm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm2<Z extends core::Object = dynamic> extends self::_Bm2&Object&Am2<self::Bm2::Z> {
+ synthetic constructor •() → self::Bm2<self::Bm2::Z>
+ ;
+}
+abstract class _Cm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::_Cm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Cm2&Object&Am2<self::_Cm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm2<Z extends core::Object = dynamic> extends self::_Cm2&Object&Am2<self::Cm2::Z> {
+ synthetic constructor •() → self::Cm2<self::Cm2::Z>
+ ;
+}
+abstract class _Dm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → core::int, self::_Dm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Dm2&Object&Am2<self::_Dm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm2<Z extends core::Object = dynamic> extends self::_Dm2&Object&Am2<self::Dm2::Z> {
+ synthetic constructor •() → self::Dm2<self::Dm2::Z>
+ ;
+}
+abstract class _Em2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::_Em2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Em2&Object&Am2<self::_Em2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Em2<Z extends core::Object = dynamic> extends self::_Em2&Object&Am2<self::Em2::Z> {
+ synthetic constructor •() → self::Em2<self::Em2::Z>
+ ;
+}
+abstract class _Fm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::_Fm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Fm2&Object&Am2<self::_Fm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm2<Z extends core::Object = dynamic> extends self::_Fm2&Object&Am2<self::Fm2::Z> {
+ synthetic constructor •() → self::Fm2<self::Fm2::Z>
+ ;
+}
+abstract class _Gm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<({x: core::int}) → dynamic, self::_Gm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Gm2&Object&Am2<self::_Gm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm2<Z extends core::Object = dynamic> extends self::_Gm2&Object&Am2<self::Gm2::Z> {
+ synthetic constructor •() → self::Gm2<self::Gm2::Z>
+ ;
+}
+abstract class _Hm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::_Hm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Hm2&Object&Am2<self::_Hm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm2<Z extends core::Object = dynamic> extends self::_Hm2&Object&Am2<self::Hm2::Z> {
+ synthetic constructor •() → self::Hm2<self::Hm2::Z>
+ ;
+}
+abstract class _Im2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::_Im2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Im2&Object&Am2<self::_Im2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Im2<Z extends core::Object = dynamic> extends self::_Im2&Object&Am2<self::Im2::Z> {
+ synthetic constructor •() → self::Im2<self::Im2::Z>
+ ;
+}
+abstract class _Jm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<core::Function, self::_Jm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Jm2&Object&Am2<self::_Jm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm2<Z extends core::Object = dynamic> extends self::_Jm2&Object&Am2<self::Jm2::Z> {
+ synthetic constructor •() → self::Jm2<self::Jm2::Z>
+ ;
+}
+abstract class _Km2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::Function) → dynamic, self::_Km2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Km2&Object&Am2<self::_Km2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Km2<Z extends core::Object = dynamic> extends self::_Km2&Object&Am2<self::Km2::Z> {
+ synthetic constructor •() → self::Km2<self::Km2::Z>
+ ;
+}
+abstract class _Lm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → (() → core::Function) → dynamic, self::_Lm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Lm2&Object&Am2<self::_Lm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm2<Z extends core::Object = dynamic> extends self::_Lm2&Object&Am2<self::Lm2::Z> {
+ synthetic constructor •() → self::Lm2<self::Lm2::Z>
+ ;
+}
+class Mm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::Mm2::Z> {
+ synthetic constructor •() → self::Mm2<self::Mm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::Nm2::Z> {
+ synthetic constructor •() → self::Nm2<self::Nm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Om2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → core::int, self::Om2::Z> {
+ synthetic constructor •() → self::Om2<self::Om2::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::Pm2::Z> {
+ synthetic constructor •() → self::Pm2<self::Pm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::Qm2::Z> {
+ synthetic constructor •() → self::Qm2<self::Qm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm2<Z extends core::Object = dynamic> = core::Object with self::Am2<({x: core::int}) → dynamic, self::Rm2::Z> {
+ synthetic constructor •() → self::Rm2<self::Rm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::Sm2::Z> {
+ synthetic constructor •() → self::Sm2<self::Sm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::Tm2::Z> {
+ synthetic constructor •() → self::Tm2<self::Tm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Um2<Z extends core::Object = dynamic> = core::Object with self::Am2<core::Function, self::Um2::Z> {
+ synthetic constructor •() → self::Um2<self::Um2::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::Function) → dynamic, self::Vm2::Z> {
+ synthetic constructor •() → self::Vm2<self::Vm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → (() → core::Function) → dynamic, self::Wm2::Z> {
+ synthetic constructor •() → self::Wm2<self::Wm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Am3<L extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am3<self::Am3::L, self::Am3::Y>
+ ;
+}
+abstract class _Bm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::int) → dynamic, self::_Bm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Bm3&Object&Am3<self::_Bm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm3<Z extends core::Object = dynamic> extends self::_Bm3&Object&Am3<self::Bm3::Z> {
+ synthetic constructor •() → self::Bm3<self::Bm3::Z>
+ ;
+}
+abstract class _Cm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::int) → dynamic, self::_Cm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Cm3&Object&Am3<self::_Cm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm3<Z extends core::Object = dynamic> extends self::_Cm3&Object&Am3<self::Cm3::Z> {
+ synthetic constructor •() → self::Cm3<self::Cm3::Z>
+ ;
+}
+abstract class _Dm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → core::int, self::_Dm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Dm3&Object&Am3<self::_Dm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm3<Z extends core::Object = dynamic> extends self::_Dm3&Object&Am3<self::Dm3::Z> {
+ synthetic constructor •() → self::Dm3<self::Dm3::Z>
+ ;
+}
+abstract class _Em3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → dynamic, self::_Em3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Em3&Object&Am3<self::_Em3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Em3<Z extends core::Object = dynamic> extends self::_Em3&Object&Am3<self::Em3::Z> {
+ synthetic constructor •() → self::Em3<self::Em3::Z>
+ ;
+}
+abstract class _Fm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → dynamic, self::_Fm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Fm3&Object&Am3<self::_Fm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm3<Z extends core::Object = dynamic> extends self::_Fm3&Object&Am3<self::Fm3::Z> {
+ synthetic constructor •() → self::Fm3<self::Fm3::Z>
+ ;
+}
+abstract class _Gm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<({x: core::int}) → dynamic, self::_Gm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Gm3&Object&Am3<self::_Gm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm3<Z extends core::Object = dynamic> extends self::_Gm3&Object&Am3<self::Gm3::Z> {
+ synthetic constructor •() → self::Gm3<self::Gm3::Z>
+ ;
+}
+abstract class _Hm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<([core::int]) → dynamic, self::_Hm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Hm3&Object&Am3<self::_Hm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm3<Z extends core::Object = dynamic> extends self::_Hm3&Object&Am3<self::Hm3::Z> {
+ synthetic constructor •() → self::Hm3<self::Hm3::Z>
+ ;
+}
+abstract class _Im3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<([core::int]) → dynamic, self::_Im3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Im3&Object&Am3<self::_Im3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Im3<Z extends core::Object = dynamic> extends self::_Im3&Object&Am3<self::Im3::Z> {
+ synthetic constructor •() → self::Im3<self::Im3::Z>
+ ;
+}
+abstract class _Jm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::Function) → dynamic, self::_Jm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Jm3&Object&Am3<self::_Jm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm3<Z extends core::Object = dynamic> extends self::_Jm3&Object&Am3<self::Jm3::Z> {
+ synthetic constructor •() → self::Jm3<self::Jm3::Z>
+ ;
+}
+abstract class _Km3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → (() → core::Function) → dynamic, self::_Km3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Km3&Object&Am3<self::_Km3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Km3<Z extends core::Object = dynamic> extends self::_Km3&Object&Am3<self::Km3::Z> {
+ synthetic constructor •() → self::Km3<self::Km3::Z>
+ ;
+}
+class Af1<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Af1<self::Af1::foo::X>
+ ;
+}
+class Bf1<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf1<self::Bf1::foo::X>
+ ;
+}
+class Cf1<X extends () → core::int = dynamic> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Cf1<self::Cf1::foo::X>
+ ;
+}
+class Df1<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Df1<self::Df1::foo::X>
+ ;
+}
+class Ef1<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef1<self::Ef1::foo::X>
+ ;
+}
+class Ff1<X extends ({x: core::int}) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Ff1<self::Ff1::foo::X>
+ ;
+}
+class Gf1<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Gf1<self::Gf1::foo::X>
+ ;
+}
+class Hf1<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf1<self::Hf1::foo::X>
+ ;
+}
+class If1<X extends core::Function = dynamic> extends core::Object {
+ static factory foo<X extends core::Function = dynamic>() → self::If1<self::If1::foo::X>
+ ;
+}
+class Jf1<X extends (core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf1<self::Jf1::foo::X>
+ ;
+}
+class Kf1<X extends () → (() → core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf1<self::Kf1::foo::X>
+ ;
+}
+class Bf2<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf2<self::Bf2::foo::X>
+ ;
+}
+class Cf2<X extends (core::int) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Cf2<self::Cf2::foo::X>
+ ;
+}
+class Df2<X extends () → core::int = dynamic> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Df2<self::Df2::foo::X>
+ ;
+}
+class Ef2<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef2<self::Ef2::foo::X>
+ ;
+}
+class Ff2<X extends () → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ff2<self::Ff2::foo::X>
+ ;
+}
+class Gf2<X extends ({x: core::int}) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Gf2<self::Gf2::foo::X>
+ ;
+}
+class Hf2<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf2<self::Hf2::foo::X>
+ ;
+}
+class If2<X extends ([core::int]) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::If2<self::If2::foo::X>
+ ;
+}
+class Jf2<X extends (core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf2<self::Jf2::foo::X>
+ ;
+}
+class Kf2<X extends () → (() → core::Function) → dynamic = dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf2<self::Kf2::foo::X>
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/clone_function_type.dart.strong.expect b/pkg/front_end/testcases/clone_function_type.dart.strong.expect
new file mode 100644
index 0000000..f2b11be
--- /dev/null
+++ b/pkg/front_end/testcases/clone_function_type.dart.strong.expect
@@ -0,0 +1,700 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/clone_function_type.dart:22:51: Error: Expected an identifier, but got '}'.
+// class Fm1<Z> extends Object with Am1<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:46:45: Error: Expected an identifier, but got '}'.
+// class Qm1<Z> = Object with Am1<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:77:51: Error: Expected an identifier, but got '}'.
+// class Fm2<Z> extends Object with Am2<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:105:45: Error: Expected an identifier, but got '}'.
+// class Qm2<Z> = Object with Am2<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:134:28: Error: Expected an identifier, but got '}'.
+// typedef TdF = Function({int});
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:190:34: Error: Expected an identifier, but got '}'.
+// class Ef1<X extends Function({int})> {
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:67:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bm2<Z> extends Object with Am2<Function(int), Z> {}
+// ^
+// pkg/front_end/testcases/clone_function_type.dart:64:11: Context: Bound of this variable is violated.
+// class Am2<X extends Function(), Y> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:70:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Cm2<Z> extends Object with Am2<Function(int x), Z> {}
+// ^
+// pkg/front_end/testcases/clone_function_type.dart:64:11: Context: Bound of this variable is violated.
+// class Am2<X extends Function(), Y> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:86:7: Error: Type argument 'dart.core::Function' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Jm2<Z> extends Object with Am2<Function, Z> {}
+// ^
+// pkg/front_end/testcases/clone_function_type.dart:64:11: Context: Bound of this variable is violated.
+// class Am2<X extends Function(), Y> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:89:7: Error: Type argument '(dart.core::Function) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Km2<Z> extends Object with Am2<Function(Function Function), Z> {}
+// ^
+// pkg/front_end/testcases/clone_function_type.dart:64:11: Context: Bound of this variable is violated.
+// class Am2<X extends Function(), Y> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:95:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Mm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Mm2<Z> = Object with Am2<Function(int), Z>;
+// ^
+// pkg/front_end/testcases/clone_function_type.dart:64:11: Context: Bound of this variable is violated.
+// class Am2<X extends Function(), Y> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:98:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Nm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Nm2<Z> = Object with Am2<Function(int x), Z>;
+// ^
+// pkg/front_end/testcases/clone_function_type.dart:64:11: Context: Bound of this variable is violated.
+// class Am2<X extends Function(), Y> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:114:7: Error: Type argument 'dart.core::Function' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Um2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Um2<Z> = Object with Am2<Function, Z>;
+// ^
+// pkg/front_end/testcases/clone_function_type.dart:64:11: Context: Bound of this variable is violated.
+// class Am2<X extends Function(), Y> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:117:7: Error: Type argument '(dart.core::Function) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Vm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Vm2<Z> = Object with Am2<Function(Function Function), Z>;
+// ^
+// pkg/front_end/testcases/clone_function_type.dart:64:11: Context: Bound of this variable is violated.
+// class Am2<X extends Function(), Y> {}
+// ^
+
+// Unhandled errors:
+//
+// pkg/front_end/testcases/clone_function_type.dart:22:51: Error: Expected an identifier, but got '}'.
+// class Fm1<Z> extends Object with Am1<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:46:45: Error: Expected an identifier, but got '}'.
+// class Qm1<Z> = Object with Am1<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:77:51: Error: Expected an identifier, but got '}'.
+// class Fm2<Z> extends Object with Am2<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:105:45: Error: Expected an identifier, but got '}'.
+// class Qm2<Z> = Object with Am2<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:134:28: Error: Expected an identifier, but got '}'.
+// typedef TdF = Function({int});
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:190:34: Error: Expected an identifier, but got '}'.
+// class Ef1<X extends Function({int})> {
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:67:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bm2<Z> extends Object with Am2<Function(int), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:70:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Cm2<Z> extends Object with Am2<Function(int x), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:86:7: Error: Type argument 'dart.core::Function' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Jm2<Z> extends Object with Am2<Function, Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:89:7: Error: Type argument '(dart.core::Function) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Km2<Z> extends Object with Am2<Function(Function Function), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:95:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Mm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Mm2<Z> = Object with Am2<Function(int), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:98:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Nm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Nm2<Z> = Object with Am2<Function(int x), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:114:7: Error: Type argument 'dart.core::Function' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Um2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Um2<Z> = Object with Am2<Function, Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:117:7: Error: Type argument '(dart.core::Function) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Vm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Vm2<Z> = Object with Am2<Function(Function Function), Z>;
+// ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef TdB = (core::int) → dynamic;
+typedef TdC = (core::int) → dynamic;
+typedef TdD = () → core::int;
+typedef TdE = () → dynamic;
+typedef TdF = () → dynamic;
+typedef TdG = ({x: core::int}) → dynamic;
+typedef TdH = ([core::int]) → dynamic;
+typedef TdI = ([core::int]) → dynamic;
+typedef TdJ = (core::Function) → dynamic;
+typedef TdK = () → (() → core::Function) → dynamic;
+class Am1<X extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am1<self::Am1::X, self::Am1::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::_Bm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Bm1&Object&Am1<self::_Bm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm1<Z extends core::Object = dynamic> extends self::_Bm1&Object&Am1<self::Bm1::Z> {
+ synthetic constructor •() → self::Bm1<self::Bm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::_Cm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Cm1&Object&Am1<self::_Cm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm1<Z extends core::Object = dynamic> extends self::_Cm1&Object&Am1<self::Cm1::Z> {
+ synthetic constructor •() → self::Cm1<self::Cm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → core::int, self::_Dm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Dm1&Object&Am1<self::_Dm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm1<Z extends core::Object = dynamic> extends self::_Dm1&Object&Am1<self::Dm1::Z> {
+ synthetic constructor •() → self::Dm1<self::Dm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::_Em1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Em1&Object&Am1<self::_Em1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Em1<Z extends core::Object = dynamic> extends self::_Em1&Object&Am1<self::Em1::Z> {
+ synthetic constructor •() → self::Em1<self::Em1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::_Fm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Fm1&Object&Am1<self::_Fm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm1<Z extends core::Object = dynamic> extends self::_Fm1&Object&Am1<self::Fm1::Z> {
+ synthetic constructor •() → self::Fm1<self::Fm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<({x: core::int}) → dynamic, self::_Gm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Gm1&Object&Am1<self::_Gm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm1<Z extends core::Object = dynamic> extends self::_Gm1&Object&Am1<self::Gm1::Z> {
+ synthetic constructor •() → self::Gm1<self::Gm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::_Hm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Hm1&Object&Am1<self::_Hm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm1<Z extends core::Object = dynamic> extends self::_Hm1&Object&Am1<self::Hm1::Z> {
+ synthetic constructor •() → self::Hm1<self::Hm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::_Im1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Im1&Object&Am1<self::_Im1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Im1<Z extends core::Object = dynamic> extends self::_Im1&Object&Am1<self::Im1::Z> {
+ synthetic constructor •() → self::Im1<self::Im1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<core::Function, self::_Jm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Jm1&Object&Am1<self::_Jm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm1<Z extends core::Object = dynamic> extends self::_Jm1&Object&Am1<self::Jm1::Z> {
+ synthetic constructor •() → self::Jm1<self::Jm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::Function) → dynamic, self::_Km1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Km1&Object&Am1<self::_Km1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Km1<Z extends core::Object = dynamic> extends self::_Km1&Object&Am1<self::Km1::Z> {
+ synthetic constructor •() → self::Km1<self::Km1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Lm1&Object&Am1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → (() → core::Function) → dynamic, self::_Lm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Lm1&Object&Am1<self::_Lm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm1<Z extends core::Object = dynamic> extends self::_Lm1&Object&Am1<self::Lm1::Z> {
+ synthetic constructor •() → self::Lm1<self::Lm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Mm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::Mm1::Z> {
+ synthetic constructor •() → self::Mm1<self::Mm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::int) → dynamic, self::Nm1::Z> {
+ synthetic constructor •() → self::Nm1<self::Nm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Om1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → core::int, self::Om1::Z> {
+ synthetic constructor •() → self::Om1<self::Om1::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::Pm1::Z> {
+ synthetic constructor •() → self::Pm1<self::Pm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → dynamic, self::Qm1::Z> {
+ synthetic constructor •() → self::Qm1<self::Qm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm1<Z extends core::Object = dynamic> = core::Object with self::Am1<({x: core::int}) → dynamic, self::Rm1::Z> {
+ synthetic constructor •() → self::Rm1<self::Rm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::Sm1::Z> {
+ synthetic constructor •() → self::Sm1<self::Sm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm1<Z extends core::Object = dynamic> = core::Object with self::Am1<([core::int]) → dynamic, self::Tm1::Z> {
+ synthetic constructor •() → self::Tm1<self::Tm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Um1<Z extends core::Object = dynamic> = core::Object with self::Am1<core::Function, self::Um1::Z> {
+ synthetic constructor •() → self::Um1<self::Um1::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm1<Z extends core::Object = dynamic> = core::Object with self::Am1<(core::Function) → dynamic, self::Vm1::Z> {
+ synthetic constructor •() → self::Vm1<self::Vm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm1<Z extends core::Object = dynamic> = core::Object with self::Am1<() → (() → core::Function) → dynamic, self::Wm1::Z> {
+ synthetic constructor •() → self::Wm1<self::Wm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Am2<X extends () → dynamic = () → dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am2<self::Am2::X, self::Am2::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::_Bm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Bm2&Object&Am2<self::_Bm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm2<Z extends core::Object = dynamic> extends self::_Bm2&Object&Am2<self::Bm2::Z> {
+ synthetic constructor •() → self::Bm2<self::Bm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::_Cm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Cm2&Object&Am2<self::_Cm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm2<Z extends core::Object = dynamic> extends self::_Cm2&Object&Am2<self::Cm2::Z> {
+ synthetic constructor •() → self::Cm2<self::Cm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → core::int, self::_Dm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Dm2&Object&Am2<self::_Dm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm2<Z extends core::Object = dynamic> extends self::_Dm2&Object&Am2<self::Dm2::Z> {
+ synthetic constructor •() → self::Dm2<self::Dm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::_Em2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Em2&Object&Am2<self::_Em2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Em2<Z extends core::Object = dynamic> extends self::_Em2&Object&Am2<self::Em2::Z> {
+ synthetic constructor •() → self::Em2<self::Em2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::_Fm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Fm2&Object&Am2<self::_Fm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm2<Z extends core::Object = dynamic> extends self::_Fm2&Object&Am2<self::Fm2::Z> {
+ synthetic constructor •() → self::Fm2<self::Fm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<({x: core::int}) → dynamic, self::_Gm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Gm2&Object&Am2<self::_Gm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm2<Z extends core::Object = dynamic> extends self::_Gm2&Object&Am2<self::Gm2::Z> {
+ synthetic constructor •() → self::Gm2<self::Gm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::_Hm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Hm2&Object&Am2<self::_Hm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm2<Z extends core::Object = dynamic> extends self::_Hm2&Object&Am2<self::Hm2::Z> {
+ synthetic constructor •() → self::Hm2<self::Hm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::_Im2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Im2&Object&Am2<self::_Im2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Im2<Z extends core::Object = dynamic> extends self::_Im2&Object&Am2<self::Im2::Z> {
+ synthetic constructor •() → self::Im2<self::Im2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<core::Function, self::_Jm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Jm2&Object&Am2<self::_Jm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm2<Z extends core::Object = dynamic> extends self::_Jm2&Object&Am2<self::Jm2::Z> {
+ synthetic constructor •() → self::Jm2<self::Jm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::Function) → dynamic, self::_Km2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Km2&Object&Am2<self::_Km2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Km2<Z extends core::Object = dynamic> extends self::_Km2&Object&Am2<self::Km2::Z> {
+ synthetic constructor •() → self::Km2<self::Km2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Lm2&Object&Am2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → (() → core::Function) → dynamic, self::_Lm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Lm2&Object&Am2<self::_Lm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm2<Z extends core::Object = dynamic> extends self::_Lm2&Object&Am2<self::Lm2::Z> {
+ synthetic constructor •() → self::Lm2<self::Lm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Mm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::Mm2::Z> {
+ synthetic constructor •() → self::Mm2<self::Mm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::int) → dynamic, self::Nm2::Z> {
+ synthetic constructor •() → self::Nm2<self::Nm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Om2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → core::int, self::Om2::Z> {
+ synthetic constructor •() → self::Om2<self::Om2::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::Pm2::Z> {
+ synthetic constructor •() → self::Pm2<self::Pm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → dynamic, self::Qm2::Z> {
+ synthetic constructor •() → self::Qm2<self::Qm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm2<Z extends core::Object = dynamic> = core::Object with self::Am2<({x: core::int}) → dynamic, self::Rm2::Z> {
+ synthetic constructor •() → self::Rm2<self::Rm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::Sm2::Z> {
+ synthetic constructor •() → self::Sm2<self::Sm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm2<Z extends core::Object = dynamic> = core::Object with self::Am2<([core::int]) → dynamic, self::Tm2::Z> {
+ synthetic constructor •() → self::Tm2<self::Tm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Um2<Z extends core::Object = dynamic> = core::Object with self::Am2<core::Function, self::Um2::Z> {
+ synthetic constructor •() → self::Um2<self::Um2::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm2<Z extends core::Object = dynamic> = core::Object with self::Am2<(core::Function) → dynamic, self::Vm2::Z> {
+ synthetic constructor •() → self::Vm2<self::Vm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm2<Z extends core::Object = dynamic> = core::Object with self::Am2<() → (() → core::Function) → dynamic, self::Wm2::Z> {
+ synthetic constructor •() → self::Wm2<self::Wm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Am3<L extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am3<self::Am3::L, self::Am3::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::int) → dynamic, self::_Bm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Bm3&Object&Am3<self::_Bm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm3<Z extends core::Object = dynamic> extends self::_Bm3&Object&Am3<self::Bm3::Z> {
+ synthetic constructor •() → self::Bm3<self::Bm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::int) → dynamic, self::_Cm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Cm3&Object&Am3<self::_Cm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm3<Z extends core::Object = dynamic> extends self::_Cm3&Object&Am3<self::Cm3::Z> {
+ synthetic constructor •() → self::Cm3<self::Cm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → core::int, self::_Dm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Dm3&Object&Am3<self::_Dm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm3<Z extends core::Object = dynamic> extends self::_Dm3&Object&Am3<self::Dm3::Z> {
+ synthetic constructor •() → self::Dm3<self::Dm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → dynamic, self::_Em3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Em3&Object&Am3<self::_Em3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Em3<Z extends core::Object = dynamic> extends self::_Em3&Object&Am3<self::Em3::Z> {
+ synthetic constructor •() → self::Em3<self::Em3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → dynamic, self::_Fm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Fm3&Object&Am3<self::_Fm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm3<Z extends core::Object = dynamic> extends self::_Fm3&Object&Am3<self::Fm3::Z> {
+ synthetic constructor •() → self::Fm3<self::Fm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<({x: core::int}) → dynamic, self::_Gm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Gm3&Object&Am3<self::_Gm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm3<Z extends core::Object = dynamic> extends self::_Gm3&Object&Am3<self::Gm3::Z> {
+ synthetic constructor •() → self::Gm3<self::Gm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<([core::int]) → dynamic, self::_Hm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Hm3&Object&Am3<self::_Hm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm3<Z extends core::Object = dynamic> extends self::_Hm3&Object&Am3<self::Hm3::Z> {
+ synthetic constructor •() → self::Hm3<self::Hm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<([core::int]) → dynamic, self::_Im3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Im3&Object&Am3<self::_Im3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Im3<Z extends core::Object = dynamic> extends self::_Im3&Object&Am3<self::Im3::Z> {
+ synthetic constructor •() → self::Im3<self::Im3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<(core::Function) → dynamic, self::_Jm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Jm3&Object&Am3<self::_Jm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm3<Z extends core::Object = dynamic> extends self::_Jm3&Object&Am3<self::Jm3::Z> {
+ synthetic constructor •() → self::Jm3<self::Jm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km3&Object&Am3<Z extends core::Object = dynamic> = core::Object with self::Am3<() → (() → core::Function) → dynamic, self::_Km3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Km3&Object&Am3<self::_Km3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Km3<Z extends core::Object = dynamic> extends self::_Km3&Object&Am3<self::Km3::Z> {
+ synthetic constructor •() → self::Km3<self::Km3::Z>
+ : super core::Object::•()
+ ;
+}
+class Af1<X extends (core::int) → dynamic = (core::int) → dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Af1<self::Af1::foo::X>
+ return null;
+}
+class Bf1<X extends (core::int) → dynamic = (core::int) → dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf1<self::Bf1::foo::X>
+ return null;
+}
+class Cf1<X extends () → core::int = () → core::int> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Cf1<self::Cf1::foo::X>
+ return null;
+}
+class Df1<X extends () → dynamic = () → dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Df1<self::Df1::foo::X>
+ return null;
+}
+class Ef1<X extends () → dynamic = () → dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef1<self::Ef1::foo::X>
+ return null;
+}
+class Ff1<X extends ({x: core::int}) → dynamic = ({x: core::int}) → dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Ff1<self::Ff1::foo::X>
+ return null;
+}
+class Gf1<X extends ([core::int]) → dynamic = ([core::int]) → dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Gf1<self::Gf1::foo::X>
+ return null;
+}
+class Hf1<X extends ([core::int]) → dynamic = ([core::int]) → dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf1<self::Hf1::foo::X>
+ return null;
+}
+class If1<X extends core::Function = core::Function> extends core::Object {
+ static factory foo<X extends core::Function = dynamic>() → self::If1<self::If1::foo::X>
+ return null;
+}
+class Jf1<X extends (core::Function) → dynamic = (core::Function) → dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf1<self::Jf1::foo::X>
+ return null;
+}
+class Kf1<X extends () → (() → core::Function) → dynamic = () → (() → core::Function) → dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf1<self::Kf1::foo::X>
+ return null;
+}
+class Bf2<X extends (core::int) → dynamic = (core::int) → dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf2<self::Bf2::foo::X>
+ return null;
+}
+class Cf2<X extends (core::int) → dynamic = (core::int) → dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Cf2<self::Cf2::foo::X>
+ return null;
+}
+class Df2<X extends () → core::int = () → core::int> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Df2<self::Df2::foo::X>
+ return null;
+}
+class Ef2<X extends () → dynamic = () → dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef2<self::Ef2::foo::X>
+ return null;
+}
+class Ff2<X extends () → dynamic = () → dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ff2<self::Ff2::foo::X>
+ return null;
+}
+class Gf2<X extends ({x: core::int}) → dynamic = ({x: core::int}) → dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Gf2<self::Gf2::foo::X>
+ return null;
+}
+class Hf2<X extends ([core::int]) → dynamic = ([core::int]) → dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf2<self::Hf2::foo::X>
+ return null;
+}
+class If2<X extends ([core::int]) → dynamic = ([core::int]) → dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::If2<self::If2::foo::X>
+ return null;
+}
+class Jf2<X extends (core::Function) → dynamic = (core::Function) → dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf2<self::Jf2::foo::X>
+ return null;
+}
+class Kf2<X extends () → (() → core::Function) → dynamic = () → (() → core::Function) → dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf2<self::Kf2::foo::X>
+ return null;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/clone_function_type.dart.strong.transformed.expect b/pkg/front_end/testcases/clone_function_type.dart.strong.transformed.expect
new file mode 100644
index 0000000..c0e8444
--- /dev/null
+++ b/pkg/front_end/testcases/clone_function_type.dart.strong.transformed.expect
@@ -0,0 +1,610 @@
+// Unhandled errors:
+//
+// pkg/front_end/testcases/clone_function_type.dart:22:51: Error: Expected an identifier, but got '}'.
+// class Fm1<Z> extends Object with Am1<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:46:45: Error: Expected an identifier, but got '}'.
+// class Qm1<Z> = Object with Am1<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:77:51: Error: Expected an identifier, but got '}'.
+// class Fm2<Z> extends Object with Am2<Function({int}), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:105:45: Error: Expected an identifier, but got '}'.
+// class Qm2<Z> = Object with Am2<Function({int}), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:134:28: Error: Expected an identifier, but got '}'.
+// typedef TdF = Function({int});
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:190:34: Error: Expected an identifier, but got '}'.
+// class Ef1<X extends Function({int})> {
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:67:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bm2<Z> extends Object with Am2<Function(int), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:70:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Cm2<Z> extends Object with Am2<Function(int x), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:86:7: Error: Type argument 'dart.core::Function' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Jm2<Z> extends Object with Am2<Function, Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:89:7: Error: Type argument '(dart.core::Function) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Object with Am2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Km2<Z> extends Object with Am2<Function(Function Function), Z> {}
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:95:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Mm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Mm2<Z> = Object with Am2<Function(int), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:98:7: Error: Type argument '(dart.core::int) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Nm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Nm2<Z> = Object with Am2<Function(int x), Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:114:7: Error: Type argument 'dart.core::Function' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Um2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Um2<Z> = Object with Am2<Function, Z>;
+// ^
+//
+// pkg/front_end/testcases/clone_function_type.dart:117:7: Error: Type argument '(dart.core::Function) → dynamic' violates the corresponding type variable bound of 'Am2' in the supertype 'Am2' of class 'Vm2'.
+// Try changing type arguments so that they conform to the bounds.
+// class Vm2<Z> = Object with Am2<Function(Function Function), Z>;
+// ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef TdB = (core::int) → dynamic;
+typedef TdC = (core::int) → dynamic;
+typedef TdD = () → core::int;
+typedef TdE = () → dynamic;
+typedef TdF = () → dynamic;
+typedef TdG = ({x: core::int}) → dynamic;
+typedef TdH = ([core::int]) → dynamic;
+typedef TdI = ([core::int]) → dynamic;
+typedef TdJ = (core::Function) → dynamic;
+typedef TdK = () → (() → core::Function) → dynamic;
+class Am1<X extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am1<self::Am1::X, self::Am1::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::int) → dynamic, self::_Bm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Bm1&Object&Am1<self::_Bm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm1<Z extends core::Object = dynamic> extends self::_Bm1&Object&Am1<self::Bm1::Z> {
+ synthetic constructor •() → self::Bm1<self::Bm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::int) → dynamic, self::_Cm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Cm1&Object&Am1<self::_Cm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm1<Z extends core::Object = dynamic> extends self::_Cm1&Object&Am1<self::Cm1::Z> {
+ synthetic constructor •() → self::Cm1<self::Cm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → core::int, self::_Dm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Dm1&Object&Am1<self::_Dm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm1<Z extends core::Object = dynamic> extends self::_Dm1&Object&Am1<self::Dm1::Z> {
+ synthetic constructor •() → self::Dm1<self::Dm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → dynamic, self::_Em1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Em1&Object&Am1<self::_Em1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Em1<Z extends core::Object = dynamic> extends self::_Em1&Object&Am1<self::Em1::Z> {
+ synthetic constructor •() → self::Em1<self::Em1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → dynamic, self::_Fm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Fm1&Object&Am1<self::_Fm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm1<Z extends core::Object = dynamic> extends self::_Fm1&Object&Am1<self::Fm1::Z> {
+ synthetic constructor •() → self::Fm1<self::Fm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<({x: core::int}) → dynamic, self::_Gm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Gm1&Object&Am1<self::_Gm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm1<Z extends core::Object = dynamic> extends self::_Gm1&Object&Am1<self::Gm1::Z> {
+ synthetic constructor •() → self::Gm1<self::Gm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<([core::int]) → dynamic, self::_Hm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Hm1&Object&Am1<self::_Hm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm1<Z extends core::Object = dynamic> extends self::_Hm1&Object&Am1<self::Hm1::Z> {
+ synthetic constructor •() → self::Hm1<self::Hm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<([core::int]) → dynamic, self::_Im1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Im1&Object&Am1<self::_Im1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Im1<Z extends core::Object = dynamic> extends self::_Im1&Object&Am1<self::Im1::Z> {
+ synthetic constructor •() → self::Im1<self::Im1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<core::Function, self::_Jm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Jm1&Object&Am1<self::_Jm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm1<Z extends core::Object = dynamic> extends self::_Jm1&Object&Am1<self::Jm1::Z> {
+ synthetic constructor •() → self::Jm1<self::Jm1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::Function) → dynamic, self::_Km1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Km1&Object&Am1<self::_Km1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Km1<Z extends core::Object = dynamic> extends self::_Km1&Object&Am1<self::Km1::Z> {
+ synthetic constructor •() → self::Km1<self::Km1::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Lm1&Object&Am1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → (() → core::Function) → dynamic, self::_Lm1&Object&Am1::Z> {
+ synthetic constructor •() → self::_Lm1&Object&Am1<self::_Lm1&Object&Am1::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm1<Z extends core::Object = dynamic> extends self::_Lm1&Object&Am1<self::Lm1::Z> {
+ synthetic constructor •() → self::Lm1<self::Lm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Mm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::int) → dynamic, self::Mm1::Z> {
+ synthetic constructor •() → self::Mm1<self::Mm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::int) → dynamic, self::Nm1::Z> {
+ synthetic constructor •() → self::Nm1<self::Nm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Om1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → core::int, self::Om1::Z> {
+ synthetic constructor •() → self::Om1<self::Om1::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → dynamic, self::Pm1::Z> {
+ synthetic constructor •() → self::Pm1<self::Pm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → dynamic, self::Qm1::Z> {
+ synthetic constructor •() → self::Qm1<self::Qm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<({x: core::int}) → dynamic, self::Rm1::Z> {
+ synthetic constructor •() → self::Rm1<self::Rm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<([core::int]) → dynamic, self::Sm1::Z> {
+ synthetic constructor •() → self::Sm1<self::Sm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<([core::int]) → dynamic, self::Tm1::Z> {
+ synthetic constructor •() → self::Tm1<self::Tm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Um1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<core::Function, self::Um1::Z> {
+ synthetic constructor •() → self::Um1<self::Um1::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<(core::Function) → dynamic, self::Vm1::Z> {
+ synthetic constructor •() → self::Vm1<self::Vm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm1<Z extends core::Object = dynamic> extends core::Object implements self::Am1<() → (() → core::Function) → dynamic, self::Wm1::Z> {
+ synthetic constructor •() → self::Wm1<self::Wm1::Z>
+ : super core::Object::•()
+ ;
+}
+class Am2<X extends () → dynamic = () → dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am2<self::Am2::X, self::Am2::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::int) → dynamic, self::_Bm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Bm2&Object&Am2<self::_Bm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm2<Z extends core::Object = dynamic> extends self::_Bm2&Object&Am2<self::Bm2::Z> {
+ synthetic constructor •() → self::Bm2<self::Bm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::int) → dynamic, self::_Cm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Cm2&Object&Am2<self::_Cm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm2<Z extends core::Object = dynamic> extends self::_Cm2&Object&Am2<self::Cm2::Z> {
+ synthetic constructor •() → self::Cm2<self::Cm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → core::int, self::_Dm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Dm2&Object&Am2<self::_Dm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm2<Z extends core::Object = dynamic> extends self::_Dm2&Object&Am2<self::Dm2::Z> {
+ synthetic constructor •() → self::Dm2<self::Dm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → dynamic, self::_Em2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Em2&Object&Am2<self::_Em2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Em2<Z extends core::Object = dynamic> extends self::_Em2&Object&Am2<self::Em2::Z> {
+ synthetic constructor •() → self::Em2<self::Em2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → dynamic, self::_Fm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Fm2&Object&Am2<self::_Fm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm2<Z extends core::Object = dynamic> extends self::_Fm2&Object&Am2<self::Fm2::Z> {
+ synthetic constructor •() → self::Fm2<self::Fm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<({x: core::int}) → dynamic, self::_Gm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Gm2&Object&Am2<self::_Gm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm2<Z extends core::Object = dynamic> extends self::_Gm2&Object&Am2<self::Gm2::Z> {
+ synthetic constructor •() → self::Gm2<self::Gm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<([core::int]) → dynamic, self::_Hm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Hm2&Object&Am2<self::_Hm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm2<Z extends core::Object = dynamic> extends self::_Hm2&Object&Am2<self::Hm2::Z> {
+ synthetic constructor •() → self::Hm2<self::Hm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<([core::int]) → dynamic, self::_Im2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Im2&Object&Am2<self::_Im2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Im2<Z extends core::Object = dynamic> extends self::_Im2&Object&Am2<self::Im2::Z> {
+ synthetic constructor •() → self::Im2<self::Im2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<core::Function, self::_Jm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Jm2&Object&Am2<self::_Jm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm2<Z extends core::Object = dynamic> extends self::_Jm2&Object&Am2<self::Jm2::Z> {
+ synthetic constructor •() → self::Jm2<self::Jm2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::Function) → dynamic, self::_Km2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Km2&Object&Am2<self::_Km2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Km2<Z extends core::Object = dynamic> extends self::_Km2&Object&Am2<self::Km2::Z> {
+ synthetic constructor •() → self::Km2<self::Km2::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Lm2&Object&Am2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → (() → core::Function) → dynamic, self::_Lm2&Object&Am2::Z> {
+ synthetic constructor •() → self::_Lm2&Object&Am2<self::_Lm2&Object&Am2::Z>
+ : super core::Object::•()
+ ;
+}
+class Lm2<Z extends core::Object = dynamic> extends self::_Lm2&Object&Am2<self::Lm2::Z> {
+ synthetic constructor •() → self::Lm2<self::Lm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Mm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::int) → dynamic, self::Mm2::Z> {
+ synthetic constructor •() → self::Mm2<self::Mm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Nm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::int) → dynamic, self::Nm2::Z> {
+ synthetic constructor •() → self::Nm2<self::Nm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Om2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → core::int, self::Om2::Z> {
+ synthetic constructor •() → self::Om2<self::Om2::Z>
+ : super core::Object::•()
+ ;
+}
+class Pm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → dynamic, self::Pm2::Z> {
+ synthetic constructor •() → self::Pm2<self::Pm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Qm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → dynamic, self::Qm2::Z> {
+ synthetic constructor •() → self::Qm2<self::Qm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Rm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<({x: core::int}) → dynamic, self::Rm2::Z> {
+ synthetic constructor •() → self::Rm2<self::Rm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Sm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<([core::int]) → dynamic, self::Sm2::Z> {
+ synthetic constructor •() → self::Sm2<self::Sm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Tm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<([core::int]) → dynamic, self::Tm2::Z> {
+ synthetic constructor •() → self::Tm2<self::Tm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Um2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<core::Function, self::Um2::Z> {
+ synthetic constructor •() → self::Um2<self::Um2::Z>
+ : super core::Object::•()
+ ;
+}
+class Vm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<(core::Function) → dynamic, self::Vm2::Z> {
+ synthetic constructor •() → self::Vm2<self::Vm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Wm2<Z extends core::Object = dynamic> extends core::Object implements self::Am2<() → (() → core::Function) → dynamic, self::Wm2::Z> {
+ synthetic constructor •() → self::Wm2<self::Wm2::Z>
+ : super core::Object::•()
+ ;
+}
+class Am3<L extends core::Object = dynamic, Y extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::Am3<self::Am3::L, self::Am3::Y>
+ : super core::Object::•()
+ ;
+}
+abstract class _Bm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<(core::int) → dynamic, self::_Bm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Bm3&Object&Am3<self::_Bm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Bm3<Z extends core::Object = dynamic> extends self::_Bm3&Object&Am3<self::Bm3::Z> {
+ synthetic constructor •() → self::Bm3<self::Bm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Cm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<(core::int) → dynamic, self::_Cm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Cm3&Object&Am3<self::_Cm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Cm3<Z extends core::Object = dynamic> extends self::_Cm3&Object&Am3<self::Cm3::Z> {
+ synthetic constructor •() → self::Cm3<self::Cm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Dm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<() → core::int, self::_Dm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Dm3&Object&Am3<self::_Dm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Dm3<Z extends core::Object = dynamic> extends self::_Dm3&Object&Am3<self::Dm3::Z> {
+ synthetic constructor •() → self::Dm3<self::Dm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Em3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<() → dynamic, self::_Em3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Em3&Object&Am3<self::_Em3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Em3<Z extends core::Object = dynamic> extends self::_Em3&Object&Am3<self::Em3::Z> {
+ synthetic constructor •() → self::Em3<self::Em3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Fm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<() → dynamic, self::_Fm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Fm3&Object&Am3<self::_Fm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Fm3<Z extends core::Object = dynamic> extends self::_Fm3&Object&Am3<self::Fm3::Z> {
+ synthetic constructor •() → self::Fm3<self::Fm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Gm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<({x: core::int}) → dynamic, self::_Gm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Gm3&Object&Am3<self::_Gm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Gm3<Z extends core::Object = dynamic> extends self::_Gm3&Object&Am3<self::Gm3::Z> {
+ synthetic constructor •() → self::Gm3<self::Gm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Hm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<([core::int]) → dynamic, self::_Hm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Hm3&Object&Am3<self::_Hm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Hm3<Z extends core::Object = dynamic> extends self::_Hm3&Object&Am3<self::Hm3::Z> {
+ synthetic constructor •() → self::Hm3<self::Hm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Im3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<([core::int]) → dynamic, self::_Im3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Im3&Object&Am3<self::_Im3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Im3<Z extends core::Object = dynamic> extends self::_Im3&Object&Am3<self::Im3::Z> {
+ synthetic constructor •() → self::Im3<self::Im3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Jm3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<(core::Function) → dynamic, self::_Jm3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Jm3&Object&Am3<self::_Jm3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Jm3<Z extends core::Object = dynamic> extends self::_Jm3&Object&Am3<self::Jm3::Z> {
+ synthetic constructor •() → self::Jm3<self::Jm3::Z>
+ : super core::Object::•()
+ ;
+}
+abstract class _Km3&Object&Am3<Z extends core::Object = dynamic> extends core::Object implements self::Am3<() → (() → core::Function) → dynamic, self::_Km3&Object&Am3::Z> {
+ synthetic constructor •() → self::_Km3&Object&Am3<self::_Km3&Object&Am3::Z>
+ : super core::Object::•()
+ ;
+}
+class Km3<Z extends core::Object = dynamic> extends self::_Km3&Object&Am3<self::Km3::Z> {
+ synthetic constructor •() → self::Km3<self::Km3::Z>
+ : super core::Object::•()
+ ;
+}
+class Af1<X extends (core::int) → dynamic = (core::int) → dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Af1<self::Af1::foo::X>
+ return null;
+}
+class Bf1<X extends (core::int) → dynamic = (core::int) → dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf1<self::Bf1::foo::X>
+ return null;
+}
+class Cf1<X extends () → core::int = () → core::int> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Cf1<self::Cf1::foo::X>
+ return null;
+}
+class Df1<X extends () → dynamic = () → dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Df1<self::Df1::foo::X>
+ return null;
+}
+class Ef1<X extends () → dynamic = () → dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef1<self::Ef1::foo::X>
+ return null;
+}
+class Ff1<X extends ({x: core::int}) → dynamic = ({x: core::int}) → dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Ff1<self::Ff1::foo::X>
+ return null;
+}
+class Gf1<X extends ([core::int]) → dynamic = ([core::int]) → dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Gf1<self::Gf1::foo::X>
+ return null;
+}
+class Hf1<X extends ([core::int]) → dynamic = ([core::int]) → dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf1<self::Hf1::foo::X>
+ return null;
+}
+class If1<X extends core::Function = core::Function> extends core::Object {
+ static factory foo<X extends core::Function = dynamic>() → self::If1<self::If1::foo::X>
+ return null;
+}
+class Jf1<X extends (core::Function) → dynamic = (core::Function) → dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf1<self::Jf1::foo::X>
+ return null;
+}
+class Kf1<X extends () → (() → core::Function) → dynamic = () → (() → core::Function) → dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf1<self::Kf1::foo::X>
+ return null;
+}
+class Bf2<X extends (core::int) → dynamic = (core::int) → dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Bf2<self::Bf2::foo::X>
+ return null;
+}
+class Cf2<X extends (core::int) → dynamic = (core::int) → dynamic> extends core::Object {
+ static factory foo<X extends (core::int) → dynamic = dynamic>() → self::Cf2<self::Cf2::foo::X>
+ return null;
+}
+class Df2<X extends () → core::int = () → core::int> extends core::Object {
+ static factory foo<X extends () → core::int = dynamic>() → self::Df2<self::Df2::foo::X>
+ return null;
+}
+class Ef2<X extends () → dynamic = () → dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ef2<self::Ef2::foo::X>
+ return null;
+}
+class Ff2<X extends () → dynamic = () → dynamic> extends core::Object {
+ static factory foo<X extends () → dynamic = dynamic>() → self::Ff2<self::Ff2::foo::X>
+ return null;
+}
+class Gf2<X extends ({x: core::int}) → dynamic = ({x: core::int}) → dynamic> extends core::Object {
+ static factory foo<X extends ({x: core::int}) → dynamic = dynamic>() → self::Gf2<self::Gf2::foo::X>
+ return null;
+}
+class Hf2<X extends ([core::int]) → dynamic = ([core::int]) → dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::Hf2<self::Hf2::foo::X>
+ return null;
+}
+class If2<X extends ([core::int]) → dynamic = ([core::int]) → dynamic> extends core::Object {
+ static factory foo<X extends ([core::int]) → dynamic = dynamic>() → self::If2<self::If2::foo::X>
+ return null;
+}
+class Jf2<X extends (core::Function) → dynamic = (core::Function) → dynamic> extends core::Object {
+ static factory foo<X extends (core::Function) → dynamic = dynamic>() → self::Jf2<self::Jf2::foo::X>
+ return null;
+}
+class Kf2<X extends () → (() → core::Function) → dynamic = () → (() → core::Function) → dynamic> extends core::Object {
+ static factory foo<X extends () → (() → core::Function) → dynamic = dynamic>() → self::Kf2<self::Kf2::foo::X>
+ return null;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/invalidate_package_part_from_package_url_as_file.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/invalidate_package_part_from_package_url_as_file.yaml
new file mode 100644
index 0000000..d5a757b
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/invalidate_package_part_from_package_url_as_file.yaml
@@ -0,0 +1,25 @@
+# Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Test that invalidating a part of a package works with package URI when the
+# part file was referenced via a package URI
+
+type: basic
+entry: "package:example/main.dart"
+strong: false
+invalidate:
+ - pkg/example/b.dart
+sources:
+ pkg/example/main.dart: |
+ part "package:example/b.dart";
+ main() {
+ print("hello");
+ b();
+ }
+ pkg/example/b.dart: |
+ part of "package:example/main.dart";
+ b() {
+ print("b1");
+ }
+ .packages: example:pkg/example
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/invalidate_package_part_from_package_url_as_package.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/invalidate_package_part_from_package_url_as_package.yaml
new file mode 100644
index 0000000..149b1ae
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/invalidate_package_part_from_package_url_as_package.yaml
@@ -0,0 +1,25 @@
+# Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Test that invalidating a part of a package works with package URI when the
+# part file was referenced via a package URI
+
+type: basic
+entry: "package:example/main.dart"
+strong: false
+invalidate:
+ - "package:example/b.dart"
+sources:
+ pkg/example/main.dart: |
+ part "package:example/b.dart";
+ main() {
+ print("hello");
+ b();
+ }
+ pkg/example/b.dart: |
+ part of "package:example/main.dart";
+ b() {
+ print("b1");
+ }
+ .packages: example:pkg/example
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/regress_35215.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/regress_35215.yaml
new file mode 100644
index 0000000..5fd397a
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/regress_35215.yaml
@@ -0,0 +1,44 @@
+# Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Load from a dill file, update a file in the dill that is the context of an
+# error in such a way that the position in the newly compiled procedure doesn't
+# exist in the old library.
+
+type: newworld
+strong: true
+worlds:
+ - entry: main.dart
+ sources:
+ main.dart: |
+ import "b.dart";
+ main() {
+ b(42);
+ }
+ b.dart: |
+ b({int named}) {
+ print("b");
+ }
+ expectedLibraryCount: 2
+ errors: true
+ - entry: main.dart
+ worldTypex: updated
+ invalidate:
+ - b.dart
+ sources:
+ main.dart: |
+ import "b.dart";
+ main() {
+ b(42);
+ }
+ b.dart: |
+ // lots of comments
+ // forcing offsets down
+ // and also adding more lines
+ // and whatnot
+ b({int named}) {
+ print("b");
+ }
+ expectedLibraryCount: 2
+ errors: true
diff --git a/pkg/front_end/testcases/regress/issue_35213.dart b/pkg/front_end/testcases/regress/issue_35213.dart
new file mode 100644
index 0000000..37a9f1c
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35213.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+f(int a int b) { }
+
+main() {
+ f(2, 3);
+}
diff --git a/pkg/front_end/testcases/regress/issue_35213.dart.legacy.expect b/pkg/front_end/testcases/regress/issue_35213.dart.legacy.expect
new file mode 100644
index 0000000..1280dd9
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35213.dart.legacy.expect
@@ -0,0 +1,21 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/regress/issue_35213.dart:5:9: Error: Expected ',' before this.
+// f(int a int b) { }
+// ^^^
+
+// Unhandled errors:
+//
+// pkg/front_end/testcases/regress/issue_35213.dart:5:9: Error: Expected ',' before this.
+// f(int a int b) { }
+// ^^^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+static method f(core::int a, core::int b) → dynamic {}
+static method main() → dynamic {
+ self::f(2, 3);
+}
+
diff --git a/pkg/front_end/testcases/regress/issue_35213.dart.legacy.transformed.expect b/pkg/front_end/testcases/regress/issue_35213.dart.legacy.transformed.expect
new file mode 100644
index 0000000..a66ce9c
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35213.dart.legacy.transformed.expect
@@ -0,0 +1,15 @@
+// Unhandled errors:
+//
+// pkg/front_end/testcases/regress/issue_35213.dart:5:9: Error: Expected ',' before this.
+// f(int a int b) { }
+// ^^^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+static method f(core::int a, core::int b) → dynamic {}
+static method main() → dynamic {
+ self::f(2, 3);
+}
+
diff --git a/pkg/front_end/testcases/regress/issue_35213.dart.outline.expect b/pkg/front_end/testcases/regress/issue_35213.dart.outline.expect
new file mode 100644
index 0000000..040a0f3
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35213.dart.outline.expect
@@ -0,0 +1,14 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/regress/issue_35213.dart:5:9: Error: Expected ',' before this.
+// f(int a int b) { }
+// ^^^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+static method f(core::int a, core::int b) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/regress/issue_35213.dart.strong.expect b/pkg/front_end/testcases/regress/issue_35213.dart.strong.expect
new file mode 100644
index 0000000..cd5fe47
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35213.dart.strong.expect
@@ -0,0 +1,20 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/regress/issue_35213.dart:5:9: Error: Expected ',' before this.
+// f(int a int b) { }
+// ^^^
+
+// Unhandled errors:
+//
+// pkg/front_end/testcases/regress/issue_35213.dart:5:9: Error: Expected ',' before this.
+// f(int a int b) { }
+// ^^^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+static method f(core::int a, core::int b) → dynamic {}
+static method main() → dynamic {
+ self::f(2, 3);
+}
diff --git a/pkg/front_end/testcases/regress/issue_35213.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_35213.dart.strong.transformed.expect
new file mode 100644
index 0000000..1f16d48
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35213.dart.strong.transformed.expect
@@ -0,0 +1,14 @@
+// Unhandled errors:
+//
+// pkg/front_end/testcases/regress/issue_35213.dart:5:9: Error: Expected ',' before this.
+// f(int a int b) { }
+// ^^^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+static method f(core::int a, core::int b) → dynamic {}
+static method main() → dynamic {
+ self::f(2, 3);
+}
diff --git a/pkg/front_end/tool/_fasta/entry_points.dart b/pkg/front_end/tool/_fasta/entry_points.dart
index bd473b2..22d2418 100644
--- a/pkg/front_end/tool/_fasta/entry_points.dart
+++ b/pkg/front_end/tool/_fasta/entry_points.dart
@@ -227,8 +227,7 @@
KernelTarget createKernelTarget(
DillTarget dillTarget, UriTranslator uriTranslator) {
- return new KernelTarget(c.fileSystem, false, dillTarget, uriTranslator,
- uriToSource: c.uriToSource);
+ return new KernelTarget(c.fileSystem, false, dillTarget, uriTranslator);
}
Future<KernelTarget> buildOutline([Uri output]) async {
diff --git a/pkg/kernel/bin/size_breakdown.dart b/pkg/kernel/bin/size_breakdown.dart
index a99233d..01fec0f 100755
--- a/pkg/kernel/bin/size_breakdown.dart
+++ b/pkg/kernel/bin/size_breakdown.dart
@@ -25,7 +25,9 @@
List<int> bytes = new File(args[0]).readAsBytesSync();
try {
Component p = new Component();
- new WrappedBinaryBuilder(bytes).readComponent(p);
+ new WrappedBinaryBuilder(bytes)
+ ..readComponent(p)
+ ..report();
} catch (e) {
print("Argument given isn't a dill file that can be loaded.");
usage();
@@ -34,41 +36,50 @@
class WrappedBinaryBuilder extends BinaryBuilder {
WrappedBinaryBuilder(var _bytes) : super(_bytes, disableLazyReading: true);
+ int offsetsSize = 0;
+ int stringTableSize = 0;
+ int linkTableSize = 0;
+ int uriToSourceSize = 0;
+ int constantTableSize = 0;
+ Map<Uri, int> librarySizes = {};
+
+ int readOffset() {
+ offsetsSize -= byteOffset;
+ int result = super.readOffset();
+ offsetsSize += byteOffset;
+ return result;
+ }
void readStringTable(List<String> table) {
- int size = -byteOffset;
+ stringTableSize -= byteOffset;
super.readStringTable(table);
- size += super.byteOffset;
- print("String table: ${_bytesToReadable(size)}.");
+ stringTableSize += byteOffset;
}
void readLinkTable(CanonicalName linkRoot) {
- int size = -byteOffset;
+ linkTableSize -= byteOffset;
super.readLinkTable(linkRoot);
- size += super.byteOffset;
- print("Link table: ${_bytesToReadable(size)}.");
+ linkTableSize += byteOffset;
}
Map<Uri, Source> readUriToSource() {
- int size = -byteOffset;
+ uriToSourceSize -= byteOffset;
var result = super.readUriToSource();
- size += super.byteOffset;
- print("URI to sources map: ${_bytesToReadable(size)}.");
+ uriToSourceSize += byteOffset;
return result;
}
void readConstantTable() {
- int size = -byteOffset;
+ constantTableSize -= byteOffset;
super.readConstantTable();
- size += super.byteOffset;
- print("Constant table: ${_bytesToReadable(size)}.");
+ constantTableSize += byteOffset;
}
Library readLibrary(Component component, int endOffset) {
int size = -byteOffset;
var result = super.readLibrary(component, endOffset);
- size += super.byteOffset;
- print("Library '${result.importUri}': ${_bytesToReadable(size)}.");
+ size += byteOffset;
+ librarySizes[result.importUri] = size;
return result;
}
@@ -82,4 +93,16 @@
}
return "${dSize.toStringAsFixed(1)} ${what[idx]} ($size B)";
}
+
+ void report() {
+ print("Offsets: ${_bytesToReadable(offsetsSize)}");
+ print("String table: ${_bytesToReadable(stringTableSize)}");
+ print("Link table: ${_bytesToReadable(linkTableSize)}");
+ print("URI to source table: ${_bytesToReadable(uriToSourceSize)}");
+ print("Constant table: ${_bytesToReadable(constantTableSize)}");
+ print("");
+ for (Uri uri in librarySizes.keys) {
+ print("Library '$uri': ${_bytesToReadable(librarySizes[uri])}.");
+ }
+ }
}
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 7555396..3006953 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -5695,7 +5695,7 @@
/// number. The returned line contains no line separators.
String getTextLine(int line) {
RangeError.checkValueInInterval(line, 1, lineStarts.length, 'line');
- if (source == null) return null;
+ if (source == null || source.isEmpty) return null;
cachedText ??= utf8.decode(source, allowMalformed: true);
// -1 as line numbers start at 1.
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 8b591ac..c4cc243 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -1155,7 +1155,10 @@
var flags = readByte();
var name = readName();
var annotations = readAnnotationList(node);
- debugPath.add(node.name?.name ?? 'redirecting-factory-constructor');
+ assert(() {
+ debugPath.add(node.name?.name ?? 'redirecting-factory-constructor');
+ return true;
+ }());
var targetReference = readMemberReference();
var typeArguments = readDartTypeList();
int typeParameterStackHeight = typeParameterStack.length;
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index b46a768..9143687 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -23,7 +23,8 @@
final StringIndexer stringIndexer;
ConstantIndexer _constantIndexer;
final UriIndexer _sourceUriIndexer = new UriIndexer();
- final Set<Uri> _knownSourceUri = new Set<Uri>();
+ bool _currentlyInNonimplementation = false;
+ final List<bool> _sourcesFromRealImplementation = new List<bool>();
Map<LibraryDependency, int> _libraryDependencyIndex =
<LibraryDependency, int>{};
@@ -34,6 +35,7 @@
final BytesSink _constantsBytesSink;
BufferedSink _constantsSink;
BufferedSink _sink;
+ bool includeSources;
List<int> libraryOffsets;
List<int> classOffsets;
@@ -53,7 +55,8 @@
///
/// The BinaryPrinter will use its own buffer, so the [sink] does not need
/// one.
- BinaryPrinter(Sink<List<int>> sink, {StringIndexer stringIndexer})
+ BinaryPrinter(Sink<List<int>> sink,
+ {StringIndexer stringIndexer, this.includeSources = true})
: _mainSink = new BufferedSink(sink),
_metadataSink = new BufferedSink(new BytesSink()),
_constantsBytesSink = new BytesSink(),
@@ -217,15 +220,16 @@
type.accept(this);
}
- // The currently active file uri where we are writing [TreeNode]s from. If
- // this is set to `null` we cannot write file offsets. The [writeOffset]
- // helper function will ensure this.
- Uri _activeFileUri;
-
// Returns the new active file uri.
Uri writeUriReference(Uri uri) {
final int index = _sourceUriIndexer.put(uri);
writeUInt30(index);
+ if (!_currentlyInNonimplementation) {
+ if (_sourcesFromRealImplementation.length <= index) {
+ _sourcesFromRealImplementation.length = index + 1;
+ }
+ _sourcesFromRealImplementation[index] = true;
+ }
return uri;
}
@@ -315,7 +319,6 @@
writeUInt32(Tag.ComponentFile);
writeUInt32(Tag.BinaryFormatVersion);
indexLinkTable(component);
- indexUris(component);
_collectMetadata(component);
if (_metadataSubsections != null) {
_writeNodeMetadataImpl(component, componentOffset);
@@ -487,10 +490,6 @@
writeUInt32(getBufferOffset() + 4); // total size.
}
- void indexUris(Component component) {
- _knownSourceUri.addAll(component.uriToSource.keys);
- }
-
void writeUriToSource(Map<Uri, Source> uriToSource) {
_binaryOffsetForSourceTable = getBufferOffset();
@@ -503,9 +502,12 @@
Utf8Encoder utf8Encoder = const Utf8Encoder();
for (Uri uri in _sourceUriIndexer.index.keys) {
index[i] = getBufferOffset();
- Source source =
- (_knownSourceUri.contains(uri) ? uriToSource[uri] : null) ??
- new Source(<int>[], const <int>[]);
+ Source source = ((includeSources &&
+ _sourcesFromRealImplementation.length > i &&
+ _sourcesFromRealImplementation[i] == true)
+ ? uriToSource[uri]
+ : null) ??
+ new Source(<int>[], const <int>[]);
writeByteList(utf8Encoder.convert(uri == null ? "" : "$uri"));
writeByteList(source.source);
@@ -571,10 +573,6 @@
}
writeOffset(int offset) {
- if (_activeFileUri == null) {
- offset = TreeNode.noOffset;
- }
-
// TODO(jensj): Delta-encoding.
// File offset ranges from -1 and up,
// but is here saved as unsigned (thus the +1)
@@ -616,11 +614,7 @@
writeByte(insideExternalLibrary ? 1 : 0);
writeCanonicalNameReference(getCanonicalNameOfLibrary(node));
writeStringReference(node.name ?? '');
- // TODO(jensj): We save (almost) the same URI twice.
-
- final Uri activeFileUriSaved = _activeFileUri;
- _activeFileUri = writeUriReference(node.fileUri);
-
+ writeUriReference(node.fileUri);
writeAnnotationList(node.annotations);
writeLibraryDependencies(node);
writeAdditionalExports(node.additionalExports);
@@ -634,8 +628,6 @@
writeNodeList(node.procedures);
procedureOffsets.add(getBufferOffset());
- _activeFileUri = activeFileUriSaved;
-
// Fixed-size ints at the end used as an index.
assert(classOffsets.length > 0);
for (int offset in classOffsets) {
@@ -705,10 +697,7 @@
void visitTypedef(Typedef node) {
_variableIndexer ??= new VariableIndexer();
writeCanonicalNameReference(getCanonicalNameOfTypedef(node));
-
- final Uri activeFileUriSaved = _activeFileUri;
- _activeFileUri = writeUriReference(node.fileUri);
-
+ writeUriReference(node.fileUri);
writeOffset(node.fileOffset);
writeStringReference(node.name);
writeAnnotationList(node.annotations);
@@ -724,8 +713,6 @@
leaveScope(typeParameters: node.typeParametersOfFunctionType);
leaveScope(typeParameters: node.typeParameters, variableScope: true);
-
- _activeFileUri = activeFileUriSaved;
}
void writeAnnotation(Expression annotation) {
@@ -753,16 +740,15 @@
void visitClass(Class node) {
classOffsets.add(getBufferOffset());
+ if (node.isAnonymousMixin) _currentlyInNonimplementation = true;
+
int flags = _encodeClassFlags(node.flags, node.level);
if (node.canonicalName == null) {
throw 'Missing canonical name for $node';
}
writeByte(Tag.Class);
writeCanonicalNameReference(getCanonicalNameOfClass(node));
-
- final Uri activeFileUriSaved = _activeFileUri;
- _activeFileUri = writeUriReference(node.fileUri);
-
+ writeUriReference(node.fileUri);
writeOffset(node.startFileOffset);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
@@ -784,13 +770,12 @@
writeNodeList(node.redirectingFactoryConstructors);
leaveScope(typeParameters: node.typeParameters);
- _activeFileUri = activeFileUriSaved;
-
assert(procedureOffsets.length > 0);
for (int offset in procedureOffsets) {
writeUInt32(offset);
}
writeUInt32(procedureOffsets.length - 1);
+ _currentlyInNonimplementation = false;
}
static final Name _emptyName = new Name('');
@@ -803,10 +788,7 @@
enterScope(memberScope: true);
writeByte(Tag.Constructor);
writeCanonicalNameReference(getCanonicalNameOfMember(node));
-
- final Uri activeFileUriSaved = _activeFileUri;
- _activeFileUri = writeUriReference(node.fileUri);
-
+ writeUriReference(node.fileUri);
writeOffset(node.startFileOffset);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
@@ -822,8 +804,6 @@
node.function.namedParameters.length);
writeNodeList(node.initializers);
- _activeFileUri = activeFileUriSaved;
-
leaveScope(memberScope: true);
}
@@ -834,13 +814,17 @@
if (node.canonicalName == null) {
throw 'Missing canonical name for $node';
}
+
+ final bool currentlyInNonimplementationSaved =
+ _currentlyInNonimplementation;
+ if (node.isNoSuchMethodForwarder || node.isSyntheticForwarder) {
+ _currentlyInNonimplementation = true;
+ }
+
enterScope(memberScope: true);
writeByte(Tag.Procedure);
writeCanonicalNameReference(getCanonicalNameOfMember(node));
-
- final Uri activeFileUriSaved = _activeFileUri;
- _activeFileUri = writeUriReference(node.fileUri);
-
+ writeUriReference(node.fileUri);
writeOffset(node.startFileOffset);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
@@ -851,11 +835,9 @@
writeOptionalReference(node.forwardingStubSuperTargetReference);
writeOptionalReference(node.forwardingStubInterfaceTargetReference);
writeOptionalNode(node.function);
-
- _activeFileUri = activeFileUriSaved;
-
leaveScope(memberScope: true);
+ _currentlyInNonimplementation = currentlyInNonimplementationSaved;
assert((node.forwardingStubSuperTarget != null) ||
!(node.isForwardingStub && node.function.body != null));
}
@@ -868,10 +850,7 @@
enterScope(memberScope: true);
writeByte(Tag.Field);
writeCanonicalNameReference(getCanonicalNameOfMember(node));
-
- final Uri activeFileUriSaved = _activeFileUri;
- _activeFileUri = writeUriReference(node.fileUri);
-
+ writeUriReference(node.fileUri);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
writeByte(node.flags);
@@ -879,9 +858,6 @@
writeAnnotationList(node.annotations);
writeNode(node.type);
writeOptionalNode(node.initializer);
-
- _activeFileUri = activeFileUriSaved;
-
leaveScope(memberScope: true);
}
@@ -896,10 +872,7 @@
memberScope: true,
variableScope: true);
writeCanonicalNameReference(getCanonicalNameOfMember(node));
-
- final Uri activeFileUriSaved = _activeFileUri;
- _activeFileUri = writeUriReference(node.fileUri);
-
+ writeUriReference(node.fileUri);
writeOffset(node.fileOffset);
writeOffset(node.fileEndOffset);
writeByte(node.flags);
@@ -914,8 +887,6 @@
writeVariableDeclarationList(node.positionalParameters);
writeVariableDeclarationList(node.namedParameters);
- _activeFileUri = activeFileUriSaved;
-
leaveScope(
typeParameters: node.typeParameters,
memberScope: true,
diff --git a/pkg/kernel/lib/binary/limited_ast_to_binary.dart b/pkg/kernel/lib/binary/limited_ast_to_binary.dart
index 82fe07d..bd00832 100644
--- a/pkg/kernel/lib/binary/limited_ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/limited_ast_to_binary.dart
@@ -24,7 +24,7 @@
LimitedBinaryPrinter(
Sink<List<int>> sink, this.predicate, this.excludeUriToSource)
- : super(sink);
+ : super(sink, includeSources: !excludeUriToSource);
@override
void computeCanonicalNames(Component component) {
@@ -60,13 +60,4 @@
var librariesToWrite = libraries.where(predicate).toList();
super.writeComponentIndex(component, librariesToWrite);
}
-
- @override
- void indexUris(Component component) {
- if (!excludeUriToSource) {
- super.indexUris(component);
- } else {
- // We pretend not to know any uris, thereby excluding all sources.
- }
- }
}
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index b453f06..5dc341f 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -5,19 +5,190 @@
import '../ast.dart'
show
BottomType,
+ Class,
DartType,
DynamicType,
FunctionType,
InterfaceType,
+ InvalidType,
NamedType,
TypeParameter,
+ TypeParameterType,
TypedefType,
VoidType;
-import '../type_algebra.dart' show substitute;
+import '../type_algebra.dart' show Substitution, substitute;
import '../type_environment.dart' show TypeEnvironment;
+import '../util/graph.dart' show Graph, computeStrongComponents;
+
+import '../visitor.dart' show DartTypeVisitor;
+
+class TypeVariableGraph extends Graph<int> {
+ List<int> vertices;
+ List<TypeParameter> typeParameters;
+ List<DartType> bounds;
+
+ // `edges[i]` is the list of indices of type variables that reference the type
+ // variable with the index `i` in their bounds.
+ List<List<int>> edges;
+
+ TypeVariableGraph(this.typeParameters, this.bounds) {
+ assert(typeParameters.length == bounds.length);
+
+ vertices = new List<int>(typeParameters.length);
+ Map<TypeParameter, int> typeParameterIndices = <TypeParameter, int>{};
+ edges = new List<List<int>>(typeParameters.length);
+ for (int i = 0; i < vertices.length; i++) {
+ vertices[i] = i;
+ typeParameterIndices[typeParameters[i]] = i;
+ edges[i] = <int>[];
+ }
+
+ for (int i = 0; i < vertices.length; i++) {
+ OccurrenceCollectorVisitor collector =
+ new OccurrenceCollectorVisitor(typeParameters.toSet());
+ collector.visit(bounds[i]);
+ for (TypeParameter typeParameter in collector.occurred) {
+ edges[typeParameterIndices[typeParameter]].add(i);
+ }
+ }
+ }
+
+ Iterable<int> neighborsOf(int index) {
+ return edges[index];
+ }
+}
+
+class OccurrenceCollectorVisitor extends DartTypeVisitor {
+ final Set<TypeParameter> typeParameters;
+ Set<TypeParameter> occurred = new Set<TypeParameter>();
+
+ OccurrenceCollectorVisitor(this.typeParameters);
+
+ visit(DartType node) => node.accept(this);
+
+ visitNamedType(NamedType node) {
+ node.type.accept(this);
+ }
+
+ visitInvalidType(InvalidType node);
+ visitDynamicType(DynamicType node);
+ visitVoidType(VoidType node);
+
+ visitInterfaceType(InterfaceType node) {
+ for (DartType argument in node.typeArguments) {
+ argument.accept(this);
+ }
+ }
+
+ visitTypedefType(TypedefType node) {
+ for (DartType argument in node.typeArguments) {
+ argument.accept(this);
+ }
+ }
+
+ visitFunctionType(FunctionType node) {
+ for (TypeParameter typeParameter in node.typeParameters) {
+ typeParameter.bound.accept(this);
+ typeParameter.defaultType?.accept(this);
+ }
+ for (DartType parameter in node.positionalParameters) {
+ parameter.accept(this);
+ }
+ for (NamedType namedParameter in node.namedParameters) {
+ namedParameter.type.accept(this);
+ }
+ node.returnType.accept(this);
+ }
+
+ visitTypeParameterType(TypeParameterType node) {
+ if (typeParameters.contains(node.parameter)) {
+ occurred.add(node.parameter);
+ }
+ }
+}
+
+DartType instantiateToBounds(DartType type, Class object) {
+ if (type is InterfaceType) {
+ for (var typeArgument in type.typeArguments) {
+ // If at least one of the arguments is not dynamic, we assume that the
+ // type is not raw and does not need instantiation of its type parameters
+ // to their bounds.
+ if (typeArgument is! DynamicType) {
+ return type;
+ }
+ }
+ return new InterfaceType.byReference(
+ type.className, calculateBounds(type.classNode.typeParameters, object));
+ }
+ if (type is TypedefType) {
+ for (var typeArgument in type.typeArguments) {
+ if (typeArgument is! DynamicType) {
+ return type;
+ }
+ }
+ return new TypedefType.byReference(type.typedefReference,
+ calculateBounds(type.typedefNode.typeParameters, object));
+ }
+ return type;
+}
+
+/// Calculates bounds to be provided as type arguments in place of missing type
+/// arguments on raw types with the given type parameters.
+///
+/// See the [description]
+/// (https://github.com/dart-lang/sdk/blob/master/docs/language/informal/instantiate-to-bound.md)
+/// of the algorithm for details.
+List<DartType> calculateBounds(
+ List<TypeParameter> typeParameters, Class object) {
+ List<DartType> bounds = new List<DartType>(typeParameters.length);
+ for (int i = 0; i < typeParameters.length; i++) {
+ DartType bound = typeParameters[i].bound;
+ if (bound == null) {
+ bound = const DynamicType();
+ } else if (bound is InterfaceType && bound.classNode == object) {
+ DartType defaultType = typeParameters[i].defaultType;
+ if (!(defaultType is InterfaceType && defaultType.classNode == object)) {
+ bound = const DynamicType();
+ }
+ }
+ bounds[i] = bound;
+ }
+
+ TypeVariableGraph graph = new TypeVariableGraph(typeParameters, bounds);
+ List<List<int>> stronglyConnected = computeStrongComponents(graph);
+ for (List<int> component in stronglyConnected) {
+ Map<TypeParameter, DartType> upperBounds = <TypeParameter, DartType>{};
+ Map<TypeParameter, DartType> lowerBounds = <TypeParameter, DartType>{};
+ for (int typeParameterIndex in component) {
+ upperBounds[typeParameters[typeParameterIndex]] = const DynamicType();
+ lowerBounds[typeParameters[typeParameterIndex]] = const BottomType();
+ }
+ Substitution substitution =
+ Substitution.fromUpperAndLowerBounds(upperBounds, lowerBounds);
+ for (int typeParameterIndex in component) {
+ bounds[typeParameterIndex] =
+ substitution.substituteType(bounds[typeParameterIndex]);
+ }
+ }
+
+ for (int i = 0; i < typeParameters.length; i++) {
+ Map<TypeParameter, DartType> upperBounds = <TypeParameter, DartType>{};
+ Map<TypeParameter, DartType> lowerBounds = <TypeParameter, DartType>{};
+ upperBounds[typeParameters[i]] = bounds[i];
+ lowerBounds[typeParameters[i]] = const BottomType();
+ Substitution substitution =
+ Substitution.fromUpperAndLowerBounds(upperBounds, lowerBounds);
+ for (int j = 0; j < typeParameters.length; j++) {
+ bounds[j] = substitution.substituteType(bounds[j]);
+ }
+ }
+
+ return bounds;
+}
+
class TypeArgumentIssue {
// The type argument that violated the bound.
final DartType argument;
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 7268136..094bd2f 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -5,8 +5,6 @@
import 'ast.dart';
-import 'util/graph.dart';
-
/// Returns a type where all occurrences of the given type parameters have been
/// replaced with the corresponding types.
///
@@ -68,126 +66,6 @@
return substitutor.isInfinite ? null : result;
}
-/// Calculates bounds to be provided as type arguments in place of missing type
-/// arguments on raw types with the given type parameters.
-///
-/// See the [description]
-/// (https://github.com/dart-lang/sdk/blob/master/docs/language/informal/instantiate-to-bound.md)
-/// of the algorithm for details.
-List<DartType> calculateBounds(
- List<TypeParameter> typeParameters, Class object) {
- List<DartType> bounds = new List<DartType>(typeParameters.length);
- for (int i = 0; i < typeParameters.length; i++) {
- DartType bound = typeParameters[i].bound;
- if (bound == null) {
- bound = const DynamicType();
- } else if (bound is InterfaceType && bound.classNode == object) {
- DartType defaultType = typeParameters[i].defaultType;
- if (!(defaultType is InterfaceType && defaultType.classNode == object)) {
- bound = const DynamicType();
- }
- }
- bounds[i] = bound;
- }
-
- _TypeVariableGraph graph = new _TypeVariableGraph(typeParameters, bounds);
- List<List<int>> stronglyConnected = computeStrongComponents(graph);
- for (List<int> component in stronglyConnected) {
- Map<TypeParameter, DartType> dynamicSubstitution =
- <TypeParameter, DartType>{};
- Map<TypeParameter, DartType> nullSubstitution = <TypeParameter, DartType>{};
- for (int typeParameterIndex in component) {
- dynamicSubstitution[typeParameters[typeParameterIndex]] =
- const DynamicType();
- nullSubstitution[typeParameters[typeParameterIndex]] = const BottomType();
- }
- _TopSubstitutor substitutor = new _TopSubstitutor(
- Substitution.fromUpperAndLowerBounds(
- dynamicSubstitution, nullSubstitution),
- false);
- for (int typeParameterIndex in component) {
- bounds[typeParameterIndex] =
- substitutor.visit(bounds[typeParameterIndex]);
- }
- }
-
- for (int i = 0; i < typeParameters.length; i++) {
- Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
- Map<TypeParameter, DartType> nullSubstitution = <TypeParameter, DartType>{};
- substitution[typeParameters[i]] = bounds[i];
- nullSubstitution[typeParameters[i]] = const BottomType();
- _TopSubstitutor substitutor = new _TopSubstitutor(
- Substitution.fromUpperAndLowerBounds(substitution, nullSubstitution),
- false);
- for (int j = 0; j < typeParameters.length; j++) {
- bounds[j] = substitutor.visit(bounds[j]);
- }
- }
-
- return bounds;
-}
-
-class _TypeVariableGraph extends Graph<int> {
- List<int> vertices;
- List<TypeParameter> typeParameters;
- List<DartType> bounds;
-
- // `edges[i]` is the list of indices of type variables that reference the type
- // variable with the index `i` in their bounds.
- List<List<int>> edges;
-
- _TypeVariableGraph(this.typeParameters, this.bounds) {
- assert(typeParameters.length == bounds.length);
-
- vertices = new List<int>(typeParameters.length);
- Map<TypeParameter, int> typeParameterIndices = <TypeParameter, int>{};
- edges = new List<List<int>>(typeParameters.length);
- for (int i = 0; i < vertices.length; i++) {
- vertices[i] = i;
- typeParameterIndices[typeParameters[i]] = i;
- edges[i] = <int>[];
- }
-
- for (int i = 0; i < vertices.length; i++) {
- _OccurrenceCollectorVisitor collector =
- new _OccurrenceCollectorVisitor(typeParameters.toSet());
- collector.visit(bounds[i]);
- for (TypeParameter typeParameter in collector.occurred) {
- edges[typeParameterIndices[typeParameter]].add(i);
- }
- }
- }
-
- Iterable<int> neighborsOf(int index) {
- return edges[index];
- }
-}
-
-DartType instantiateToBounds(DartType type, Class object) {
- if (type is InterfaceType) {
- for (var typeArgument in type.typeArguments) {
- // If at least one of the arguments is not dynamic, we assume that the
- // type is not raw and does not need instantiation of its type parameters
- // to their bounds.
- if (typeArgument is! DynamicType) {
- return type;
- }
- }
- return new InterfaceType.byReference(
- type.className, calculateBounds(type.classNode.typeParameters, object));
- }
- if (type is TypedefType) {
- for (var typeArgument in type.typeArguments) {
- if (typeArgument is! DynamicType) {
- return type;
- }
- }
- return new TypedefType.byReference(type.typedefReference,
- calculateBounds(type.typedefNode.typeParameters, object));
- }
- return type;
-}
-
/// Returns true if [type] contains a reference to any of the given [variables].
///
/// It is an error to call this with a [type] that contains a [FunctionType]
@@ -854,52 +732,3 @@
return node.defaultType.accept(this);
}
}
-
-class _OccurrenceCollectorVisitor extends DartTypeVisitor {
- final Set<TypeParameter> typeParameters;
- Set<TypeParameter> occurred = new Set<TypeParameter>();
-
- _OccurrenceCollectorVisitor(this.typeParameters);
-
- visit(DartType node) => node.accept(this);
-
- visitNamedType(NamedType node) {
- node.type.accept(this);
- }
-
- visitInvalidType(InvalidType node);
- visitDynamicType(DynamicType node);
- visitVoidType(VoidType node);
-
- visitInterfaceType(InterfaceType node) {
- for (DartType argument in node.typeArguments) {
- argument.accept(this);
- }
- }
-
- visitTypedefType(TypedefType node) {
- for (DartType argument in node.typeArguments) {
- argument.accept(this);
- }
- }
-
- visitFunctionType(FunctionType node) {
- for (TypeParameter typeParameter in node.typeParameters) {
- typeParameter.bound.accept(this);
- typeParameter.defaultType?.accept(this);
- }
- for (DartType parameter in node.positionalParameters) {
- parameter.accept(this);
- }
- for (NamedType namedParameter in node.namedParameters) {
- namedParameter.type.accept(this);
- }
- node.returnType.accept(this);
- }
-
- visitTypeParameterType(TypeParameterType node) {
- if (typeParameters.contains(node.parameter)) {
- occurred.add(node.parameter);
- }
- }
-}
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index ea0b8d1..9bd0e37 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -259,6 +259,7 @@
useAnalyzerCfe: boolOption("use-cfe"),
useAnalyzerFastaParser: boolOption("analyzer-use-fasta-parser"),
useBlobs: boolOption("use-blobs"),
+ keepGeneratedFiles: boolOption("keep-generated-files"),
useDart2JSWithKernel: boolOption("dart2js-with-kernel"),
useDart2JSOldFrontEnd: boolOption("dart2js-old-frontend"),
useFastStartup: boolOption("fast-startup"),
@@ -314,6 +315,9 @@
// TODO(rnystrom): What is this?
final bool useBlobs;
+ // Keep generated files (instead of deleting them).
+ final bool keepGeneratedFiles;
+
// TODO(rnystrom): Remove these when Dart 1.0 is no longer supported.
final bool useDart2JSWithKernel;
final bool useDart2JSOldFrontEnd;
@@ -339,6 +343,7 @@
bool useAnalyzerCfe,
bool useAnalyzerFastaParser,
bool useBlobs,
+ bool keepGeneratedFiles,
bool useDart2JSWithKernel,
bool useDart2JSOldFrontEnd,
bool useFastStartup,
@@ -357,6 +362,7 @@
useAnalyzerCfe = useAnalyzerCfe ?? false,
useAnalyzerFastaParser = useAnalyzerFastaParser ?? false,
useBlobs = useBlobs ?? false,
+ keepGeneratedFiles = keepGeneratedFiles ?? false,
useDart2JSWithKernel = useDart2JSWithKernel ?? false,
useDart2JSOldFrontEnd = useDart2JSOldFrontEnd ?? false,
useFastStartup = useFastStartup ?? false,
@@ -384,6 +390,7 @@
useAnalyzerCfe == other.useAnalyzerCfe &&
useAnalyzerFastaParser == other.useAnalyzerFastaParser &&
useBlobs == other.useBlobs &&
+ keepGeneratedFiles == other.keepGeneratedFiles &&
useDart2JSWithKernel == other.useDart2JSWithKernel &&
useDart2JSOldFrontEnd == other.useDart2JSOldFrontEnd &&
useFastStartup == other.useFastStartup &&
@@ -418,7 +425,8 @@
(useFastStartup ? 2048 : 0) ^
(useHotReload ? 4096 : 0) ^
(useHotReloadRollback ? 8192 : 0) ^
- (useSdk ? 16384 : 0);
+ (useSdk ? 16384 : 0) ^
+ (keepGeneratedFiles ? 32768 : 0);
String toString() {
var buffer = new StringBuffer();
@@ -444,6 +452,7 @@
if (useAnalyzerCfe) fields.add("use-cfe");
if (useAnalyzerFastaParser) fields.add("analyzer-use-fasta-parser");
if (useBlobs) fields.add("use-blobs");
+ if (keepGeneratedFiles) fields.add("keep-generated-files");
if (useDart2JSWithKernel) fields.add("dart2js-with-kernel");
if (useDart2JSOldFrontEnd) fields.add("dart2js-old-frontend");
if (useFastStartup) fields.add("fast-startup");
@@ -507,6 +516,10 @@
if (useBlobs || other.useBlobs) {
fields.add("useBlobs $useBlobs ${other.useBlobs}");
}
+ if (keepGeneratedFiles || other.keepGeneratedFiles) {
+ fields.add(
+ "keepGeneratedFiles $keepGeneratedFiles ${other.keepGeneratedFiles}");
+ }
if (useDart2JSWithKernel || other.useDart2JSWithKernel) {
fields.add("useDart2JSWithKernel "
"$useDart2JSWithKernel ${other.useDart2JSWithKernel}");
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 69c2c9f..b5d7d03 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -565,7 +565,7 @@
1 /* isolateId chosen randomly */,
[] /* source files */,
false /* suppress warnings */,
- true /* synchronous async */,
+ false /* generate bytecode */,
null /* package_config */,
null /* multirootFilepaths */,
null /* multirootScheme */,
diff --git a/pkg/vm/lib/transformations/pragma.dart b/pkg/vm/lib/transformations/pragma.dart
index 3252cc3..0ab0b88 100644
--- a/pkg/vm/lib/transformations/pragma.dart
+++ b/pkg/vm/lib/transformations/pragma.dart
@@ -9,6 +9,7 @@
const kEntryPointPragmaName = "vm:entry-point";
const kExactResultTypePragmaName = "vm:exact-result-type";
+const kNonNullableResultType = "vm:non-nullable-result-type";
abstract class ParsedPragma {}
@@ -29,6 +30,10 @@
ParsedResultTypeByPathPragma(this.path);
}
+class ParsedNonNullableResultType extends ParsedPragma {
+ ParsedNonNullableResultType();
+}
+
abstract class PragmaAnnotationParser {
/// May return 'null' if the annotation does not represent a recognized
/// @pragma.
@@ -91,6 +96,8 @@
}
throw "ERROR: Unsupported option to '$kExactResultTypePragmaName' "
"pragma: $options";
+ case kNonNullableResultType:
+ return new ParsedNonNullableResultType();
default:
return null;
}
diff --git a/pkg/vm/lib/transformations/type_flow/native_code.dart b/pkg/vm/lib/transformations/type_flow/native_code.dart
index cb6b7ce..291237b 100644
--- a/pkg/vm/lib/transformations/type_flow/native_code.dart
+++ b/pkg/vm/lib/transformations/type_flow/native_code.dart
@@ -159,12 +159,14 @@
Type handleNativeProcedure(
Member member, EntryPointsListener entryPointsListener) {
Type returnType = null;
+ bool nullable = null;
for (var annotation in member.annotations) {
ParsedPragma pragma = _matcher.parsePragma(annotation);
if (pragma == null) continue;
if (pragma is ParsedResultTypeByTypePragma ||
- pragma is ParsedResultTypeByPathPragma) {
+ pragma is ParsedResultTypeByPathPragma ||
+ pragma is ParsedNonNullableResultType) {
// We can only use the 'vm:exact-result-type' pragma on methods in core
// libraries for safety reasons. See 'result_type_pragma.md', detail 1.2
// for explanation.
@@ -177,7 +179,7 @@
var type = pragma.type;
if (type is InterfaceType) {
returnType = entryPointsListener.addAllocatedClass(type.classNode);
- break;
+ continue;
}
throw "ERROR: Invalid return type for native method: ${pragma.type}";
} else if (pragma is ParsedResultTypeByPathPragma) {
@@ -192,16 +194,22 @@
// Error is thrown on the next line if the class is not found.
Class klass = _libraryIndex.getClass(libName, klassName);
Type concreteClass = entryPointsListener.addAllocatedClass(klass);
-
returnType = concreteClass;
- break;
+ } else if (pragma is ParsedNonNullableResultType) {
+ nullable = false;
}
}
+ if (returnType != null && nullable != null) {
+ throw 'ERROR: Cannot have both, @pragma("$kExactResultTypePragmaName") '
+ 'and @pragma("$kNonNullableResultType"), annotating the same member.';
+ }
+
if (returnType != null) {
return returnType;
} else {
- return new Type.fromStatic(member.function.returnType);
+ final coneType = new Type.cone(member.function.returnType);
+ return nullable == false ? coneType : new Type.nullable(coneType);
}
}
}
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 51a0d82..cf23ea8 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -96,6 +96,8 @@
dartType = _normalizeDartType(dartType);
if ((dartType == const DynamicType()) || (dartType == const VoidType())) {
return const AnyType();
+ } else if (dartType == const BottomType()) {
+ return new Type.empty();
} else {
return new ConeType(dartType);
}
diff --git a/pkg/vm/lib/v8_snapshot_profile.dart b/pkg/vm/lib/v8_snapshot_profile.dart
new file mode 100644
index 0000000..ec01774
--- /dev/null
+++ b/pkg/vm/lib/v8_snapshot_profile.dart
@@ -0,0 +1,239 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "package:dart2js_info/src/graph.dart";
+
+class _NodeInfo {
+ int type;
+ int name;
+ int id;
+ int selfSize;
+ int edgeCount;
+ _NodeInfo(
+ this.type,
+ this.name,
+ this.id,
+ this.selfSize,
+ this.edgeCount,
+ );
+}
+
+const List<String> _kRequiredNodeFields = [
+ "type",
+ "name",
+ "id",
+ "self_size",
+ "edge_count",
+];
+
+class _EdgeInfo {
+ int type;
+ int nameOrIndex;
+ int nodeOffset;
+ _EdgeInfo(
+ this.type,
+ this.nameOrIndex,
+ this.nodeOffset,
+ );
+}
+
+const List<String> _kRequiredEdgeFields = [
+ "type",
+ "name_or_index",
+ "to_node",
+];
+
+class NodeInfo {
+ String type;
+ String name;
+ int id;
+ int selfSize;
+ NodeInfo(
+ this.type,
+ this.name,
+ this.id,
+ this.selfSize,
+ );
+}
+
+class V8SnapshotProfile extends Graph<int> {
+ // Indexed by node offset.
+ final Map<int, _NodeInfo> _nodes = {};
+
+ // Indexed by start node offset.
+ final Map<int, List<_EdgeInfo>> _toEdges = {};
+ final Map<int, List<_EdgeInfo>> _fromEdges = {};
+
+ List<String> _nodeFields = [];
+ List<String> _edgeFields = [];
+
+ List<String> _nodeTypes = [];
+ List<String> _edgeTypes = [];
+
+ List<String> _strings = [];
+
+ // Only used to ensure IDs are unique.
+ Set<int> _ids = Set<int>();
+
+ V8SnapshotProfile.fromJson(Map top) {
+ final Map snapshot = top["snapshot"];
+ _parseMetadata(snapshot["meta"]);
+
+ _parseStrings(top["strings"]);
+ Expect.equals(snapshot["node_count"], _parseNodes(top["nodes"]));
+ Expect.equals(snapshot["edge_count"], _parseEdges(top["edges"]));
+
+ _calculateFromEdges();
+ }
+
+ void _parseMetadata(Map meta) {
+ final List nodeFields = meta["node_fields"];
+ nodeFields.forEach(_nodeFields.add);
+ Expect.isTrue(_kRequiredNodeFields.every(_nodeFields.contains));
+
+ final List edgeFields = meta["edge_fields"];
+ edgeFields.forEach(_edgeFields.add);
+ Expect.isTrue(_kRequiredEdgeFields.every(_edgeFields.contains));
+
+ // First entry of "node_types" is an array with the actual node types. IDK
+ // what the other entries are for.
+ List nodeTypes = meta["node_types"];
+ nodeTypes = nodeTypes[0];
+ nodeTypes.forEach(_nodeTypes.add);
+
+ // Same for edges.
+ List edgeTypes = meta["edge_types"];
+ edgeTypes = edgeTypes[0];
+ edgeTypes.forEach(_edgeTypes.add);
+ }
+
+ int _parseNodes(List nodes) {
+ final int typeIndex = _nodeFields.indexOf("type");
+ final int nameIndex = _nodeFields.indexOf("name");
+ final int idIndex = _nodeFields.indexOf("id");
+ final int selfSizeIndex = _nodeFields.indexOf("self_size");
+ final int edgeCountIndex = _nodeFields.indexOf("edge_count");
+
+ int offset = 0;
+ for (; offset < nodes.length; offset += _nodeFields.length) {
+ final int type = nodes[offset + typeIndex];
+ Expect.isTrue(0 <= type && type < _nodeTypes.length);
+
+ final int name = nodes[offset + nameIndex];
+ Expect.isTrue(0 <= name && name < _strings.length);
+
+ final int id = nodes[offset + idIndex];
+ Expect.isTrue(id >= 0);
+ Expect.isFalse(_ids.contains(id));
+ _ids.add(id);
+
+ final int selfSize = nodes[offset + selfSizeIndex];
+ Expect.isTrue(selfSize >= 0);
+
+ final int edgeCount = nodes[offset + edgeCountIndex];
+ Expect.isTrue(edgeCount >= 0);
+
+ _nodes[offset] = _NodeInfo(type, name, id, selfSize, edgeCount);
+ }
+
+ Expect.equals(offset, nodes.length);
+ return offset ~/ _nodeFields.length;
+ }
+
+ int _parseEdges(List edges) {
+ final int typeIndex = _edgeFields.indexOf("type");
+ final int nameOrIndexIndex = _edgeFields.indexOf("name_or_index");
+ final int toNodeIndex = _edgeFields.indexOf("to_node");
+
+ int edgeOffset = 0;
+ for (int nodeOffset = 0;
+ nodeOffset < _nodes.length * _nodeFields.length;
+ nodeOffset += _nodeFields.length) {
+ final int edgeCount = _nodes[nodeOffset].edgeCount;
+ final List<_EdgeInfo> nodeEdges = List<_EdgeInfo>(edgeCount);
+ for (int i = 0; i < edgeCount; ++i, edgeOffset += _edgeFields.length) {
+ final int type = edges[edgeOffset + typeIndex];
+ Expect.isTrue(0 <= type && type < _edgeTypes.length);
+
+ final int nameOrIndex = edges[edgeOffset + nameOrIndexIndex];
+ if (_edgeTypes[type] == "property") {
+ Expect.isTrue(0 <= nameOrIndex && nameOrIndex < _strings.length);
+ } else if (_edgeTypes[type] == "element") {
+ Expect.isTrue(nameOrIndex >= 0);
+ }
+
+ final int toNode = edges[edgeOffset + toNodeIndex];
+ checkNode(toNode);
+ nodeEdges[i] = _EdgeInfo(type, nameOrIndex, toNode);
+ }
+ _toEdges[nodeOffset] = nodeEdges;
+ }
+
+ Expect.equals(edgeOffset, edges.length);
+ return edgeOffset ~/ _edgeFields.length;
+ }
+
+ void checkNode(int offset) {
+ Expect.isTrue(offset >= 0 &&
+ offset % _nodeFields.length == 0 &&
+ offset ~/ _nodeFields.length < _nodes.length);
+ }
+
+ void _calculateFromEdges() {
+ for (final MapEntry<int, List<_EdgeInfo>> entry in _toEdges.entries) {
+ final int fromNode = entry.key;
+ for (final _EdgeInfo edge in entry.value) {
+ final List<_EdgeInfo> backEdges =
+ _fromEdges.putIfAbsent(edge.nodeOffset, () => <_EdgeInfo>[]);
+ backEdges.add(_EdgeInfo(edge.type, edge.nameOrIndex, fromNode));
+ }
+ }
+ }
+
+ void _parseStrings(List strings) => strings.forEach(_strings.add);
+
+ int get accountedBytes {
+ int sum = 0;
+ for (final _NodeInfo info in _nodes.values) {
+ sum += info.selfSize;
+ }
+ return sum;
+ }
+
+ int get unknownCount {
+ final int unknownType = _nodeTypes.indexOf("Unknown");
+ Expect.isTrue(unknownType >= 0);
+
+ int count = 0;
+ for (final MapEntry<int, _NodeInfo> entry in _nodes.entries) {
+ if (entry.value.type == unknownType) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ bool get isEmpty => _nodes.isEmpty;
+ int get nodeCount => _nodes.length;
+
+ Iterable<int> get nodes => _nodes.keys;
+
+ Iterable<int> targetsOf(int source) {
+ return _toEdges[source].map((_EdgeInfo i) => i.nodeOffset);
+ }
+
+ Iterable<int> sourcesOf(int source) {
+ return _fromEdges[source].map((_EdgeInfo i) => i.nodeOffset);
+ }
+
+ int get root => 0;
+
+ NodeInfo operator [](int node) {
+ _NodeInfo info = _nodes[node];
+ final type = info.type != null ? _nodeTypes[info.type] : null;
+ final name = info.name != null ? _strings[info.name] : null;
+ return NodeInfo(type, name, info.id, info.selfSize);
+ }
+}
diff --git a/pkg/vm/tool/precompiler2 b/pkg/vm/tool/precompiler2
index 1d49fff..c6f5421 100755
--- a/pkg/vm/tool/precompiler2
+++ b/pkg/vm/tool/precompiler2
@@ -13,7 +13,6 @@
# passed to Fasta.
set -e
-set -x
OPTIONS=()
GEN_KERNEL_OPTIONS=()
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index a6f8e93..3eb59b3 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -7,7 +7,10 @@
import("runtime_args.gni")
config("dart_public_config") {
- include_dirs = [ "include" ]
+ include_dirs = [
+ ".",
+ "include",
+ ]
}
# Adds PRODUCT define if Flutter has specified "release" for dart_runtime_mode
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index cec8c52..a5c2317 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -157,6 +157,8 @@
"dfe.cc",
"dfe.h",
"gen_snapshot.cc",
+ "kernel_isolate.cc",
+ "kernel_isolate.h",
"options.cc",
"options.h",
"vmservice_impl.cc",
@@ -340,6 +342,7 @@
"..:dart_config",
"..:dart_os_config",
] + extra_configs
+ public_configs = [ "..:dart_public_config" ]
if (is_fuchsia) {
configs -= [ "//build/config:symbol_visibility_hidden" ]
}
@@ -714,6 +717,8 @@
"dart_embedder_api_impl.cc",
"error_exit.cc",
"error_exit.h",
+ "kernel_isolate.cc",
+ "kernel_isolate.h",
"main.cc",
"main_options.cc",
"main_options.h",
@@ -936,6 +941,8 @@
"dfe.h",
"error_exit.cc",
"error_exit.h",
+ "kernel_isolate.cc",
+ "kernel_isolate.h",
"run_vm_tests.cc",
"snapshot_utils.cc",
"snapshot_utils.h",
diff --git a/runtime/bin/dfe.h b/runtime/bin/dfe.h
index af520658..47d95d2 100644
--- a/runtime/bin/dfe.h
+++ b/runtime/bin/dfe.h
@@ -5,6 +5,7 @@
#ifndef RUNTIME_BIN_DFE_H_
#define RUNTIME_BIN_DFE_H_
+#include "bin/kernel_isolate.h"
#include "include/dart_api.h"
#include "include/dart_native_api.h"
#include "platform/assert.h"
diff --git a/runtime/bin/file_fuchsia.cc b/runtime/bin/file_fuchsia.cc
index 0fd8939..40aaf7d 100644
--- a/runtime/bin/file_fuchsia.cc
+++ b/runtime/bin/file_fuchsia.cc
@@ -76,12 +76,31 @@
}
MappedMemory* File::Map(MapType type, int64_t position, int64_t length) {
- UNIMPLEMENTED();
- return NULL;
+ ASSERT(handle_->fd() >= 0);
+ ASSERT(length > 0);
+ int prot = PROT_NONE;
+ switch (type) {
+ case kReadOnly:
+ prot = PROT_READ;
+ break;
+ case kReadExecute:
+ prot = PROT_READ | PROT_EXEC;
+ break;
+ default:
+ return NULL;
+ }
+ void* addr = mmap(NULL, length, prot, MAP_PRIVATE, handle_->fd(), position);
+ if (addr == MAP_FAILED) {
+ return NULL;
+ }
+ return new MappedMemory(addr, length);
}
void MappedMemory::Unmap() {
- UNIMPLEMENTED();
+ int result = munmap(address_, size_);
+ ASSERT(result == 0);
+ address_ = 0;
+ size_ = 0;
}
int64_t File::Read(void* buffer, int64_t num_bytes) {
diff --git a/runtime/bin/file_system_watcher_fuchsia.cc b/runtime/bin/file_system_watcher_fuchsia.cc
index aa943eb..d898542 100644
--- a/runtime/bin/file_system_watcher_fuchsia.cc
+++ b/runtime/bin/file_system_watcher_fuchsia.cc
@@ -7,16 +7,18 @@
#include "bin/file_system_watcher.h"
+#include <errno.h>
+
namespace dart {
namespace bin {
Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
- UNIMPLEMENTED();
+ errno = ENOSYS;
return DartUtils::NewDartOSError();
}
intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
- UNIMPLEMENTED();
+ errno = ENOSYS;
return -1;
}
@@ -25,7 +27,6 @@
}
void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
- UNIMPLEMENTED();
}
intptr_t FileSystemWatcher::Init() {
@@ -33,7 +34,6 @@
}
void FileSystemWatcher::Close(intptr_t id) {
- UNIMPLEMENTED();
}
intptr_t FileSystemWatcher::WatchPath(intptr_t id,
@@ -41,7 +41,7 @@
const char* path,
int events,
bool recursive) {
- UNIMPLEMENTED();
+ errno = ENOSYS;
return -1;
}
diff --git a/runtime/bin/kernel_isolate.cc b/runtime/bin/kernel_isolate.cc
new file mode 100644
index 0000000..c6bc711
--- /dev/null
+++ b/runtime/bin/kernel_isolate.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "bin/kernel_isolate.h"
+
+#include "vm/dart_api_impl.h"
+#include "vm/isolate.h"
+#include "vm/kernel_isolate.h"
+
+namespace dart {
+
+DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ return false;
+#else
+ Isolate* iso = reinterpret_cast<Isolate*>(isolate);
+ return KernelIsolate::IsKernelIsolate(iso);
+#endif
+}
+
+DART_EXPORT bool Dart_KernelIsolateIsRunning() {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ return false;
+#else
+ return KernelIsolate::IsRunning();
+#endif
+}
+
+DART_EXPORT Dart_Port Dart_KernelPort() {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ return false;
+#else
+ return KernelIsolate::KernelPort();
+#endif
+}
+
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileToKernel(const char* script_uri,
+ const uint8_t* platform_kernel,
+ intptr_t platform_kernel_size,
+ bool incremental_compile,
+ const char* package_config) {
+ API_TIMELINE_DURATION(Thread::Current());
+
+ Dart_KernelCompilationResult result;
+#if defined(DART_PRECOMPILED_RUNTIME)
+ result.status = Dart_KernelCompilationStatus_Unknown;
+ result.error = strdup("Dart_CompileToKernel is unsupported.");
+#else
+ result = KernelIsolate::CompileToKernel(script_uri, platform_kernel,
+ platform_kernel_size, 0, NULL,
+ incremental_compile, package_config);
+ if (result.status == Dart_KernelCompilationStatus_Ok) {
+ Dart_KernelCompilationResult accept_result =
+ KernelIsolate::AcceptCompilation();
+ if (accept_result.status != Dart_KernelCompilationStatus_Ok) {
+ FATAL1(
+ "An error occurred in the CFE while accepting the most recent"
+ " compilation results: %s",
+ accept_result.error);
+ }
+ }
+#endif
+ return result;
+}
+
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileSourcesToKernel(const char* script_uri,
+ const uint8_t* platform_kernel,
+ intptr_t platform_kernel_size,
+ int source_files_count,
+ Dart_SourceFile sources[],
+ bool incremental_compile,
+ const char* package_config,
+ const char* multiroot_filepaths,
+ const char* multiroot_scheme) {
+ Dart_KernelCompilationResult result;
+#if defined(DART_PRECOMPILED_RUNTIME)
+ result.status = Dart_KernelCompilationStatus_Unknown;
+ result.error = strdup("Dart_CompileSourcesToKernel is unsupported.");
+#else
+ result = KernelIsolate::CompileToKernel(
+ script_uri, platform_kernel, platform_kernel_size, source_files_count,
+ sources, incremental_compile, package_config, multiroot_filepaths,
+ multiroot_scheme);
+ if (result.status == Dart_KernelCompilationStatus_Ok) {
+ if (KernelIsolate::AcceptCompilation().status !=
+ Dart_KernelCompilationStatus_Ok) {
+ FATAL(
+ "An error occurred in the CFE while accepting the most recent"
+ " compilation results.");
+ }
+ }
+#endif
+ return result;
+}
+
+DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies() {
+ Dart_KernelCompilationResult result;
+#if defined(DART_PRECOMPILED_RUNTIME)
+ result.status = Dart_KernelCompilationStatus_Unknown;
+ result.error = strdup("Dart_KernelListDependencies is unsupported.");
+#else
+ result = KernelIsolate::ListDependencies();
+#endif
+ return result;
+}
+
+} // namespace dart
diff --git a/runtime/bin/kernel_isolate.h b/runtime/bin/kernel_isolate.h
new file mode 100644
index 0000000..4a9e667
--- /dev/null
+++ b/runtime/bin/kernel_isolate.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_BIN_KERNEL_ISOLATE_H_
+#define RUNTIME_BIN_KERNEL_ISOLATE_H_
+
+#include "include/dart_api.h"
+
+namespace dart {
+
+typedef enum {
+ Dart_KernelCompilationStatus_Unknown = -1,
+ Dart_KernelCompilationStatus_Ok = 0,
+ Dart_KernelCompilationStatus_Error = 1,
+ Dart_KernelCompilationStatus_Crash = 2,
+} Dart_KernelCompilationStatus;
+
+typedef struct {
+ Dart_KernelCompilationStatus status;
+ char* error;
+
+ uint8_t* kernel;
+ intptr_t kernel_size;
+} Dart_KernelCompilationResult;
+
+DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate);
+DART_EXPORT bool Dart_KernelIsolateIsRunning();
+DART_EXPORT Dart_Port Dart_KernelPort();
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileToKernel(const char* script_uri,
+ const uint8_t* platform_kernel,
+ const intptr_t platform_kernel_size,
+ bool incremental_compile,
+ const char* package_config);
+
+typedef struct {
+ const char* uri;
+ const char* source;
+} Dart_SourceFile;
+DART_EXPORT Dart_KernelCompilationResult
+Dart_CompileSourcesToKernel(const char* script_uri,
+ const uint8_t* platform_kernel,
+ intptr_t platform_kernel_size,
+ int source_files_count,
+ Dart_SourceFile source_files[],
+ bool incremental_compile,
+ const char* package_config,
+ const char* multiroot_filepaths,
+ const char* multiroot_scheme);
+
+DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies();
+
+#define DART_KERNEL_ISOLATE_NAME "kernel-service"
+
+} // namespace dart
+
+#endif // RUNTIME_BIN_KERNEL_ISOLATE_H_
diff --git a/runtime/bin/platform_patch.dart b/runtime/bin/platform_patch.dart
index dd7d88a..99b4e7c 100644
--- a/runtime/bin/platform_patch.dart
+++ b/runtime/bin/platform_patch.dart
@@ -5,6 +5,7 @@
// part of "common_patch.dart";
@patch
+@pragma("vm:entry-point")
class _Platform {
@patch
static int _numberOfProcessors() native "Platform_NumberOfProcessors";
diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc
index 08a7dcb..1608bc9 100644
--- a/runtime/bin/process_fuchsia.cc
+++ b/runtime/bin/process_fuchsia.cc
@@ -176,7 +176,7 @@
static zx_status_t Add(zx_handle_t process) {
MonitorLocker locker(monitor_);
- LOG_INFO("ExitCodeHandler Adding Process: %ld\n", process);
+ LOG_INFO("ExitCodeHandler Adding Process: %u\n", process);
return zx_object_wait_async(process, port_, static_cast<uint64_t>(process),
ZX_TASK_TERMINATED, ZX_WAIT_ASYNC_ONCE);
}
@@ -230,7 +230,7 @@
zx_handle_t process = static_cast<zx_handle_t>(pkt.key);
zx_signals_t observed = pkt.signal.observed;
if ((observed & ZX_TASK_TERMINATED) == ZX_SIGNAL_NONE) {
- LOG_ERR("ExitCodeHandler: Unexpected signals, process %ld: %lx\n",
+ LOG_ERR("ExitCodeHandler: Unexpected signals, process %u: %ux\n",
process, observed);
}
SendProcessStatus(process);
@@ -242,7 +242,7 @@
}
static void SendProcessStatus(zx_handle_t process) {
- LOG_INFO("ExitCodeHandler thread getting process status: %ld\n", process);
+ LOG_INFO("ExitCodeHandler thread getting process status: %u\n", process);
int return_code = -1;
zx_info_process_t proc_info;
zx_status_t status = zx_object_get_info(
@@ -254,11 +254,11 @@
return_code = proc_info.return_code;
}
zx_handle_close(process);
- LOG_INFO("ExitCodeHandler thread process %ld exited with %d\n", process,
+ LOG_INFO("ExitCodeHandler thread process %u exited with %d\n", process,
return_code);
const intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(process);
- LOG_INFO("ExitCodeHandler thread sending %ld code %d on fd %ld\n", process,
+ LOG_INFO("ExitCodeHandler thread sending %u code %d on fd %ld\n", process,
return_code, exit_code_fd);
if (exit_code_fd != 0) {
int exit_message[2];
@@ -274,11 +274,11 @@
}
LOG_INFO("ExitCodeHandler thread wrote %ld bytes to fd %ld\n", result,
exit_code_fd);
- LOG_INFO("ExitCodeHandler thread removing process %ld from list\n",
+ LOG_INFO("ExitCodeHandler thread removing process %u from list\n",
process);
ProcessInfoList::RemoveProcess(process);
} else {
- LOG_ERR("ExitCodeHandler: Process %ld not found\n", process);
+ LOG_ERR("ExitCodeHandler: Process %u not found\n", process);
}
}
@@ -615,8 +615,9 @@
char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
uint32_t flags = FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC |
FDIO_SPAWN_CLONE_NAMESPACE;
- status = fdio_spawn_vmo(ZX_HANDLE_INVALID, flags, vmo, program_arguments_,
- program_environment_, 4, actions, &process, err_msg);
+ status =
+ fdio_spawn_vmo(ZX_HANDLE_INVALID, flags, vmo, program_arguments_,
+ program_environment_, 4, actions, &process, err_msg);
if (status != ZX_OK) {
LOG_ERR("ProcessStarter: Start() fdio_spawn_vmo failed\n");
@@ -626,7 +627,7 @@
return status;
}
- LOG_INFO("ProcessStarter: Start() adding %ld to list with exit_pipe %d\n",
+ LOG_INFO("ProcessStarter: Start() adding %u to list with exit_pipe %d\n",
process, exit_pipe_fds[1]);
ProcessInfoList::AddProcess(process, exit_pipe_fds[1]);
ExitCodeHandler::Start();
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index 375fb93..373eb7d 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -192,6 +192,7 @@
static _currentRss() native "ProcessInfo_CurrentRSS";
}
+@pragma("vm:entry-point")
class _ProcessStartStatus {
@pragma("vm:entry-point", "set")
int _errorCode; // Set to OS error code if process start failed.
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
index 5d61f88..876e789 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -64,6 +64,7 @@
* are backed by an external C array of bytes, so that both Dart code and
* native code can access the same data.
*/
+@pragma("vm:entry-point")
class _SecureFilterImpl extends NativeFieldWrapperClass1
implements _SecureFilter {
// Performance is improved if a full buffer of plaintext fits
diff --git a/runtime/bin/socket_base_fuchsia.cc b/runtime/bin/socket_base_fuchsia.cc
index b89abf2..d6c9495a 100644
--- a/runtime/bin/socket_base_fuchsia.cc
+++ b/runtime/bin/socket_base_fuchsia.cc
@@ -118,8 +118,7 @@
intptr_t num_bytes,
RawAddr* addr,
SocketOpKind sync) {
- LOG_ERR("SocketBase::RecvFrom is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return -1;
}
@@ -152,8 +151,7 @@
intptr_t num_bytes,
const RawAddr& addr,
SocketOpKind sync) {
- LOG_ERR("SocketBase::SendTo is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return -1;
}
@@ -182,19 +180,16 @@
}
void SocketBase::GetError(intptr_t fd, OSError* os_error) {
- LOG_ERR("SocketBase::GetError is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
+ os_error->SetCodeAndMessage(OSError::kSystem, errno);
}
int SocketBase::GetType(intptr_t fd) {
- LOG_ERR("SocketBase::GetType is unimplemented\n");
- UNIMPLEMENTED();
- return File::kOther;
+ errno = ENOSYS;
+ return -1;
}
intptr_t SocketBase::GetStdioHandle(intptr_t num) {
- LOG_ERR("SocketBase::GetStdioHandle is unimplemented\n");
- UNIMPLEMENTED();
return num;
}
@@ -246,8 +241,7 @@
char* host,
intptr_t host_len,
OSError** os_error) {
- LOG_ERR("SocketBase::ReverseLookup is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
@@ -335,8 +329,7 @@
}
bool SocketBase::GetNoDelay(intptr_t fd, bool* enabled) {
- LOG_ERR("SocketBase::GetNoDelay is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
@@ -351,40 +344,34 @@
bool SocketBase::GetMulticastLoop(intptr_t fd,
intptr_t protocol,
bool* enabled) {
- LOG_ERR("SocketBase::GetMulticastLoop is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool SocketBase::SetMulticastLoop(intptr_t fd,
intptr_t protocol,
bool enabled) {
- LOG_ERR("SocketBase::SetMulticastLoop is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool SocketBase::GetMulticastHops(intptr_t fd, intptr_t protocol, int* value) {
- LOG_ERR("SocketBase::GetMulticastHops is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool SocketBase::SetMulticastHops(intptr_t fd, intptr_t protocol, int value) {
- LOG_ERR("SocketBase::SetMulticastHops is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool SocketBase::GetBroadcast(intptr_t fd, bool* enabled) {
- LOG_ERR("SocketBase::GetBroadcast is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool SocketBase::SetBroadcast(intptr_t fd, bool enabled) {
- LOG_ERR("SocketBase::SetBroadcast is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
@@ -392,8 +379,7 @@
const RawAddr& addr,
const RawAddr&,
int interfaceIndex) {
- LOG_ERR("SocketBase::JoinMulticast is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
@@ -401,8 +387,7 @@
const RawAddr& addr,
const RawAddr&,
int interfaceIndex) {
- LOG_ERR("SocketBase::LeaveMulticast is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
diff --git a/runtime/bin/socket_fuchsia.cc b/runtime/bin/socket_fuchsia.cc
index 9655e23..d45119d 100644
--- a/runtime/bin/socket_fuchsia.cc
+++ b/runtime/bin/socket_fuchsia.cc
@@ -104,8 +104,7 @@
intptr_t Socket::CreateBindConnect(const RawAddr& addr,
const RawAddr& source_addr) {
- LOG_ERR("SocketBase::CreateBindConnect is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return -1;
}
@@ -113,8 +112,7 @@
bool reuseAddress,
bool reusePort,
int ttl) {
- LOG_ERR("SocketBase::CreateBindDatagram is unimplemented\n");
- UNIMPLEMENTED();
+ errno = ENOSYS;
return -1;
}
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 9d11929..6b3e495 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -1071,16 +1071,17 @@
}
getOption(SocketOption option) {
- if (option is! SocketOption) throw new ArgumentError(option);
+ if (option == null) throw new ArgumentError.notNull("option");
var result = nativeGetOption(option._value, address.type._value);
if (result is OSError) throw result;
return result;
}
bool setOption(SocketOption option, value) {
- if (option is! SocketOption) throw new ArgumentError(option);
+ if (option == null) throw new ArgumentError.notNull("option");
var result = nativeSetOption(option._value, address.type._value, value);
- if (result is OSError) throw result;
+ if (result != null) throw result;
+ return true;
}
InternetAddress multicastAddress(
@@ -1145,7 +1146,7 @@
int nativeGetSocketId() native "Socket_GetSocketId";
OSError nativeGetError() native "Socket_GetError";
nativeGetOption(int option, int protocol) native "Socket_GetOption";
- bool nativeSetOption(int option, int protocol, value)
+ OSError nativeSetOption(int option, int protocol, value)
native "Socket_SetOption";
OSError nativeJoinMulticast(List<int> addr, List<int> interfaceAddr,
int interfaceIndex) native "Socket_JoinMulticast";
diff --git a/runtime/bin/stdio_fuchsia.cc b/runtime/bin/stdio_fuchsia.cc
index 65a2918..a626fee 100644
--- a/runtime/bin/stdio_fuchsia.cc
+++ b/runtime/bin/stdio_fuchsia.cc
@@ -7,47 +7,56 @@
#include "bin/stdio.h"
+#include <errno.h>
+
+#include "platform/signal_blocker.h"
+
namespace dart {
namespace bin {
bool Stdin::ReadByte(intptr_t fd, int* byte) {
- UNIMPLEMENTED();
- return false;
+ unsigned char b;
+ ssize_t s = TEMP_FAILURE_RETRY(read(fd, &b, 1));
+ if (s < 0) {
+ return false;
+ }
+ *byte = (s == 0) ? -1 : b;
+ return true;
}
bool Stdin::GetEchoMode(intptr_t fd, bool* enabled) {
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool Stdin::SetEchoMode(intptr_t fd, bool enabled) {
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool Stdin::GetLineMode(intptr_t fd, bool* enabled) {
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool Stdin::SetLineMode(intptr_t fd, bool enabled) {
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool Stdin::AnsiSupported(intptr_t fd, bool* supported) {
- UNIMPLEMENTED();
- return false;
+ *supported = false;
+ return true;
}
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
- UNIMPLEMENTED();
+ errno = ENOSYS;
return false;
}
bool Stdout::AnsiSupported(intptr_t fd, bool* supported) {
- UNIMPLEMENTED();
- return false;
+ *supported = false;
+ return true;
}
} // namespace bin
diff --git a/runtime/docs/compiler/pragmas_recognized_by_compiler.md b/runtime/docs/compiler/pragmas_recognized_by_compiler.md
new file mode 100644
index 0000000..21b2d13
--- /dev/null
+++ b/runtime/docs/compiler/pragmas_recognized_by_compiler.md
@@ -0,0 +1,83 @@
+# @pragma annotations recognized by the compiler.
+
+## Annotations for return types and field types.
+
+The VM is not able to see across method calls (apart from inlining) and
+therefore does not know anything about the return'ed values of calls, except for
+the interface type of the signature.
+
+To improve this we have two types of additional information sources the VM
+utilizes to gain knowledge about return types:
+
+ - inferred types (stored in kernel metadata): these are computed by global
+ transformations (e.g. TFA) and are only available in AOT mode
+
+ - @pragma annotations: these are recognized in JIT and AOT mode
+
+This return type information is mainly used in the VM's type propagator.
+
+Since those annotations side-step the normal type system, they are unsafe and we
+therefore restrict those annotations to only have an affect inside dart:
+libraries.
+
+### @pragma("vm:exact-result-type", <type>) annotation
+
+Tells the VM about the exact result type (i.e. the exact class-id) of a function
+or a field load.
+
+There are two limitations on this pragma:
+
+0. The Dart object returned by the method at runtime must have **exactly** the type specified in the annotation (not a subtype).
+
+1. The exact return type declared in the pragma must be a subtype of the interface type declared in the method signature.
+ Note that this restriction is not enforced automatically by the compiler.
+
+If those limitations are violated, undefined behavior may result.
+Note that since `null` is an instance of the `Null` type, which is a subtype of any other, exactness of the annotated result type implies that the result must be non-null.
+
+#### Syntax
+
+```dart
+class A {}
+class B extends A {}
+
+// Reference to type via type literal
+@pragma("vm:exact-result-type", B)
+A foo() native "foo_impl";
+
+// Reference to type via path
+@pragma("vm:exact-result-type", "dart:core#_Smi");
+int foo() native "foo_impl";
+
+class C {
+ // Reference to type via type literal
+ @pragma('vm:exact-result-type', B)
+ final B bValue;
+
+ // Reference to type via path
+ @pragma('vm:exact-result-type', "dart:core#_Smi")
+ final int intValue;
+}
+```
+
+### @pragma("vm:non-nullable-result-type") annotation
+
+Tells the VM that the method/field cannot return `null`.
+
+There is one limitation on this pragma:
+
+0. The Dart object returned by the method at runtime **must not** return `null`.
+
+If this limitation is violated, undefined behavior may result.
+
+#### Syntax
+
+```dart
+@pragma("vm:non-nullable-result-type")
+A foo() native "foo_impl";
+
+class C {
+ @pragma('vm:non-nullable-result-type");
+ final int value;
+}
+```
diff --git a/runtime/docs/compiler/result_type_pragma.md b/runtime/docs/compiler/result_type_pragma.md
deleted file mode 100644
index 2bc5032..0000000
--- a/runtime/docs/compiler/result_type_pragma.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# `vm:exact-result-type` pragma
-
-To facilitate type-flow analysis and other optimizations, Dart methods may use
-the pragma `vm:exact-result-type` to declare an exact return type different than
-the return type in the signature of the method. There are three limitations on
-this pragma:
-
-0. The Dart object returned by the method at runtime must have exactly the type
-specified in the annotation (not a subtype).
-
-1. The exact return type declared in the pragma must be a subtype of the return
- type declared in the method signature.
- Note that this restriction is not enforced automatically by the compiler.
-
-2. `vm:exact-result-type` may only be attached to methods in the `dart:*`
- libraries.
- This pragma can introduce unsafe behavior since it allows the compiler to
- make stronger assumptions during optimization than what the sound strong-mode
- type system allows, so it is only allowed in the core library where the Dart
- VM team can ensure that it is not misused.
-
-If limitations 0 or 1 are violated, undefined behavior may result.
-Note that since `null` is an instance of the `Null` type, which is a subtype of any other, exactness of the annotated result type implies that the result must be non-null.
-
-## Syntax
-
-### Reference to type via type literal
-
-```dart
-class A {}
-class B extends A {}
-
-@pragma('vm:exact-result-type', B)
-A foo() native 'foo_impl';
-```
-
-### Reference to type via path
-
-```dart
-@pragma('vm:exact-result-type', 'dart:core#_Smi');
-int foo() native 'foo_impl';
-```
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index b55d192..9bfdefa 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1509,6 +1509,19 @@
bool* is_static);
/**
+ * Is this object a closure resulting from a tear-off (closurized method)?
+ *
+ * Returns true for closures produced when an ordinary method is accessed
+ * through a getter call. Returns false otherwise, in particular for closures
+ * produced from local function declarations.
+ *
+ * \param object Some Object.
+ *
+ * \return true if Object is a tear-off.
+ */
+DART_EXPORT bool Dart_IsTearOff(Dart_Handle object);
+
+/**
* Retrieves the function of a closure.
*
* \return A handle to the function of the closure, or an error handle if the
@@ -3070,65 +3083,6 @@
DART_EXPORT Dart_Handle Dart_SetPeer(Dart_Handle object, void* peer);
/*
- * ======
- * Kernel
- * ======
- */
-
-/**
- * Experimental support for Dart to Kernel parser isolate.
- *
- * TODO(hausner): Document finalized interface.
- *
- */
-
-// TODO(33433): Remove kernel service from the embedding API.
-
-typedef enum {
- Dart_KernelCompilationStatus_Unknown = -1,
- Dart_KernelCompilationStatus_Ok = 0,
- Dart_KernelCompilationStatus_Error = 1,
- Dart_KernelCompilationStatus_Crash = 2,
-} Dart_KernelCompilationStatus;
-
-typedef struct {
- Dart_KernelCompilationStatus status;
- char* error;
-
- uint8_t* kernel;
- intptr_t kernel_size;
-} Dart_KernelCompilationResult;
-
-DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate);
-DART_EXPORT bool Dart_KernelIsolateIsRunning();
-DART_EXPORT Dart_Port Dart_KernelPort();
-DART_EXPORT Dart_KernelCompilationResult
-Dart_CompileToKernel(const char* script_uri,
- const uint8_t* platform_kernel,
- const intptr_t platform_kernel_size,
- bool incremental_compile,
- const char* package_config);
-
-typedef struct {
- const char* uri;
- const char* source;
-} Dart_SourceFile;
-DART_EXPORT Dart_KernelCompilationResult
-Dart_CompileSourcesToKernel(const char* script_uri,
- const uint8_t* platform_kernel,
- intptr_t platform_kernel_size,
- int source_files_count,
- Dart_SourceFile source_files[],
- bool incremental_compile,
- const char* package_config,
- const char* multiroot_filepaths,
- const char* multiroot_scheme);
-
-DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies();
-
-#define DART_KERNEL_ISOLATE_NAME "kernel-service"
-
-/*
* =======
* Service
* =======
diff --git a/runtime/lib/class_id.dart b/runtime/lib/class_id.dart
index 2260a75..ff9d0b6 100644
--- a/runtime/lib/class_id.dart
+++ b/runtime/lib/class_id.dart
@@ -4,7 +4,9 @@
// part of "internal_patch.dart";
+@pragma("vm:entry-point")
class ClassID {
+ @pragma("vm:entry-point")
@pragma("vm:exact-result-type", "dart:core#_Smi")
static int getID(Object value) native "ClassID_getID";
diff --git a/runtime/lib/class_id_fasta.dart b/runtime/lib/class_id_fasta.dart
index 0a89db4..f8579c0 100644
--- a/runtime/lib/class_id_fasta.dart
+++ b/runtime/lib/class_id_fasta.dart
@@ -4,14 +4,24 @@
// part of "internal_patch.dart";
+@pragma("vm:entry-point")
class ClassID {
+ @pragma("vm:entry-point")
@pragma("vm:exact-result-type", "dart:core#_Smi")
static int getID(Object value) native "ClassID_getID";
+ @pragma("vm:entry-point")
static final int cidArray = 0;
+ @pragma("vm:entry-point")
static final int cidExternalOneByteString = 0;
+ @pragma("vm:entry-point")
static final int cidGrowableObjectArray = 0;
+ @pragma("vm:entry-point")
static final int cidImmutableArray = 0;
+ @pragma("vm:entry-point")
static final int cidOneByteString = 0;
+ @pragma("vm:entry-point")
static final int cidTwoByteString = 0;
+ @pragma("vm:entry-point")
+ static final int cidUint8ArrayView = 0;
}
diff --git a/runtime/lib/convert_patch.dart b/runtime/lib/convert_patch.dart
index 0802cbb..3d99c0d 100644
--- a/runtime/lib/convert_patch.dart
+++ b/runtime/lib/convert_patch.dart
@@ -7,7 +7,7 @@
/// used by patches of that library. We plan to change this when we have a
/// shared front end and simply use parts.
-import "dart:_internal" show POWERS_OF_TEN, patch;
+import "dart:_internal" show POWERS_OF_TEN, patch, ClassID;
import "dart:typed_data" show Uint8List, Uint16List;
@@ -1816,3 +1816,27 @@
_sink.close();
}
}
+
+@patch
+int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
+ final to = endIndex;
+
+ // Special case for _Uint8ArrayView.
+ final cid = ClassID.getID(units);
+ if (identical(cid, ClassID.cidUint8ArrayView)) {
+ if (from >= 0 && to >= 0 && to <= units.length) {
+ for (int i = from; i < to; i++) {
+ final unit = units[i];
+ if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
+ }
+ return to - from;
+ }
+ }
+
+ // Fall through to normal case.
+ for (var i = from; i < to; i++) {
+ final unit = units[i];
+ if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
+ }
+ return to - from;
+}
diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart
index f2de9c0..266d433 100644
--- a/runtime/lib/double.dart
+++ b/runtime/lib/double.dart
@@ -40,6 +40,7 @@
return _trunc_div(other.toDouble());
}
+ @pragma("vm:non-nullable-result-type")
int _trunc_div(double other) native "Double_trunc_div";
@pragma("vm:exact-result-type", _Double)
@@ -71,7 +72,9 @@
return (other is num) && _equal(other.toDouble());
}
+ @pragma("vm:exact-result-type", bool)
bool _equal(double other) native "Double_equal";
+ @pragma("vm:exact-result-type", bool)
bool _equalToInteger(int other) native "Double_equalToInteger";
@pragma("vm:exact-result-type", bool)
@@ -84,6 +87,7 @@
return _greaterThan(other.toDouble());
}
+ @pragma("vm:exact-result-type", bool)
bool _greaterThan(double other) native "Double_greaterThan";
@pragma("vm:exact-result-type", bool)
@@ -175,6 +179,7 @@
return this;
}
+ @pragma("vm:non-nullable-result-type")
int toInt() native "Double_toInt";
double toDouble() {
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index b39ae32..2289012 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -5,10 +5,14 @@
// part of "core_patch.dart";
abstract class _IntegerImplementation implements int {
+ @pragma("vm:non-nullable-result-type")
num operator +(num other) => other._addFromInteger(this);
+ @pragma("vm:non-nullable-result-type")
num operator -(num other) => other._subFromInteger(this);
+ @pragma("vm:non-nullable-result-type")
num operator *(num other) => other._mulFromInteger(this);
+ @pragma("vm:non-nullable-result-type")
int operator ~/(num other) {
if ((other is int) && (other == 0)) {
throw const IntegerDivisionByZeroException();
@@ -20,6 +24,7 @@
return this.toDouble() / other.toDouble();
}
+ @pragma("vm:non-nullable-result-type")
num operator %(num other) {
if ((other is int) && (other == 0)) {
throw const IntegerDivisionByZeroException();
@@ -27,34 +32,51 @@
return other._moduloFromInteger(this);
}
+ @pragma("vm:non-nullable-result-type")
int operator -() {
return 0 - this;
}
+ @pragma("vm:non-nullable-result-type")
int operator &(int other) => other._bitAndFromInteger(this);
+ @pragma("vm:non-nullable-result-type")
int operator |(int other) => other._bitOrFromInteger(this);
+ @pragma("vm:non-nullable-result-type")
int operator ^(int other) => other._bitXorFromInteger(this);
num remainder(num other) {
return other._remainderFromInteger(this);
}
+ @pragma("vm:non-nullable-result-type")
int _bitAndFromSmi(_Smi other) native "Integer_bitAndFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _bitAndFromInteger(int other) native "Integer_bitAndFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _bitOrFromInteger(int other) native "Integer_bitOrFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _bitXorFromInteger(int other) native "Integer_bitXorFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _shrFromInteger(int other) native "Integer_shrFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _shlFromInteger(int other) native "Integer_shlFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _addFromInteger(int other) native "Integer_addFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _subFromInteger(int other) native "Integer_subFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _mulFromInteger(int other) native "Integer_mulFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _truncDivFromInteger(int other) native "Integer_truncDivFromInteger";
+ @pragma("vm:non-nullable-result-type")
int _moduloFromInteger(int other) native "Integer_moduloFromInteger";
int _remainderFromInteger(int other) {
return other - (other ~/ this) * this;
}
+ @pragma("vm:non-nullable-result-type")
int operator >>(int other) => other._shrFromInteger(this);
+ @pragma("vm:non-nullable-result-type")
int operator <<(int other) => other._shlFromInteger(this);
@pragma("vm:exact-result-type", bool)
@@ -664,7 +686,9 @@
}
int get hashCode => this;
int get _identityHashCode => this;
+ @pragma("vm:non-nullable-result-type")
int operator ~() native "Mint_bitNegate";
+ @pragma("vm:exact-result-type", "dart:core#_Smi")
int get bitLength native "Mint_bitLength";
int _bitAndFromSmi(_Smi other) => _bitAndFromInteger(other);
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index 2575da5..c84b78b 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -77,7 +77,7 @@
intptr_t write_cursor = 0;
if (for_async_function) {
// Place the asynchronous gap marker at the top of the stack trace.
- code = StubCode::AsynchronousGapMarker_entry()->code();
+ code = StubCode::AsynchronousGapMarker().raw();
ASSERT(!code.IsNull());
offset = Smi::New(0);
code_array.SetAt(write_cursor, code);
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index 103959b..e90667a 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -222,6 +222,19 @@
static String _createOneByteString(List<int> charCodes, int start, int len) {
// It's always faster to do this in Dart than to call into the runtime.
var s = _OneByteString._allocate(len);
+
+ // Special case for _Uint8ArrayView.
+ final cid = ClassID.getID(charCodes);
+ if (identical(cid, ClassID.cidUint8ArrayView)) {
+ if (start >= 0 && len >= 0) {
+ for (int i = 0; i < len; i++) {
+ s._setAt(i, charCodes[start + i]);
+ }
+ return s;
+ }
+ }
+
+ // Fall through to normal case.
for (int i = 0; i < len; i++) {
s._setAt(i, charCodes[start + i]);
}
diff --git a/runtime/lib/typed_data.cc b/runtime/lib/typed_data.cc
index 0a81886..36e480a 100644
--- a/runtime/lib/typed_data.cc
+++ b/runtime/lib/typed_data.cc
@@ -147,9 +147,15 @@
}
// We check the length parameter against a possible maximum length for the
-// array based on available physical addressable memory on the system. The
-// maximum possible length is a scaled value of kSmiMax which is set up based
-// on whether the underlying architecture is 32-bit or 64-bit.
+// array based on available physical addressable memory on the system.
+//
+// More specifically
+//
+// TypedData::MaxElements(cid) is equal to (kSmiMax / ElementSizeInBytes(cid))
+//
+// which ensures that the number of bytes the array holds is guaranteed to fit
+// into a _Smi.
+//
// Argument 0 is type arguments and is ignored.
#define TYPED_DATA_NEW(name) \
DEFINE_NATIVE_ENTRY(TypedData_##name##_new, 2) { \
diff --git a/runtime/lib/typed_data_patch.dart b/runtime/lib/typed_data_patch.dart
index 9c5f7d6..91d7efd 100644
--- a/runtime/lib/typed_data_patch.dart
+++ b/runtime/lib/typed_data_patch.dart
@@ -39,12 +39,14 @@
@pragma("vm:entry-point")
factory ByteData(int length) {
final list = new Uint8List(length) as _TypedList;
+ _rangeCheck(list.lengthInBytes, 0, length);
return new _ByteDataView(list, 0, length);
}
// Called directly from C code.
@pragma("vm:entry-point")
factory ByteData._view(_TypedList typedData, int offsetInBytes, int length) {
+ _rangeCheck(typedData.lengthInBytes, offsetInBytes, length);
return new _ByteDataView(typedData, offsetInBytes, length);
}
}
@@ -1904,87 +1906,118 @@
ByteData asByteData([int offsetInBytes = 0, int length]) {
length ??= this.lengthInBytes - offsetInBytes;
+ _rangeCheck(this._data.lengthInBytes, offsetInBytes, length);
return new _ByteDataView(this._data, offsetInBytes, length);
}
Int8List asInt8List([int offsetInBytes = 0, int length]) {
- length ??= this.lengthInBytes - offsetInBytes;
+ length ??= (this.lengthInBytes - offsetInBytes) ~/ Int8List.bytesPerElement;
+ _rangeCheck(
+ this.lengthInBytes, offsetInBytes, length * Int8List.bytesPerElement);
return new _Int8ArrayView(this, offsetInBytes, length);
}
Uint8List asUint8List([int offsetInBytes = 0, int length]) {
- length ??= this.lengthInBytes - offsetInBytes;
+ length ??=
+ (this.lengthInBytes - offsetInBytes) ~/ Uint8List.bytesPerElement;
+ _rangeCheck(
+ this.lengthInBytes, offsetInBytes, length * Uint8List.bytesPerElement);
return new _Uint8ArrayView(this, offsetInBytes, length);
}
Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
- length ??= this.lengthInBytes - offsetInBytes;
+ length ??= (this.lengthInBytes - offsetInBytes) ~/
+ Uint8ClampedList.bytesPerElement;
+ _rangeCheck(this.lengthInBytes, offsetInBytes,
+ length * Uint8ClampedList.bytesPerElement);
return new _Uint8ClampedArrayView(this, offsetInBytes, length);
}
Int16List asInt16List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Int16List.bytesPerElement;
+ _rangeCheck(
+ this.lengthInBytes, offsetInBytes, length * Int16List.bytesPerElement);
return new _Int16ArrayView(this, offsetInBytes, length);
}
Uint16List asUint16List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Uint16List.bytesPerElement;
+ _rangeCheck(
+ this.lengthInBytes, offsetInBytes, length * Uint16List.bytesPerElement);
return new _Uint16ArrayView(this, offsetInBytes, length);
}
Int32List asInt32List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Int32List.bytesPerElement;
+ _rangeCheck(
+ this.lengthInBytes, offsetInBytes, length * Int32List.bytesPerElement);
return new _Int32ArrayView(this, offsetInBytes, length);
}
Uint32List asUint32List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Uint32List.bytesPerElement;
+ _rangeCheck(
+ this.lengthInBytes, offsetInBytes, length * Uint32List.bytesPerElement);
return new _Uint32ArrayView(this, offsetInBytes, length);
}
Int64List asInt64List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Int64List.bytesPerElement;
+ _rangeCheck(
+ this.lengthInBytes, offsetInBytes, length * Int64List.bytesPerElement);
return new _Int64ArrayView(this, offsetInBytes, length);
}
Uint64List asUint64List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Uint64List.bytesPerElement;
+ _rangeCheck(
+ this.lengthInBytes, offsetInBytes, length * Uint64List.bytesPerElement);
return new _Uint64ArrayView(this, offsetInBytes, length);
}
Float32List asFloat32List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Float32List.bytesPerElement;
+ _rangeCheck(this.lengthInBytes, offsetInBytes,
+ length * Float32List.bytesPerElement);
return new _Float32ArrayView(this, offsetInBytes, length);
}
Float64List asFloat64List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Float64List.bytesPerElement;
+ _rangeCheck(this.lengthInBytes, offsetInBytes,
+ length * Float64List.bytesPerElement);
return new _Float64ArrayView(this, offsetInBytes, length);
}
Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Float32x4List.bytesPerElement;
+ _rangeCheck(this.lengthInBytes, offsetInBytes,
+ length * Float32x4List.bytesPerElement);
return new _Float32x4ArrayView(this, offsetInBytes, length);
}
Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Int32x4List.bytesPerElement;
+ _rangeCheck(this.lengthInBytes, offsetInBytes,
+ length * Int32x4List.bytesPerElement);
return new _Int32x4ArrayView(this, offsetInBytes, length);
}
Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
length ??=
(this.lengthInBytes - offsetInBytes) ~/ Float64x2List.bytesPerElement;
+ _rangeCheck(this.lengthInBytes, offsetInBytes,
+ length * Float64x2List.bytesPerElement);
return new _Float64x2ArrayView(this, offsetInBytes, length);
}
}
@@ -3544,8 +3577,13 @@
return _typedData.buffer;
}
+ @pragma("vm:non-nullable-result-type")
final _TypedList _typedData;
+
+ @pragma("vm:exact-result-type", "dart:core#_Smi")
final int offsetInBytes;
+
+ @pragma("vm:exact-result-type", "dart:core#_Smi")
final int length;
}
@@ -3554,17 +3592,8 @@
with _IntListMixin
implements Int8List {
// Constructor.
- _Int8ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Int8List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, _offsetInBytes,
- length * Int8List.bytesPerElement);
- }
+ _Int8ArrayView(_ByteBuffer buffer, int offsetInBytes, int length)
+ : super(buffer, offsetInBytes, length);
// Method(s) implementing List interface.
int operator [](int index) {
@@ -3599,17 +3628,8 @@
with _IntListMixin
implements Uint8List {
// Constructor.
- _Uint8ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Uint8List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, _offsetInBytes,
- length * Uint8List.bytesPerElement);
- }
+ _Uint8ArrayView(_ByteBuffer buffer, int offsetInBytes, int length)
+ : super(buffer, offsetInBytes, length);
// Method(s) implementing List interface.
int operator [](int index) {
@@ -3644,18 +3664,8 @@
with _IntListMixin
implements Uint8ClampedList {
// Constructor.
- _Uint8ClampedArrayView(_ByteBuffer buffer,
- [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Uint8List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Uint8List.bytesPerElement);
- }
+ _Uint8ClampedArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length);
// Method(s) implementing List interface.
int operator [](int index) {
@@ -3690,16 +3700,8 @@
with _IntListMixin
implements Int16List {
// Constructor.
- _Int16ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Int16List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Int16List.bytesPerElement);
+ _Int16ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Int16List.bytesPerElement);
}
@@ -3748,16 +3750,8 @@
with _IntListMixin
implements Uint16List {
// Constructor.
- _Uint16ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Uint16List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Uint16List.bytesPerElement);
+ _Uint16ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Uint16List.bytesPerElement);
}
@@ -3807,16 +3801,8 @@
with _IntListMixin
implements Int32List {
// Constructor.
- _Int32ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Int32List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Int32List.bytesPerElement);
+ _Int32ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Int32List.bytesPerElement);
}
@@ -3853,16 +3839,8 @@
with _IntListMixin
implements Uint32List {
// Constructor.
- _Uint32ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Uint32List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Uint32List.bytesPerElement);
+ _Uint32ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Uint32List.bytesPerElement);
}
@@ -3899,16 +3877,8 @@
with _IntListMixin
implements Int64List {
// Constructor.
- _Int64ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Int64List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Int64List.bytesPerElement);
+ _Int64ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Int64List.bytesPerElement);
}
@@ -3945,16 +3915,8 @@
with _IntListMixin
implements Uint64List {
// Constructor.
- _Uint64ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Uint64List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Uint64List.bytesPerElement);
+ _Uint64ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Uint64List.bytesPerElement);
}
@@ -3991,16 +3953,8 @@
with _DoubleListMixin
implements Float32List {
// Constructor.
- _Float32ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Float32List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Float32List.bytesPerElement);
+ _Float32ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Float32List.bytesPerElement);
}
@@ -4037,16 +3991,8 @@
with _DoubleListMixin
implements Float64List {
// Constructor.
- _Float64ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Float64List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Float64List.bytesPerElement);
+ _Float64ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Float64List.bytesPerElement);
}
@@ -4083,16 +4029,8 @@
with _Float32x4ListMixin
implements Float32x4List {
// Constructor.
- _Float32x4ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Float32x4List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Float32x4List.bytesPerElement);
+ _Float32x4ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Float32x4List.bytesPerElement);
}
@@ -4129,16 +4067,8 @@
with _Int32x4ListMixin
implements Int32x4List {
// Constructor.
- _Int32x4ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Int32x4List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Int32x4List.bytesPerElement);
+ _Int32x4ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Int32x4List.bytesPerElement);
}
@@ -4175,16 +4105,8 @@
with _Float64x2ListMixin
implements Float64x2List {
// Constructor.
- _Float64x2ArrayView(_ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
- : super(
- buffer,
- _offsetInBytes,
- _defaultIfNull(
- _length,
- ((buffer.lengthInBytes - _offsetInBytes) ~/
- Float64x2List.bytesPerElement))) {
- _rangeCheck(buffer.lengthInBytes, offsetInBytes,
- length * Float64x2List.bytesPerElement);
+ _Float64x2ArrayView(_ByteBuffer buffer, int _offsetInBytes, int _length)
+ : super(buffer, _offsetInBytes, _length) {
_offsetAlignmentCheck(_offsetInBytes, Float64x2List.bytesPerElement);
}
@@ -4218,12 +4140,7 @@
@pragma("vm:entry-point")
class _ByteDataView implements ByteData {
- _ByteDataView(_TypedList typedData, int _offsetInBytes, int _lengthInBytes)
- : _typedData = typedData,
- _offset = _offsetInBytes,
- length = _lengthInBytes {
- _rangeCheck(_typedData.lengthInBytes, _offset, length);
- }
+ _ByteDataView(this._typedData, this._offset, this.length);
// Method(s) implementing TypedData interface.
_ByteBuffer get buffer {
@@ -4511,6 +4428,9 @@
return value & 0xFFFFFFFF;
}
+// In addition to explicitly checking the range, this method implicitly ensures
+// that all arguments are non-null (a no such method error gets thrown
+// otherwise).
void _rangeCheck(int listLength, int start, int length) {
if (length < 0) {
throw new RangeError.value(length);
@@ -4529,10 +4449,3 @@
'BYTES_PER_ELEMENT ($alignment)');
}
}
-
-int _defaultIfNull(object, value) {
- if (object == null) {
- return value;
- }
- return object;
-}
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
index c288d6a..aa87514 100644
--- a/runtime/lib/vmservice.cc
+++ b/runtime/lib/vmservice.cc
@@ -79,6 +79,7 @@
#endif // !PRODUCT
DEFINE_NATIVE_ENTRY(VMService_SendIsolateServiceMessage, 2) {
+#ifndef PRODUCT
if (!FLAG_support_service) {
return Bool::Get(false).raw();
}
@@ -95,25 +96,33 @@
bool result = PortMap::PostMessage(
writer.WriteMessage(message, sp.Id(), Message::kOOBPriority));
return Bool::Get(result).raw();
+#else
+ return Object::null();
+#endif
}
DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 1) {
+#ifndef PRODUCT
GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
if (FLAG_support_service) {
return Service::HandleRootMessage(message);
}
+#endif
return Object::null();
}
DEFINE_NATIVE_ENTRY(VMService_SendObjectRootServiceMessage, 1) {
+#ifndef PRODUCT
GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
if (FLAG_support_service) {
return Service::HandleObjectRootMessage(message);
}
+#endif
return Object::null();
}
DEFINE_NATIVE_ENTRY(VMService_OnStart, 0) {
+#ifndef PRODUCT
if (FLAG_trace_service) {
OS::PrintErr("vm-service: Booting dart:vmservice library.\n");
}
@@ -122,7 +131,6 @@
if (!FLAG_support_service) {
return Object::null();
}
-#ifndef PRODUCT
// Register running isolates with service.
RegisterRunningIsolatesVisitor register_isolates(thread);
if (FLAG_trace_service) {
@@ -134,16 +142,19 @@
}
DEFINE_NATIVE_ENTRY(VMService_OnExit, 0) {
+#ifndef PRODUCT
if (FLAG_trace_service) {
OS::PrintErr("vm-service: processed exit message.\n");
MessageHandler* message_handler = isolate->message_handler();
OS::PrintErr("vm-service: live ports = %" Pd "\n",
message_handler->live_ports());
}
+#endif
return Object::null();
}
DEFINE_NATIVE_ENTRY(VMService_OnServerAddressChange, 1) {
+#ifndef PRODUCT
if (!FLAG_support_service) {
return Object::null();
}
@@ -153,31 +164,42 @@
} else {
ServiceIsolate::SetServerAddress(address.ToCString());
}
+#endif
return Object::null();
}
DEFINE_NATIVE_ENTRY(VMService_ListenStream, 1) {
+#ifndef PRODUCT
GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
bool result = false;
if (FLAG_support_service) {
result = Service::ListenStream(stream_id.ToCString());
}
return Bool::Get(result).raw();
+#else
+ return Object::null();
+#endif
}
DEFINE_NATIVE_ENTRY(VMService_CancelStream, 1) {
+#ifndef PRODUCT
GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
if (FLAG_support_service) {
Service::CancelStream(stream_id.ToCString());
}
+#endif
return Object::null();
}
DEFINE_NATIVE_ENTRY(VMService_RequestAssets, 0) {
+#ifndef PRODUCT
if (!FLAG_support_service) {
return Object::null();
}
return Service::RequestAssets();
+#else
+ return Object::null();
+#endif
}
#ifndef PRODUCT
diff --git a/runtime/observatory/tests/service/dominator_tree_user_test.dart b/runtime/observatory/tests/service/dominator_tree_user_test.dart
index a0e9fd4..d2053d2 100644
--- a/runtime/observatory/tests/service/dominator_tree_user_test.dart
+++ b/runtime/observatory/tests/service/dominator_tree_user_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=
// VMOptions=--use_compactor
+// VMOptions=--use_compactor --force_evacuation
import 'package:observatory/heap_snapshot.dart';
import 'package:observatory/models.dart' as M;
diff --git a/runtime/observatory/tests/service/dominator_tree_vm_test.dart b/runtime/observatory/tests/service/dominator_tree_vm_test.dart
index 7fa6e9b..6199bf5 100644
--- a/runtime/observatory/tests/service/dominator_tree_vm_test.dart
+++ b/runtime/observatory/tests/service/dominator_tree_vm_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=
// VMOptions=--use_compactor
+// VMOptions=--use_compactor --force_evacuation
import 'package:observatory/heap_snapshot.dart';
import 'package:observatory/models.dart' as M;
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 57670e29..c6010cb 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -43,7 +43,6 @@
set_name_rpc_test: RuntimeError
set_vm_name_rpc_test: RuntimeError
simple_reload_test: RuntimeError
-step_through_arithmetic_test: RuntimeError
unused_changes_in_last_reload_test: RuntimeError
valid_source_locations_test: RuntimeError
@@ -61,7 +60,6 @@
evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
pause_on_unhandled_async_exceptions2_test: Pass, Slow
positive_token_pos_test: RuntimeError # Issue 34746
-step_through_arithmetic_test: RuntimeError # probably constant evaluator pre-evaluating e.g. 1+2
unused_changes_in_last_reload_test: RuntimeError
[ $compiler == dartkp ]
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 11c9d32..0dfd620 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -238,6 +238,23 @@
#error Automatic compiler detection failed.
#endif
+#ifdef _MSC_VER
+#elif __GNUC__
+#define DART_HAS_COMPUTED_GOTO 1
+#else
+#error Automatic compiler detection failed.
+#endif
+
+// LIKELY/UNLIKELY give the compiler branch preditions that may affect block
+// scheduling.
+#ifdef __GNUC__
+#define LIKELY(cond) __builtin_expect((cond), 1)
+#define UNLIKELY(cond) __builtin_expect((cond), 0)
+#else
+#define LIKELY(cond) cond
+#define UNLIKELY(cond) cond
+#endif
+
// DART_UNUSED indicates to the compiler that a variable or typedef is expected
// to be unused and disables the related warning.
#ifdef __GNUC__
diff --git a/runtime/tests/vm/dart/entrypoints/static_this_test.dart b/runtime/tests/vm/dart/entrypoints/static_this_test.dart
index fc9253e..8b962ed 100644
--- a/runtime/tests/vm/dart/entrypoints/static_this_test.dart
+++ b/runtime/tests/vm/dart/entrypoints/static_this_test.dart
@@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// VMOptions=--enable-testing-pragmas --no-background-compilation --enable-inlining-annotations --optimization-counter-threshold=10
-// VMOptions=--enable-testing-pragmas --no-background-compilation --enable-inlining-annotations --optimization-counter-threshold=10 -Denable_inlining=true
+// VMOptions=--enable-testing-pragmas --no-background-compilation --enable-inlining-annotations --optimization-counter-threshold=5
+// VMOptions=--enable-testing-pragmas --no-background-compilation --enable-inlining-annotations --optimization-counter-threshold=5 -Denable_inlining=true
// Test that 'StaticCall's against "this" go through the unchecked entry-point.
diff --git a/runtime/tests/vm/dart/entrypoints/super_test.dart b/runtime/tests/vm/dart/entrypoints/super_test.dart
index 2a17e61..e923180 100644
--- a/runtime/tests/vm/dart/entrypoints/super_test.dart
+++ b/runtime/tests/vm/dart/entrypoints/super_test.dart
@@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// VMOptions=--enable-testing-pragmas --no-background-compilation --enable-inlining-annotations --optimization-counter-threshold=10 -Denable_inlining=true
-// VMOptions=--enable-testing-pragmas --no-background-compilation --enable-inlining-annotations --optimization-counter-threshold=10
+// VMOptions=--enable-testing-pragmas --no-background-compilation --enable-inlining-annotations --optimization-counter-threshold=5 -Denable_inlining=true
+// VMOptions=--enable-testing-pragmas --no-background-compilation --enable-inlining-annotations --optimization-counter-threshold=5
// Test that 'StaticCall's against "super" go through the unchecked entrypoint.
diff --git a/runtime/tests/vm/dart/snapshot_test_helper.dart b/runtime/tests/vm/dart/snapshot_test_helper.dart
index 9b4394a..5c27ced 100644
--- a/runtime/tests/vm/dart/snapshot_test_helper.dart
+++ b/runtime/tests/vm/dart/snapshot_test_helper.dart
@@ -83,7 +83,10 @@
final generate1Result = await runDartBinary('GENERATE SNAPSHOT 1', [
'--deterministic',
- '--dump_tables',
+ '--trace_class_finalization',
+ '--trace_type_finalization',
+ '--trace_compiler',
+ '--verbose_gc',
'--snapshot=$snapshot1Path',
'--snapshot-kind=$snapshotKind',
Platform.script.toFilePath(),
@@ -93,7 +96,10 @@
final generate2Result = await runDartBinary('GENERATE SNAPSHOT 2', [
'--deterministic',
- '--dump_tables',
+ '--trace_class_finalization',
+ '--trace_type_finalization',
+ '--trace_compiler',
+ '--verbose_gc',
'--snapshot=$snapshot2Path',
'--snapshot-kind=$snapshotKind',
Platform.script.toFilePath(),
diff --git a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
new file mode 100644
index 0000000..ede572c
--- /dev/null
+++ b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:convert";
+import "dart:io";
+
+import "package:expect/expect.dart";
+import "package:vm/v8_snapshot_profile.dart";
+
+String path(List<String> segments) {
+ return "/" + segments.join("/");
+}
+
+test(bool use_elf) async {
+ if (Platform.isWindows) return;
+ if (Platform.isMacOS && use_elf) return;
+
+ final String outputDir = Platform.isMacOS ? "xcodebuild" : "out";
+
+ final List<String> sdkBaseSegments =
+ Uri.file(Platform.resolvedExecutable).pathSegments.toList();
+ sdkBaseSegments.replaceRange(
+ sdkBaseSegments.indexOf(outputDir), sdkBaseSegments.length, []);
+
+ // Generate the snapshot profile.
+ final String thisTestPath = path(sdkBaseSegments) +
+ "/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart";
+
+ final Directory temp = await Directory.systemTemp.createTemp();
+ final String snapshotPath = temp.path + "/test.snap";
+
+ final List<String> precompiler2Args = [
+ "--write-v8-snapshot-profile-to=${temp.path}/profile.heapsnapshot",
+ thisTestPath,
+ snapshotPath,
+ ];
+
+ if (use_elf) {
+ precompiler2Args.insert(0, "--build-elf");
+ }
+
+ final ProcessResult result = await Process.run(
+ "pkg/vm/tool/precompiler2",
+ precompiler2Args,
+ workingDirectory: path(sdkBaseSegments),
+ runInShell: true,
+ );
+
+ // The precompiler2 script tried using GCC for the wrong architecture. We
+ // don't have a workaround for this now.
+ if (use_elf &&
+ result.exitCode != 0 &&
+ result.stderr.contains("Assembler messages")) {
+ return;
+ }
+
+ print(precompiler2Args);
+ print(result.stderr);
+ print(result.stdout);
+
+ Expect.equals(result.exitCode, 0);
+ Expect.equals(result.stderr, "");
+ Expect.equals(result.stdout, "");
+
+ final V8SnapshotProfile profile = V8SnapshotProfile.fromJson(JsonDecoder()
+ .convert(File("${temp.path}/profile.heapsnapshot").readAsStringSync()));
+
+ // Verify that there are no "unknown" nodes. These are emitted when we see a
+ // reference to an some object but no other metadata about the object was
+ // recorded. We should at least record the type for every object in the graph
+ // (in some cases the shallow size can legitimately be 0, e.g. for "base
+ // objects").
+ for (final int node in profile.nodes) {
+ if (profile[node].type == "Unknown") {
+ print(profile[node].id);
+ }
+ Expect.notEquals(profile[node].type, "Unknown");
+ }
+
+ // Verify that all nodes are reachable from the declared roots.
+ int unreachableNodes = 0;
+ Set<int> nodesReachableFromRoots = profile.preOrder(profile.root).toSet();
+ for (final int node in profile.nodes) {
+ if (!nodesReachableFromRoots.contains(node)) {
+ ++unreachableNodes;
+ }
+ }
+ Expect.equals(unreachableNodes, 0);
+
+ // Verify that the actual size of the snapshot is close to the sum of the
+ // shallow sizes of all objects in the profile. They will not be exactly equal
+ // because of global headers and padding.
+ if (use_elf) {
+ await Process.run("strip", [snapshotPath]);
+ }
+ final int actual = await File(snapshotPath).length();
+ final int expected = profile.accountedBytes;
+ Expect.isTrue((actual - expected).abs() / actual < 0.01);
+}
+
+main() async {
+ test(false);
+ test(true);
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index c955046..804a35a 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -10,8 +10,8 @@
cc/Fail0: Fail # These tests are expected to crash on all platforms.
cc/Fail1: Fail # These tests are expected to crash on all platforms.
cc/Fail2: Fail # These tests are expected to crash on all platforms.
-cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: Fail, Crash # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline)
-cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: Fail, Crash # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline)
+cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: Fail, Crash # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline).
+cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: Fail, Crash # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline).
cc/IsolateReload_PendingStaticCall_DefinedToNSM: Fail # Issue 32981
cc/IsolateReload_PendingStaticCall_NSMToDefined: Fail, Crash # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline)
cc/IsolateReload_PendingUnqualifiedCall_InstanceToStatic: Fail # Issue 32981
@@ -23,6 +23,18 @@
dart/slow_path_shared_stub_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
dart/stack_overflow_shared_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
+[ $system == macos ]
+# Tests failing or crashing are sometimes reported as timeout on MacOS. See issues 35268 and 35275.
+cc/ArrayNew_Overflow_Crash: Crash, Fail, Timeout # These tests are expected to crash on all platforms
+cc/CodeImmutability: Crash, Fail, Timeout # These tests are expected to crash on all platforms
+cc/IsolateReload_PendingStaticCall_NSMToDefined: Fail, Crash, Timeout # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline)
+cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: Fail, Crash, Timeout # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline)
+cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: Fail, Crash, Timeout # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline)
+cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: Fail, Crash, Timeout # Issue 32981. Fails on non-Windows, crashes on Windows (because of test.py special handline)
+
+[ $system == macos && ($compiler == dartk || $compiler == dartkb) && $runtime == vm ]
+cc/Class_ComputeEndTokenPos: Crash, Timeout # May also time out on MacOS (issues 35268 and 35275).
+
[ $mode == debug ]
dart/appjit_cha_deopt_test: Pass, Slow # Quite slow in debug mode, uses --optimization-counter-threshold=100
@@ -314,3 +326,9 @@
[ $builder_tag == obfuscated && $compiler == dartkp ]
dart/optimized_stacktrace_line_and_column_test: SkipByDesign # Looks for filenames in stacktrace output
dart/optimized_stacktrace_line_test: SkipByDesign # Looks for filenames in stacktrace output
+
+[ $compiler != dartkp || $arch == arm || $arch == arm64 ]
+dart/v8_snapshot_profile_writer_test: SkipByDesign # Only relevant for AOT. Doesn't work in cross-compilation (has to run on the host).
+
+[ $compiler == dartkp ]
+dart/v8_snapshot_profile_writer_test: Pass, Slow # Can be slow due to re-invoking the precompiler.
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index daa7248..acbd08a 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -105,11 +105,7 @@
objects_.Add(cls);
}
- RawObject** from = cls->from();
- RawObject** to = cls->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(cls);
}
void WriteAlloc(Serializer* s) {
@@ -118,9 +114,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawClass* cls = predefined_[i];
+ s->AssignRef(cls);
+ AutoTraceObject(cls);
intptr_t class_id = cls->ptr()->id_;
s->WriteCid(class_id);
- s->AssignRef(cls);
}
count = objects_.length();
s->WriteUnsigned(count);
@@ -142,18 +139,14 @@
}
void WriteClass(Serializer* s, RawClass* cls) {
- Snapshot::Kind kind = s->kind();
- RawObject** from = cls->from();
- RawObject** to = cls->to_snapshot(kind);
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObjectName(cls, cls->ptr()->name_);
+ WriteFromTo(cls);
intptr_t class_id = cls->ptr()->id_;
if (class_id == kIllegalCid) {
s->UnexpectedObject(cls, "Class with illegal cid");
}
s->WriteCid(class_id);
- if (kind != Snapshot::kFullAOT) {
+ if (s->kind() != Snapshot::kFullAOT) {
s->Write<int32_t>(cls->ptr()->kernel_offset_);
}
s->Write<int32_t>(cls->ptr()->instance_size_in_words_);
@@ -200,22 +193,17 @@
}
void ReadFill(Deserializer* d) {
- Snapshot::Kind kind = d->kind();
bool is_vm_object = d->isolate() == Dart::vm_isolate();
ClassTable* table = d->isolate()->class_table();
for (intptr_t id = predefined_start_index_; id < predefined_stop_index_;
id++) {
RawClass* cls = reinterpret_cast<RawClass*>(d->Ref(id));
- RawObject** from = cls->from();
- RawObject** to_snapshot = cls->to_snapshot(kind);
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(cls);
intptr_t class_id = d->ReadCid();
cls->ptr()->id_ = class_id;
#if !defined(DART_PRECOMPILED_RUNTIME)
- if (kind != Snapshot::kFullAOT) {
+ if (d->kind() != Snapshot::kFullAOT) {
cls->ptr()->kernel_offset_ = d->Read<int32_t>();
}
#endif
@@ -238,15 +226,7 @@
RawClass* cls = reinterpret_cast<RawClass*>(d->Ref(id));
Deserializer::InitializeHeader(cls, kClassCid, Class::InstanceSize(),
is_vm_object);
- RawObject** from = cls->from();
- RawObject** to_snapshot = cls->to_snapshot(kind);
- RawObject** to = cls->to();
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to_snapshot + 1; p <= to; p++) {
- *p = Object::null();
- }
+ ReadFromTo(cls);
intptr_t class_id = d->ReadCid();
@@ -256,7 +236,7 @@
cls->ptr()->id_ = class_id;
#if !defined(DART_PRECOMPILED_RUNTIME)
- if (kind != Snapshot::kFullAOT) {
+ if (d->kind() != Snapshot::kFullAOT) {
cls->ptr()->kernel_offset_ = d->Read<int32_t>();
}
#endif
@@ -302,9 +282,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawTypeArguments* type_args = objects_[i];
+ s->AssignRef(type_args);
+ AutoTraceObject(type_args);
intptr_t length = Smi::Value(type_args->ptr()->length_);
s->WriteUnsigned(length);
- s->AssignRef(type_args);
}
}
@@ -312,6 +293,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawTypeArguments* type_args = objects_[i];
+ AutoTraceObject(type_args);
intptr_t length = Smi::Value(type_args->ptr()->length_);
s->WriteUnsigned(length);
s->Write<bool>(type_args->IsCanonical());
@@ -378,12 +360,7 @@
void Trace(Serializer* s, RawObject* object) {
RawPatchClass* cls = PatchClass::RawCast(object);
objects_.Add(cls);
-
- RawObject** from = cls->from();
- RawObject** to = cls->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(cls);
}
void WriteAlloc(Serializer* s) {
@@ -400,12 +377,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawPatchClass* cls = objects_[i];
- RawObject** from = cls->from();
- RawObject** to = cls->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
-
+ AutoTraceObject(cls);
+ WriteFromTo(cls);
if (s->kind() != Snapshot::kFullAOT) {
s->Write<int32_t>(cls->ptr()->library_kernel_offset_);
}
@@ -440,15 +413,7 @@
RawPatchClass* cls = reinterpret_cast<RawPatchClass*>(d->Ref(id));
Deserializer::InitializeHeader(cls, kPatchClassCid,
PatchClass::InstanceSize(), is_vm_object);
- RawObject** from = cls->from();
- RawObject** to_snapshot = cls->to_snapshot(d->kind());
- RawObject** to = cls->to();
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to_snapshot + 1; p <= to; p++) {
- *p = Object::null();
- }
+ ReadFromTo(cls);
#if !defined(DART_PRECOMPILED_RUNTIME)
if (d->kind() != Snapshot::kFullAOT) {
cls->ptr()->library_kernel_offset_ = d->Read<int32_t>();
@@ -469,11 +434,7 @@
RawFunction* func = Function::RawCast(object);
objects_.Add(func);
- RawObject** from = func->from();
- RawObject** to = func->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(func);
if (kind == Snapshot::kFull) {
NOT_IN_PRECOMPILED(s->Push(func->ptr()->bytecode_));
} else if (kind == Snapshot::kFullAOT) {
@@ -501,20 +462,17 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawFunction* func = objects_[i];
- RawObject** from = func->from();
- RawObject** to = func->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObjectName(func, func->ptr()->name_);
+ WriteFromTo(func);
if (kind == Snapshot::kFull) {
- NOT_IN_PRECOMPILED(s->WriteRef(func->ptr()->bytecode_));
+ NOT_IN_PRECOMPILED(WriteField(func, bytecode_));
} else if (kind == Snapshot::kFullAOT) {
- s->WriteRef(func->ptr()->code_);
+ WriteField(func, code_);
} else if (s->kind() == Snapshot::kFullJIT) {
- NOT_IN_PRECOMPILED(s->WriteRef(func->ptr()->unoptimized_code_));
- NOT_IN_PRECOMPILED(s->WriteRef(func->ptr()->bytecode_));
- s->WriteRef(func->ptr()->code_);
- s->WriteRef(func->ptr()->ic_data_array_);
+ NOT_IN_PRECOMPILED(WriteField(func, unoptimized_code_));
+ NOT_IN_PRECOMPILED(WriteField(func, bytecode_));
+ WriteField(func, code_);
+ WriteField(func, ic_data_array_);
}
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -557,15 +515,7 @@
RawFunction* func = reinterpret_cast<RawFunction*>(d->Ref(id));
Deserializer::InitializeHeader(func, kFunctionCid,
Function::InstanceSize(), is_vm_object);
- RawObject** from = func->from();
- RawObject** to_snapshot = func->to_snapshot(d->kind());
- RawObject** to = func->to();
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to_snapshot + 1; p <= to; p++) {
- *p = Object::null();
- }
+ ReadFromTo(func);
if (kind == Snapshot::kFull) {
NOT_IN_PRECOMPILED(func->ptr()->bytecode_ =
@@ -639,11 +589,9 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
} else if (FLAG_enable_interpreter && func.HasBytecode()) {
// Set the code entry_point to InterpretCall stub.
- func.SetInstructions(
- Code::Handle(StubCode::InterpretCall_entry()->code()));
+ func.SetInstructions(StubCode::InterpretCall());
} else if (FLAG_use_bytecode_compiler && func.HasBytecode()) {
- func.SetInstructions(
- Code::Handle(StubCode::LazyCompile_entry()->code()));
+ func.SetInstructions(StubCode::LazyCompile());
#endif // !defined(DART_PRECOMPILED_RUNTIME)
} else {
func.ClearCode(); // Set code and entrypoint to lazy compile stub.
@@ -691,6 +639,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawClosureData* data = objects_[i];
+ AutoTraceObject(data);
if (s->kind() != Snapshot::kFullAOT) {
s->WriteRef(data->ptr()->context_scope_);
}
@@ -750,12 +699,7 @@
void Trace(Serializer* s, RawObject* object) {
RawSignatureData* data = SignatureData::RawCast(object);
objects_.Add(data);
-
- RawObject** from = data->from();
- RawObject** to = data->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(data);
}
void WriteAlloc(Serializer* s) {
@@ -772,11 +716,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawSignatureData* data = objects_[i];
- RawObject** from = data->from();
- RawObject** to = data->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(data);
+ WriteFromTo(data);
}
}
@@ -808,11 +749,7 @@
RawSignatureData* data = reinterpret_cast<RawSignatureData*>(d->Ref(id));
Deserializer::InitializeHeader(
data, kSignatureDataCid, SignatureData::InstanceSize(), is_vm_object);
- RawObject** from = data->from();
- RawObject** to = data->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(data);
}
}
};
@@ -827,12 +764,7 @@
void Trace(Serializer* s, RawObject* object) {
RawRedirectionData* data = RedirectionData::RawCast(object);
objects_.Add(data);
-
- RawObject** from = data->from();
- RawObject** to = data->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(data);
}
void WriteAlloc(Serializer* s) {
@@ -849,11 +781,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawRedirectionData* data = objects_[i];
- RawObject** from = data->from();
- RawObject** to = data->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(data);
+ WriteFromTo(data);
}
}
@@ -887,11 +816,7 @@
Deserializer::InitializeHeader(data, kRedirectionDataCid,
RedirectionData::InstanceSize(),
is_vm_object);
- RawObject** from = data->from();
- RawObject** to = data->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(data);
}
}
};
@@ -957,6 +882,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawField* field = objects_[i];
+ AutoTraceObject(field);
s->WriteRef(field->ptr()->name_);
s->WriteRef(field->ptr()->owner_);
@@ -1033,16 +959,7 @@
RawField* field = reinterpret_cast<RawField*>(d->Ref(id));
Deserializer::InitializeHeader(field, kFieldCid, Field::InstanceSize(),
is_vm_object);
- RawObject** from = field->from();
- RawObject** to_snapshot = field->to_snapshot(kind);
- RawObject** to = field->to();
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to_snapshot + 1; p <= to; p++) {
- *p = Object::null();
- }
-
+ ReadFromTo(field);
if (kind != Snapshot::kFullAOT) {
field->ptr()->token_pos_ = d->ReadTokenPosition();
field->ptr()->end_token_pos_ = d->ReadTokenPosition();
@@ -1091,12 +1008,7 @@
void Trace(Serializer* s, RawObject* object) {
RawScript* script = Script::RawCast(object);
objects_.Add(script);
-
- RawObject** from = script->from();
- RawObject** to = script->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(script);
}
void WriteAlloc(Serializer* s) {
@@ -1110,16 +1022,11 @@
}
void WriteFill(Serializer* s) {
- Snapshot::Kind kind = s->kind();
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawScript* script = objects_[i];
- RawObject** from = script->from();
- RawObject** to = script->to_snapshot(kind);
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
-
+ AutoTraceObject(script);
+ WriteFromTo(script);
s->Write<int32_t>(script->ptr()->line_offset_);
s->Write<int32_t>(script->ptr()->col_offset_);
s->Write<int8_t>(script->ptr()->kind_);
@@ -1148,23 +1055,13 @@
}
void ReadFill(Deserializer* d) {
- Snapshot::Kind kind = d->kind();
bool is_vm_object = d->isolate() == Dart::vm_isolate();
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawScript* script = reinterpret_cast<RawScript*>(d->Ref(id));
Deserializer::InitializeHeader(script, kScriptCid, Script::InstanceSize(),
is_vm_object);
- RawObject** from = script->from();
- RawObject** to_snapshot = script->to_snapshot(kind);
- RawObject** to = script->to();
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to_snapshot + 1; p <= to; p++) {
- *p = Object::null();
- }
-
+ ReadFromTo(script);
script->ptr()->line_offset_ = d->Read<int32_t>();
script->ptr()->col_offset_ = d->Read<int32_t>();
script->ptr()->kind_ = d->Read<int8_t>();
@@ -1183,12 +1080,7 @@
void Trace(Serializer* s, RawObject* object) {
RawLibrary* lib = Library::RawCast(object);
objects_.Add(lib);
-
- RawObject** from = lib->from();
- RawObject** to = lib->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(lib);
}
void WriteAlloc(Serializer* s) {
@@ -1205,12 +1097,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawLibrary* lib = objects_[i];
- RawObject** from = lib->from();
- RawObject** to = lib->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
-
+ AutoTraceObjectName(lib, lib->ptr()->url_);
+ WriteFromTo(lib);
s->Write<int32_t>(lib->ptr()->index_);
s->Write<uint16_t>(lib->ptr()->num_imports_);
s->Write<int8_t>(lib->ptr()->load_state_);
@@ -1250,16 +1138,7 @@
RawLibrary* lib = reinterpret_cast<RawLibrary*>(d->Ref(id));
Deserializer::InitializeHeader(lib, kLibraryCid, Library::InstanceSize(),
is_vm_object);
- RawObject** from = lib->from();
- RawObject** to_snapshot = lib->to_snapshot(d->kind());
- RawObject** to = lib->to();
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to_snapshot + 1; p <= to; p++) {
- *p = Object::null();
- }
-
+ ReadFromTo(lib);
lib->ptr()->native_entry_resolver_ = NULL;
lib->ptr()->native_entry_symbol_resolver_ = NULL;
lib->ptr()->index_ = d->Read<int32_t>();
@@ -1287,12 +1166,7 @@
void Trace(Serializer* s, RawObject* object) {
RawNamespace* ns = Namespace::RawCast(object);
objects_.Add(ns);
-
- RawObject** from = ns->from();
- RawObject** to = ns->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(ns);
}
void WriteAlloc(Serializer* s) {
@@ -1309,11 +1183,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawNamespace* ns = objects_[i];
- RawObject** from = ns->from();
- RawObject** to = ns->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(ns);
+ WriteFromTo(ns);
}
}
@@ -1344,11 +1215,7 @@
RawNamespace* ns = reinterpret_cast<RawNamespace*>(d->Ref(id));
Deserializer::InitializeHeader(ns, kNamespaceCid,
Namespace::InstanceSize(), is_vm_object);
- RawObject** from = ns->from();
- RawObject** to = ns->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(ns);
}
}
};
@@ -1364,12 +1231,7 @@
void Trace(Serializer* s, RawObject* object) {
RawKernelProgramInfo* info = KernelProgramInfo::RawCast(object);
objects_.Add(info);
-
- RawObject** from = info->from();
- RawObject** to = info->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(info);
}
void WriteAlloc(Serializer* s) {
@@ -1386,11 +1248,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawKernelProgramInfo* info = objects_[i];
- RawObject** from = info->from();
- RawObject** to = info->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(info);
+ WriteFromTo(info);
}
}
@@ -1425,15 +1284,7 @@
Deserializer::InitializeHeader(info, kKernelProgramInfoCid,
KernelProgramInfo::InstanceSize(),
is_vm_object);
- RawObject** from = info->from();
- RawObject** to = info->to_snapshot(d->kind());
- RawObject** end = info->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to + 1; p <= end; p++) {
- *p = Object::null();
- }
+ ReadFromTo(info);
}
}
@@ -1496,6 +1347,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawCode* code = objects_[i];
+ AutoTraceObject(code);
intptr_t pointer_offsets_length =
Code::PtrOffBits::decode(code->ptr()->state_bits_);
@@ -1647,12 +1499,7 @@
void Trace(Serializer* s, RawObject* object) {
RawBytecode* bytecode = Bytecode::RawCast(object);
objects_.Add(bytecode);
-
- RawObject** from = bytecode->from();
- RawObject** to = bytecode->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(bytecode);
}
void WriteAlloc(Serializer* s) {
@@ -1670,11 +1517,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawBytecode* bytecode = objects_[i];
- RawObject** from = bytecode->from();
- RawObject** to = bytecode->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ WriteFromTo(bytecode);
s->Write<int32_t>(bytecode->ptr()->source_positions_binary_offset_);
}
}
@@ -1706,11 +1549,7 @@
RawBytecode* bytecode = reinterpret_cast<RawBytecode*>(d->Ref(id));
Deserializer::InitializeHeader(bytecode, kBytecodeCid,
Bytecode::InstanceSize(), is_vm_object);
- RawObject** from = bytecode->from();
- RawObject** to = bytecode->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(bytecode);
bytecode->ptr()->source_positions_binary_offset_ = d->Read<int32_t>();
}
}
@@ -1742,9 +1581,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawObjectPool* pool = objects_[i];
+ s->AssignRef(pool);
+ AutoTraceObject(pool);
intptr_t length = pool->ptr()->length_;
s->WriteUnsigned(length);
- s->AssignRef(pool);
}
}
@@ -1752,6 +1592,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawObjectPool* pool = objects_[i];
+ AutoTraceObject(pool);
intptr_t length = pool->ptr()->length_;
s->WriteUnsigned(length);
uint8_t* entry_bits = pool->ptr()->entry_bits();
@@ -1761,14 +1602,12 @@
switch (ObjectPool::TypeBits::decode(entry_bits[j])) {
case ObjectPool::kTaggedObject: {
#if !defined(TARGET_ARCH_DBC)
- if ((entry.raw_obj_ ==
- StubCode::CallNoScopeNative_entry()->code()) ||
- (entry.raw_obj_ ==
- StubCode::CallAutoScopeNative_entry()->code())) {
+ if ((entry.raw_obj_ == StubCode::CallNoScopeNative().raw()) ||
+ (entry.raw_obj_ == StubCode::CallAutoScopeNative().raw())) {
// Natives can run while precompiling, becoming linked and
// switching their stub. Reset to the initial stub used for
// lazy-linking.
- s->WriteRef(StubCode::CallBootstrapNative_entry()->code());
+ s->WriteRef(StubCode::CallBootstrapNative().raw());
break;
}
#endif
@@ -1904,12 +1743,13 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawObject* object = shared_objects_[i];
+ s->AssignRef(object);
+ AutoTraceObject(object);
uint32_t offset;
if (!s->GetSharedDataOffset(object, &offset)) {
UNREACHABLE();
}
s->WriteUnsigned(offset);
- s->AssignRef(object);
}
count = objects_.length();
@@ -1917,12 +1757,14 @@
uint32_t running_offset = 0;
for (intptr_t i = 0; i < count; i++) {
RawObject* object = objects_[i];
+ s->AssignRef(object);
+ AutoTraceObject(object);
uint32_t offset = s->GetDataOffset(object);
+ s->TraceDataOffset(offset);
ASSERT(Utils::IsAligned(offset, kObjectAlignment));
ASSERT(offset > running_offset);
s->WriteUnsigned((offset - running_offset) >> kObjectAlignmentLog2);
running_offset = offset;
- s->AssignRef(object);
}
}
@@ -1982,9 +1824,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawExceptionHandlers* handlers = objects_[i];
+ s->AssignRef(handlers);
+ AutoTraceObject(handlers);
intptr_t length = handlers->ptr()->num_entries_;
s->WriteUnsigned(length);
- s->AssignRef(handlers);
}
}
@@ -1992,6 +1835,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawExceptionHandlers* handlers = objects_[i];
+ AutoTraceObject(handlers);
intptr_t length = handlers->ptr()->num_entries_;
s->WriteUnsigned(length);
s->WriteRef(handlers->ptr()->handled_types_data_);
@@ -2076,9 +1920,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawContext* context = objects_[i];
+ s->AssignRef(context);
+ AutoTraceObject(context);
intptr_t length = context->ptr()->num_variables_;
s->WriteUnsigned(length);
- s->AssignRef(context);
}
}
@@ -2086,6 +1931,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawContext* context = objects_[i];
+ AutoTraceObject(context);
intptr_t length = context->ptr()->num_variables_;
s->WriteUnsigned(length);
s->WriteRef(context->ptr()->parent_);
@@ -2145,11 +1991,7 @@
objects_.Add(scope);
intptr_t length = scope->ptr()->num_variables_;
- RawObject** from = scope->from();
- RawObject** to = scope->to(length);
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(scope, length);
}
void WriteAlloc(Serializer* s) {
@@ -2158,9 +2000,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawContextScope* scope = objects_[i];
+ s->AssignRef(scope);
+ AutoTraceObject(scope);
intptr_t length = scope->ptr()->num_variables_;
s->WriteUnsigned(length);
- s->AssignRef(scope);
}
}
@@ -2168,14 +2011,11 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawContextScope* scope = objects_[i];
+ AutoTraceObject(scope);
intptr_t length = scope->ptr()->num_variables_;
s->WriteUnsigned(length);
s->Write<bool>(scope->ptr()->is_implicit_);
- RawObject** from = scope->from();
- RawObject** to = scope->to(length);
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ WriteFromTo(scope, length);
}
}
@@ -2212,11 +2052,7 @@
is_vm_object);
scope->ptr()->num_variables_ = length;
scope->ptr()->is_implicit_ = d->Read<bool>();
- RawObject** from = scope->from();
- RawObject** to = scope->to(length);
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(scope, length);
}
}
};
@@ -2230,12 +2066,7 @@
void Trace(Serializer* s, RawObject* object) {
RawUnlinkedCall* unlinked = UnlinkedCall::RawCast(object);
objects_.Add(unlinked);
-
- RawObject** from = unlinked->from();
- RawObject** to = unlinked->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(unlinked);
}
void WriteAlloc(Serializer* s) {
@@ -2252,11 +2083,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawUnlinkedCall* unlinked = objects_[i];
- RawObject** from = unlinked->from();
- RawObject** to = unlinked->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(unlinked);
+ WriteFromTo(unlinked);
}
}
@@ -2290,11 +2118,7 @@
Deserializer::InitializeHeader(unlinked, kUnlinkedCallCid,
UnlinkedCall::InstanceSize(),
is_vm_object);
- RawObject** from = unlinked->from();
- RawObject** to = unlinked->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(unlinked);
}
}
};
@@ -2308,12 +2132,7 @@
void Trace(Serializer* s, RawObject* object) {
RawICData* ic = ICData::RawCast(object);
objects_.Add(ic);
-
- RawObject** from = ic->from();
- RawObject** to = ic->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(ic);
}
void WriteAlloc(Serializer* s) {
@@ -2331,11 +2150,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawICData* ic = objects_[i];
- RawObject** from = ic->from();
- RawObject** to = ic->to_snapshot(kind);
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(ic);
+ WriteFromTo(ic);
if (kind != Snapshot::kFullAOT) {
NOT_IN_PRECOMPILED(s->Write<int32_t>(ic->ptr()->deopt_id_));
}
@@ -2367,22 +2183,13 @@
}
void ReadFill(Deserializer* d) {
- Snapshot::Kind kind = d->kind();
bool is_vm_object = d->isolate() == Dart::vm_isolate();
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawICData* ic = reinterpret_cast<RawICData*>(d->Ref(id));
Deserializer::InitializeHeader(ic, kICDataCid, ICData::InstanceSize(),
is_vm_object);
- RawObject** from = ic->from();
- RawObject** to_snapshot = ic->to_snapshot(kind);
- RawObject** to = ic->to();
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to_snapshot + 1; p <= to; p++) {
- *p = Object::null();
- }
+ ReadFromTo(ic);
NOT_IN_PRECOMPILED(ic->ptr()->deopt_id_ = d->Read<int32_t>());
ic->ptr()->state_bits_ = d->Read<int32_t>();
#if defined(TAG_IC_DATA)
@@ -2402,12 +2209,7 @@
void Trace(Serializer* s, RawObject* object) {
RawMegamorphicCache* cache = MegamorphicCache::RawCast(object);
objects_.Add(cache);
-
- RawObject** from = cache->from();
- RawObject** to = cache->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(cache);
}
void WriteAlloc(Serializer* s) {
@@ -2424,11 +2226,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawMegamorphicCache* cache = objects_[i];
- RawObject** from = cache->from();
- RawObject** to = cache->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(cache);
+ WriteFromTo(cache);
s->Write<int32_t>(cache->ptr()->filled_entry_count_);
}
}
@@ -2463,11 +2262,7 @@
Deserializer::InitializeHeader(cache, kMegamorphicCacheCid,
MegamorphicCache::InstanceSize(),
is_vm_object);
- RawObject** from = cache->from();
- RawObject** to = cache->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(cache);
cache->ptr()->filled_entry_count_ = d->Read<int32_t>();
}
}
@@ -2500,6 +2295,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawSubtypeTestCache* cache = objects_[i];
+ AutoTraceObject(cache);
s->WriteRef(cache->ptr()->cache_);
}
}
@@ -2548,12 +2344,7 @@
void Trace(Serializer* s, RawObject* object) {
RawLanguageError* error = LanguageError::RawCast(object);
objects_.Add(error);
-
- RawObject** from = error->from();
- RawObject** to = error->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(error);
}
void WriteAlloc(Serializer* s) {
@@ -2570,11 +2361,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawLanguageError* error = objects_[i];
- RawObject** from = error->from();
- RawObject** to = error->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(error);
+ WriteFromTo(error);
s->WriteTokenPosition(error->ptr()->token_pos_);
s->Write<bool>(error->ptr()->report_after_token_);
s->Write<int8_t>(error->ptr()->kind_);
@@ -2610,11 +2398,7 @@
Deserializer::InitializeHeader(error, kLanguageErrorCid,
LanguageError::InstanceSize(),
is_vm_object);
- RawObject** from = error->from();
- RawObject** to = error->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(error);
error->ptr()->token_pos_ = d->ReadTokenPosition();
error->ptr()->report_after_token_ = d->Read<bool>();
error->ptr()->kind_ = d->Read<int8_t>();
@@ -2632,12 +2416,7 @@
void Trace(Serializer* s, RawObject* object) {
RawUnhandledException* exception = UnhandledException::RawCast(object);
objects_.Add(exception);
-
- RawObject** from = exception->from();
- RawObject** to = exception->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(exception);
}
void WriteAlloc(Serializer* s) {
@@ -2654,11 +2433,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawUnhandledException* exception = objects_[i];
- RawObject** from = exception->from();
- RawObject** to = exception->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(exception);
+ WriteFromTo(exception);
}
}
@@ -2692,11 +2468,7 @@
Deserializer::InitializeHeader(exception, kUnhandledExceptionCid,
UnhandledException::InstanceSize(),
is_vm_object);
- RawObject** from = exception->from();
- RawObject** to = exception->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(exception);
}
}
};
@@ -2747,6 +2519,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawInstance* instance = objects_[i];
+ AutoTraceObject(instance);
s->Write<bool>(instance->IsCanonical());
intptr_t offset = Instance::NextFieldOffset();
while (offset < next_field_offset) {
@@ -2828,12 +2601,7 @@
void Trace(Serializer* s, RawObject* object) {
RawLibraryPrefix* prefix = LibraryPrefix::RawCast(object);
objects_.Add(prefix);
-
- RawObject** from = prefix->from();
- RawObject** to = prefix->to_snapshot(s->kind());
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(prefix);
}
void WriteAlloc(Serializer* s) {
@@ -2847,15 +2615,11 @@
}
void WriteFill(Serializer* s) {
- Snapshot::Kind kind = s->kind();
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawLibraryPrefix* prefix = objects_[i];
- RawObject** from = prefix->from();
- RawObject** to = prefix->to_snapshot(kind);
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(prefix);
+ WriteFromTo(prefix);
s->Write<uint16_t>(prefix->ptr()->num_imports_);
s->Write<bool>(prefix->ptr()->is_deferred_load_);
}
@@ -2883,7 +2647,6 @@
}
void ReadFill(Deserializer* d) {
- Snapshot::Kind kind = d->kind();
bool is_vm_object = d->isolate() == Dart::vm_isolate();
for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -2892,16 +2655,7 @@
Deserializer::InitializeHeader(prefix, kLibraryPrefixCid,
LibraryPrefix::InstanceSize(),
is_vm_object);
- RawObject** from = prefix->from();
- RawObject** to_snapshot = prefix->to_snapshot(kind);
- RawObject** to = prefix->to();
- for (RawObject** p = from; p <= to_snapshot; p++) {
- *p = d->ReadRef();
- }
- for (RawObject** p = to_snapshot + 1; p <= to; p++) {
- *p = Object::null();
- }
-
+ ReadFromTo(prefix);
prefix->ptr()->num_imports_ = d->Read<uint16_t>();
prefix->ptr()->is_deferred_load_ = d->Read<bool>();
prefix->ptr()->is_loaded_ = !prefix->ptr()->is_deferred_load_;
@@ -2924,11 +2678,7 @@
objects_.Add(type);
}
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(type);
if (type->ptr()->type_class_id_->IsHeapObject()) {
// Type class is still an unresolved class.
@@ -2965,11 +2715,8 @@
intptr_t count = canonical_objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawType* type = canonical_objects_[i];
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(type);
+ WriteFromTo(type);
s->WriteTokenPosition(type->ptr()->token_pos_);
s->Write<int8_t>(type->ptr()->type_state_);
if (should_write_type_testing_stub) {
@@ -2981,11 +2728,8 @@
count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawType* type = objects_[i];
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(type);
+ WriteFromTo(type);
s->WriteTokenPosition(type->ptr()->token_pos_);
s->Write<int8_t>(type->ptr()->type_state_);
if (should_write_type_testing_stub) {
@@ -3048,11 +2792,7 @@
RawType* type = reinterpret_cast<RawType*>(d->Ref(id));
Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
is_vm_isolate, true);
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(type);
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->type_state_ = d->Read<int8_t>();
if (should_read_type_testing_stub) {
@@ -3066,11 +2806,7 @@
RawType* type = reinterpret_cast<RawType*>(d->Ref(id));
Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
is_vm_isolate);
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(type);
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->type_state_ = d->Read<int8_t>();
if (should_read_type_testing_stub) {
@@ -3123,12 +2859,7 @@
void Trace(Serializer* s, RawObject* object) {
RawTypeRef* type = TypeRef::RawCast(object);
objects_.Add(type);
-
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(type);
}
void WriteAlloc(Serializer* s) {
@@ -3148,11 +2879,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawTypeRef* type = objects_[i];
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(type);
+ WriteFromTo(type);
if (should_write_type_testing_stub) {
RawInstructions* instr = type_testing_stubs_.LookupByAddresss(
type->ptr()->type_test_stub_entry_point_);
@@ -3192,11 +2920,7 @@
RawTypeRef* type = reinterpret_cast<RawTypeRef*>(d->Ref(id));
Deserializer::InitializeHeader(type, kTypeRefCid, TypeRef::InstanceSize(),
is_vm_object);
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(type);
if (should_read_type_testing_stub) {
instr_ = d->ReadInstructions();
type_ = type;
@@ -3232,12 +2956,7 @@
RawTypeParameter* type = TypeParameter::RawCast(object);
objects_.Add(type);
ASSERT(!type->IsCanonical());
-
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(type);
}
void WriteAlloc(Serializer* s) {
@@ -3257,11 +2976,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawTypeParameter* type = objects_[i];
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(type);
+ WriteFromTo(type);
s->Write<int32_t>(type->ptr()->parameterized_class_id_);
s->WriteTokenPosition(type->ptr()->token_pos_);
s->Write<int16_t>(type->ptr()->index_);
@@ -3306,11 +3022,7 @@
RawTypeParameter* type = reinterpret_cast<RawTypeParameter*>(d->Ref(id));
Deserializer::InitializeHeader(
type, kTypeParameterCid, TypeParameter::InstanceSize(), is_vm_object);
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(type);
type->ptr()->parameterized_class_id_ = d->Read<int32_t>();
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->index_ = d->Read<int16_t>();
@@ -3347,12 +3059,7 @@
void Trace(Serializer* s, RawObject* object) {
RawBoundedType* type = BoundedType::RawCast(object);
objects_.Add(type);
-
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(type);
}
void WriteAlloc(Serializer* s) {
@@ -3369,11 +3076,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawBoundedType* type = objects_[i];
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(type);
+ WriteFromTo(type);
}
}
@@ -3405,11 +3109,7 @@
RawBoundedType* type = reinterpret_cast<RawBoundedType*>(d->Ref(id));
Deserializer::InitializeHeader(type, kBoundedTypeCid,
BoundedType::InstanceSize(), is_vm_object);
- RawObject** from = type->from();
- RawObject** to = type->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(type);
}
}
};
@@ -3423,12 +3123,7 @@
void Trace(Serializer* s, RawObject* object) {
RawClosure* closure = Closure::RawCast(object);
objects_.Add(closure);
-
- RawObject** from = closure->from();
- RawObject** to = closure->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(closure);
}
void WriteAlloc(Serializer* s) {
@@ -3445,12 +3140,9 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawClosure* closure = objects_[i];
+ AutoTraceObject(closure);
s->Write<bool>(closure->IsCanonical());
- RawObject** from = closure->from();
- RawObject** to = closure->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ WriteFromTo(closure);
}
}
@@ -3483,11 +3175,7 @@
Deserializer::InitializeHeader(closure, kClosureCid,
Closure::InstanceSize(), is_vm_object,
is_canonical);
- RawObject** from = closure->from();
- RawObject** to = closure->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(closure);
}
}
};
@@ -3514,15 +3202,17 @@
s->WriteUnsigned(smis_.length() + mints_.length());
for (intptr_t i = 0; i < smis_.length(); i++) {
RawSmi* smi = smis_[i];
+ s->AssignRef(smi);
+ AutoTraceObject(smi);
s->Write<bool>(true);
s->Write<int64_t>(Smi::Value(smi));
- s->AssignRef(smi);
}
for (intptr_t i = 0; i < mints_.length(); i++) {
RawMint* mint = mints_[i];
+ s->AssignRef(mint);
+ AutoTraceObject(mint);
s->Write<bool>(mint->IsCanonical());
s->Write<int64_t>(mint->ptr()->value_);
- s->AssignRef(mint);
}
}
@@ -3606,6 +3296,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawDouble* dbl = objects_[i];
+ AutoTraceObject(dbl);
s->Write<bool>(dbl->IsCanonical());
s->Write<double>(dbl->ptr()->value_);
}
@@ -3654,12 +3345,7 @@
void Trace(Serializer* s, RawObject* object) {
RawGrowableObjectArray* array = GrowableObjectArray::RawCast(object);
objects_.Add(array);
-
- RawObject** from = array->from();
- RawObject** to = array->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(array);
}
void WriteAlloc(Serializer* s) {
@@ -3676,12 +3362,9 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawGrowableObjectArray* array = objects_[i];
+ AutoTraceObject(array);
s->Write<bool>(array->IsCanonical());
- RawObject** from = array->from();
- RawObject** to = array->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ WriteFromTo(array);
}
}
@@ -3717,11 +3400,7 @@
Deserializer::InitializeHeader(list, kGrowableObjectArrayCid,
GrowableObjectArray::InstanceSize(),
is_vm_object, is_canonical);
- RawObject** from = list->from();
- RawObject** to = list->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(list);
}
}
};
@@ -3744,9 +3423,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawTypedData* data = objects_[i];
+ s->AssignRef(data);
+ AutoTraceObject(data);
intptr_t length = Smi::Value(data->ptr()->length_);
s->WriteUnsigned(length);
- s->AssignRef(data);
}
}
@@ -3755,6 +3435,7 @@
intptr_t element_size = TypedData::ElementSizeInBytes(cid_);
for (intptr_t i = 0; i < count; i++) {
RawTypedData* data = objects_[i];
+ AutoTraceObject(data);
intptr_t length = Smi::Value(data->ptr()->length_);
s->WriteUnsigned(length);
s->Write<bool>(data->IsCanonical());
@@ -3837,6 +3518,7 @@
intptr_t element_size = ExternalTypedData::ElementSizeInBytes(cid_);
for (intptr_t i = 0; i < count; i++) {
RawExternalTypedData* data = objects_[i];
+ AutoTraceObject(data);
intptr_t length = Smi::Value(data->ptr()->length_);
s->WriteUnsigned(length);
uint8_t* cdata = reinterpret_cast<uint8_t*>(data->ptr()->data_);
@@ -3898,12 +3580,7 @@
void Trace(Serializer* s, RawObject* object) {
RawStackTrace* trace = StackTrace::RawCast(object);
objects_.Add(trace);
-
- RawObject** from = trace->from();
- RawObject** to = trace->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(trace);
}
void WriteAlloc(Serializer* s) {
@@ -3920,11 +3597,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawStackTrace* trace = objects_[i];
- RawObject** from = trace->from();
- RawObject** to = trace->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(trace);
+ WriteFromTo(trace);
}
}
@@ -3956,11 +3630,7 @@
RawStackTrace* trace = reinterpret_cast<RawStackTrace*>(d->Ref(id));
Deserializer::InitializeHeader(trace, kStackTraceCid,
StackTrace::InstanceSize(), is_vm_object);
- RawObject** from = trace->from();
- RawObject** to = trace->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(trace);
}
}
};
@@ -3974,12 +3644,7 @@
void Trace(Serializer* s, RawObject* object) {
RawRegExp* regexp = RegExp::RawCast(object);
objects_.Add(regexp);
-
- RawObject** from = regexp->from();
- RawObject** to = regexp->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(regexp);
}
void WriteAlloc(Serializer* s) {
@@ -3996,12 +3661,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawRegExp* regexp = objects_[i];
- RawObject** from = regexp->from();
- RawObject** to = regexp->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
-
+ AutoTraceObject(regexp);
+ WriteFromTo(regexp);
s->Write<int32_t>(regexp->ptr()->num_registers_);
s->Write<int8_t>(regexp->ptr()->type_flags_);
}
@@ -4034,12 +3695,7 @@
RawRegExp* regexp = reinterpret_cast<RawRegExp*>(d->Ref(id));
Deserializer::InitializeHeader(regexp, kRegExpCid, RegExp::InstanceSize(),
is_vm_object);
- RawObject** from = regexp->from();
- RawObject** to = regexp->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
-
+ ReadFromTo(regexp);
regexp->ptr()->num_registers_ = d->Read<int32_t>();
regexp->ptr()->type_flags_ = d->Read<int8_t>();
}
@@ -4055,12 +3711,7 @@
void Trace(Serializer* s, RawObject* object) {
RawWeakProperty* property = WeakProperty::RawCast(object);
objects_.Add(property);
-
- RawObject** from = property->from();
- RawObject** to = property->to();
- for (RawObject** p = from; p <= to; p++) {
- s->Push(*p);
- }
+ PushFromTo(property);
}
void WriteAlloc(Serializer* s) {
@@ -4077,11 +3728,8 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawWeakProperty* property = objects_[i];
- RawObject** from = property->from();
- RawObject** to = property->to();
- for (RawObject** p = from; p <= to; p++) {
- s->WriteRef(*p);
- }
+ AutoTraceObject(property);
+ WriteFromTo(property);
}
}
@@ -4115,11 +3763,7 @@
Deserializer::InitializeHeader(property, kWeakPropertyCid,
WeakProperty::InstanceSize(),
is_vm_object);
- RawObject** from = property->from();
- RawObject** to = property->to();
- for (RawObject** p = from; p <= to; p++) {
- *p = d->ReadRef();
- }
+ ReadFromTo(property);
}
}
};
@@ -4163,6 +3807,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawLinkedHashMap* map = objects_[i];
+ AutoTraceObject(map);
s->Write<bool>(map->IsCanonical());
s->WriteRef(map->ptr()->type_arguments_);
@@ -4274,9 +3919,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawArray* array = objects_[i];
+ s->AssignRef(array);
+ AutoTraceObject(array);
intptr_t length = Smi::Value(array->ptr()->length_);
s->WriteUnsigned(length);
- s->AssignRef(array);
}
}
@@ -4284,6 +3930,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawArray* array = objects_[i];
+ AutoTraceObject(array);
intptr_t length = Smi::Value(array->ptr()->length_);
s->WriteUnsigned(length);
s->Write<bool>(array->IsCanonical());
@@ -4356,9 +4003,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawOneByteString* str = objects_[i];
+ s->AssignRef(str);
+ AutoTraceObject(str);
intptr_t length = Smi::Value(str->ptr()->length_);
s->WriteUnsigned(length);
- s->AssignRef(str);
}
}
@@ -4366,6 +4014,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawOneByteString* str = objects_[i];
+ AutoTraceObject(str);
intptr_t length = Smi::Value(str->ptr()->length_);
s->WriteUnsigned(length);
s->Write<bool>(str->IsCanonical());
@@ -4433,9 +4082,10 @@
s->WriteUnsigned(count);
for (intptr_t i = 0; i < count; i++) {
RawTwoByteString* str = objects_[i];
+ s->AssignRef(str);
+ AutoTraceObject(str);
intptr_t length = Smi::Value(str->ptr()->length_);
s->WriteUnsigned(length);
- s->AssignRef(str);
}
}
@@ -4443,6 +4093,7 @@
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawTwoByteString* str = objects_[i];
+ AutoTraceObject(str);
intptr_t length = Smi::Value(str->ptr()->length_);
s->WriteUnsigned(length);
s->Write<bool>(str->IsCanonical());
@@ -4512,7 +4163,9 @@
uint8_t** buffer,
ReAlloc alloc,
intptr_t initial_size,
- ImageWriter* image_writer)
+ ImageWriter* image_writer,
+ bool vm,
+ V8SnapshotProfileWriter* profile_writer)
: StackResource(thread),
heap_(thread->isolate()->heap()),
zone_(thread->zone()),
@@ -4524,7 +4177,9 @@
num_cids_(0),
num_base_objects_(0),
num_written_objects_(0),
- next_ref_index_(1)
+ next_ref_index_(1),
+ vm_(vm),
+ profile_writer_(profile_writer)
#if defined(SNAPSHOT_BACKTRACE)
,
current_parent_(Object::null()),
@@ -4542,6 +4197,43 @@
delete[] clusters_by_cid_;
}
+void Serializer::TraceStartWritingObject(const char* type,
+ RawObject* obj,
+ RawString* name) {
+ if (profile_writer_ == nullptr) return;
+
+ intptr_t id = 0;
+ if (obj->IsHeapObject()) {
+ id = heap_->GetObjectId(obj);
+ } else {
+ id = smi_ids_.Lookup(Smi::RawCast(obj))->id_;
+ }
+ ASSERT(id != 0);
+
+ const char* name_str = nullptr;
+ if (name != nullptr) {
+ String& str = thread()->StringHandle();
+ str = name;
+ name_str = str.ToCString();
+ }
+
+ object_currently_writing_id_ = id;
+ profile_writer_->SetObjectTypeAndName(
+ {V8SnapshotProfileWriter::kSnapshot, id}, type, name_str);
+ object_currently_writing_start_ = stream_.Position();
+}
+
+void Serializer::TraceEndWritingObject() {
+ if (profile_writer_ != nullptr) {
+ ASSERT(object_currently_writing_id_ != 0);
+ profile_writer_->AttributeBytesTo(
+ {V8SnapshotProfileWriter::kSnapshot, object_currently_writing_id_},
+ stream_.Position() - object_currently_writing_start_);
+ object_currently_writing_id_ = 0;
+ object_currently_writing_start_ = 0;
+ }
+}
+
SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
@@ -4679,6 +4371,31 @@
const intptr_t offset = image_writer_->GetTextOffsetFor(instr, code);
ASSERT(offset != 0);
Write<int32_t>(offset);
+
+ // If offset < 0, it's pointing to a shared instruction. We don't profile
+ // references to shared text/data (since they don't consume any space). Of
+ // course, the space taken for the reference is profiled.
+ if (profile_writer_ != nullptr && offset >= 0) {
+ // Instructions cannot be roots.
+ ASSERT(object_currently_writing_id_ != 0);
+ auto offset_space = vm_ ? V8SnapshotProfileWriter::kVmText
+ : V8SnapshotProfileWriter::kIsolateText;
+ profile_writer_->AttributeReferenceTo(
+ {V8SnapshotProfileWriter::kSnapshot, object_currently_writing_id_},
+ {offset_space, offset < 0 ? -offset : offset});
+ }
+}
+
+void Serializer::TraceDataOffset(uint32_t offset) {
+ if (profile_writer_ != nullptr) {
+ // ROData cannot be roots.
+ ASSERT(object_currently_writing_id_ != 0);
+ auto offset_space = vm_ ? V8SnapshotProfileWriter::kVmData
+ : V8SnapshotProfileWriter::kIsolateData;
+ profile_writer_->AttributeReferenceTo(
+ {V8SnapshotProfileWriter::kSnapshot, object_currently_writing_id_},
+ {offset_space, offset});
+ }
}
bool Serializer::GetSharedDataOffset(RawObject* object,
@@ -4923,30 +4640,36 @@
// These objects are always allocated by Object::InitOnce, so they are not
// written into the snapshot.
- AddBaseObject(Object::null());
- AddBaseObject(Object::sentinel().raw());
- AddBaseObject(Object::transition_sentinel().raw());
- AddBaseObject(Object::empty_array().raw());
- AddBaseObject(Object::zero_array().raw());
- AddBaseObject(Object::dynamic_type().raw());
- AddBaseObject(Object::void_type().raw());
- AddBaseObject(Object::empty_type_arguments().raw());
- AddBaseObject(Bool::True().raw());
- AddBaseObject(Bool::False().raw());
+ AddBaseObject(Object::null(), "Null", "<null>");
+ AddBaseObject(Object::sentinel().raw(), "Sentinel");
+ AddBaseObject(Object::transition_sentinel().raw(), "Sentinel");
+ AddBaseObject(Object::empty_array().raw(), "Array", "<empty_array>");
+ AddBaseObject(Object::zero_array().raw(), "Array", "<zero_array>");
+ AddBaseObject(Object::dynamic_type().raw(), "Type", "<dynamic type>");
+ AddBaseObject(Object::void_type().raw(), "Type", "<void type>");
+ AddBaseObject(Object::empty_type_arguments().raw(), "TypeArguments", "[]");
+ AddBaseObject(Bool::True().raw(), "bool", "true");
+ AddBaseObject(Bool::False().raw(), "bool", "false");
ASSERT(Object::extractor_parameter_types().raw() != Object::null());
- AddBaseObject(Object::extractor_parameter_types().raw());
+ AddBaseObject(Object::extractor_parameter_types().raw(), "Array",
+ "<extractor parameter types>");
ASSERT(Object::extractor_parameter_names().raw() != Object::null());
- AddBaseObject(Object::extractor_parameter_names().raw());
- AddBaseObject(Object::empty_context_scope().raw());
- AddBaseObject(Object::empty_descriptors().raw());
- AddBaseObject(Object::empty_var_descriptors().raw());
- AddBaseObject(Object::empty_exception_handlers().raw());
+ AddBaseObject(Object::extractor_parameter_names().raw(), "Array",
+ "<extractor parameter names>");
+ AddBaseObject(Object::empty_context_scope().raw(), "ContextScope", "<empty>");
+ AddBaseObject(Object::empty_descriptors().raw(), "PcDescriptors", "<empty>");
+ AddBaseObject(Object::empty_var_descriptors().raw(), "LocalVarDescriptors",
+ "<empty>");
+ AddBaseObject(Object::empty_exception_handlers().raw(), "ExceptionHandlers",
+ "<empty>");
for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
- AddBaseObject(ArgumentsDescriptor::cached_args_descriptors_[i]);
+ AddBaseObject(ArgumentsDescriptor::cached_args_descriptors_[i],
+ "ArgumentsDescriptor", "<cached arguments descriptor>");
}
for (intptr_t i = 0; i < ICData::kCachedICDataArrayCount; i++) {
- AddBaseObject(ICData::cached_icdata_arrays_[i]);
+ AddBaseObject(ICData::cached_icdata_arrays_[i], "ICData",
+ "<cached icdata>");
}
ClassTable* table = isolate()->class_table();
@@ -4954,15 +4677,15 @@
// Error has no class object.
if (cid != kErrorCid) {
ASSERT(table->HasValidClassAt(cid));
- AddBaseObject(table->At(cid));
+ AddBaseObject(table->At(cid), "Class");
}
}
- AddBaseObject(table->At(kDynamicCid));
- AddBaseObject(table->At(kVoidCid));
+ AddBaseObject(table->At(kDynamicCid), "Class");
+ AddBaseObject(table->At(kVoidCid), "Class");
if (!Snapshot::IncludesCode(kind_)) {
for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
- AddBaseObject(StubCode::EntryAt(i)->code());
+ AddBaseObject(StubCode::EntryAt(i).raw(), "Code", "<stub code>");
}
}
}
@@ -4977,7 +4700,7 @@
Push(symbols.raw());
if (Snapshot::IncludesCode(kind_)) {
for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
- Push(StubCode::EntryAt(i)->code());
+ Push(StubCode::EntryAt(i).raw());
}
}
if (seeds != NULL) {
@@ -4989,10 +4712,10 @@
Serialize();
// Write roots.
- WriteRef(symbols.raw());
+ WriteRootRef(symbols.raw());
if (Snapshot::IncludesCode(kind_)) {
for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
- WriteRef(StubCode::EntryAt(i)->code());
+ WriteRootRef(StubCode::EntryAt(i).raw());
}
}
@@ -5035,7 +4758,7 @@
// Write roots.
for (RawObject** p = from; p <= to; p++) {
- WriteRef(*p);
+ WriteRootRef(*p);
}
#if defined(DEBUG)
@@ -5385,7 +5108,7 @@
if (!Snapshot::IncludesCode(kind_)) {
for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
- AddBaseObject(StubCode::EntryAt(i)->code());
+ AddBaseObject(StubCode::EntryAt(i).raw());
}
}
}
@@ -5407,10 +5130,10 @@
symbol_table ^= ReadRef();
isolate()->object_store()->set_symbol_table(symbol_table);
if (Snapshot::IncludesCode(kind_)) {
- Code& code = Code::Handle(zone_);
for (intptr_t i = 0; i < StubCode::NumEntries(); i++) {
- code ^= ReadRef();
- StubCode::EntryAtPut(i, new StubEntry(code));
+ Code* code = Code::ReadOnlyHandle();
+ *code ^= ReadRef();
+ StubCode::EntryAtPut(i, code);
}
}
@@ -5571,6 +5294,13 @@
KernelProgramInfo& kernel_program_info_;
};
+#if defined(DART_PRECOMPILER)
+DEFINE_FLAG(charp,
+ write_v8_snapshot_profile_to,
+ NULL,
+ "Write a snapshot profile in V8 format to a file.");
+#endif
+
FullSnapshotWriter::FullSnapshotWriter(Snapshot::Kind kind,
uint8_t** vm_snapshot_data_buffer,
uint8_t** isolate_snapshot_data_buffer,
@@ -5634,6 +5364,12 @@
saved_symbol_table_ = object_store->symbol_table();
new_vm_symbol_table_ = Dart::vm_isolate()->object_store()->symbol_table();
}
+
+#if defined(DART_PRECOMPILER)
+ if (FLAG_write_v8_snapshot_profile_to != nullptr) {
+ profile_writer_ = new (zone()) V8SnapshotProfileWriter(zone());
+ }
+#endif
}
FullSnapshotWriter::~FullSnapshotWriter() {
@@ -5651,7 +5387,8 @@
ASSERT(vm_snapshot_data_buffer_ != NULL);
Serializer serializer(thread(), kind_, vm_snapshot_data_buffer_, alloc_,
- kInitialSize, vm_image_writer_);
+ kInitialSize, vm_image_writer_, /*vm=*/true,
+ profile_writer_);
serializer.ReserveHeader();
serializer.WriteVersionAndFeatures(true);
@@ -5665,10 +5402,12 @@
clustered_vm_size_ = serializer.bytes_written();
if (Snapshot::IncludesCode(kind_)) {
+ vm_image_writer_->SetProfileWriter(profile_writer_);
vm_image_writer_->Write(serializer.stream(), true);
mapped_data_size_ += vm_image_writer_->data_size();
mapped_text_size_ += vm_image_writer_->text_size();
vm_image_writer_->ResetOffsets();
+ vm_image_writer_->ClearProfileWriter();
}
// The clustered part + the direct mapped data part.
@@ -5681,7 +5420,8 @@
thread(), Timeline::GetIsolateStream(), "WriteIsolateSnapshot"));
Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
- kInitialSize, isolate_image_writer_);
+ kInitialSize, isolate_image_writer_, /*vm=*/false,
+ profile_writer_);
ObjectStore* object_store = isolate()->object_store();
ASSERT(object_store != NULL);
@@ -5694,6 +5434,7 @@
clustered_isolate_size_ = serializer.bytes_written();
if (Snapshot::IncludesCode(kind_)) {
+ isolate_image_writer_->SetProfileWriter(profile_writer_);
isolate_image_writer_->Write(serializer.stream(), false);
#if defined(DART_PRECOMPILER)
isolate_image_writer_->DumpStatistics();
@@ -5702,6 +5443,7 @@
mapped_data_size_ += isolate_image_writer_->data_size();
mapped_text_size_ += isolate_image_writer_->text_size();
isolate_image_writer_->ResetOffsets();
+ isolate_image_writer_->ClearProfileWriter();
}
// The clustered part + the direct mapped data part.
@@ -5730,6 +5472,12 @@
clustered_vm_size_ + clustered_isolate_size_ + mapped_data_size_ +
mapped_text_size_);
}
+
+#if defined(DART_PRECOMPILER)
+ if (FLAG_write_v8_snapshot_profile_to != nullptr) {
+ profile_writer_->Write(FLAG_write_v8_snapshot_profile_to);
+ }
+#endif
}
FullSnapshotReader::FullSnapshotReader(const Snapshot* snapshot,
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 1f64d11..79bdd8d 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -16,6 +16,7 @@
#include "vm/object.h"
#include "vm/snapshot.h"
#include "vm/type_testing_stubs.h"
+#include "vm/v8_snapshot_writer.h"
#include "vm/version.h"
#if defined(DEBUG)
@@ -132,7 +133,9 @@
uint8_t** buffer,
ReAlloc alloc,
intptr_t initial_size,
- ImageWriter* image_writer_);
+ ImageWriter* image_writer_,
+ bool vm_,
+ V8SnapshotProfileWriter* profile_writer = nullptr);
~Serializer();
intptr_t WriteVMSnapshot(const Array& symbols,
@@ -142,12 +145,26 @@
void AddVMIsolateBaseObjects();
- void AddBaseObject(RawObject* base_object) {
- AssignRef(base_object);
+ void AddBaseObject(RawObject* base_object,
+ const char* type = nullptr,
+ const char* name = nullptr) {
+ intptr_t ref = AssignRef(base_object);
num_base_objects_++;
+
+ if (profile_writer_ != nullptr) {
+ if (type == nullptr) {
+ type = "Unknown";
+ }
+ if (name == nullptr) {
+ name = "<base object>";
+ }
+ profile_writer_->SetObjectTypeAndName(
+ {V8SnapshotProfileWriter::kSnapshot, ref}, type, name);
+ profile_writer_->AddRoot({V8SnapshotProfileWriter::kSnapshot, ref});
+ }
}
- void AssignRef(RawObject* object) {
+ intptr_t AssignRef(RawObject* object) {
ASSERT(next_ref_index_ != 0);
if (object->IsHeapObject()) {
// The object id weak table holds image offsets for Instructions instead
@@ -168,7 +185,7 @@
smi_ids_.Insert(new_pair);
}
}
- next_ref_index_++;
+ return next_ref_index_++;
}
void Push(RawObject* object);
@@ -202,6 +219,11 @@
WriteStream* stream() { return &stream_; }
intptr_t bytes_written() { return stream_.bytes_written(); }
+ void TraceStartWritingObject(const char* type,
+ RawObject* obj,
+ RawString* name);
+ void TraceEndWritingObject();
+
// Writes raw data to the stream (basic type).
// sizeof(T) must be in {1,2,4,8}.
template <typename T>
@@ -214,41 +236,74 @@
}
void Align(intptr_t alignment) { stream_.Align(alignment); }
- void WriteRef(RawObject* object) {
+ void WriteRef(RawObject* object, bool is_root = false) {
+ intptr_t id = 0;
if (!object->IsHeapObject()) {
RawSmi* smi = Smi::RawCast(object);
- intptr_t id = smi_ids_.Lookup(smi)->id_;
+ id = smi_ids_.Lookup(smi)->id_;
if (id == 0) {
FATAL("Missing ref");
}
- WriteUnsigned(id);
- return;
+ } else {
+ // The object id weak table holds image offsets for Instructions instead
+ // of ref indices.
+ ASSERT(!object->IsInstructions());
+ id = heap_->GetObjectId(object);
+ if (id == 0) {
+ if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
+ WriteRef(Object::null());
+ return;
+ }
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
+ WriteRef(Object::null());
+ return;
+ }
+#endif // !DART_PRECOMPILED_RUNTIME
+ if (object->IsSendPort()) {
+ // TODO(rmacnak): Do a better job of resetting fields in
+ // precompilation and assert this is unreachable.
+ WriteRef(Object::null());
+ return;
+ }
+ FATAL("Missing ref");
+ }
}
- // The object id weak table holds image offsets for Instructions instead
- // of ref indices.
- ASSERT(!object->IsInstructions());
- intptr_t id = heap_->GetObjectId(object);
- if (id == 0) {
- if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
- WriteRef(Object::null());
- return;
- }
-#if !defined(DART_PRECOMPILED_RUNTIME)
- if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
- WriteRef(Object::null());
- return;
- }
-#endif // !DART_PRECOMPILED_RUNTIME
- if (object->IsSendPort()) {
- // TODO(rmacnak): Do a better job of resetting fields in precompilation
- // and assert this is unreachable.
- WriteRef(Object::null());
- return;
- }
- FATAL("Missing ref");
- }
WriteUnsigned(id);
+
+ if (profile_writer_ != nullptr) {
+ if (object_currently_writing_id_ != 0) {
+ profile_writer_->AttributeReferenceTo(
+ {V8SnapshotProfileWriter::kSnapshot, object_currently_writing_id_},
+ {V8SnapshotProfileWriter::kSnapshot, id});
+ } else {
+ ASSERT(is_root);
+ profile_writer_->AddRoot({V8SnapshotProfileWriter::kSnapshot, id});
+ }
+ }
+ }
+
+ template <typename T, typename... P>
+ void WriteFromTo(T* obj, P&&... args) {
+ RawObject** from = obj->from();
+ RawObject** to = obj->to_snapshot(kind(), args...);
+ for (RawObject** p = from; p <= to; p++) {
+ WriteRef(*p);
+ }
+ }
+
+ template <typename T, typename... P>
+ void PushFromTo(T* obj, P&&... args) {
+ RawObject** from = obj->from();
+ RawObject** to = obj->to_snapshot(kind(), args...);
+ for (RawObject** p = from; p <= to; p++) {
+ Push(*p);
+ }
+ }
+
+ void WriteRootRef(RawObject* object) {
+ WriteRef(object, /* is_root = */ true);
}
void WriteTokenPosition(TokenPosition pos) {
@@ -263,6 +318,7 @@
void WriteInstructions(RawInstructions* instr, RawCode* code);
bool GetSharedDataOffset(RawObject* object, uint32_t* offset) const;
uint32_t GetDataOffset(RawObject* object) const;
+ void TraceDataOffset(uint32_t offset);
intptr_t GetDataSize() const;
intptr_t GetTextSize() const;
@@ -286,6 +342,13 @@
intptr_t next_ref_index_;
SmiObjectIdMap smi_ids_;
+ // True if writing VM snapshot, false for Isolate snapshot.
+ bool vm_;
+
+ V8SnapshotProfileWriter* profile_writer_ = nullptr;
+ intptr_t object_currently_writing_id_ = 0;
+ intptr_t object_currently_writing_start_ = 0;
+
#if defined(SNAPSHOT_BACKTRACE)
RawObject* current_parent_;
GrowableArray<Object*> parent_pairs_;
@@ -294,6 +357,35 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Serializer);
};
+#define AutoTraceObject(obj) \
+ SerializerWritingObjectScope scope_##__COUNTER__(s, name(), obj, nullptr)
+
+#define AutoTraceObjectName(obj, str) \
+ SerializerWritingObjectScope scope_##__COUNTER__(s, name(), obj, str)
+
+#define WriteField(obj, field) s->WriteRef(obj->ptr()->field);
+
+#define WriteFieldValue(field, value) s->WriteRef(value);
+
+#define WriteFromTo(obj, ...) s->WriteFromTo(obj, ##__VA_ARGS__);
+
+#define PushFromTo(obj, ...) s->PushFromTo(obj, ##__VA_ARGS__);
+
+struct SerializerWritingObjectScope {
+ SerializerWritingObjectScope(Serializer* serializer,
+ const char* type,
+ RawObject* object,
+ RawString* name)
+ : serializer_(serializer) {
+ serializer_->TraceStartWritingObject(type, object, name);
+ }
+
+ ~SerializerWritingObjectScope() { serializer_->TraceEndWritingObject(); }
+
+ private:
+ Serializer* serializer_;
+};
+
class Deserializer : public StackResource {
public:
Deserializer(Thread* thread,
@@ -351,6 +443,20 @@
RawObject* ReadRef() { return Ref(ReadUnsigned()); }
+ template <typename T, typename... P>
+ void ReadFromTo(T* obj, P&&... params) {
+ RawObject** from = obj->from();
+ RawObject** to_snapshot = obj->to_snapshot(kind(), params...);
+ RawObject** to = obj->to(params...);
+ for (RawObject** p = from; p <= to_snapshot; p++) {
+ *p = ReadRef();
+ }
+ // TODO(sjindel/rmacnak): Is this really necessary?
+ for (RawObject** p = to_snapshot + 1; p <= to; p++) {
+ *p = Object::null();
+ }
+ }
+
TokenPosition ReadTokenPosition() {
return TokenPosition::SnapshotDecode(Read<int32_t>());
}
@@ -391,6 +497,8 @@
DeserializationCluster** clusters_;
};
+#define ReadFromTo(obj, ...) d->ReadFromTo(obj, ##__VA_ARGS__);
+
class FullSnapshotWriter {
public:
static const intptr_t kInitialSize = 64 * KB;
@@ -446,6 +554,8 @@
intptr_t mapped_data_size_;
intptr_t mapped_text_size_;
+ V8SnapshotProfileWriter* profile_writer_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(FullSnapshotWriter);
};
diff --git a/runtime/vm/code_patcher_arm64_test.cc b/runtime/vm/code_patcher_arm64_test.cc
index 113a7b8..c2437cf 100644
--- a/runtime/vm/code_patcher_arm64_test.cc
+++ b/runtime/vm/code_patcher_arm64_test.cc
@@ -44,7 +44,7 @@
__ set_constant_pool_allowed(true);
__ LoadObject(R5, ic_data);
- __ BranchLinkPatchable(*StubCode::OneArgCheckInlineCache_entry());
+ __ BranchLinkPatchable(StubCode::OneArgCheckInlineCache());
__ ret();
}
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index 3e3ca0b..9463dae 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -44,7 +44,7 @@
__ set_constant_pool_allowed(true);
__ LoadObject(R9, ic_data);
- __ BranchLinkPatchable(*StubCode::OneArgCheckInlineCache_entry());
+ __ BranchLinkPatchable(StubCode::OneArgCheckInlineCache());
__ Ret();
}
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index a843893..19e4563 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -41,7 +41,7 @@
function, target_name, args_descriptor, 15, 1, ICData::kInstance));
__ LoadObject(ECX, ic_data);
- __ Call(*StubCode::OneArgCheckInlineCache_entry());
+ __ Call(StubCode::OneArgCheckInlineCache());
__ ret();
}
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index 90bd5f5..d6ac021 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -44,7 +44,7 @@
__ set_constant_pool_allowed(true);
__ LoadObject(RBX, ic_data);
- __ CallPatchable(*StubCode::OneArgCheckInlineCache_entry());
+ __ CallPatchable(StubCode::OneArgCheckInlineCache());
__ ret();
}
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 216bdb5..d355960 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -9,6 +9,7 @@
#include "vm/compiler/aot/aot_call_specializer.h"
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/assembler/disassembler.h"
+#include "vm/compiler/backend/block_scheduler.h"
#include "vm/compiler/backend/branch_optimizer.h"
#include "vm/compiler/backend/constant_propagator.h"
#include "vm/compiler/backend/flow_graph.h"
@@ -824,94 +825,6 @@
return parsed_function->function().raw();
}
-RawObject* Precompiler::EvaluateStaticInitializer(const Field& field) {
- ASSERT(field.is_static());
- // The VM sets the field's value to transiton_sentinel prior to
- // evaluating the initializer value.
- ASSERT(field.StaticValue() == Object::transition_sentinel().raw());
- LongJumpScope jump;
- if (setjmp(*jump.Set()) == 0) {
- // Under precompilation, the initializer may have already been compiled, in
- // which case use it. Under lazy compilation or early in precompilation, the
- // initializer has not yet been created, so create it now, but don't bother
- // remembering it because it won't be used again.
- Function& initializer = Function::Handle();
- if (!field.HasPrecompiledInitializer()) {
- initializer = CompileStaticInitializer(field);
- } else {
- initializer ^= field.PrecompiledInitializer();
- }
- // Invoke the function to evaluate the expression.
- return DartEntry::InvokeFunction(initializer, Object::empty_array());
- } else {
- Thread* const thread = Thread::Current();
- StackZone zone(thread);
- const Error& error = Error::Handle(thread->zone(), thread->sticky_error());
- thread->clear_sticky_error();
- return error.raw();
- }
- UNREACHABLE();
- return Object::null();
-}
-
-RawObject* Precompiler::ExecuteOnce(SequenceNode* fragment) {
- LongJumpScope jump;
- if (setjmp(*jump.Set()) == 0) {
- Thread* const thread = Thread::Current();
-
- // Create a dummy function object for the code generator.
- // The function needs to be associated with a named Class: the interface
- // Function fits the bill.
- const char* kEvalConst = "eval_const";
- const Function& func = Function::ZoneHandle(Function::New(
- String::Handle(Symbols::New(thread, kEvalConst)),
- RawFunction::kRegularFunction,
- true, // static function
- false, // not const function
- false, // not abstract
- false, // not external
- false, // not native
- Class::Handle(Type::Handle(Type::DartFunctionType()).type_class()),
- fragment->token_pos()));
-
- func.set_result_type(Object::dynamic_type());
- func.set_num_fixed_parameters(0);
- func.SetNumOptionalParameters(0, true);
- // Manually generated AST, do not recompile.
- func.SetIsOptimizable(false);
- func.set_is_debuggable(false);
-
- // We compile the function here, even though InvokeFunction() below
- // would compile func automatically. We are checking fewer invariants
- // here.
- ParsedFunction* parsed_function = new ParsedFunction(thread, func);
- parsed_function->SetNodeSequence(fragment);
- fragment->scope()->AddVariable(parsed_function->EnsureExpressionTemp());
- fragment->scope()->AddVariable(parsed_function->current_context_var());
- parsed_function->AllocateVariables();
-
- // Non-optimized code generator.
- DartCompilationPipeline pipeline;
- PrecompileParsedFunctionHelper helper(/* precompiler = */ NULL,
- parsed_function,
- /* optimized = */ false);
- helper.Compile(&pipeline);
- NOT_IN_PRODUCT(Code::Handle(func.unoptimized_code())
- .set_var_descriptors(Object::empty_var_descriptors()));
-
- const Object& result = PassiveObject::Handle(
- DartEntry::InvokeFunction(func, Object::empty_array()));
- return result.raw();
- } else {
- Thread* const thread = Thread::Current();
- const Object& result = PassiveObject::Handle(thread->sticky_error());
- thread->clear_sticky_error();
- return result.raw();
- }
- UNREACHABLE();
- return Object::null();
-}
-
void Precompiler::AddFunction(const Function& function) {
if (enqueued_functions_.HasKey(&function)) return;
@@ -1019,20 +932,22 @@
while (it.HasNext()) {
cls = it.GetNextClass();
+ // Check for @pragma on the class itself.
if (cls.has_pragma()) {
- // Check for @pragma on the class itself.
metadata ^= lib.GetMetadata(cls);
if (metadata_defines_entrypoint() == EntryPointPragma::kAlways) {
AddInstantiatedClass(cls);
}
+ }
- // Check for @pragma on any fields in the class.
- members = cls.fields();
- implicit_getters = GrowableObjectArray::New(members.Length());
- implicit_setters = GrowableObjectArray::New(members.Length());
- implicit_static_getters = GrowableObjectArray::New(members.Length());
- for (intptr_t k = 0; k < members.Length(); ++k) {
- field ^= members.At(k);
+ // Check for @pragma on any fields in the class.
+ members = cls.fields();
+ implicit_getters = GrowableObjectArray::New(members.Length());
+ implicit_setters = GrowableObjectArray::New(members.Length());
+ implicit_static_getters = GrowableObjectArray::New(members.Length());
+ for (intptr_t k = 0; k < members.Length(); ++k) {
+ field ^= members.At(k);
+ if (field.has_pragma()) {
metadata ^= lib.GetMetadata(field);
if (metadata.IsNull()) continue;
EntryPointPragma pragma = metadata_defines_entrypoint();
@@ -1537,7 +1452,7 @@
}
ASSERT(Object::dynamic_type().type_test_stub_entry_point() !=
- StubCode::DefaultTypeTest_entry()->EntryPoint());
+ StubCode::DefaultTypeTest().EntryPoint());
}
void Precompiler::DropTypes() {
@@ -2028,9 +1943,8 @@
unlinked_.set_args_descriptor(args_descriptor_);
unlinked_ = DedupUnlinkedCall(unlinked_);
pool.SetObjectAt(i, unlinked_);
- } else if (entry_.raw() ==
- StubCode::ICCallThroughFunction_entry()->code()) {
- target_code_ = StubCode::UnlinkedCall_entry()->code();
+ } else if (entry_.raw() == StubCode::ICCallThroughFunction().raw()) {
+ target_code_ = StubCode::UnlinkedCall().raw();
pool.SetObjectAt(i, target_code_);
}
}
@@ -2314,8 +2228,12 @@
FlowGraphPrinter::PrintGraph("Unoptimized Compilation", flow_graph);
}
+ BlockScheduler block_scheduler(flow_graph);
CompilerPassState pass_state(thread(), flow_graph, &speculative_policy,
precompiler_);
+ pass_state.block_scheduler = &block_scheduler;
+ pass_state.reorder_blocks =
+ FlowGraph::ShouldReorderBlocks(function, optimized());
NOT_IN_PRODUCT(pass_state.compiler_timeline = compiler_timeline);
if (optimized()) {
@@ -2604,7 +2522,7 @@
// TODO(dartbug.com/30524) instead call to Obfuscator::Rename from a place
// where these are looked up.
#define PREVENT_RENAMING(class_name, function_name, recognized_enum, \
- result_type, fingerprint) \
+ fingerprint) \
do { \
PreventRenaming(#class_name); \
PreventRenaming(#function_name); \
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index 47ac594..7c4dacac 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -239,9 +239,6 @@
Zone* zone,
const Function& function);
- static RawObject* EvaluateStaticInitializer(const Field& field);
- static RawObject* ExecuteOnce(SequenceNode* fragment);
-
static RawFunction* CompileStaticInitializer(const Field& field);
// Returns true if get:runtimeType is not overloaded by any class.
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index 320d6e3..2ca5b32 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -2522,13 +2522,12 @@
vmulqs(qd, qn, qd);
}
-void Assembler::Branch(const StubEntry& stub_entry,
+void Assembler::Branch(const Code& target,
ObjectPool::Patchability patchable,
Register pp,
Condition cond) {
- const Code& target_code = Code::ZoneHandle(stub_entry.code());
const int32_t offset = ObjectPool::element_offset(
- object_pool_wrapper().FindObject(target_code, patchable));
+ object_pool_wrapper().FindObject(target, patchable));
LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, pp, cond);
Branch(FieldAddress(CODE_REG, Code::entry_point_offset()), cond);
}
@@ -2551,12 +2550,6 @@
blx(LR); // Use blx instruction so that the return branch prediction works.
}
-void Assembler::BranchLink(const StubEntry& stub_entry,
- ObjectPool::Patchability patchable) {
- const Code& code = Code::ZoneHandle(stub_entry.code());
- BranchLink(code, patchable);
-}
-
void Assembler::BranchLinkPatchable(const Code& target,
Code::EntryKind entry_kind) {
BranchLink(target, ObjectPool::kPatchable, entry_kind);
@@ -2576,10 +2569,9 @@
blx(LR);
}
-void Assembler::BranchLinkWithEquivalence(const StubEntry& stub_entry,
+void Assembler::BranchLinkWithEquivalence(const Code& target,
const Object& equivalence,
Code::EntryKind entry_kind) {
- const Code& target = Code::ZoneHandle(stub_entry.code());
// Make sure that class CallPattern is able to patch the label referred
// to by this code sequence.
// For added code robustness, use 'blx lr' in a patchable sequence and
@@ -2596,11 +2588,6 @@
blx(LR); // Use blx instruction so that the return branch prediction works.
}
-void Assembler::BranchLinkPatchable(const StubEntry& stub_entry,
- Code::EntryKind entry_kind) {
- BranchLinkPatchable(Code::ZoneHandle(stub_entry.code()), entry_kind);
-}
-
void Assembler::BranchLinkOffset(Register base, int32_t offset) {
ASSERT(base != PC);
ASSERT(base != IP);
@@ -3418,7 +3405,8 @@
PushList((1 << R0) | (1 << IP) | (1 << LR)); // Preserve R0, IP, LR.
LoadImmediate(R0, reinterpret_cast<int32_t>(message));
// PrintStopMessage() preserves all registers.
- BranchLink(&StubCode::PrintStopMessage_entry()->label());
+ ExternalLabel label(StubCode::PrintStopMessage().EntryPoint());
+ BranchLink(&label);
PopList((1 << R0) | (1 << IP) | (1 << LR)); // Restore R0, IP, LR.
}
bkpt(Instr::kStopMessageCode);
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index 801f1c3..b4c35c9 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -21,7 +21,6 @@
// Forward declarations.
class RuntimeEntry;
-class StubEntry;
class RegisterSet;
// Instruction encoding bits.
@@ -656,7 +655,7 @@
void bx(Register rm, Condition cond = AL);
void blx(Register rm, Condition cond = AL);
- void Branch(const StubEntry& stub_entry,
+ void Branch(const Code& code,
ObjectPool::Patchability patchable = ObjectPool::kNotPatchable,
Register pp = PP,
Condition cond = AL);
@@ -664,28 +663,22 @@
void Branch(const Address& address, Condition cond = AL);
void BranchLink(
- const StubEntry& stub_entry,
- ObjectPool::Patchability patchable = ObjectPool::kNotPatchable);
- void BranchLink(const Code& code,
- ObjectPool::Patchability patchable,
- Code::EntryKind entry_kind = Code::EntryKind::kNormal);
+ const Code& code,
+ ObjectPool::Patchability patchable = ObjectPool::kNotPatchable,
+ Code::EntryKind entry_kind = Code::EntryKind::kNormal);
void BranchLinkToRuntime();
void CallNullErrorShared(bool save_fpu_registers);
// Branch and link to an entry address. Call sequence can be patched.
void BranchLinkPatchable(
- const StubEntry& stub_entry,
- Code::EntryKind entry_kind = Code::EntryKind::kNormal);
-
- void BranchLinkPatchable(
const Code& code,
Code::EntryKind entry_kind = Code::EntryKind::kNormal);
// Emit a call that shares its object pool entries with other calls
// that have the same equivalence marker.
void BranchLinkWithEquivalence(
- const StubEntry& stub_entry,
+ const Code& code,
const Object& equivalence,
Code::EntryKind entry_kind = Code::EntryKind::kNormal);
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 5780bbd..b76aad5 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -626,10 +626,9 @@
}
}
-void Assembler::Branch(const StubEntry& stub_entry,
+void Assembler::Branch(const Code& target,
Register pp,
ObjectPool::Patchability patchable) {
- const Code& target = Code::ZoneHandle(stub_entry.code());
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper().FindObject(target, patchable));
LoadWordFromPoolOffset(CODE_REG, offset, pp);
@@ -637,13 +636,12 @@
br(TMP);
}
-void Assembler::BranchPatchable(const StubEntry& stub_entry) {
- Branch(stub_entry, PP, ObjectPool::kPatchable);
+void Assembler::BranchPatchable(const Code& code) {
+ Branch(code, PP, ObjectPool::kPatchable);
}
-void Assembler::BranchLink(const StubEntry& stub_entry,
+void Assembler::BranchLink(const Code& target,
ObjectPool::Patchability patchable) {
- const Code& target = Code::ZoneHandle(stub_entry.code());
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper().FindObject(target, patchable));
LoadWordFromPoolOffset(CODE_REG, offset);
@@ -651,18 +649,13 @@
blr(TMP);
}
-void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) {
- BranchLink(stub_entry, ObjectPool::kPatchable);
-}
-
void Assembler::BranchLinkToRuntime() {
ldr(LR, Address(THR, Thread::call_to_runtime_entry_point_offset()));
blr(LR);
}
-void Assembler::BranchLinkWithEquivalence(const StubEntry& stub_entry,
+void Assembler::BranchLinkWithEquivalence(const Code& target,
const Object& equivalence) {
- const Code& target = Code::ZoneHandle(stub_entry.code());
const int32_t offset = ObjectPool::element_offset(
object_pool_wrapper().FindObject(target, equivalence));
LoadWordFromPoolOffset(CODE_REG, offset);
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 761ec23..4d3d69a 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -21,7 +21,6 @@
// Forward declarations.
class RuntimeEntry;
-class StubEntry;
class RegisterSet;
class Immediate : public ValueObject {
@@ -1350,24 +1349,25 @@
void BranchIfSmi(Register reg, Label* label) { tbz(label, reg, kSmiTag); }
- void Branch(const StubEntry& stub_entry,
+ void Branch(const Code& code,
Register pp,
ObjectPool::Patchability patchable = ObjectPool::kNotPatchable);
- void BranchPatchable(const StubEntry& stub_entry);
+ void BranchPatchable(const Code& code);
void BranchLink(
- const StubEntry& stub_entry,
+ const Code& code,
ObjectPool::Patchability patchable = ObjectPool::kNotPatchable);
- void BranchLinkPatchable(const StubEntry& stub_entry);
+ void BranchLinkPatchable(const Code& code) {
+ BranchLink(code, ObjectPool::kPatchable);
+ }
void BranchLinkToRuntime();
void CallNullErrorShared(bool save_fpu_registers);
// Emit a call that shares its object pool entries with other calls
// that have the same equivalence marker.
- void BranchLinkWithEquivalence(const StubEntry& stub_entry,
- const Object& equivalence);
+ void BranchLinkWithEquivalence(const Code& code, const Object& equivalence);
void AddImmediate(Register dest, int64_t imm) {
AddImmediate(dest, dest, imm);
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index a936849..97823b4 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2132,8 +2132,7 @@
entry.Call(this, argument_count);
}
-void Assembler::Call(const StubEntry& stub_entry, bool movable_target) {
- const Code& target = Code::ZoneHandle(stub_entry.code());
+void Assembler::Call(const Code& target, bool movable_target) {
LoadObject(CODE_REG, target, movable_target);
call(FieldAddress(CODE_REG, Code::entry_point_offset()));
}
@@ -2142,13 +2141,13 @@
call(Address(THR, Thread::call_to_runtime_entry_point_offset()));
}
-void Assembler::Jmp(const StubEntry& stub_entry) {
- const ExternalLabel label(stub_entry.EntryPoint());
+void Assembler::Jmp(const Code& target) {
+ const ExternalLabel label(target.EntryPoint());
jmp(&label);
}
-void Assembler::J(Condition condition, const StubEntry& stub_entry) {
- const ExternalLabel label(stub_entry.EntryPoint());
+void Assembler::J(Condition condition, const Code& target) {
+ const ExternalLabel label(target.EntryPoint());
j(condition, &label);
}
@@ -2368,8 +2367,8 @@
if (FLAG_print_stop_message) {
pushl(EAX); // Preserve EAX.
movl(EAX, Immediate(reinterpret_cast<int32_t>(message)));
- Call(*StubCode::PrintStopMessage_entry()); // Passing message in EAX.
- popl(EAX); // Restore EAX.
+ Call(StubCode::PrintStopMessage()); // Passing message in EAX.
+ popl(EAX); // Restore EAX.
}
// Emit the int3 instruction.
int3(); // Execution can be resumed with the 'cont' command in gdb.
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h
index 4c4854c..9fcc3eb 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.h
+++ b/runtime/vm/compiler/assembler/assembler_ia32.h
@@ -18,7 +18,6 @@
// Forward declarations.
class RuntimeEntry;
-class StubEntry;
class Immediate : public ValueObject {
public:
@@ -650,13 +649,13 @@
void CallRuntime(const RuntimeEntry& entry, intptr_t argument_count);
- void Call(const StubEntry& stub_entry, bool movable_target = false);
+ void Call(const Code& code, bool movable_target = false);
void CallToRuntime();
void CallNullErrorShared(bool save_fpu_registers) { UNREACHABLE(); }
- void Jmp(const StubEntry& stub_entry);
- void J(Condition condition, const StubEntry& stub_entry);
+ void Jmp(const Code& code);
+ void J(Condition condition, const Code& code);
/*
* Loading and comparing classes of objects.
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 26a220a..cd3206c 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -58,10 +58,8 @@
call(TMP);
}
-void Assembler::CallPatchable(const StubEntry& stub_entry,
- Code::EntryKind entry_kind) {
+void Assembler::CallPatchable(const Code& target, Code::EntryKind entry_kind) {
ASSERT(constant_pool_allowed());
- const Code& target = Code::ZoneHandle(stub_entry.code());
const intptr_t idx =
object_pool_wrapper().AddObject(target, ObjectPool::kPatchable);
const int32_t offset = ObjectPool::element_offset(idx);
@@ -69,20 +67,18 @@
call(FieldAddress(CODE_REG, Code::entry_point_offset(entry_kind)));
}
-void Assembler::CallWithEquivalence(const StubEntry& stub_entry,
+void Assembler::CallWithEquivalence(const Code& target,
const Object& equivalence,
Code::EntryKind entry_kind) {
ASSERT(constant_pool_allowed());
- const Code& target = Code::ZoneHandle(stub_entry.code());
const intptr_t idx = object_pool_wrapper().FindObject(target, equivalence);
const int32_t offset = ObjectPool::element_offset(idx);
LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag);
call(FieldAddress(CODE_REG, Code::entry_point_offset(entry_kind)));
}
-void Assembler::Call(const StubEntry& stub_entry) {
+void Assembler::Call(const Code& target) {
ASSERT(constant_pool_allowed());
- const Code& target = Code::ZoneHandle(stub_entry.code());
const intptr_t idx =
object_pool_wrapper().FindObject(target, ObjectPool::kNotPatchable);
const int32_t offset = ObjectPool::element_offset(idx);
@@ -878,13 +874,11 @@
}
}
-void Assembler::J(Condition condition,
- const StubEntry& stub_entry,
- Register pp) {
+void Assembler::J(Condition condition, const Code& target, Register pp) {
Label no_jump;
// Negate condition.
j(static_cast<Condition>(condition ^ 1), &no_jump, kNearJump);
- Jmp(stub_entry, pp);
+ Jmp(target, pp);
Bind(&no_jump);
}
@@ -921,9 +915,8 @@
jmp(TMP);
}
-void Assembler::JmpPatchable(const StubEntry& stub_entry, Register pp) {
+void Assembler::JmpPatchable(const Code& target, Register pp) {
ASSERT((pp != PP) || constant_pool_allowed());
- const Code& target = Code::ZoneHandle(stub_entry.code());
const intptr_t idx =
object_pool_wrapper().AddObject(target, ObjectPool::kPatchable);
const int32_t offset = ObjectPool::element_offset(idx);
@@ -932,9 +925,8 @@
jmp(TMP);
}
-void Assembler::Jmp(const StubEntry& stub_entry, Register pp) {
+void Assembler::Jmp(const Code& target, Register pp) {
ASSERT((pp != PP) || constant_pool_allowed());
- const Code& target = Code::ZoneHandle(stub_entry.code());
const intptr_t idx =
object_pool_wrapper().FindObject(target, ObjectPool::kNotPatchable);
const int32_t offset = ObjectPool::element_offset(idx);
@@ -1401,7 +1393,8 @@
pushq(TMP); // Preserve TMP register.
pushq(RDI); // Preserve RDI register.
LoadImmediate(RDI, Immediate(message_address));
- call(&StubCode::PrintStopMessage_entry()->label());
+ ExternalLabel label(StubCode::PrintStopMessage().EntryPoint());
+ call(&label);
popq(RDI); // Restore RDI register.
popq(TMP); // Restore TMP register.
}
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index 0d6e3cf..dc61bb9 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -20,7 +20,6 @@
// Forward declarations.
class RuntimeEntry;
-class StubEntry;
class Immediate : public ValueObject {
public:
@@ -628,7 +627,7 @@
void jmp(const Address& address) { EmitUnaryL(address, 0xFF, 4); }
void jmp(Label* label, bool near = kFarJump);
void jmp(const ExternalLabel* label);
- void jmp(const StubEntry& stub_entry);
+ void jmp(const Code& code);
// Issue memory to memory move through a TMP register.
// TODO(koda): Assert that these are not used for heap objects.
@@ -689,12 +688,12 @@
void LoadFunctionFromCalleePool(Register dst,
const Function& function,
Register new_pp);
- void JmpPatchable(const StubEntry& stub_entry, Register pp);
- void Jmp(const StubEntry& stub_entry, Register pp = PP);
- void J(Condition condition, const StubEntry& stub_entry, Register pp);
- void CallPatchable(const StubEntry& stub_entry,
+ void JmpPatchable(const Code& code, Register pp);
+ void Jmp(const Code& code, Register pp = PP);
+ void J(Condition condition, const Code& code, Register pp);
+ void CallPatchable(const Code& code,
Code::EntryKind entry_kind = Code::EntryKind::kNormal);
- void Call(const StubEntry& stub_entry);
+ void Call(const Code& stub_entry);
void CallToRuntime();
void CallNullErrorShared(bool save_fpu_registers);
@@ -702,7 +701,7 @@
// Emit a call that shares its object pool entries with other calls
// that have the same equivalence marker.
void CallWithEquivalence(
- const StubEntry& stub_entry,
+ const Code& code,
const Object& equivalence,
Code::EntryKind entry_kind = Code::EntryKind::kNormal);
diff --git a/runtime/vm/compiler/backend/block_scheduler.cc b/runtime/vm/compiler/backend/block_scheduler.cc
index 24dc895..451c824 100644
--- a/runtime/vm/compiler/backend/block_scheduler.cc
+++ b/runtime/vm/compiler/backend/block_scheduler.cc
@@ -55,6 +55,9 @@
if (!FLAG_reorder_basic_blocks) {
return;
}
+ if (FLAG_precompiled_mode) {
+ return;
+ }
const Array& ic_data_array =
Array::Handle(flow_graph()->zone(),
@@ -155,6 +158,18 @@
}
void BlockScheduler::ReorderBlocks() const {
+ if (FLAG_precompiled_mode) {
+ ReorderBlocksAOT();
+ } else {
+ ReorderBlocksJIT();
+ }
+}
+
+void BlockScheduler::ReorderBlocksJIT() const {
+ if (!FLAG_reorder_basic_blocks) {
+ return;
+ }
+
// Add every block to a chain of length 1 and compute a list of edges
// sorted by weight.
intptr_t block_count = flow_graph()->preorder().length();
@@ -215,6 +230,68 @@
}
}
+// Moves blocks ending in a throw/rethrow, as well as any block post-dominated
+// by such a throwing block, to the end.
+void BlockScheduler::ReorderBlocksAOT() const {
+ if (!FLAG_reorder_basic_blocks) {
+ return;
+ }
+
+ auto& reverse_postorder = flow_graph()->reverse_postorder();
+ const intptr_t block_count = reverse_postorder.length();
+ GrowableArray<bool> is_terminating(block_count);
+ is_terminating.FillWith(false, 0, block_count);
+
+ // Any block in the worklist is marked and any of its unconditional
+ // predecessors need to be marked as well.
+ GrowableArray<BlockEntryInstr*> worklist;
+
+ // Add all throwing blocks to the worklist.
+ for (intptr_t i = 0; i < block_count; ++i) {
+ auto block = reverse_postorder[i];
+ auto last = block->last_instruction();
+ if (last->IsThrow() || last->IsReThrow()) {
+ const intptr_t preorder_nr = block->preorder_number();
+ is_terminating[preorder_nr] = true;
+ worklist.Add(block);
+ }
+ }
+
+ // Follow all indirect predecessors which unconditionally will end up in a
+ // throwing block.
+ while (worklist.length() > 0) {
+ auto block = worklist.RemoveLast();
+ for (intptr_t i = 0; i < block->PredecessorCount(); ++i) {
+ auto predecessor = block->PredecessorAt(i);
+ if (predecessor->last_instruction()->IsGoto()) {
+ const intptr_t preorder_nr = predecessor->preorder_number();
+ if (!is_terminating[preorder_nr]) {
+ is_terminating[preorder_nr] = true;
+ worklist.Add(predecessor);
+ }
+ }
+ }
+ }
+
+ // Emit code in reverse postorder but move any throwing blocks to the very
+ // end.
+ auto& codegen_order = *flow_graph()->CodegenBlockOrder(true);
+ for (intptr_t i = 0; i < block_count; ++i) {
+ auto block = reverse_postorder[i];
+ const intptr_t preorder_nr = block->preorder_number();
+ if (!is_terminating[preorder_nr]) {
+ codegen_order.Add(block);
+ }
+ }
+ for (intptr_t i = 0; i < block_count; ++i) {
+ auto block = reverse_postorder[i];
+ const intptr_t preorder_nr = block->preorder_number();
+ if (is_terminating[preorder_nr]) {
+ codegen_order.Add(block);
+ }
+ }
+}
+
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/backend/block_scheduler.h b/runtime/vm/compiler/backend/block_scheduler.h
index f1f1217..90308bc 100644
--- a/runtime/vm/compiler/backend/block_scheduler.h
+++ b/runtime/vm/compiler/backend/block_scheduler.h
@@ -18,10 +18,12 @@
FlowGraph* flow_graph() const { return flow_graph_; }
void AssignEdgeWeights() const;
-
void ReorderBlocks() const;
private:
+ void ReorderBlocksAOT() const;
+ void ReorderBlocksJIT() const;
+
FlowGraph* const flow_graph_;
};
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 01b1cc8..a156279 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -270,11 +270,11 @@
bool FlowGraphCompiler::IsEmptyBlock(BlockEntryInstr* block) const {
// Entry-points cannot be merged because they must have assembly
// prologue emitted which should not be included in any block they jump to.
- return !block->IsCatchBlockEntry() && !block->HasNonRedundantParallelMove() &&
+ return !block->IsGraphEntry() && !block->IsFunctionEntry() &&
+ !block->IsCatchBlockEntry() && !block->IsOsrEntry() &&
+ !block->IsIndirectEntry() && !block->HasNonRedundantParallelMove() &&
block->next()->IsGoto() &&
- !block->next()->AsGoto()->HasNonRedundantParallelMove() &&
- !block->IsIndirectEntry() && !block->IsFunctionEntry() &&
- !block->IsOsrEntry();
+ !block->next()->AsGoto()->HasNonRedundantParallelMove();
}
void FlowGraphCompiler::CompactBlock(BlockEntryInstr* block) {
@@ -706,7 +706,7 @@
}
void FlowGraphCompiler::AddPcRelativeCallStubTarget(const Code& stub_code) {
- ASSERT(stub_code.IsZoneHandle());
+ ASSERT(stub_code.IsZoneHandle() || stub_code.IsReadOnlyHandle());
ASSERT(!stub_code.IsNull());
static_calls_target_table_.Add(new (zone()) StaticCallsStruct(
Code::kPcRelativeCall, assembler()->CodeSize(), NULL, &stub_code));
@@ -719,7 +719,7 @@
}
void FlowGraphCompiler::AddStubCallTarget(const Code& code) {
- ASSERT(code.IsZoneHandle());
+ ASSERT(code.IsZoneHandle() || code.IsReadOnlyHandle());
static_calls_target_table_.Add(new (zone()) StaticCallsStruct(
Code::kCallViaCode, assembler()->CodeSize(), NULL, &code));
}
@@ -1208,10 +1208,10 @@
#if !defined(TARGET_ARCH_DBC)
void FlowGraphCompiler::GenerateCallWithDeopt(TokenPosition token_pos,
intptr_t deopt_id,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- GenerateCall(token_pos, stub_entry, kind, locs);
+ GenerateCall(token_pos, stub, kind, locs);
const intptr_t deopt_id_after = DeoptId::ToDeoptAfter(deopt_id);
if (is_optimizing()) {
AddDeoptIndexAtCall(deopt_id_after);
@@ -1222,31 +1222,31 @@
}
}
-static const StubEntry* StubEntryFor(const ICData& ic_data, bool optimized) {
+static const Code& StubEntryFor(const ICData& ic_data, bool optimized) {
switch (ic_data.NumArgsTested()) {
case 1:
#if defined(TARGET_ARCH_X64)
if (ic_data.IsTrackingExactness()) {
if (optimized) {
- return StubCode::
- OneArgOptimizedCheckInlineCacheWithExactnessCheck_entry();
+ return StubCode::OneArgOptimizedCheckInlineCacheWithExactnessCheck();
} else {
- return StubCode::OneArgCheckInlineCacheWithExactnessCheck_entry();
+ return StubCode::OneArgCheckInlineCacheWithExactnessCheck();
}
}
#else
// TODO(dartbug.com/34170) Port exactness tracking to other platforms.
ASSERT(!ic_data.IsTrackingExactness());
#endif
- return optimized ? StubCode::OneArgOptimizedCheckInlineCache_entry()
- : StubCode::OneArgCheckInlineCache_entry();
+ return optimized ? StubCode::OneArgOptimizedCheckInlineCache()
+ : StubCode::OneArgCheckInlineCache();
case 2:
ASSERT(!ic_data.IsTrackingExactness());
- return optimized ? StubCode::TwoArgsOptimizedCheckInlineCache_entry()
- : StubCode::TwoArgsCheckInlineCache_entry();
+ return optimized ? StubCode::TwoArgsOptimizedCheckInlineCache()
+ : StubCode::TwoArgsCheckInlineCache();
default:
+ ic_data.Print();
UNIMPLEMENTED();
- return nullptr;
+ return Code::Handle();
}
}
@@ -1267,7 +1267,7 @@
// Emit IC call that will count and thus may need reoptimization at
// function entry.
ASSERT(may_reoptimize() || flow_graph().IsCompiledForOsr());
- EmitOptimizedInstanceCall(*StubEntryFor(ic_data, /*optimized=*/true),
+ EmitOptimizedInstanceCall(StubEntryFor(ic_data, /*optimized=*/true),
ic_data, deopt_id, token_pos, locs, entry_kind);
return;
}
@@ -1281,7 +1281,7 @@
return;
}
- EmitInstanceCall(*StubEntryFor(ic_data, /*optimized=*/false), ic_data,
+ EmitInstanceCall(StubEntryFor(ic_data, /*optimized=*/false), ic_data,
deopt_id, token_pos, locs);
}
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index e7deb03..dd1cf66 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -444,24 +444,24 @@
LocationSummary* locs);
void GenerateCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs);
void GenerateCallWithDeopt(TokenPosition token_pos,
intptr_t deopt_id,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs);
void GeneratePatchableCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs);
void GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind = Code::EntryKind::kNormal);
@@ -528,14 +528,14 @@
bool fall_through_if_inside = false);
void EmitOptimizedInstanceCall(
- const StubEntry& stub_entry,
+ const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs,
Code::EntryKind entry_kind = Code::EntryKind::kNormal);
- void EmitInstanceCall(const StubEntry& stub_entry,
+ void EmitInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
@@ -937,7 +937,8 @@
function(function_arg),
code(code_arg) {
ASSERT((function == NULL) || function->IsZoneHandle());
- ASSERT((code == NULL) || code->IsZoneHandle());
+ ASSERT((code == NULL) || code->IsZoneHandle() ||
+ code->IsReadOnlyHandle());
}
private:
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 3e786a8..00c9618 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -209,19 +209,19 @@
if (test_kind == kTestTypeOneArg) {
ASSERT(instantiator_type_arguments_reg == kNoRegister);
ASSERT(function_type_arguments_reg == kNoRegister);
- __ BranchLink(*StubCode::Subtype1TestCache_entry());
+ __ BranchLink(StubCode::Subtype1TestCache());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(instantiator_type_arguments_reg == kNoRegister);
ASSERT(function_type_arguments_reg == kNoRegister);
- __ BranchLink(*StubCode::Subtype2TestCache_entry());
+ __ BranchLink(StubCode::Subtype2TestCache());
} else if (test_kind == kTestTypeFourArgs) {
ASSERT(instantiator_type_arguments_reg == R2);
ASSERT(function_type_arguments_reg == R1);
- __ BranchLink(*StubCode::Subtype4TestCache_entry());
+ __ BranchLink(StubCode::Subtype4TestCache());
} else if (test_kind == kTestTypeSixArgs) {
ASSERT(instantiator_type_arguments_reg == R2);
ASSERT(function_type_arguments_reg == R1);
- __ BranchLink(*StubCode::Subtype6TestCache_entry());
+ __ BranchLink(StubCode::Subtype6TestCache());
} else {
UNREACHABLE();
}
@@ -875,8 +875,8 @@
}
__ CompareImmediate(R3, GetOptimizationThreshold());
ASSERT(function_reg == R8);
- __ Branch(*StubCode::OptimizeFunction_entry(), ObjectPool::kNotPatchable,
- new_pp, GE);
+ __ Branch(StubCode::OptimizeFunction(), ObjectPool::kNotPatchable, new_pp,
+ GE);
}
__ Comment("Enter frame");
if (flow_graph().IsCompiledForOsr()) {
@@ -960,29 +960,29 @@
}
void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLink(stub_entry);
+ __ BranchLink(stub);
EmitCallsiteMetadata(token_pos, DeoptId::kNone, kind, locs);
- AddStubCallTarget(Code::ZoneHandle(stub_entry.code()));
+ AddStubCallTarget(stub);
}
void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLinkPatchable(stub_entry);
+ __ BranchLinkPatchable(stub);
EmitCallsiteMetadata(token_pos, DeoptId::kNone, kind, locs);
}
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind) {
- __ BranchLinkPatchable(stub_entry, entry_kind);
+ __ BranchLinkPatchable(stub, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
}
@@ -996,8 +996,8 @@
// call sites are never patched for breakpoints: the function is deoptimized
// and the unoptimized code with IC calls for static calls is patched instead.
ASSERT(is_optimizing());
- const auto& stub_entry = *StubCode::CallStaticFunction_entry();
- __ BranchLinkWithEquivalence(stub_entry, target, entry_kind);
+ const auto& stub = StubCode::CallStaticFunction();
+ __ BranchLinkWithEquivalence(stub, target, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
AddStaticCallTarget(target);
}
@@ -1033,7 +1033,7 @@
#endif // DEBUG
}
-void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry,
+void FlowGraphCompiler::EmitOptimizedInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
@@ -1049,20 +1049,19 @@
__ LoadObject(R8, parsed_function().function());
__ LoadUniqueObject(R9, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
- locs, entry_kind);
+ GenerateDartCall(deopt_id, token_pos, stub, RawPcDescriptors::kIcCall, locs,
+ entry_kind);
__ Drop(ic_data.CountWithTypeArgs());
}
-void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
+void FlowGraphCompiler::EmitInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
__ LoadUniqueObject(R9, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
- locs);
+ GenerateDartCall(deopt_id, token_pos, stub, RawPcDescriptors::kIcCall, locs);
__ Drop(ic_data.CountWithTypeArgs());
}
@@ -1115,8 +1114,7 @@
TokenPosition token_pos,
LocationSummary* locs) {
ASSERT(ic_data.NumArgsTested() == 1);
- const Code& initial_stub =
- Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code());
+ const Code& initial_stub = StubCode::ICCallThroughFunction();
__ Comment("SwitchableCall");
__ LoadFromOffset(kWord, R0, SP,
@@ -1137,10 +1135,10 @@
TokenPosition token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- const StubEntry* stub_entry =
+ const Code& stub =
StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(R9, ic_data);
- GenerateDartCall(deopt_id, token_pos, *stub_entry,
+ GenerateDartCall(deopt_id, token_pos, stub,
RawPcDescriptors::kUnoptStaticCall, locs);
__ Drop(count_with_type_args);
}
@@ -1177,11 +1175,9 @@
__ Push(reg);
__ PushObject(obj);
if (is_optimizing()) {
- __ BranchLinkPatchable(
- *StubCode::OptimizedIdenticalWithNumberCheck_entry());
+ __ BranchLinkPatchable(StubCode::OptimizedIdenticalWithNumberCheck());
} else {
- __ BranchLinkPatchable(
- *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
+ __ BranchLinkPatchable(StubCode::UnoptimizedIdenticalWithNumberCheck());
}
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
// Stub returns result in flags (result of a cmp, we need Z computed).
@@ -1202,11 +1198,9 @@
__ Push(left);
__ Push(right);
if (is_optimizing()) {
- __ BranchLinkPatchable(
- *StubCode::OptimizedIdenticalWithNumberCheck_entry());
+ __ BranchLinkPatchable(StubCode::OptimizedIdenticalWithNumberCheck());
} else {
- __ BranchLinkPatchable(
- *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
+ __ BranchLinkPatchable(StubCode::UnoptimizedIdenticalWithNumberCheck());
}
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
// Stub returns result in flags (result of a cmp, we need Z computed).
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 50ca711..82e5a82 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -204,19 +204,19 @@
if (test_kind == kTestTypeOneArg) {
ASSERT(instantiator_type_arguments_reg == kNoRegister);
ASSERT(function_type_arguments_reg == kNoRegister);
- __ BranchLink(*StubCode::Subtype1TestCache_entry());
+ __ BranchLink(StubCode::Subtype1TestCache());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(instantiator_type_arguments_reg == kNoRegister);
ASSERT(function_type_arguments_reg == kNoRegister);
- __ BranchLink(*StubCode::Subtype2TestCache_entry());
+ __ BranchLink(StubCode::Subtype2TestCache());
} else if (test_kind == kTestTypeFourArgs) {
ASSERT(instantiator_type_arguments_reg == R1);
ASSERT(function_type_arguments_reg == R2);
- __ BranchLink(*StubCode::Subtype4TestCache_entry());
+ __ BranchLink(StubCode::Subtype4TestCache());
} else if (test_kind == kTestTypeSixArgs) {
ASSERT(instantiator_type_arguments_reg == R1);
ASSERT(function_type_arguments_reg == R2);
- __ BranchLink(*StubCode::Subtype6TestCache_entry());
+ __ BranchLink(StubCode::Subtype6TestCache());
} else {
UNREACHABLE();
}
@@ -860,7 +860,7 @@
ASSERT(function_reg == R6);
Label dont_optimize;
__ b(&dont_optimize, LT);
- __ Branch(*StubCode::OptimizeFunction_entry(), new_pp);
+ __ Branch(StubCode::OptimizeFunction(), new_pp);
__ Bind(&dont_optimize);
}
__ Comment("Enter frame");
@@ -936,30 +936,30 @@
}
void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLink(stub_entry);
+ __ BranchLink(stub);
EmitCallsiteMetadata(token_pos, DeoptId::kNone, kind, locs);
- AddStubCallTarget(Code::ZoneHandle(stub_entry.code()));
+ AddStubCallTarget(stub);
}
void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ BranchLinkPatchable(stub_entry);
+ __ BranchLinkPatchable(stub);
EmitCallsiteMetadata(token_pos, DeoptId::kNone, kind, locs);
}
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind) {
// TODO(sjindel/entrypoints): Support multiple entrypoints on ARM64.
- __ BranchLinkPatchable(stub_entry);
+ __ BranchLinkPatchable(stub);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
}
@@ -974,8 +974,8 @@
// call sites are never patched for breakpoints: the function is deoptimized
// and the unoptimized code with IC calls for static calls is patched instead.
ASSERT(is_optimizing());
- const auto& stub_entry = *StubCode::CallStaticFunction_entry();
- __ BranchLinkWithEquivalence(stub_entry, target);
+ const Code& stub = StubCode::CallStaticFunction();
+ __ BranchLinkWithEquivalence(stub, target);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
AddStaticCallTarget(target);
}
@@ -1004,7 +1004,7 @@
__ StoreFieldToOffset(TMP, R0, Array::element_offset(edge_id));
}
-void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry,
+void FlowGraphCompiler::EmitOptimizedInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
@@ -1021,20 +1021,18 @@
__ LoadObject(R6, parsed_function().function());
__ LoadUniqueObject(R5, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
- locs);
+ GenerateDartCall(deopt_id, token_pos, stub, RawPcDescriptors::kIcCall, locs);
__ Drop(ic_data.CountWithTypeArgs());
}
-void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
+void FlowGraphCompiler::EmitInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
__ LoadUniqueObject(R5, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
- locs);
+ GenerateDartCall(deopt_id, token_pos, stub, RawPcDescriptors::kIcCall, locs);
__ Drop(ic_data.CountWithTypeArgs());
}
@@ -1088,8 +1086,7 @@
TokenPosition token_pos,
LocationSummary* locs) {
ASSERT(ic_data.NumArgsTested() == 1);
- const Code& initial_stub =
- Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code());
+ const Code& initial_stub = StubCode::ICCallThroughFunction();
auto& op = __ object_pool_wrapper();
@@ -1118,10 +1115,10 @@
TokenPosition token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- const StubEntry* stub_entry =
+ const Code& stub =
StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(R5, ic_data);
- GenerateDartCall(deopt_id, token_pos, *stub_entry,
+ GenerateDartCall(deopt_id, token_pos, stub,
RawPcDescriptors::kUnoptStaticCall, locs);
__ Drop(count_with_type_args);
}
@@ -1159,11 +1156,9 @@
__ Push(reg);
__ PushObject(obj);
if (is_optimizing()) {
- __ BranchLinkPatchable(
- *StubCode::OptimizedIdenticalWithNumberCheck_entry());
+ __ BranchLinkPatchable(StubCode::OptimizedIdenticalWithNumberCheck());
} else {
- __ BranchLinkPatchable(
- *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
+ __ BranchLinkPatchable(StubCode::UnoptimizedIdenticalWithNumberCheck());
}
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
// Stub returns result in flags (result of a cmp, we need Z computed).
@@ -1184,11 +1179,9 @@
__ Push(left);
__ Push(right);
if (is_optimizing()) {
- __ BranchLinkPatchable(
- *StubCode::OptimizedIdenticalWithNumberCheck_entry());
+ __ BranchLinkPatchable(StubCode::OptimizedIdenticalWithNumberCheck());
} else {
- __ BranchLinkPatchable(
- *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
+ __ BranchLinkPatchable(StubCode::UnoptimizedIdenticalWithNumberCheck());
}
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
// Stub returns result in flags (result of a cmp, we need Z computed).
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 2b1f13a..c60cdb3 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -166,7 +166,7 @@
ASSERT(deopt_env() != NULL);
__ pushl(CODE_REG);
- __ Call(*StubCode::Deoptimize_entry());
+ __ Call(StubCode::Deoptimize());
set_pc_offset(assembler->CodeSize());
__ int3();
#undef __
@@ -210,21 +210,21 @@
ASSERT(function_type_arguments_reg == kNoRegister);
__ pushl(raw_null);
__ pushl(raw_null);
- __ Call(*StubCode::Subtype1TestCache_entry());
+ __ Call(StubCode::Subtype1TestCache());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(instantiator_type_arguments_reg == kNoRegister);
ASSERT(function_type_arguments_reg == kNoRegister);
__ pushl(raw_null);
__ pushl(raw_null);
- __ Call(*StubCode::Subtype2TestCache_entry());
+ __ Call(StubCode::Subtype2TestCache());
} else if (test_kind == kTestTypeFourArgs) {
__ pushl(instantiator_type_arguments_reg);
__ pushl(function_type_arguments_reg);
- __ Call(*StubCode::Subtype4TestCache_entry());
+ __ Call(StubCode::Subtype4TestCache());
} else if (test_kind == kTestTypeSixArgs) {
__ pushl(instantiator_type_arguments_reg);
__ pushl(function_type_arguments_reg);
- __ Call(*StubCode::Subtype6TestCache_entry());
+ __ Call(StubCode::Subtype6TestCache());
} else {
UNREACHABLE();
}
@@ -799,7 +799,7 @@
__ cmpl(FieldAddress(function_reg, Function::usage_counter_offset()),
Immediate(GetOptimizationThreshold()));
ASSERT(function_reg == EBX);
- __ J(GREATER_EQUAL, *StubCode::OptimizeFunction_entry());
+ __ J(GREATER_EQUAL, StubCode::OptimizeFunction());
}
__ Comment("Enter frame");
if (flow_graph().IsCompiledForOsr()) {
@@ -855,22 +855,22 @@
}
void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ Call(stub_entry);
+ __ Call(stub);
EmitCallsiteMetadata(token_pos, DeoptId::kNone, kind, locs);
- AddStubCallTarget(Code::ZoneHandle(stub_entry.code()));
+ AddStubCallTarget(stub);
}
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind) {
// TODO(sjindel/entrypoints): Support multiple entrypoints on IA32.
- __ Call(stub_entry);
+ __ Call(stub);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
}
@@ -881,8 +881,8 @@
const Function& target,
Code::EntryKind entry_kind) {
// TODO(sjindel/entrypoints): Support multiple entrypoints on IA32.
- const auto& stub_entry = *StubCode::CallStaticFunction_entry();
- __ Call(stub_entry, true /* movable_target */);
+ const auto& stub = StubCode::CallStaticFunction();
+ __ Call(stub, true /* movable_target */);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
AddStaticCallTarget(target);
}
@@ -901,10 +901,10 @@
TokenPosition token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- const StubEntry& stub_entry =
- *StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
+ const Code& stub =
+ StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(ECX, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry,
+ GenerateDartCall(deopt_id, token_pos, stub,
RawPcDescriptors::kUnoptStaticCall, locs);
__ Drop(count_with_type_args);
}
@@ -921,7 +921,7 @@
__ IncrementSmiField(FieldAddress(EAX, Array::element_offset(edge_id)), 1);
}
-void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry,
+void FlowGraphCompiler::EmitOptimizedInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
@@ -937,20 +937,18 @@
// Pass the function explicitly, it is used in IC stub.
__ LoadObject(EBX, parsed_function().function());
__ LoadObject(ECX, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
- locs);
+ GenerateDartCall(deopt_id, token_pos, stub, RawPcDescriptors::kIcCall, locs);
__ Drop(ic_data.CountWithTypeArgs());
}
-void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
+void FlowGraphCompiler::EmitInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
__ LoadObject(ECX, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
- locs);
+ GenerateDartCall(deopt_id, token_pos, stub, RawPcDescriptors::kIcCall, locs);
__ Drop(ic_data.CountWithTypeArgs());
}
@@ -1038,9 +1036,9 @@
__ pushl(reg);
__ PushObject(obj);
if (is_optimizing()) {
- __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
+ __ Call(StubCode::OptimizedIdenticalWithNumberCheck());
} else {
- __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
+ __ Call(StubCode::UnoptimizedIdenticalWithNumberCheck());
}
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
// Stub returns result in flags (result of a cmpl, we need ZF computed).
@@ -1061,9 +1059,9 @@
__ pushl(left);
__ pushl(right);
if (is_optimizing()) {
- __ Call(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
+ __ Call(StubCode::OptimizedIdenticalWithNumberCheck());
} else {
- __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
+ __ Call(StubCode::UnoptimizedIdenticalWithNumberCheck());
}
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
// Stub returns result in flags (result of a cmpl, we need ZF computed).
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 45a5f13..579e9f1 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -209,19 +209,19 @@
if (test_kind == kTestTypeOneArg) {
ASSERT(instantiator_type_arguments_reg == kNoRegister);
ASSERT(function_type_arguments_reg == kNoRegister);
- __ Call(*StubCode::Subtype1TestCache_entry());
+ __ Call(StubCode::Subtype1TestCache());
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(instantiator_type_arguments_reg == kNoRegister);
ASSERT(function_type_arguments_reg == kNoRegister);
- __ Call(*StubCode::Subtype2TestCache_entry());
+ __ Call(StubCode::Subtype2TestCache());
} else if (test_kind == kTestTypeFourArgs) {
ASSERT(RDX == instantiator_type_arguments_reg);
ASSERT(RCX == function_type_arguments_reg);
- __ Call(*StubCode::Subtype4TestCache_entry());
+ __ Call(StubCode::Subtype4TestCache());
} else if (test_kind == kTestTypeSixArgs) {
ASSERT(RDX == instantiator_type_arguments_reg);
ASSERT(RCX == function_type_arguments_reg);
- __ Call(*StubCode::Subtype6TestCache_entry());
+ __ Call(StubCode::Subtype6TestCache());
} else {
UNREACHABLE();
}
@@ -875,7 +875,7 @@
__ cmpl(FieldAddress(function_reg, Function::usage_counter_offset()),
Immediate(GetOptimizationThreshold()));
ASSERT(function_reg == RDI);
- __ J(GREATER_EQUAL, *StubCode::OptimizeFunction_entry(), new_pp);
+ __ J(GREATER_EQUAL, StubCode::OptimizeFunction(), new_pp);
}
ASSERT(StackSize() >= 0);
__ Comment("Enter frame");
@@ -951,29 +951,29 @@
}
void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ Call(stub_entry);
+ __ Call(stub);
EmitCallsiteMetadata(token_pos, DeoptId::kNone, kind, locs);
- AddStubCallTarget(Code::ZoneHandle(stub_entry.code()));
+ AddStubCallTarget(stub);
}
void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs) {
- __ CallPatchable(stub_entry);
+ __ CallPatchable(stub);
EmitCallsiteMetadata(token_pos, DeoptId::kNone, kind, locs);
}
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
- const StubEntry& stub_entry,
+ const Code& stub,
RawPcDescriptors::Kind kind,
LocationSummary* locs,
Code::EntryKind entry_kind) {
- __ CallPatchable(stub_entry, entry_kind);
+ __ CallPatchable(stub, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
}
@@ -987,7 +987,7 @@
// call sites are never patched for breakpoints: the function is deoptimized
// and the unoptimized code with IC calls for static calls is patched instead.
ASSERT(is_optimizing());
- const auto& stub_entry = *StubCode::CallStaticFunction_entry();
+ const auto& stub_entry = StubCode::CallStaticFunction();
__ CallWithEquivalence(stub_entry, target, entry_kind);
EmitCallsiteMetadata(token_pos, deopt_id, kind, locs);
AddStaticCallTarget(target);
@@ -1007,10 +1007,10 @@
TokenPosition token_pos,
LocationSummary* locs,
const ICData& ic_data) {
- const StubEntry* stub_entry =
+ const Code& stub =
StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
__ LoadObject(RBX, ic_data);
- GenerateDartCall(deopt_id, token_pos, *stub_entry,
+ GenerateDartCall(deopt_id, token_pos, stub,
RawPcDescriptors::kUnoptStaticCall, locs);
__ Drop(count_with_type_args, RCX);
}
@@ -1028,7 +1028,7 @@
__ IncrementSmiField(FieldAddress(RAX, Array::element_offset(edge_id)), 1);
}
-void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry,
+void FlowGraphCompiler::EmitOptimizedInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
@@ -1043,20 +1043,19 @@
// Pass the function explicitly, it is used in IC stub.
__ LoadObject(RDI, parsed_function().function());
__ LoadUniqueObject(RBX, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
- locs, entry_kind);
+ GenerateDartCall(deopt_id, token_pos, stub, RawPcDescriptors::kIcCall, locs,
+ entry_kind);
__ Drop(ic_data.CountWithTypeArgs(), RCX);
}
-void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
+void FlowGraphCompiler::EmitInstanceCall(const Code& stub,
const ICData& ic_data,
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
__ LoadUniqueObject(RBX, ic_data);
- GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
- locs);
+ GenerateDartCall(deopt_id, token_pos, stub, RawPcDescriptors::kIcCall, locs);
__ Drop(ic_data.CountWithTypeArgs(), RCX);
}
@@ -1107,8 +1106,7 @@
TokenPosition token_pos,
LocationSummary* locs) {
ASSERT(ic_data.NumArgsTested() == 1);
- const Code& initial_stub =
- Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code());
+ const Code& initial_stub = StubCode::ICCallThroughFunction();
__ Comment("SwitchableCall");
__ movq(RDI, Address(RSP, (ic_data.CountWithoutTypeArgs() - 1) * kWordSize));
@@ -1161,9 +1159,9 @@
__ pushq(reg);
__ PushObject(obj);
if (is_optimizing()) {
- __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
+ __ CallPatchable(StubCode::OptimizedIdenticalWithNumberCheck());
} else {
- __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
+ __ CallPatchable(StubCode::UnoptimizedIdenticalWithNumberCheck());
}
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
// Stub returns result in flags (result of a cmpq, we need ZF computed).
@@ -1184,9 +1182,9 @@
__ pushq(left);
__ pushq(right);
if (is_optimizing()) {
- __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
+ __ CallPatchable(StubCode::OptimizedIdenticalWithNumberCheck());
} else {
- __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
+ __ CallPatchable(StubCode::UnoptimizedIdenticalWithNumberCheck());
}
AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
// Stub returns result in flags (result of a cmpq, we need ZF computed).
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index ad4cd91..b8a44ec 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -3917,19 +3917,19 @@
// DBC does not use specialized inline cache stubs for smi operations.
#if !defined(TARGET_ARCH_DBC)
-static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) {
+static RawCode* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) {
if (!FLAG_two_args_smi_icd) {
- return 0;
+ return Code::null();
}
switch (kind) {
case Token::kADD:
- return StubCode::SmiAddInlineCache_entry();
+ return StubCode::SmiAddInlineCache().raw();
case Token::kSUB:
- return StubCode::SmiSubInlineCache_entry();
+ return StubCode::SmiSubInlineCache().raw();
case Token::kEQ:
- return StubCode::SmiEqualInlineCache_entry();
+ return StubCode::SmiEqualInlineCache().raw();
default:
- return NULL;
+ return Code::null();
}
}
#else
@@ -4037,16 +4037,17 @@
compiler->AddCurrentDescriptor(RawPcDescriptors::kRewind, deopt_id(),
token_pos());
bool is_smi_two_args_op = false;
- const StubEntry* stub_entry = TwoArgsSmiOpInlineCacheEntry(token_kind());
- if (stub_entry != nullptr) {
+ const Code& stub =
+ Code::ZoneHandle(TwoArgsSmiOpInlineCacheEntry(token_kind()));
+ if (!stub.IsNull()) {
// We have a dedicated inline cache stub for this operation, add an
// an initial Smi/Smi check with count 0.
is_smi_two_args_op = call_ic_data->AddSmiSmiCheckForFastSmiStubs();
}
if (is_smi_two_args_op) {
ASSERT(ArgumentCount() == 2);
- compiler->EmitInstanceCall(*stub_entry, *call_ic_data, deopt_id(),
- token_pos(), locs());
+ compiler->EmitInstanceCall(stub, *call_ic_data, deopt_id(), token_pos(),
+ locs());
} else {
compiler->GenerateInstanceCall(deopt_id(), token_pos(), locs(),
*call_ic_data);
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 4051382..cc806de 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -1977,8 +1977,6 @@
virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
};
-class InductionVariableInfo;
-
class PhiInstr : public Definition {
public:
PhiInstr(JoinEntryInstr* block, intptr_t num_inputs)
@@ -1986,7 +1984,6 @@
inputs_(num_inputs),
representation_(kTagged),
reaching_defs_(NULL),
- loop_variable_info_(NULL),
is_alive_(false),
is_receiver_(kUnknownReceiver) {
for (intptr_t i = 0; i < num_inputs; ++i) {
@@ -2042,14 +2039,6 @@
// A phi is redundant if all input operands are the same.
bool IsRedundant() const;
- void set_induction_variable_info(InductionVariableInfo* info) {
- loop_variable_info_ = info;
- }
-
- InductionVariableInfo* induction_variable_info() {
- return loop_variable_info_;
- }
-
PRINT_TO_SUPPORT
enum ReceiverType { kUnknownReceiver = -1, kNotReceiver = 0, kReceiver = 1 };
@@ -2071,7 +2060,6 @@
GrowableArray<Value*> inputs_;
Representation representation_;
BitVector* reaching_defs_;
- InductionVariableInfo* loop_variable_info_;
bool is_alive_;
int8_t is_receiver_;
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 0026a95..3bc424f 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -941,14 +941,14 @@
// into the runtime system.
uword entry;
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
- const StubEntry* stub_entry;
+ const Code* stub;
if (link_lazily()) {
- stub_entry = StubCode::CallBootstrapNative_entry();
+ stub = &StubCode::CallBootstrapNative();
entry = NativeEntry::LinkNativeCallEntry();
} else {
entry = reinterpret_cast<uword>(native_c_function());
if (is_bootstrap_native()) {
- stub_entry = StubCode::CallBootstrapNative_entry();
+ stub = &StubCode::CallBootstrapNative();
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(
entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
@@ -957,12 +957,12 @@
// In the case of non bootstrap native methods the CallNativeCFunction
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
- stub_entry = StubCode::CallAutoScopeNative_entry();
+ stub = &StubCode::CallAutoScopeNative();
} else {
// In the case of non bootstrap native methods the CallNativeCFunction
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
- stub_entry = StubCode::CallNoScopeNative_entry();
+ stub = &StubCode::CallNoScopeNative();
}
}
__ LoadImmediate(R1, argc_tag);
@@ -971,10 +971,10 @@
R9, &label,
link_lazily() ? ObjectPool::kPatchable : ObjectPool::kNotPatchable);
if (link_lazily()) {
- compiler->GeneratePatchableCall(token_pos(), *stub_entry,
+ compiler->GeneratePatchableCall(token_pos(), *stub,
RawPcDescriptors::kOther, locs());
} else {
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+ compiler->GenerateCall(token_pos(), *stub, RawPcDescriptors::kOther,
locs());
}
__ Pop(result);
@@ -2019,7 +2019,6 @@
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(
compiler->zone(), StubCode::GetAllocationStubForClass(cls_));
- const StubEntry stub_entry(stub);
LocationSummary* locs = instruction()->locs();
@@ -2027,7 +2026,7 @@
compiler->SaveLiveRegisters(locs);
compiler->GenerateCall(TokenPosition::kNoSource, // No token position.
- stub_entry, RawPcDescriptors::kOther, locs);
+ stub, RawPcDescriptors::kOther, locs);
__ MoveRegister(result_, R0);
compiler->RestoreLiveRegisters(locs);
__ b(exit_label());
@@ -2555,7 +2554,7 @@
}
}
compiler->GenerateCallWithDeopt(token_pos(), deopt_id(),
- *StubCode::AllocateArray_entry(),
+ StubCode::AllocateArray(),
RawPcDescriptors::kOther, locs());
ASSERT(locs()->out(0).reg() == kResultReg);
}
@@ -2833,7 +2832,7 @@
__ LoadImmediate(R1, instruction()->num_context_variables());
compiler->GenerateCall(instruction()->token_pos(),
- *StubCode::AllocateContext_entry(),
+ StubCode::AllocateContext(),
RawPcDescriptors::kOther, locs);
ASSERT(instruction()->locs()->out(0).reg() == R0);
compiler->RestoreLiveRegisters(instruction()->locs());
@@ -2879,7 +2878,7 @@
ASSERT(locs()->out(0).reg() == R0);
__ LoadImmediate(R1, num_context_variables());
- compiler->GenerateCall(token_pos(), *StubCode::AllocateContext_entry(),
+ compiler->GenerateCall(token_pos(), StubCode::AllocateContext(),
RawPcDescriptors::kOther, locs());
}
@@ -6727,15 +6726,13 @@
}
const Code& stub = Code::ZoneHandle(
compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
- const StubEntry stub_entry(stub);
- compiler->GenerateCall(token_pos(), stub_entry, RawPcDescriptors::kOther,
- locs());
+ compiler->GenerateCall(token_pos(), stub, RawPcDescriptors::kOther, locs());
__ Drop(ArgumentCount()); // Discard arguments.
}
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- __ BranchLinkPatchable(*StubCode::DebugStepCheck_entry());
+ __ BranchLinkPatchable(StubCode::DebugStepCheck());
compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
compiler->RecordSafepoint(locs());
}
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index bd7fe21..a3a7868 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -831,14 +831,14 @@
// into the runtime system.
uword entry;
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
- const StubEntry* stub_entry;
+ const Code* stub;
if (link_lazily()) {
- stub_entry = StubCode::CallBootstrapNative_entry();
+ stub = &StubCode::CallBootstrapNative();
entry = NativeEntry::LinkNativeCallEntry();
} else {
entry = reinterpret_cast<uword>(native_c_function());
if (is_bootstrap_native()) {
- stub_entry = StubCode::CallBootstrapNative_entry();
+ stub = &StubCode::CallBootstrapNative();
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(
entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
@@ -847,12 +847,12 @@
// In the case of non bootstrap native methods the CallNativeCFunction
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
- stub_entry = StubCode::CallAutoScopeNative_entry();
+ stub = &StubCode::CallAutoScopeNative();
} else {
// In the case of non bootstrap native methods the CallNativeCFunction
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
- stub_entry = StubCode::CallNoScopeNative_entry();
+ stub = &StubCode::CallNoScopeNative();
}
}
__ LoadImmediate(R1, argc_tag);
@@ -861,10 +861,10 @@
R5, &label,
link_lazily() ? ObjectPool::kPatchable : ObjectPool::kNotPatchable);
if (link_lazily()) {
- compiler->GeneratePatchableCall(token_pos(), *stub_entry,
+ compiler->GeneratePatchableCall(token_pos(), *stub,
RawPcDescriptors::kOther, locs());
} else {
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+ compiler->GenerateCall(token_pos(), *stub, RawPcDescriptors::kOther,
locs());
}
__ Pop(result);
@@ -1834,7 +1834,6 @@
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(
compiler->zone(), StubCode::GetAllocationStubForClass(cls_));
- const StubEntry stub_entry(stub);
LocationSummary* locs = instruction()->locs();
@@ -1842,7 +1841,7 @@
compiler->SaveLiveRegisters(locs);
compiler->GenerateCall(TokenPosition::kNoSource, // No token position.
- stub_entry, RawPcDescriptors::kOther, locs);
+ stub, RawPcDescriptors::kOther, locs);
__ MoveRegister(result_, R0);
compiler->RestoreLiveRegisters(locs);
__ b(exit_label());
@@ -2251,7 +2250,7 @@
}
}
compiler->GenerateCallWithDeopt(token_pos(), deopt_id(),
- *StubCode::AllocateArray_entry(),
+ StubCode::AllocateArray(),
RawPcDescriptors::kOther, locs());
ASSERT(locs()->out(0).reg() == kResultReg);
}
@@ -2521,7 +2520,7 @@
__ LoadImmediate(R1, instruction()->num_context_variables());
compiler->GenerateCall(instruction()->token_pos(),
- *StubCode::AllocateContext_entry(),
+ StubCode::AllocateContext(),
RawPcDescriptors::kOther, locs);
ASSERT(instruction()->locs()->out(0).reg() == R0);
compiler->RestoreLiveRegisters(instruction()->locs());
@@ -2567,7 +2566,7 @@
ASSERT(locs()->out(0).reg() == R0);
__ LoadImmediate(R1, num_context_variables());
- compiler->GenerateCall(token_pos(), *StubCode::AllocateContext_entry(),
+ compiler->GenerateCall(token_pos(), StubCode::AllocateContext(),
RawPcDescriptors::kOther, locs());
}
@@ -5965,15 +5964,13 @@
}
const Code& stub = Code::ZoneHandle(
compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
- const StubEntry stub_entry(stub);
- compiler->GenerateCall(token_pos(), stub_entry, RawPcDescriptors::kOther,
- locs());
+ compiler->GenerateCall(token_pos(), stub, RawPcDescriptors::kOther, locs());
__ Drop(ArgumentCount()); // Discard arguments.
}
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- __ BranchLinkPatchable(*StubCode::DebugStepCheck_entry());
+ __ BranchLinkPatchable(StubCode::DebugStepCheck());
compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
compiler->RecordSafepoint(locs());
}
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index b4c0e35..ce677dc 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -823,21 +823,20 @@
__ movl(EDX, Immediate(argc_tag));
- const StubEntry* stub_entry;
+ const Code* stub;
// There is no lazy-linking support on ia32.
ASSERT(!link_lazily());
if (is_bootstrap_native()) {
- stub_entry = StubCode::CallBootstrapNative_entry();
+ stub = &StubCode::CallBootstrapNative();
} else if (is_auto_scope()) {
- stub_entry = StubCode::CallAutoScopeNative_entry();
+ stub = &StubCode::CallAutoScopeNative();
} else {
- stub_entry = StubCode::CallNoScopeNative_entry();
+ stub = &StubCode::CallNoScopeNative();
}
const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
__ movl(ECX, Immediate(label.address()));
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
- locs());
+ compiler->GenerateCall(token_pos(), *stub, RawPcDescriptors::kOther, locs());
__ popl(result);
@@ -1723,14 +1722,13 @@
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(
compiler->zone(), StubCode::GetAllocationStubForClass(cls_));
- const StubEntry stub_entry(stub);
LocationSummary* locs = instruction()->locs();
locs->live_registers()->Remove(Location::RegisterLocation(result_));
compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(TokenPosition::kNoSource, stub_entry,
+ compiler->GenerateCall(TokenPosition::kNoSource, stub,
RawPcDescriptors::kOther, locs);
__ MoveRegister(result_, EAX);
compiler->RestoreLiveRegisters(locs);
@@ -2136,7 +2134,7 @@
__ Bind(&slow_path);
compiler->GenerateCallWithDeopt(token_pos(), deopt_id(),
- *StubCode::AllocateArray_entry(),
+ StubCode::AllocateArray(),
RawPcDescriptors::kOther, locs());
__ Bind(&done);
ASSERT(locs()->out(0).reg() == kResultReg);
@@ -2410,7 +2408,7 @@
__ movl(EDX, Immediate(instruction()->num_context_variables()));
compiler->GenerateCall(instruction()->token_pos(),
- *StubCode::AllocateContext_entry(),
+ StubCode::AllocateContext(),
RawPcDescriptors::kOther, locs);
ASSERT(instruction()->locs()->out(0).reg() == EAX);
compiler->RestoreLiveRegisters(instruction()->locs());
@@ -2458,7 +2456,7 @@
ASSERT(locs()->out(0).reg() == EAX);
__ movl(EDX, Immediate(num_context_variables()));
- compiler->GenerateCall(token_pos(), *StubCode::AllocateContext_entry(),
+ compiler->GenerateCall(token_pos(), StubCode::AllocateContext(),
RawPcDescriptors::kOther, locs());
}
@@ -6165,15 +6163,13 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Code& stub = Code::ZoneHandle(
compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
- const StubEntry stub_entry(stub);
- compiler->GenerateCall(token_pos(), stub_entry, RawPcDescriptors::kOther,
- locs());
+ compiler->GenerateCall(token_pos(), stub, RawPcDescriptors::kOther, locs());
__ Drop(ArgumentCount()); // Discard arguments.
}
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- __ Call(*StubCode::DebugStepCheck_entry());
+ __ Call(StubCode::DebugStepCheck());
compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
compiler->RecordSafepoint(locs());
}
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 9553b94..4ae5a22 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -849,24 +849,24 @@
__ leaq(RAX, Address(RSP, ArgumentCount() * kWordSize));
__ LoadImmediate(R10, Immediate(argc_tag));
- const StubEntry* stub_entry;
+ const Code* stub;
if (link_lazily()) {
- stub_entry = StubCode::CallBootstrapNative_entry();
+ stub = &StubCode::CallBootstrapNative();
ExternalLabel label(NativeEntry::LinkNativeCallEntry());
__ LoadNativeEntry(RBX, &label, ObjectPool::kPatchable);
- compiler->GeneratePatchableCall(token_pos(), *stub_entry,
+ compiler->GeneratePatchableCall(token_pos(), *stub,
RawPcDescriptors::kOther, locs());
} else {
if (is_bootstrap_native()) {
- stub_entry = StubCode::CallBootstrapNative_entry();
+ stub = &StubCode::CallBootstrapNative();
} else if (is_auto_scope()) {
- stub_entry = StubCode::CallAutoScopeNative_entry();
+ stub = &StubCode::CallAutoScopeNative();
} else {
- stub_entry = StubCode::CallNoScopeNative_entry();
+ stub = &StubCode::CallNoScopeNative();
}
const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
__ LoadNativeEntry(RBX, &label, ObjectPool::kNotPatchable);
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+ compiler->GenerateCall(token_pos(), *stub, RawPcDescriptors::kOther,
locs());
}
__ popq(result);
@@ -1017,7 +1017,6 @@
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(
compiler->zone(), StubCode::GetAllocationStubForClass(cls_));
- const StubEntry stub_entry(stub);
LocationSummary* locs = instruction()->locs();
@@ -1025,7 +1024,7 @@
compiler->SaveLiveRegisters(locs);
compiler->GenerateCall(TokenPosition::kNoSource, // No token position.
- stub_entry, RawPcDescriptors::kOther, locs);
+ stub, RawPcDescriptors::kOther, locs);
__ MoveRegister(result_, RAX);
compiler->RestoreLiveRegisters(locs);
__ jmp(exit_label());
@@ -2264,7 +2263,7 @@
__ Bind(&slow_path);
compiler->GenerateCallWithDeopt(token_pos(), deopt_id(),
- *StubCode::AllocateArray_entry(),
+ StubCode::AllocateArray(),
RawPcDescriptors::kOther, locs());
__ Bind(&done);
ASSERT(locs()->out(0).reg() == kResultReg);
@@ -2534,7 +2533,7 @@
__ LoadImmediate(R10, Immediate(instruction()->num_context_variables()));
compiler->GenerateCall(instruction()->token_pos(),
- *StubCode::AllocateContext_entry(),
+ StubCode::AllocateContext(),
RawPcDescriptors::kOther, locs);
ASSERT(instruction()->locs()->out(0).reg() == RAX);
compiler->RestoreLiveRegisters(instruction()->locs());
@@ -2581,7 +2580,7 @@
ASSERT(locs()->out(0).reg() == RAX);
__ LoadImmediate(R10, Immediate(num_context_variables()));
- compiler->GenerateCall(token_pos(), *StubCode::AllocateContext_entry(),
+ compiler->GenerateCall(token_pos(), StubCode::AllocateContext(),
RawPcDescriptors::kOther, locs());
}
@@ -6297,15 +6296,13 @@
}
const Code& stub = Code::ZoneHandle(
compiler->zone(), StubCode::GetAllocationStubForClass(cls()));
- const StubEntry stub_entry(stub);
- compiler->GenerateCall(token_pos(), stub_entry, RawPcDescriptors::kOther,
- locs());
+ compiler->GenerateCall(token_pos(), stub, RawPcDescriptors::kOther, locs());
__ Drop(ArgumentCount()); // Discard arguments.
}
void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT(!compiler->is_optimizing());
- __ CallPatchable(*StubCode::DebugStepCheck_entry());
+ __ CallPatchable(StubCode::DebugStepCheck());
compiler->AddCurrentDescriptor(stub_kind_, deopt_id_, token_pos());
compiler->RecordSafepoint(locs());
}
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index bb5778a..61a6a51 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -2692,6 +2692,22 @@
return true;
}
+static bool InlineLoadClassId(FlowGraph* flow_graph,
+ Instruction* call,
+ GraphEntryInstr* graph_entry,
+ FunctionEntryInstr** entry,
+ Instruction** last) {
+ *entry =
+ new (Z) FunctionEntryInstr(graph_entry, flow_graph->allocate_block_id(),
+ call->GetBlock()->try_index(), DeoptId::kNone);
+ (*entry)->InheritDeoptTarget(Z, call);
+ auto load_cid = new (Z)
+ LoadClassIdInstr(call->PushArgumentAt(0)->value()->CopyWithType(Z));
+ flow_graph->InsertBefore(call, load_cid, nullptr, FlowGraph::kValue);
+ *last = load_cid;
+ return true;
+}
+
// Adds an explicit bounds check for a typed getter/setter.
static void PrepareInlineTypedArrayBoundsCheck(FlowGraph* flow_graph,
Instruction* call,
@@ -3605,6 +3621,8 @@
}
return InlineGetIndexed(flow_graph, kind, call, receiver, graph_entry,
entry, last, can_speculate);
+ case MethodRecognizer::kClassIDgetID:
+ return InlineLoadClassId(flow_graph, call, graph_entry, entry, last);
default:
break;
}
diff --git a/runtime/vm/compiler/backend/loops.cc b/runtime/vm/compiler/backend/loops.cc
index 394da9e..707864e 100644
--- a/runtime/vm/compiler/backend/loops.cc
+++ b/runtime/vm/compiler/backend/loops.cc
@@ -65,16 +65,19 @@
void Classify(LoopInfo* loop, Definition* def);
void ClassifySCC(LoopInfo* loop);
- // Transfer methods. Computes how induction of the operands, if any,
+ // Transfer methods. Compute how induction of the operands, if any,
// tranfers over the operation performed by the given definition.
InductionVar* TransferPhi(LoopInfo* loop, Definition* def, intptr_t idx = -1);
InductionVar* TransferBinary(LoopInfo* loop, Definition* def);
InductionVar* TransferUnary(LoopInfo* loop, Definition* def);
- // Solver methods. Computes how temporary meaning given to the
+ // Solver methods. Compute how temporary meaning given to the
// definitions in a cycle transfer over the operation performed
// by the given definition.
InductionVar* SolvePhi(LoopInfo* loop, Definition* def, intptr_t idx = -1);
+ InductionVar* SolveConstraint(LoopInfo* loop,
+ Definition* def,
+ InductionVar* init);
InductionVar* SolveBinary(LoopInfo* loop,
Definition* def,
InductionVar* init);
@@ -239,8 +242,8 @@
}
} else if (def->IsPhi()) {
induc = TransferPhi(loop, def);
- } else if (def->IsRedefinition() || def->IsConstraint() || def->IsBox() ||
- def->IsUnbox()) {
+ } else if (def->IsRedefinition() || def->IsBox() || def->IsUnbox() ||
+ def->IsConstraint()) {
induc = Lookup(loop, def->InputAt(0)->definition()); // pass-through
} else if (def->IsBinaryIntegerOp()) {
induc = TransferBinary(loop, def);
@@ -278,9 +281,10 @@
InductionVar* update = nullptr;
if (def->IsPhi()) {
update = SolvePhi(loop, def);
- } else if (def->IsRedefinition() || def->IsConstraint() || def->IsBox() ||
- def->IsUnbox()) {
+ } else if (def->IsRedefinition() || def->IsBox() || def->IsUnbox()) {
update = LookupCycle(def->InputAt(0)->definition()); // pass-through
+ } else if (def->IsConstraint()) {
+ update = SolveConstraint(loop, def, init);
} else if (def->IsBinaryIntegerOp()) {
update = SolveBinary(loop, def, init);
} else if (def->IsUnaryIntegerOp()) {
@@ -381,6 +385,21 @@
return induc;
}
+InductionVar* InductionVarAnalysis::SolveConstraint(LoopInfo* loop,
+ Definition* def,
+ InductionVar* init) {
+ InductionVar* c = LookupCycle(def->InputAt(0)->definition());
+ if (c == init) {
+ // Record a non-artifical bound constraint on a phi.
+ // TODO(ajcbik): detect full loop logic, trip counts, etc.
+ ConstraintInstr* constraint = def->AsConstraint();
+ if (constraint->target() != nullptr) {
+ loop->limit_ = constraint;
+ }
+ }
+ return c;
+}
+
InductionVar* InductionVarAnalysis::SolveBinary(LoopInfo* loop,
Definition* def,
InductionVar* init) {
@@ -629,6 +648,7 @@
blocks_(blocks),
back_edges_(),
induction_(),
+ limit_(nullptr),
outer_(nullptr),
inner_(nullptr),
next_(nullptr) {}
@@ -650,9 +670,9 @@
return false;
}
-bool LoopInfo::IsHeaderPhi(Instruction* instr) const {
- return instr->IsPhi() && instr->GetBlock() == header_ &&
- !instr->AsPhi()->IsRedundant(); // phi(x,..,x) = x
+bool LoopInfo::IsHeaderPhi(Definition* def) const {
+ return def != nullptr && def->IsPhi() && def->GetBlock() == header_ &&
+ !def->AsPhi()->IsRedundant(); // phi(x,..,x) = x
}
bool LoopInfo::IsIn(LoopInfo* loop) const {
@@ -679,6 +699,8 @@
}
void LoopInfo::AddInduction(Definition* def, InductionVar* induc) {
+ ASSERT(def != nullptr);
+ ASSERT(induc != nullptr);
induction_.Insert(InductionKV::Pair(def, induc));
}
diff --git a/runtime/vm/compiler/backend/loops.h b/runtime/vm/compiler/backend/loops.h
index 1d5b45a..30fdf59 100644
--- a/runtime/vm/compiler/backend/loops.h
+++ b/runtime/vm/compiler/backend/loops.h
@@ -38,7 +38,7 @@
// Constructor for a constant.
explicit InductionVar(int64_t offset) : InductionVar(offset, 0, nullptr) {}
- // Constructor for induction.
+ // Constructor for an induction.
InductionVar(Kind kind, InductionVar* initial, InductionVar* next)
: kind_(kind), initial_(initial), next_(next) {
ASSERT(IsInvariant(initial));
@@ -73,6 +73,29 @@
return false;
}
+ // Getters.
+ Kind kind() const { return kind_; }
+ int64_t offset() const {
+ ASSERT(kind_ == kInvariant);
+ return offset_;
+ }
+ int64_t mult() const {
+ ASSERT(kind_ == kInvariant);
+ return mult_;
+ }
+ Definition* def() const {
+ ASSERT(kind_ == kInvariant);
+ return def_;
+ }
+ InductionVar* initial() const {
+ ASSERT(kind_ != kInvariant);
+ return initial_;
+ }
+ InductionVar* next() const {
+ ASSERT(kind_ != kInvariant);
+ return next_;
+ }
+
// For debugging.
const char* ToCString() const;
@@ -134,8 +157,8 @@
// Returns true if given block is backedge of this loop.
bool IsBackEdge(BlockEntryInstr* block) const;
- // Returns true if given instruction is a header phi for this loop.
- bool IsHeaderPhi(Instruction* instr) const;
+ // Returns true if given definition is a header phi for this loop.
+ bool IsHeaderPhi(Definition* def) const;
// Returns true if this loop is nested inside given loop.
bool IsIn(LoopInfo* loop) const;
@@ -158,8 +181,9 @@
// Getters.
intptr_t id() const { return id_; }
BlockEntryInstr* header() const { return header_; }
- const GrowableArray<BlockEntryInstr*>& back_edges() { return back_edges_; }
BitVector* blocks() const { return blocks_; }
+ const GrowableArray<BlockEntryInstr*>& back_edges() { return back_edges_; }
+ ConstraintInstr* limit() const { return limit_; }
LoopInfo* outer() const { return outer_; }
LoopInfo* inner() const { return inner_; }
LoopInfo* next() const { return next_; }
@@ -187,9 +211,12 @@
// Back edges of loop (usually one).
GrowableArray<BlockEntryInstr*> back_edges_;
- // Map instruction -> induction for this loop.
+ // Map definition -> induction for this loop.
DirectChainedHashMap<InductionKV> induction_;
+ // Constraint on a header phi.
+ ConstraintInstr* limit_;
+
// Loop hierarchy.
LoopInfo* outer_;
LoopInfo* inner_;
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 5b50229..d94536a 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -30,7 +30,7 @@
void RangeAnalysis::Analyze() {
CollectValues();
InsertConstraints();
- DiscoverSimpleInductionVariables();
+ flow_graph_->GetLoopHierarchy().ComputeInduction();
InferRanges();
EliminateRedundantBoundsChecks();
MarkUnreachableBlocks();
@@ -43,6 +43,7 @@
RemoveConstraints();
}
+// Helper method to chase to a constrained definition.
static Definition* UnwrapConstraint(Definition* defn) {
while (defn->IsConstraint()) {
defn = defn->AsConstraint()->value()->definition();
@@ -50,167 +51,6 @@
return defn;
}
-// Simple induction variable is a variable that satisfies the following pattern:
-//
-// v1 <- phi(v0, v1 + 1)
-//
-// If there are two simple induction variables in the same block and one of
-// them is constrained - then another one is constrained as well, e.g.
-// from
-//
-// B1:
-// v3 <- phi(v0, v3 + 1)
-// v4 <- phi(v2, v4 + 1)
-// Bx:
-// v3 is constrained to [v0, v1]
-//
-// it follows that
-//
-// Bx:
-// v4 is constrained to [v2, v2 + (v0 - v1)]
-//
-// This pass essentially pattern matches induction variables introduced
-// like this:
-//
-// for (var i = i0, j = j0; i < L; i++, j++) {
-// j is known to be within [j0, j0 + (L - i0 - 1)]
-// }
-//
-class InductionVariableInfo : public ZoneAllocated {
- public:
- InductionVariableInfo(PhiInstr* phi,
- Definition* initial_value,
- BinarySmiOpInstr* increment,
- ConstraintInstr* limit)
- : phi_(phi),
- initial_value_(initial_value),
- increment_(increment),
- limit_(limit),
- bound_(NULL) {}
-
- PhiInstr* phi() const { return phi_; }
- Definition* initial_value() const { return initial_value_; }
- BinarySmiOpInstr* increment() const { return increment_; }
-
- // Outermost constraint that constrains this induction variable into
- // [-inf, X] range.
- ConstraintInstr* limit() const { return limit_; }
-
- // Induction variable from the same join block that has limiting constraint.
- PhiInstr* bound() const { return bound_; }
- void set_bound(PhiInstr* bound) { bound_ = bound; }
-
- private:
- PhiInstr* phi_;
- Definition* initial_value_;
- BinarySmiOpInstr* increment_;
- ConstraintInstr* limit_;
-
- PhiInstr* bound_;
-};
-
-static ConstraintInstr* FindBoundingConstraint(PhiInstr* phi,
- Definition* defn) {
- ConstraintInstr* limit = NULL;
- for (ConstraintInstr* constraint = defn->AsConstraint(); constraint != NULL;
- constraint = constraint->value()->definition()->AsConstraint()) {
- if (constraint->target() == NULL) {
- continue; // Only interested in non-artifical constraints.
- }
-
- Range* constraining_range = constraint->constraint();
- if (constraining_range->min().Equals(RangeBoundary::MinSmi()) &&
- (constraining_range->max().IsSymbol() &&
- phi->IsDominatedBy(constraining_range->max().symbol()))) {
- limit = constraint;
- }
- }
-
- return limit;
-}
-
-static InductionVariableInfo* DetectSimpleInductionVariable(PhiInstr* phi) {
- if (phi->Type()->ToCid() != kSmiCid) {
- return NULL;
- }
-
- if (phi->InputCount() != 2) {
- return NULL;
- }
-
- BitVector* loop_blocks = phi->block()->loop_info()->blocks();
-
- const intptr_t backedge_idx =
- loop_blocks->Contains(phi->block()->PredecessorAt(0)->preorder_number())
- ? 0
- : 1;
-
- Definition* initial_value = phi->InputAt(1 - backedge_idx)->definition();
-
- BinarySmiOpInstr* increment =
- UnwrapConstraint(phi->InputAt(backedge_idx)->definition())
- ->AsBinarySmiOp();
-
- if ((increment != NULL) && (increment->op_kind() == Token::kADD) &&
- (UnwrapConstraint(increment->left()->definition()) == phi) &&
- increment->right()->BindsToConstant() &&
- increment->right()->BoundConstant().IsSmi() &&
- (Smi::Cast(increment->right()->BoundConstant()).Value() == 1)) {
- return new InductionVariableInfo(
- phi, initial_value, increment,
- FindBoundingConstraint(phi, increment->left()->definition()));
- }
-
- return NULL;
-}
-
-// TODO(ajcbik): move induction variable recognition in loop framework
-void RangeAnalysis::DiscoverSimpleInductionVariables() {
- GrowableArray<InductionVariableInfo*> loop_variables;
-
- for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
- !block_it.Done(); block_it.Advance()) {
- BlockEntryInstr* block = block_it.Current();
-
- JoinEntryInstr* join = block->AsJoinEntry();
- if (join != NULL && join->loop_info() != NULL &&
- join->loop_info()->header() == join) {
- loop_variables.Clear();
-
- for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) {
- PhiInstr* current = phi_it.Current();
-
- InductionVariableInfo* info = DetectSimpleInductionVariable(current);
- if (info != NULL) {
- if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
- THR_Print("Simple loop variable: %s bound <%s>\n",
- current->ToCString(),
- info->limit() != NULL ? info->limit()->ToCString() : "?");
- }
-
- loop_variables.Add(info);
- }
- }
- }
-
- InductionVariableInfo* bound = NULL;
- for (intptr_t i = 0; i < loop_variables.length(); i++) {
- if (loop_variables[i]->limit() != NULL) {
- bound = loop_variables[i];
- break;
- }
- }
-
- if (bound != NULL) {
- for (intptr_t i = 0; i < loop_variables.length(); i++) {
- InductionVariableInfo* info = loop_variables[i];
- info->set_bound(bound->phi());
- info->phi()->set_induction_variable_info(info);
- }
- }
- }
-}
-
void RangeAnalysis::CollectValues() {
auto graph_entry = flow_graph_->graph_entry();
@@ -1077,6 +917,8 @@
}
typedef Definition* (BoundsCheckGeneralizer::*PhiBoundFunc)(PhiInstr*,
+ LoopInfo*,
+ InductionVar*,
Instruction*);
// Construct symbolic lower bound for a value at the given point.
@@ -1091,6 +933,52 @@
value, point);
}
+ // Helper methods to implement "older" business logic.
+ // TODO(ajcbik): generalize with new induction variable information
+
+ // Only accept loops with a smi constraint on smi induction.
+ LoopInfo* GetSmiBoundedLoop(PhiInstr* phi) {
+ LoopInfo* loop = phi->GetBlock()->loop_info();
+ if (loop == nullptr) {
+ return nullptr;
+ }
+ ConstraintInstr* limit = loop->limit();
+ if (limit == nullptr) {
+ return nullptr;
+ }
+ Definition* def = UnwrapConstraint(limit->value()->definition());
+ Range* constraining_range = limit->constraint();
+ if (GetSmiInduction(loop, def) != nullptr &&
+ constraining_range->min().Equals(RangeBoundary::MinSmi()) &&
+ constraining_range->max().IsSymbol() &&
+ def->IsDominatedBy(constraining_range->max().symbol())) {
+ return loop;
+ }
+ return nullptr;
+ }
+
+ // Only accept smi linear induction with unit stride.
+ InductionVar* GetSmiInduction(LoopInfo* loop, Definition* def) {
+ if (loop != nullptr && def->Type()->ToCid() == kSmiCid) {
+ InductionVar* induc = loop->LookupInduction(def);
+ if (induc != nullptr && induc->kind() == InductionVar::kLinear &&
+ induc->next()->offset() == 1 && induc->next()->mult() == 0) {
+ return induc;
+ }
+ }
+ return nullptr;
+ }
+
+ // Reconstruct invariant (phi-init is always already in the graph).
+ Definition* GenerateInvariant(InductionVar* induc) {
+ if (induc->mult() == 0) {
+ return flow_graph_->GetConstant(
+ Smi::ZoneHandle(Smi::New(induc->offset())));
+ }
+ ASSERT(induc->offset() == 0 && induc->mult() == 1);
+ return induc->def();
+ }
+
// Construct symbolic bound for a value at the given point:
//
// 1. if value is an induction variable use its bounds;
@@ -1109,8 +997,10 @@
value = UnwrapConstraint(value);
if (value->IsPhi()) {
PhiInstr* phi = value->AsPhi();
- if (phi->induction_variable_info() != NULL) {
- return (this->*phi_bound_func)(phi, point);
+ LoopInfo* loop = GetSmiBoundedLoop(phi);
+ InductionVar* induc = GetSmiInduction(loop, phi);
+ if (induc != nullptr) {
+ return (this->*phi_bound_func)(phi, loop, induc, point);
}
} else if (value->IsBinarySmiOp()) {
BinarySmiOpInstr* bin_op = value->AsBinarySmiOp();
@@ -1131,58 +1021,61 @@
}
}
}
-
return value;
}
- Definition* InductionVariableUpperBound(PhiInstr* phi, Instruction* point) {
- const InductionVariableInfo& info = *phi->induction_variable_info();
- if (info.bound() == phi) {
- if (point->IsDominatedBy(info.limit())) {
- // Given induction variable
- //
- // x <- phi(x0, x + 1)
- //
- // and a constraint x <= M that dominates the given
- // point we conclude that M is an upper bound for x.
- return RangeBoundaryToDefinition(info.limit()->constraint()->max());
- }
- } else {
- const InductionVariableInfo& bound_info =
- *info.bound()->induction_variable_info();
- if (point->IsDominatedBy(bound_info.limit())) {
- // Given two induction variables
- //
- // x <- phi(x0, x + 1)
- // y <- phi(y0, y + 1)
- //
- // and a constraint x <= M that dominates the given
- // point we can conclude that
- //
- // y <= y0 + (M - x0)
- //
- Definition* limit =
- RangeBoundaryToDefinition(bound_info.limit()->constraint()->max());
- BinarySmiOpInstr* loop_length = MakeBinaryOp(
- Token::kSUB, ConstructUpperBound(limit, point),
- ConstructLowerBound(bound_info.initial_value(), point));
- return MakeBinaryOp(Token::kADD,
- ConstructUpperBound(info.initial_value(), point),
- loop_length);
- }
+ Definition* InductionVariableUpperBound(PhiInstr* phi,
+ LoopInfo* loop,
+ InductionVar* induc,
+ Instruction* point) {
+ // Test if limit dominates given point.
+ ConstraintInstr* limit = loop->limit();
+ if (!point->IsDominatedBy(limit)) {
+ return phi;
}
-
- return phi;
+ // Decide between direct or indirect bound.
+ Definition* bounded_phi = UnwrapConstraint(limit->value()->definition());
+ if (bounded_phi == phi) {
+ // Given a smi bounded loop with smi induction variable
+ //
+ // x <- phi(x0, x + 1)
+ //
+ // and a constraint x <= M that dominates the given
+ // point we conclude that M is an upper bound for x.
+ return RangeBoundaryToDefinition(limit->constraint()->max());
+ } else {
+ // Given a smi bounded loop with two smi induction variables
+ //
+ // x <- phi(x0, x + 1)
+ // y <- phi(y0, y + 1)
+ //
+ // and a constraint x <= M that dominates the given
+ // point we can conclude that
+ //
+ // y <= y0 + (M - x0)
+ //
+ InductionVar* bounded_induc = GetSmiInduction(loop, bounded_phi);
+ Definition* x0 = GenerateInvariant(bounded_induc->initial());
+ Definition* y0 = GenerateInvariant(induc->initial());
+ Definition* m = RangeBoundaryToDefinition(limit->constraint()->max());
+ BinarySmiOpInstr* loop_length =
+ MakeBinaryOp(Token::kSUB, ConstructUpperBound(m, point),
+ ConstructLowerBound(x0, point));
+ return MakeBinaryOp(Token::kADD, ConstructUpperBound(y0, point),
+ loop_length);
+ }
}
- Definition* InductionVariableLowerBound(PhiInstr* phi, Instruction* point) {
- // Given induction variable
+ Definition* InductionVariableLowerBound(PhiInstr* phi,
+ LoopInfo* loop,
+ InductionVar* induc,
+ Instruction* point) {
+ // Given a smi bounded loop with smi induction variable
//
// x <- phi(x0, x + 1)
//
// we can conclude that LowerBound(x) == x0.
- const InductionVariableInfo& info = *phi->induction_variable_info();
- return ConstructLowerBound(info.initial_value(), point);
+ return ConstructLowerBound(GenerateInvariant(induc->initial()), point);
}
// Try to re-associate binary operations in the floating DAG of operations
diff --git a/runtime/vm/compiler/backend/range_analysis.h b/runtime/vm/compiler/backend/range_analysis.h
index 0b25eaa..56dc78e 100644
--- a/runtime/vm/compiler/backend/range_analysis.h
+++ b/runtime/vm/compiler/backend/range_analysis.h
@@ -538,8 +538,8 @@
enum JoinOperator { NONE, WIDEN, NARROW };
static char OpPrefix(JoinOperator op);
- // Collect all values that were proven to be smi in smi_values_ array and all
- // CheckSmi instructions in smi_check_ array.
+ // Collect all integer values (smi or int), all 64-bit binary
+ // and shift operations, and all check bounds.
void CollectValues();
// Iterate over smi values and constrain them at branch successors.
@@ -583,8 +583,6 @@
// Convert mint operations that stay within int32 range into Int32 operations.
void NarrowMintToInt32();
- void DiscoverSimpleInductionVariables();
-
// Remove artificial Constraint instructions and replace them with actual
// unconstrained definitions.
void RemoveConstraints();
@@ -600,11 +598,11 @@
Range int64_range_;
- // Value that are known to be smi or mint.
+ // All values that are known to be smi or mint.
GrowableArray<Definition*> values_;
+ // All 64-bit binary and shift operations.
GrowableArray<BinaryInt64OpInstr*> binary_int64_ops_;
-
GrowableArray<ShiftIntegerOpInstr*> shift_int64_ops_;
// All CheckArrayBound instructions.
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index c1d69a5..79574ea 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -126,10 +126,21 @@
intptr_t nullable_cid = kDynamicCid;
bool is_nullable = true;
+ if (field.has_pragma()) {
+ const intptr_t cid = MethodRecognizer::ResultCidFromPragma(field);
+ if (cid != kDynamicCid) {
+ nullable_cid = cid;
+ is_nullable = false;
+ } else if (MethodRecognizer::HasNonNullableResultTypeFromPragma(field)) {
+ is_nullable = false;
+ }
+ }
+
if (field.guarded_cid() != kIllegalCid &&
field.guarded_cid() != kDynamicCid) {
- nullable_cid = field.guarded_cid();
- is_nullable = field.is_nullable();
+ nullable_cid =
+ nullable_cid != kDynamicCid ? nullable_cid : field.guarded_cid();
+ is_nullable = is_nullable && field.is_nullable();
if (thread->isolate()->use_field_guards()) {
ASSERT(parsed_function != nullptr);
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index f17daa6..19c03ae 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -1182,17 +1182,23 @@
}
CompileType PolymorphicInstanceCallInstr::ComputeType() const {
+ bool is_nullable = CompileType::kNullable;
if (IsSureToCallSingleRecognizedTarget()) {
const Function& target = *targets_.TargetAt(0)->target;
- if (target.recognized_kind() != MethodRecognizer::kUnknown) {
- return CompileType::FromCid(MethodRecognizer::ResultCid(target));
+ if (target.has_pragma()) {
+ const intptr_t cid = MethodRecognizer::ResultCidFromPragma(target);
+ if (cid != kDynamicCid) {
+ return CompileType::FromCid(cid);
+ } else if (MethodRecognizer::HasNonNullableResultTypeFromPragma(target)) {
+ is_nullable = CompileType::kNonNullable;
+ }
}
}
if (Isolate::Current()->can_use_strong_mode_types()) {
CompileType* type = instance_call()->Type();
TraceStrongModeType(this, type);
- return *type;
+ return is_nullable ? *type : type->CopyNonNullable();
}
return CompileType::Dynamic();
@@ -1207,8 +1213,15 @@
return *inferred_type;
}
- if (function_.recognized_kind() != MethodRecognizer::kUnknown) {
- return CompileType::FromCid(MethodRecognizer::ResultCid(function_));
+ bool is_nullable = CompileType::kNullable;
+ if (function_.has_pragma()) {
+ const intptr_t cid = MethodRecognizer::ResultCidFromPragma(function_);
+ if (cid != kDynamicCid) {
+ return CompileType::FromCid(cid);
+ }
+ if (MethodRecognizer::HasNonNullableResultTypeFromPragma(function_)) {
+ is_nullable = CompileType::kNonNullable;
+ }
}
if (Isolate::Current()->can_use_strong_mode_types()) {
@@ -1219,8 +1232,8 @@
// non-instantiated types properly.
if (result_type.IsInstantiated()) {
TraceStrongModeType(this, result_type);
- const bool is_nullable =
- (inferred_type == NULL) || inferred_type->is_nullable();
+ is_nullable = is_nullable &&
+ (inferred_type == nullptr || inferred_type->is_nullable());
return CompileType::FromAbstractType(result_type, is_nullable);
}
}
@@ -1319,11 +1332,9 @@
}
const Isolate* isolate = Isolate::Current();
- intptr_t cid = kDynamicCid;
const AbstractType* abstract_type = NULL;
if (isolate->can_use_strong_mode_types() ||
(field_type.IsFunctionType() || field_type.HasTypeClass())) {
- cid = kIllegalCid; // Abstract type is known, calculate cid lazily.
abstract_type = &field_type;
TraceStrongModeType(this, *abstract_type);
}
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index 948259e..1dd24e3 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -187,6 +187,10 @@
VisitInstanceCall(call);
}
}
+ } else if (auto static_call = instr->AsStaticCall()) {
+ // If TFA devirtualized instance calls to static calls we also want to
+ // process them here.
+ VisitStaticCall(static_call);
} else if (instr->IsPolymorphicInstanceCall()) {
SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall());
}
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index 988d0834..daeb0fe 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -270,9 +270,7 @@
INVOKE_PASS(WriteBarrierElimination);
INVOKE_PASS(FinalizeGraph);
INVOKE_PASS(AllocateRegisters);
- if (mode == kJIT) {
- INVOKE_PASS(ReorderBlocks);
- }
+ INVOKE_PASS(ReorderBlocks);
}
COMPILER_PASS(ComputeSSA, {
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index 4e54a2b..eadab31 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -639,8 +639,7 @@
JoinEntryInstr* nsm = BuildJoinEntry();
Fragment failing(nsm);
- const Code& nsm_handler =
- Code::ZoneHandle(StubCode::CallClosureNoSuchMethod_entry()->code());
+ const Code& nsm_handler = StubCode::CallClosureNoSuchMethod();
failing += LoadArgDescriptor();
failing += TailCall(nsm_handler);
diff --git a/runtime/vm/compiler/frontend/constant_evaluator.cc b/runtime/vm/compiler/frontend/constant_evaluator.cc
index 19e33c2..872e7f2 100644
--- a/runtime/vm/compiler/frontend/constant_evaluator.cc
+++ b/runtime/vm/compiler/frontend/constant_evaluator.cc
@@ -254,8 +254,6 @@
}
RawObject* ConstantEvaluator::EvaluateAnnotations() {
- BailoutIfBackgroundCompilation();
-
intptr_t list_length = helper_->ReadListLength(); // read list length.
const Array& metadata_values =
Array::Handle(Z, Array::New(list_length, H.allocation_space()));
@@ -858,6 +856,10 @@
}
void ConstantEvaluator::EvaluateConstantExpression() {
+ // Please note that this constants array is constructed exactly once, see
+ // ReadConstantTable() and is immutable from that point on, so there is no
+ // need to guard against concurrent access between mutator and background
+ // compiler.
KernelConstantsMap constant_map(H.constants().raw());
result_ ^= constant_map.GetOrDie(helper_->ReadUInt());
ASSERT(constant_map.Release().raw() == H.constants().raw());
@@ -1042,13 +1044,16 @@
if (script_.compile_time_constants() == Array::null()) {
return false;
}
- KernelConstantsMap constants(script_.compile_time_constants());
- *value ^= constants.GetOrNull(kernel_offset + helper_->data_program_offset_,
- &is_present);
- // Mutator compiler thread may add constants while background compiler
- // is running, and thus change the value of 'compile_time_constants';
- // do not assert that 'compile_time_constants' has not changed.
- constants.Release();
+ {
+ // Any access to constants arrays must be locked since mutator and
+ // background compiler can access the array at the same time.
+ SafepointMutexLocker ml(H.thread()->isolate()->kernel_constants_mutex());
+
+ KernelConstantsMap constants(script_.compile_time_constants());
+ *value ^= constants.GetOrNull(kernel_offset + helper_->data_program_offset_,
+ &is_present);
+ constants.Release();
+ }
return is_present;
}
@@ -1071,10 +1076,16 @@
HashTables::New<KernelConstantsMap>(kInitialConstMapSize, Heap::kNew));
script_.set_compile_time_constants(array);
}
- KernelConstantsMap constants(script_.compile_time_constants());
- constants.InsertNewOrGetValue(kernel_offset + helper_->data_program_offset_,
- value);
- script_.set_compile_time_constants(constants.Release());
+ {
+ // Any access to constants arrays must be locked since mutator and
+ // background compiler can access the array at the same time.
+ SafepointMutexLocker ml(H.thread()->isolate()->kernel_constants_mutex());
+
+ KernelConstantsMap constants(script_.compile_time_constants());
+ constants.InsertNewOrGetValue(kernel_offset + helper_->data_program_offset_,
+ value);
+ script_.set_compile_time_constants(constants.Release());
+ }
}
ConstantHelper::ConstantHelper(Zone* zone,
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index e5b3cf0..8524fd8 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -35,10 +35,6 @@
return klass;
}
-bool StreamingFlowGraphBuilder::optimizing() {
- return flow_graph_builder_->optimizing_;
-}
-
FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldInitializer() {
FieldHelper field_helper(this);
field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
@@ -1633,25 +1629,30 @@
Fragment StreamingFlowGraphBuilder::BuildEntryPointsIntrospection() {
if (!FLAG_enable_testing_pragmas) return Drop();
- Function& function = Function::Handle(parsed_function()->function().raw());
+ auto& function = Function::Handle(Z, parsed_function()->function().raw());
if (function.IsImplicitClosureFunction()) {
- const Function& parent =
- Function::ZoneHandle(Z, function.parent_function());
- const String& func_name = String::ZoneHandle(Z, parent.name());
- const Class& owner = Class::ZoneHandle(Z, parent.Owner());
+ const auto& parent = Function::Handle(Z, function.parent_function());
+ const auto& func_name = String::Handle(Z, parent.name());
+ const auto& owner = Class::Handle(Z, parent.Owner());
function = owner.LookupFunction(func_name);
}
- Object& options = Object::Handle();
- if (!function.FindPragma(I, Symbols::vm_trace_entrypoints(), &options) ||
+ auto& tmp = Object::Handle(Z);
+ tmp = function.Owner();
+ tmp = Class::Cast(tmp).library();
+ auto& library = Library::Cast(tmp);
+
+ Object& options = Object::Handle(Z);
+ if (!library.FindPragma(H.thread(), function, Symbols::vm_trace_entrypoints(),
+ &options) ||
options.IsNull() || !options.IsClosure()) {
return Drop();
}
- Closure& closure = Closure::ZoneHandle(Z, Closure::Cast(options).raw());
+ auto& closure = Closure::ZoneHandle(Z, Closure::Cast(options).raw());
LocalVariable* entry_point_num = MakeTemporary();
- String& function_name = String::ZoneHandle(
+ auto& function_name = String::ZoneHandle(
Z, String::New(function.ToLibNamePrefixedQualifiedCString(), Heap::kOld));
if (parsed_function()->function().IsImplicitClosureFunction()) {
function_name = String::Concat(
@@ -1669,7 +1670,7 @@
call_hook += Constant(Function::ZoneHandle(Z, closure.function()));
call_hook += B->ClosureCall(TokenPosition::kNoSource,
/*type_args_len=*/0, /*argument_count=*/3,
- /*argument_names=*/Array::Handle());
+ /*argument_names=*/Array::ZoneHandle(Z));
call_hook += Drop(); // result of closure call
call_hook += Drop(); // entrypoint number
return call_hook;
@@ -3503,11 +3504,6 @@
}
}
-static bool IsNumberLiteral(Tag tag) {
- return tag == kNegativeIntLiteral || tag == kPositiveIntLiteral ||
- tag == kSpecializedIntLiteral || tag == kDoubleLiteral;
-}
-
Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) {
const intptr_t offset = ReaderOffset() - 1; // Include the tag.
const TokenPosition position = ReadPosition(); // read position.
@@ -3521,39 +3517,6 @@
call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
const Tag receiver_tag = PeekTag(); // peek tag for receiver.
- if (IsNumberLiteral(receiver_tag) &&
- (!optimizing() || constant_evaluator_.IsCached(offset))) {
- const intptr_t before_branch_offset = ReaderOffset();
-
- SkipExpression(); // read receiver (it's just a number literal).
-
- const String& name = ReadNameAsMethodName(); // read name.
- const Token::Kind token_kind =
- MethodTokenRecognizer::RecognizeTokenKind(name);
- intptr_t argument_count = PeekArgumentsCount() + 1;
-
- if ((argument_count == 1) && (token_kind == Token::kNEGATE)) {
- const Object& result = Object::ZoneHandle(
- Z, constant_evaluator_.EvaluateExpressionSafe(offset));
- if (!result.IsError()) {
- SkipArguments(); // read arguments.
- SkipCanonicalNameReference(); // read interface_target_reference.
- return Constant(result);
- }
- } else if ((argument_count == 2) &&
- Token::IsBinaryArithmeticOperator(token_kind) &&
- IsNumberLiteral(PeekArgumentsFirstPositionalTag())) {
- const Object& result = Object::ZoneHandle(
- Z, constant_evaluator_.EvaluateExpressionSafe(offset));
- if (!result.IsError()) {
- SkipArguments(); // read arguments.
- SkipCanonicalNameReference(); // read interface_target_reference.
- return Constant(result);
- }
- }
-
- SetOffset(before_branch_offset);
- }
bool is_unchecked_closure_call = false;
bool is_unchecked_call = false;
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 6a1e201..b16d914 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -54,8 +54,6 @@
Fragment BuildStatementAt(intptr_t kernel_offset);
private:
- bool optimizing();
-
Thread* thread() const { return flow_graph_builder_->thread_; }
FlowGraph* BuildGraphOfFieldInitializer();
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 64485a3..348d98f 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -546,8 +546,8 @@
call->set_is_known_list_constructor(true);
return;
}
- if (target.recognized_kind() != MethodRecognizer::kUnknown) {
- intptr_t recognized_cid = MethodRecognizer::ResultCid(target);
+ if (target.has_pragma()) {
+ intptr_t recognized_cid = MethodRecognizer::ResultCidFromPragma(target);
if (recognized_cid != kDynamicCid) {
ASSERT((result_type == NULL) || (result_type->cid == kDynamicCid) ||
(result_type->cid == recognized_cid));
diff --git a/runtime/vm/compiler/intrinsifier.cc b/runtime/vm/compiler/intrinsifier.cc
index bf445f5..4a22001 100644
--- a/runtime/vm/compiler/intrinsifier.cc
+++ b/runtime/vm/compiler/intrinsifier.cc
@@ -87,7 +87,7 @@
IntrinsicDesc* intrinsics;
};
-#define DEFINE_INTRINSIC(class_name, function_name, destination, type, fp) \
+#define DEFINE_INTRINSIC(class_name, function_name, destination, fp) \
{#class_name, #function_name},
// clang-format off
@@ -230,7 +230,7 @@
new FlowGraph(parsed_function, graph_entry, block_id, prologue_info);
const Function& function = parsed_function.function();
switch (function.recognized_kind()) {
-#define EMIT_CASE(class_name, function_name, enum_name, type, fp) \
+#define EMIT_CASE(class_name, function_name, enum_name, fp) \
case MethodRecognizer::k##enum_name: \
if (!Build_##enum_name(graph)) return false; \
break;
@@ -300,7 +300,7 @@
#define EMIT_BREAKPOINT()
#endif
-#define EMIT_CASE(class_name, function_name, enum_name, type, fp) \
+#define EMIT_CASE(class_name, function_name, enum_name, fp) \
case MethodRecognizer::k##enum_name: { \
compiler->assembler()->Comment("Intrinsic"); \
Label normal_ir_body; \
diff --git a/runtime/vm/compiler/intrinsifier.h b/runtime/vm/compiler/intrinsifier.h
index be8a563..23d5436 100644
--- a/runtime/vm/compiler/intrinsifier.h
+++ b/runtime/vm/compiler/intrinsifier.h
@@ -43,7 +43,7 @@
static bool CanIntrinsify(const Function& function);
-#define DECLARE_FUNCTION(class_name, function_name, enum_name, type, fp) \
+#define DECLARE_FUNCTION(class_name, function_name, enum_name, fp) \
static void enum_name(Assembler* assembler, Label* normal_ir_body);
ALL_INTRINSICS_LIST(DECLARE_FUNCTION)
@@ -55,7 +55,7 @@
#undef DECLARE_FUNCTION
#if !defined(TARGET_ARCH_DBC)
-#define DECLARE_FUNCTION(class_name, function_name, enum_name, type, fp) \
+#define DECLARE_FUNCTION(class_name, function_name, enum_name, fp) \
static bool Build_##enum_name(FlowGraph* flow_graph);
GRAPH_INTRINSICS_LIST(DECLARE_FUNCTION)
diff --git a/runtime/vm/compiler/intrinsifier_dbc.cc b/runtime/vm/compiler/intrinsifier_dbc.cc
index 0cad04a..b09a15f 100644
--- a/runtime/vm/compiler/intrinsifier_dbc.cc
+++ b/runtime/vm/compiler/intrinsifier_dbc.cc
@@ -25,7 +25,7 @@
return -1;
}
-#define DEFINE_FUNCTION(class_name, test_function_name, enum_name, type, fp) \
+#define DEFINE_FUNCTION(class_name, test_function_name, enum_name, fp) \
void Intrinsifier::enum_name(Assembler* assembler, Label* normal_ir_body) { \
if (Simulator::IsSupportedIntrinsic(Simulator::k##enum_name##Intrinsic)) { \
assembler->Intrinsic(Simulator::k##enum_name##Intrinsic); \
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index 972285d..89f360a 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -110,7 +110,7 @@
FLAG_optimization_counter_threshold = -1;
FLAG_polymorphic_with_deopt = false;
FLAG_precompiled_mode = true;
- FLAG_reorder_basic_blocks = false;
+ FLAG_reorder_basic_blocks = true;
FLAG_use_field_guards = false;
FLAG_use_cha_deopt = false;
@@ -1018,7 +1018,7 @@
// The non-optimizing compiler can get an unhandled exception
// due to OOM or Stack overflow errors, it should not however
// bail out.
- ASSERT(error.IsUnhandledException() ||
+ ASSERT(error.IsUnhandledException() || error.IsUnwindError() ||
(error.IsLanguageError() &&
LanguageError::Cast(error).kind() != Report::kBailout));
return error.raw();
@@ -1362,7 +1362,7 @@
#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_DBC) && \
!defined(TARGET_ARCH_IA32)
if (FLAG_precompiled_mode) {
- return Precompiler::EvaluateStaticInitializer(field);
+ UNREACHABLE();
}
#endif
ASSERT(field.is_static());
@@ -1436,7 +1436,7 @@
#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_DBC) && \
!defined(TARGET_ARCH_IA32)
if (FLAG_precompiled_mode) {
- return Precompiler::ExecuteOnce(fragment);
+ UNREACHABLE();
}
#endif
LongJumpScope jump;
diff --git a/runtime/vm/compiler/method_recognizer.cc b/runtime/vm/compiler/method_recognizer.cc
index d3dbb90..be12f08 100644
--- a/runtime/vm/compiler/method_recognizer.cc
+++ b/runtime/vm/compiler/method_recognizer.cc
@@ -35,20 +35,29 @@
}
}
-intptr_t MethodRecognizer::ResultCid(const Function& function) {
- // Use the 'vm:exact-result-type' annotation if available. This can only be
- // used within the core library, see 'result_type_pragma.md', detail 1.2 for
- // explanation.
- Class& cls = Thread::Current()->ClassHandle();
- Library& lib = Thread::Current()->LibraryHandle();
- cls = function.Owner();
- lib = cls.library();
- const bool can_use_pragma = lib.IsAnyCoreLibrary();
- cls = Class::null();
+intptr_t MethodRecognizer::ResultCidFromPragma(
+ const Object& function_or_field) {
+ // TODO(vm-team): The caller should only call us if the
+ // function_or_field.has_pragma(). If this method turns out to be a
+ // performance problem nonetheless, we could consider adding a cache.
+ auto T = Thread::Current();
+ auto Z = T->zone();
+ auto& klass = Class::Handle(Z);
+ if (function_or_field.IsFunction()) {
+ auto& function = Function::Cast(function_or_field);
+ ASSERT(function.has_pragma());
+ klass = function.Owner();
+ } else {
+ auto& field = Field::Cast(function_or_field);
+ ASSERT(field.has_pragma());
+ klass = field.Owner();
+ }
+ auto& library = Library::Handle(Z, klass.library());
+ const bool can_use_pragma = library.IsAnyCoreLibrary();
if (can_use_pragma) {
- Isolate* I = Isolate::Current();
- auto& option = Object::Handle();
- if (function.FindPragma(I, Symbols::vm_exact_result_type(), &option)) {
+ auto& option = Object::Handle(Z);
+ if (library.FindPragma(T, function_or_field,
+ Symbols::vm_exact_result_type(), &option)) {
if (option.IsType()) {
return Type::Cast(option).type_class_id();
} else if (option.IsString()) {
@@ -68,17 +77,13 @@
}
}
if (!parse_failure && library_end > 0) {
- auto& libraryUri = String::Handle(
- String::SubString(str, 0, library_end, Heap::kOld));
- auto& className = String::Handle(
- String::SubString(str, library_end + 1,
- str.Length() - library_end - 1, Heap::kOld));
-
- Library& lib = Library::Handle(
- Library::LookupLibrary(Thread::Current(), libraryUri));
- if (!lib.IsNull()) {
- Class& klass =
- Class::Handle(lib.LookupClassAllowPrivate(className));
+ auto& tmp = String::Handle(Z);
+ tmp = String::SubString(str, 0, library_end, Heap::kOld);
+ library = Library::LookupLibrary(Thread::Current(), tmp);
+ if (!library.IsNull()) {
+ tmp = String::SubString(str, library_end + 1,
+ str.Length() - library_end - 1, Heap::kOld);
+ klass = library.LookupClassAllowPrivate(tmp);
if (!klass.IsNull()) {
return klass.id();
}
@@ -88,31 +93,35 @@
}
}
- // No result-type annotation can be used, so fall back on the table of
- // recognized methods.
- switch (function.recognized_kind()) {
-#define DEFINE_CASE(cname, fname, ename, result_type, fingerprint) \
- case k##ename: { \
- const intptr_t cid = k##result_type##Cid; \
- if (cid != kDynamicCid) { \
- String& err = String::Handle(); \
- err = function.QualifiedScrubbedName(); \
- err = String::Concat( \
- err, \
- String::Handle(String::New(" (MethodRecognizer::k" #ename \
- ") should be using pragma annotation" \
- " rather than method recognizer.", \
- Heap::kOld)), \
- Heap::kOld); \
- FATAL(err.ToCString()); \
- } \
- return cid; \
+ return kDynamicCid;
+}
+
+bool MethodRecognizer::HasNonNullableResultTypeFromPragma(
+ const Object& function_or_field) {
+ auto T = Thread::Current();
+ auto Z = T->zone();
+ auto& klass = Class::Handle(Z);
+ if (function_or_field.IsFunction()) {
+ auto& function = Function::Cast(function_or_field);
+ ASSERT(function.has_pragma());
+ klass = function.Owner();
+ } else {
+ auto& field = Field::Cast(function_or_field);
+ ASSERT(field.has_pragma());
+ klass = field.Owner();
}
- RECOGNIZED_LIST(DEFINE_CASE)
-#undef DEFINE_CASE
- default:
- return kDynamicCid;
+ auto& library = Library::Handle(Z, klass.library());
+ const bool can_use_pragma = library.IsAnyCoreLibrary();
+ if (can_use_pragma) {
+ auto& option = Object::Handle(Z);
+ if (library.FindPragma(T, function_or_field,
+ Symbols::vm_non_nullable_result_type(), &option)) {
+ return true;
+ }
}
+
+ // If nothing said otherwise, the return type is nullable.
+ return false;
}
intptr_t MethodRecognizer::MethodKindToReceiverCid(Kind kind) {
@@ -201,8 +210,7 @@
return kIllegalCid;
}
-#define KIND_TO_STRING(class_name, function_name, enum_name, type, fp) \
- #enum_name,
+#define KIND_TO_STRING(class_name, function_name, enum_name, fp) #enum_name,
static const char* recognized_list_method_name[] = {
"Unknown", RECOGNIZED_LIST(KIND_TO_STRING)};
#undef KIND_TO_STRING
@@ -219,7 +227,7 @@
Libraries(&libs);
Function& func = Function::Handle();
-#define SET_RECOGNIZED_KIND(class_name, function_name, enum_name, type, fp) \
+#define SET_RECOGNIZED_KIND(class_name, function_name, enum_name, fp) \
func = Library::GetFunction(libs, #class_name, #function_name); \
if (!func.IsNull()) { \
CHECK_FINGERPRINT3(func, class_name, function_name, enum_name, fp); \
@@ -279,7 +287,7 @@
GrowableArray<Library*> libs(3);
Libraries(&libs);
-#define ADD_RECOGNIZED_METHOD(class_name, function_name, enum_name, type, fp) \
+#define ADD_RECOGNIZED_METHOD(class_name, function_name, enum_name, fp) \
func = Library::GetFunction(libs, #class_name, #function_name); \
methods.Add(func);
diff --git a/runtime/vm/compiler/method_recognizer.h b/runtime/vm/compiler/method_recognizer.h
index d53528c..c3310b8 100644
--- a/runtime/vm/compiler/method_recognizer.h
+++ b/runtime/vm/compiler/method_recognizer.h
@@ -17,337 +17,307 @@
// correct fingerprint from the mismatch error (or use Library::GetFunction()
// and print func.SourceFingerprint()).
#define OTHER_RECOGNIZED_LIST(V) \
- V(::, identical, ObjectIdentical, Bool, 0x49c6e96a) \
- V(ClassID, getID, ClassIDgetID, Smi, 0x7b18b257) \
- V(Object, Object., ObjectConstructor, Dynamic, 0x681617fe) \
- V(List, ., ListFactory, Dynamic, 0x629f8324) \
- V(_List, ., ObjectArrayAllocate, Array, 0x2121902f) \
- V(_TypedList, _getInt8, ByteArrayBaseGetInt8, Smi, 0x7041895a) \
- V(_TypedList, _getUint8, ByteArrayBaseGetUint8, Smi, 0x336fa3ea) \
- V(_TypedList, _getInt16, ByteArrayBaseGetInt16, Smi, 0x231bbe2e) \
- V(_TypedList, _getUint16, ByteArrayBaseGetUint16, Smi, 0x0371785f) \
- V(_TypedList, _getInt32, ByteArrayBaseGetInt32, Dynamic, 0x65ab3a20) \
- V(_TypedList, _getUint32, ByteArrayBaseGetUint32, Dynamic, 0x0cb0fcf6) \
- V(_TypedList, _getInt64, ByteArrayBaseGetInt64, Dynamic, 0x7db75d78) \
- V(_TypedList, _getUint64, ByteArrayBaseGetUint64, Dynamic, 0x1487cfc6) \
- V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, Double, 0x6674ea6f) \
- V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, Double, 0x236c6e7a) \
- V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, Float32x4, \
- 0x5c367ffb) \
- V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, Int32x4, 0x772d1c0f) \
- V(_TypedList, _setInt8, ByteArrayBaseSetInt8, Dynamic, 0x12bae36a) \
- V(_TypedList, _setUint8, ByteArrayBaseSetUint8, Dynamic, 0x15821cc9) \
- V(_TypedList, _setInt16, ByteArrayBaseSetInt16, Dynamic, 0x1f8237fa) \
- V(_TypedList, _setUint16, ByteArrayBaseSetUint16, Dynamic, 0x181e5d16) \
- V(_TypedList, _setInt32, ByteArrayBaseSetInt32, Dynamic, 0x7ddb9f87) \
- V(_TypedList, _setUint32, ByteArrayBaseSetUint32, Dynamic, 0x74094f8d) \
- V(_TypedList, _setInt64, ByteArrayBaseSetInt64, Dynamic, 0x4741396e) \
- V(_TypedList, _setUint64, ByteArrayBaseSetUint64, Dynamic, 0x3b398ae4) \
- V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, Dynamic, 0x03db087b) \
- V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, Dynamic, 0x38a80b0d) \
- V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, Dynamic, 0x40052c4e) \
- V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, Dynamic, 0x07b89f54) \
- V(::, _toClampedUint8, ConvertIntToClampedUint8, Smi, 0x564b0435) \
- V(_StringBase, _interpolate, StringBaseInterpolate, Dynamic, 0x01ecb15a) \
- V(_IntegerImplementation, toDouble, IntegerToDouble, Double, 0x05da96ed) \
- V(_Double, _add, DoubleAdd, Double, 0x2a38277b) \
- V(_Double, _sub, DoubleSub, Double, 0x4f466391) \
- V(_Double, _mul, DoubleMul, Double, 0x175e4f66) \
- V(_Double, _div, DoubleDiv, Double, 0x0854181b) \
- V(::, min, MathMin, Dynamic, 0x32ebc57d) \
- V(::, max, MathMax, Dynamic, 0x377e8889) \
- V(::, _doublePow, MathDoublePow, Double, 0x5add0ec1) \
- V(::, _intPow, MathIntPow, Dynamic, 0x11b45569) \
- V(Float32x4, Float32x4., Float32x4Constructor, Float32x4, 0x26ea459b) \
- V(Float32x4, Float32x4.zero, Float32x4Zero, Float32x4, 0x16eca604) \
- V(Float32x4, Float32x4.splat, Float32x4Splat, Float32x4, 0x694e83e3) \
- V(Float32x4, Float32x4.fromInt32x4Bits, Int32x4ToFloat32x4, Float32x4, \
- 0x2f62ebd3) \
- V(Float32x4, Float32x4.fromFloat64x2, Float64x2ToFloat32x4, Float32x4, \
- 0x50ed6910) \
- V(_Float32x4, shuffle, Float32x4Shuffle, Float32x4, 0x7829101f) \
- V(_Float32x4, shuffleMix, Float32x4ShuffleMix, Float32x4, 0x4182c06b) \
- V(_Float32x4, get:signMask, Float32x4GetSignMask, Dynamic, 0x1d08b351) \
- V(_Float32x4, equal, Float32x4Equal, Int32x4, 0x11adb239) \
- V(_Float32x4, greaterThan, Float32x4GreaterThan, Int32x4, 0x48adaf58) \
- V(_Float32x4, greaterThanOrEqual, Float32x4GreaterThanOrEqual, Int32x4, \
- 0x32db94ca) \
- V(_Float32x4, lessThan, Float32x4LessThan, Int32x4, 0x425b000c) \
- V(_Float32x4, lessThanOrEqual, Float32x4LessThanOrEqual, Int32x4, \
- 0x0278c2f8) \
- V(_Float32x4, notEqual, Float32x4NotEqual, Int32x4, 0x2987cd26) \
- V(_Float32x4, min, Float32x4Min, Float32x4, 0x5ed74b6f) \
- V(_Float32x4, max, Float32x4Max, Float32x4, 0x68696442) \
- V(_Float32x4, scale, Float32x4Scale, Float32x4, 0x704e4122) \
- V(_Float32x4, sqrt, Float32x4Sqrt, Float32x4, 0x2c967a6f) \
- V(_Float32x4, reciprocalSqrt, Float32x4ReciprocalSqrt, Float32x4, \
- 0x6264bfe8) \
- V(_Float32x4, reciprocal, Float32x4Reciprocal, Float32x4, 0x3cd7e819) \
- V(_Float32x4, unary-, Float32x4Negate, Float32x4, 0x37accb52) \
- V(_Float32x4, abs, Float32x4Abs, Float32x4, 0x471cdd87) \
- V(_Float32x4, clamp, Float32x4Clamp, Float32x4, 0x2cb30492) \
- V(_Float32x4, withX, Float32x4WithX, Float32x4, 0x4e336aff) \
- V(_Float32x4, withY, Float32x4WithY, Float32x4, 0x0a72b910) \
- V(_Float32x4, withZ, Float32x4WithZ, Float32x4, 0x31e93658) \
- V(_Float32x4, withW, Float32x4WithW, Float32x4, 0x60ddc105) \
- V(Float64x2, Float64x2., Float64x2Constructor, Float64x2, 0x43054b9f) \
- V(Float64x2, Float64x2.zero, Float64x2Zero, Float64x2, 0x4af12f9d) \
- V(Float64x2, Float64x2.splat, Float64x2Splat, Float64x2, 0x134edef0) \
- V(Float64x2, Float64x2.fromFloat32x4, Float32x4ToFloat64x2, Float64x2, \
- 0x17d6b5e4) \
- V(_Float64x2, get:x, Float64x2GetX, Double, 0x58c09c58) \
- V(_Float64x2, get:y, Float64x2GetY, Double, 0x3cf5e5b8) \
- V(_Float64x2, unary-, Float64x2Negate, Float64x2, 0x415ca009) \
- V(_Float64x2, abs, Float64x2Abs, Float64x2, 0x031f9e47) \
- V(_Float64x2, sqrt, Float64x2Sqrt, Float64x2, 0x77f711dd) \
- V(_Float64x2, get:signMask, Float64x2GetSignMask, Dynamic, 0x27deda4b) \
- V(_Float64x2, scale, Float64x2Scale, Float64x2, 0x26830a61) \
- V(_Float64x2, withX, Float64x2WithX, Float64x2, 0x1d2bcaf5) \
- V(_Float64x2, withY, Float64x2WithY, Float64x2, 0x383ed6ac) \
- V(_Float64x2, min, Float64x2Min, Float64x2, 0x28d7ddf6) \
- V(_Float64x2, max, Float64x2Max, Float64x2, 0x0bd74e5b) \
- V(Int32x4, Int32x4., Int32x4Constructor, Int32x4, 0x480555a9) \
- V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, Int32x4, 0x36aa6963) \
- V(Int32x4, Int32x4.fromFloat32x4Bits, Float32x4ToInt32x4, Int32x4, \
- 0x6715388a) \
- V(_Int32x4, get:flagX, Int32x4GetFlagX, Bool, 0x56396c82) \
- V(_Int32x4, get:flagY, Int32x4GetFlagY, Bool, 0x44704738) \
- V(_Int32x4, get:flagZ, Int32x4GetFlagZ, Bool, 0x20d6ff37) \
- V(_Int32x4, get:flagW, Int32x4GetFlagW, Bool, 0x5045616a) \
- V(_Int32x4, get:signMask, Int32x4GetSignMask, Dynamic, 0x2c1fb2a3) \
- V(_Int32x4, shuffle, Int32x4Shuffle, Int32x4, 0x20bc0b16) \
- V(_Int32x4, shuffleMix, Int32x4ShuffleMix, Int32x4, 0x5c7056e1) \
- V(_Int32x4, select, Int32x4Select, Float32x4, 0x6b49654f) \
- V(_Int32x4, withFlagX, Int32x4WithFlagX, Int32x4, 0x0ef58fcf) \
- V(_Int32x4, withFlagY, Int32x4WithFlagY, Int32x4, 0x6485a9c4) \
- V(_Int32x4, withFlagZ, Int32x4WithFlagZ, Int32x4, 0x267acdfa) \
- V(_Int32x4, withFlagW, Int32x4WithFlagW, Int32x4, 0x345ac675) \
- V(_HashVMBase, get:_index, LinkedHashMap_getIndex, TypedDataUint32Array, \
- 0x02477157) \
- V(_HashVMBase, set:_index, LinkedHashMap_setIndex, Dynamic, 0x4fc8d5e0) \
- V(_HashVMBase, get:_data, LinkedHashMap_getData, Array, 0x2d7a70ac) \
- V(_HashVMBase, set:_data, LinkedHashMap_setData, Dynamic, 0x0ec032e8) \
- V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, Smi, 0x088599ed) \
- V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, Dynamic, 0x5f42ca86)\
- V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, Smi, 0x32f3b13b) \
- V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, Dynamic, 0x7219c45b)\
- V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, Smi, \
- 0x558481c2) \
- V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, Dynamic, \
- 0x5aa9888d) \
- V(::, _classRangeCheck, ClassRangeCheck, Bool, 0x2ae76b84) \
- V(::, _classRangeCheckNegative, ClassRangeCheckNegated, Bool, 0x5acdfb75) \
+ V(::, identical, ObjectIdentical, 0x49c6e96a) \
+ V(ClassID, getID, ClassIDgetID, 0x7b18b257) \
+ V(Object, Object., ObjectConstructor, 0x681617fe) \
+ V(List, ., ListFactory, 0x629f8324) \
+ V(_List, ., ObjectArrayAllocate, 0x2121902f) \
+ V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x7041895a) \
+ V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x336fa3ea) \
+ V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x231bbe2e) \
+ V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 0x0371785f) \
+ V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 0x65ab3a20) \
+ V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 0x0cb0fcf6) \
+ V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 0x7db75d78) \
+ V(_TypedList, _getUint64, ByteArrayBaseGetUint64, 0x1487cfc6) \
+ V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 0x6674ea6f) \
+ V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 0x236c6e7a) \
+ V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 0x5c367ffb) \
+ V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 0x772d1c0f) \
+ V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 0x12bae36a) \
+ V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 0x15821cc9) \
+ V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 0x1f8237fa) \
+ V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 0x181e5d16) \
+ V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 0x7ddb9f87) \
+ V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 0x74094f8d) \
+ V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 0x4741396e) \
+ V(_TypedList, _setUint64, ByteArrayBaseSetUint64, 0x3b398ae4) \
+ V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 0x03db087b) \
+ V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x38a80b0d) \
+ V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x40052c4e) \
+ V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x07b89f54) \
+ V(::, _toClampedUint8, ConvertIntToClampedUint8, 0x564b0435) \
+ V(_StringBase, _interpolate, StringBaseInterpolate, 0x01ecb15a) \
+ V(_IntegerImplementation, toDouble, IntegerToDouble, 0x05da96ed) \
+ V(_Double, _add, DoubleAdd, 0x2a38277b) \
+ V(_Double, _sub, DoubleSub, 0x4f466391) \
+ V(_Double, _mul, DoubleMul, 0x175e4f66) \
+ V(_Double, _div, DoubleDiv, 0x0854181b) \
+ V(::, min, MathMin, 0x32ebc57d) \
+ V(::, max, MathMax, 0x377e8889) \
+ V(::, _doublePow, MathDoublePow, 0x5add0ec1) \
+ V(::, _intPow, MathIntPow, 0x11b45569) \
+ V(Float32x4, Float32x4., Float32x4Constructor, 0x26ea459b) \
+ V(Float32x4, Float32x4.zero, Float32x4Zero, 0x16eca604) \
+ V(Float32x4, Float32x4.splat, Float32x4Splat, 0x694e83e3) \
+ V(Float32x4, Float32x4.fromInt32x4Bits, Int32x4ToFloat32x4, 0x2f62ebd3) \
+ V(Float32x4, Float32x4.fromFloat64x2, Float64x2ToFloat32x4, 0x50ed6910) \
+ V(_Float32x4, shuffle, Float32x4Shuffle, 0x7829101f) \
+ V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 0x4182c06b) \
+ V(_Float32x4, get:signMask, Float32x4GetSignMask, 0x1d08b351) \
+ V(_Float32x4, equal, Float32x4Equal, 0x11adb239) \
+ V(_Float32x4, greaterThan, Float32x4GreaterThan, 0x48adaf58) \
+ V(_Float32x4, greaterThanOrEqual, Float32x4GreaterThanOrEqual, 0x32db94ca) \
+ V(_Float32x4, lessThan, Float32x4LessThan, 0x425b000c) \
+ V(_Float32x4, lessThanOrEqual, Float32x4LessThanOrEqual, 0x0278c2f8) \
+ V(_Float32x4, notEqual, Float32x4NotEqual, 0x2987cd26) \
+ V(_Float32x4, min, Float32x4Min, 0x5ed74b6f) \
+ V(_Float32x4, max, Float32x4Max, 0x68696442) \
+ V(_Float32x4, scale, Float32x4Scale, 0x704e4122) \
+ V(_Float32x4, sqrt, Float32x4Sqrt, 0x2c967a6f) \
+ V(_Float32x4, reciprocalSqrt, Float32x4ReciprocalSqrt, 0x6264bfe8) \
+ V(_Float32x4, reciprocal, Float32x4Reciprocal, 0x3cd7e819) \
+ V(_Float32x4, unary-, Float32x4Negate, 0x37accb52) \
+ V(_Float32x4, abs, Float32x4Abs, 0x471cdd87) \
+ V(_Float32x4, clamp, Float32x4Clamp, 0x2cb30492) \
+ V(_Float32x4, withX, Float32x4WithX, 0x4e336aff) \
+ V(_Float32x4, withY, Float32x4WithY, 0x0a72b910) \
+ V(_Float32x4, withZ, Float32x4WithZ, 0x31e93658) \
+ V(_Float32x4, withW, Float32x4WithW, 0x60ddc105) \
+ V(Float64x2, Float64x2., Float64x2Constructor, 0x43054b9f) \
+ V(Float64x2, Float64x2.zero, Float64x2Zero, 0x4af12f9d) \
+ V(Float64x2, Float64x2.splat, Float64x2Splat, 0x134edef0) \
+ V(Float64x2, Float64x2.fromFloat32x4, Float32x4ToFloat64x2, 0x17d6b5e4) \
+ V(_Float64x2, get:x, Float64x2GetX, 0x58c09c58) \
+ V(_Float64x2, get:y, Float64x2GetY, 0x3cf5e5b8) \
+ V(_Float64x2, unary-, Float64x2Negate, 0x415ca009) \
+ V(_Float64x2, abs, Float64x2Abs, 0x031f9e47) \
+ V(_Float64x2, sqrt, Float64x2Sqrt, 0x77f711dd) \
+ V(_Float64x2, get:signMask, Float64x2GetSignMask, 0x27deda4b) \
+ V(_Float64x2, scale, Float64x2Scale, 0x26830a61) \
+ V(_Float64x2, withX, Float64x2WithX, 0x1d2bcaf5) \
+ V(_Float64x2, withY, Float64x2WithY, 0x383ed6ac) \
+ V(_Float64x2, min, Float64x2Min, 0x28d7ddf6) \
+ V(_Float64x2, max, Float64x2Max, 0x0bd74e5b) \
+ V(Int32x4, Int32x4., Int32x4Constructor, 0x480555a9) \
+ V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 0x36aa6963) \
+ V(Int32x4, Int32x4.fromFloat32x4Bits, Float32x4ToInt32x4, 0x6715388a) \
+ V(_Int32x4, get:flagX, Int32x4GetFlagX, 0x56396c82) \
+ V(_Int32x4, get:flagY, Int32x4GetFlagY, 0x44704738) \
+ V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 0x20d6ff37) \
+ V(_Int32x4, get:flagW, Int32x4GetFlagW, 0x5045616a) \
+ V(_Int32x4, get:signMask, Int32x4GetSignMask, 0x2c1fb2a3) \
+ V(_Int32x4, shuffle, Int32x4Shuffle, 0x20bc0b16) \
+ V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 0x5c7056e1) \
+ V(_Int32x4, select, Int32x4Select, 0x6b49654f) \
+ V(_Int32x4, withFlagX, Int32x4WithFlagX, 0x0ef58fcf) \
+ V(_Int32x4, withFlagY, Int32x4WithFlagY, 0x6485a9c4) \
+ V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 0x267acdfa) \
+ V(_Int32x4, withFlagW, Int32x4WithFlagW, 0x345ac675) \
+ V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 0x02477157) \
+ V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 0x4fc8d5e0) \
+ V(_HashVMBase, get:_data, LinkedHashMap_getData, 0x2d7a70ac) \
+ V(_HashVMBase, set:_data, LinkedHashMap_setData, 0x0ec032e8) \
+ V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 0x088599ed) \
+ V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 0x5f42ca86) \
+ V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 0x32f3b13b) \
+ V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 0x7219c45b) \
+ V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 0x558481c2) \
+ V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 0x5aa9888d) \
+ V(::, _classRangeCheck, ClassRangeCheck, 0x2ae76b84) \
+ V(::, _classRangeCheckNegative, ClassRangeCheckNegated, 0x5acdfb75) \
// List of intrinsics:
// (class-name, function-name, intrinsification method, fingerprint).
#define CORE_LIB_INTRINSIC_LIST(V) \
- V(_Smi, ~, Smi_bitNegate, Smi, 0x67299f4f) \
- V(_Smi, get:bitLength, Smi_bitLength, Smi, 0x25b3cb0a) \
- V(_Smi, _bitAndFromSmi, Smi_bitAndFromSmi, Smi, 0x562d5047) \
- V(_BigIntImpl, _lsh, Bigint_lsh, Dynamic, 0x5b6cfc8b) \
- V(_BigIntImpl, _rsh, Bigint_rsh, Dynamic, 0x6ff14a49) \
- V(_BigIntImpl, _absAdd, Bigint_absAdd, Dynamic, 0x5bf14238) \
- V(_BigIntImpl, _absSub, Bigint_absSub, Dynamic, 0x1de5bd32) \
- V(_BigIntImpl, _mulAdd, Bigint_mulAdd, Smi, 0x6f277966) \
- V(_BigIntImpl, _sqrAdd, Bigint_sqrAdd, Smi, 0x68e4c8ea) \
- V(_BigIntImpl, _estimateQuotientDigit, Bigint_estimateQuotientDigit, Smi, \
+ V(_Smi, ~, Smi_bitNegate, 0x67299f4f) \
+ V(_Smi, get:bitLength, Smi_bitLength, 0x25b3cb0a) \
+ V(_Smi, _bitAndFromSmi, Smi_bitAndFromSmi, 0x562d5047) \
+ V(_BigIntImpl, _lsh, Bigint_lsh, 0x5b6cfc8b) \
+ V(_BigIntImpl, _rsh, Bigint_rsh, 0x6ff14a49) \
+ V(_BigIntImpl, _absAdd, Bigint_absAdd, 0x5bf14238) \
+ V(_BigIntImpl, _absSub, Bigint_absSub, 0x1de5bd32) \
+ V(_BigIntImpl, _mulAdd, Bigint_mulAdd, 0x6f277966) \
+ V(_BigIntImpl, _sqrAdd, Bigint_sqrAdd, 0x68e4c8ea) \
+ V(_BigIntImpl, _estimateQuotientDigit, Bigint_estimateQuotientDigit, \
0x35456d91) \
- V(_BigIntMontgomeryReduction, _mulMod, Montgomery_mulMod, Smi, 0x0f7b0375) \
- V(_Double, >, Double_greaterThan, Bool, 0x4f1375a3) \
- V(_Double, >=, Double_greaterEqualThan, Bool, 0x4260c184) \
- V(_Double, <, Double_lessThan, Bool, 0x365d1eba) \
- V(_Double, <=, Double_lessEqualThan, Bool, 0x74b5eb64) \
- V(_Double, ==, Double_equal, Bool, 0x613492fc) \
- V(_Double, +, Double_add, Double, 0x53994370) \
- V(_Double, -, Double_sub, Double, 0x3b69d466) \
- V(_Double, *, Double_mul, Double, 0x2bb9bd5d) \
- V(_Double, /, Double_div, Double, 0x483eee28) \
- V(_Double, get:hashCode, Double_hashCode, Dynamic, 0x702b77b7) \
- V(_Double, get:_identityHashCode, Double_identityHash, Dynamic, 0x7bda5549) \
- V(_Double, get:isNaN, Double_getIsNaN, Bool, 0x0af9d4a9) \
- V(_Double, get:isInfinite, Double_getIsInfinite, Bool, 0x0f7acb47) \
- V(_Double, get:isNegative, Double_getIsNegative, Bool, 0x3a59e7f4) \
- V(_Double, _mulFromInteger, Double_mulFromInteger, Double, 0x2017fcf6) \
- V(_Double, .fromInteger, DoubleFromInteger, Double, 0x6d234f4b) \
- V(_GrowableList, .withData, GrowableArray_Allocate, GrowableObjectArray, \
- 0x28b2138e) \
- V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, Dynamic, 0x380184b1) \
- V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, Dynamic, \
- 0x79b8f955) \
- V(Object, ==, ObjectEquals, Bool, 0x7b32a55a) \
- V(Object, get:runtimeType, ObjectRuntimeType, Type, 0x00e8ab29) \
- V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, Bool, 0x4dc50799) \
- V(_StringBase, get:hashCode, String_getHashCode, Smi, 0x78c3d446) \
- V(_StringBase, get:_identityHashCode, String_identityHash, Smi, 0x0472b1d8) \
- V(_StringBase, get:isEmpty, StringBaseIsEmpty, Bool, 0x4a8b29c8) \
- V(_StringBase, _substringMatches, StringBaseSubstringMatches, Bool, \
- 0x46de4f10) \
- V(_StringBase, [], StringBaseCharAt, Dynamic, 0x7cbb8603) \
- V(_OneByteString, get:hashCode, OneByteString_getHashCode, Smi, 0x78c3d446) \
+ V(_BigIntMontgomeryReduction, _mulMod, Montgomery_mulMod, 0x0f7b0375) \
+ V(_Double, >, Double_greaterThan, 0x4f1375a3) \
+ V(_Double, >=, Double_greaterEqualThan, 0x4260c184) \
+ V(_Double, <, Double_lessThan, 0x365d1eba) \
+ V(_Double, <=, Double_lessEqualThan, 0x74b5eb64) \
+ V(_Double, ==, Double_equal, 0x613492fc) \
+ V(_Double, +, Double_add, 0x53994370) \
+ V(_Double, -, Double_sub, 0x3b69d466) \
+ V(_Double, *, Double_mul, 0x2bb9bd5d) \
+ V(_Double, /, Double_div, 0x483eee28) \
+ V(_Double, get:hashCode, Double_hashCode, 0x702b77b7) \
+ V(_Double, get:_identityHashCode, Double_identityHash, 0x7bda5549) \
+ V(_Double, get:isNaN, Double_getIsNaN, 0x0af9d4a9) \
+ V(_Double, get:isInfinite, Double_getIsInfinite, 0x0f7acb47) \
+ V(_Double, get:isNegative, Double_getIsNegative, 0x3a59e7f4) \
+ V(_Double, _mulFromInteger, Double_mulFromInteger, 0x2017fcf6) \
+ V(_Double, .fromInteger, DoubleFromInteger, 0x6d234f4b) \
+ V(_GrowableList, .withData, GrowableArray_Allocate, 0x28b2138e) \
+ V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, 0x380184b1) \
+ V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, 0x79b8f955) \
+ V(Object, ==, ObjectEquals, 0x7b32a55a) \
+ V(Object, get:runtimeType, ObjectRuntimeType, 0x00e8ab29) \
+ V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, 0x4dc50799) \
+ V(_StringBase, get:hashCode, String_getHashCode, 0x78c3d446) \
+ V(_StringBase, get:_identityHashCode, String_identityHash, 0x0472b1d8) \
+ V(_StringBase, get:isEmpty, StringBaseIsEmpty, 0x4a8b29c8) \
+ V(_StringBase, _substringMatches, StringBaseSubstringMatches, 0x46de4f10) \
+ V(_StringBase, [], StringBaseCharAt, 0x7cbb8603) \
+ V(_OneByteString, get:hashCode, OneByteString_getHashCode, 0x78c3d446) \
V(_OneByteString, _substringUncheckedNative, \
- OneByteString_substringUnchecked, OneByteString, 0x3538ad86) \
- V(_OneByteString, _setAt, OneByteStringSetAt, Dynamic, 0x11ffddd1) \
- V(_OneByteString, _allocate, OneByteString_allocate, OneByteString, \
- 0x74933376) \
- V(_OneByteString, ==, OneByteString_equality, Bool, 0x4eda197e) \
- V(_TwoByteString, ==, TwoByteString_equality, Bool, 0x4eda197e) \
- V(_Type, get:hashCode, Type_getHashCode, Smi, 0x18d1523f) \
- V(::, _getHash, Object_getHash, Smi, 0x2827856d) \
- V(::, _setHash, Object_setHash, Dynamic, 0x690faebd) \
+ OneByteString_substringUnchecked, 0x3538ad86) \
+ V(_OneByteString, _setAt, OneByteStringSetAt, 0x11ffddd1) \
+ V(_OneByteString, _allocate, OneByteString_allocate, 0x74933376) \
+ V(_OneByteString, ==, OneByteString_equality, 0x4eda197e) \
+ V(_TwoByteString, ==, TwoByteString_equality, 0x4eda197e) \
+ V(_Type, get:hashCode, Type_getHashCode, 0x18d1523f) \
+ V(::, _getHash, Object_getHash, 0x2827856d) \
+ V(::, _setHash, Object_setHash, 0x690faebd) \
#define CORE_INTEGER_LIB_INTRINSIC_LIST(V) \
V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger, \
- Dynamic, 0x6a10c54a) \
- V(_IntegerImplementation, +, Integer_add, Dynamic, 0x43d53af7) \
- V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, Dynamic, \
+ 0x6a10c54a) \
+ V(_IntegerImplementation, +, Integer_add, 0x43d53af7) \
+ V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, \
0x3fa4b1ed) \
- V(_IntegerImplementation, -, Integer_sub, Dynamic, 0x2dc22e03) \
+ V(_IntegerImplementation, -, Integer_sub, 0x2dc22e03) \
V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger, \
- Dynamic, 0x3216e299) \
- V(_IntegerImplementation, *, Integer_mul, Dynamic, 0x4e7a1c24) \
+ 0x3216e299) \
+ V(_IntegerImplementation, *, Integer_mul, 0x4e7a1c24) \
V(_IntegerImplementation, _moduloFromInteger, Integer_moduloFromInteger, \
- Dynamic, 0x6348b974) \
- V(_IntegerImplementation, ~/, Integer_truncDivide, Dynamic, 0x4efb2d39) \
- V(_IntegerImplementation, unary-, Integer_negate, Dynamic, 0x428bf6fa) \
+ 0x6348b974) \
+ V(_IntegerImplementation, ~/, Integer_truncDivide, 0x4efb2d39) \
+ V(_IntegerImplementation, unary-, Integer_negate, 0x428bf6fa) \
V(_IntegerImplementation, _bitAndFromInteger, Integer_bitAndFromInteger, \
- Dynamic, 0x395b1678) \
- V(_IntegerImplementation, &, Integer_bitAnd, Dynamic, 0x5ab35f30) \
+ 0x395b1678) \
+ V(_IntegerImplementation, &, Integer_bitAnd, 0x5ab35f30) \
V(_IntegerImplementation, _bitOrFromInteger, Integer_bitOrFromInteger, \
- Dynamic, 0x6a36b395) \
- V(_IntegerImplementation, |, Integer_bitOr, Dynamic, 0x267fa107) \
+ 0x6a36b395) \
+ V(_IntegerImplementation, |, Integer_bitOr, 0x267fa107) \
V(_IntegerImplementation, _bitXorFromInteger, Integer_bitXorFromInteger, \
- Dynamic, 0x72da93f0) \
- V(_IntegerImplementation, ^, Integer_bitXor, Dynamic, 0x0c7b0230) \
+ 0x72da93f0) \
+ V(_IntegerImplementation, ^, Integer_bitXor, 0x0c7b0230) \
V(_IntegerImplementation, _greaterThanFromInteger, \
- Integer_greaterThanFromInt, Bool, 0x4a50ed58) \
- V(_IntegerImplementation, >, Integer_greaterThan, Bool, 0x6599a6e1) \
- V(_IntegerImplementation, ==, Integer_equal, Bool, 0x58abc487) \
- V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger, Bool, \
+ Integer_greaterThanFromInt, 0x4a50ed58) \
+ V(_IntegerImplementation, >, Integer_greaterThan, 0x6599a6e1) \
+ V(_IntegerImplementation, ==, Integer_equal, 0x58abc487) \
+ V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger, \
0x063be842) \
- V(_IntegerImplementation, <, Integer_lessThan, Bool, 0x365d1eba) \
- V(_IntegerImplementation, <=, Integer_lessEqualThan, Bool, 0x74b5eb64) \
- V(_IntegerImplementation, >=, Integer_greaterEqualThan, Bool, 0x4260c184) \
- V(_IntegerImplementation, <<, Integer_shl, Dynamic, 0x371c45fa) \
- V(_IntegerImplementation, >>, Integer_sar, Dynamic, 0x2b630578) \
- V(_Double, toInt, DoubleToInteger, Dynamic, 0x26ef344b) \
+ V(_IntegerImplementation, <, Integer_lessThan, 0x365d1eba) \
+ V(_IntegerImplementation, <=, Integer_lessEqualThan, 0x74b5eb64) \
+ V(_IntegerImplementation, >=, Integer_greaterEqualThan, 0x4260c184) \
+ V(_IntegerImplementation, <<, Integer_shl, 0x371c45fa) \
+ V(_IntegerImplementation, >>, Integer_sar, 0x2b630578) \
+ V(_Double, toInt, DoubleToInteger, 0x26ef344b) \
#define MATH_LIB_INTRINSIC_LIST(V) \
- V(::, sqrt, MathSqrt, Double, 0x70482cf3) \
- V(_Random, _nextState, Random_nextState, Dynamic, 0x2842c4d5) \
+ V(::, sqrt, MathSqrt, 0x70482cf3) \
+ V(_Random, _nextState, Random_nextState, 0x2842c4d5) \
#define GRAPH_MATH_LIB_INTRINSIC_LIST(V) \
- V(::, sin, MathSin, Double, 0x6b7bd98c) \
- V(::, cos, MathCos, Double, 0x459bf5fe) \
- V(::, tan, MathTan, Double, 0x3bcd772a) \
- V(::, asin, MathAsin, Double, 0x2ecc2fcd) \
- V(::, acos, MathAcos, Double, 0x08cf2212) \
- V(::, atan, MathAtan, Double, 0x1e2731d5) \
- V(::, atan2, MathAtan2, Double, 0x39f1fa41) \
+ V(::, sin, MathSin, 0x6b7bd98c) \
+ V(::, cos, MathCos, 0x459bf5fe) \
+ V(::, tan, MathTan, 0x3bcd772a) \
+ V(::, asin, MathAsin, 0x2ecc2fcd) \
+ V(::, acos, MathAcos, 0x08cf2212) \
+ V(::, atan, MathAtan, 0x1e2731d5) \
+ V(::, atan2, MathAtan2, 0x39f1fa41) \
#define TYPED_DATA_LIB_INTRINSIC_LIST(V) \
- V(Int8List, ., TypedData_Int8Array_factory, TypedDataInt8Array, 0x7e39a3a1) \
- V(Uint8List, ., TypedData_Uint8Array_factory, TypedDataUint8Array, \
- 0x3a79adf7) \
- V(Uint8ClampedList, ., TypedData_Uint8ClampedArray_factory, \
- TypedDataUint8ClampedArray, 0x67f38395) \
- V(Int16List, ., TypedData_Int16Array_factory, TypedDataInt16Array, \
- 0x6477bda8) \
- V(Uint16List, ., TypedData_Uint16Array_factory, TypedDataUint16Array, \
- 0x5707c5a2) \
- V(Int32List, ., TypedData_Int32Array_factory, TypedDataInt32Array, \
- 0x2b96ec0e) \
- V(Uint32List, ., TypedData_Uint32Array_factory, \
- TypedDataUint32Array, 0x0c1c0d62) \
- V(Int64List, ., TypedData_Int64Array_factory, \
- TypedDataInt64Array, 0x279ab485) \
- V(Uint64List, ., TypedData_Uint64Array_factory, \
- TypedDataUint64Array, 0x7bcb89c2) \
- V(Float32List, ., TypedData_Float32Array_factory, \
- TypedDataFloat32Array, 0x43506c09) \
- V(Float64List, ., TypedData_Float64Array_factory, \
- TypedDataFloat64Array, 0x1fde3eaf) \
- V(Float32x4List, ., TypedData_Float32x4Array_factory, \
- TypedDataFloat32x4Array, 0x4a4030d6) \
- V(Int32x4List, ., TypedData_Int32x4Array_factory, \
- TypedDataInt32x4Array, 0x6dd02406) \
- V(Float64x2List, ., TypedData_Float64x2Array_factory, \
- TypedDataFloat64x2Array, 0x688e4e97) \
+ V(Int8List, ., TypedData_Int8Array_factory, 0x7e39a3a1) \
+ V(Uint8List, ., TypedData_Uint8Array_factory, 0x3a79adf7) \
+ V(Uint8ClampedList, ., TypedData_Uint8ClampedArray_factory, 0x67f38395) \
+ V(Int16List, ., TypedData_Int16Array_factory, 0x6477bda8) \
+ V(Uint16List, ., TypedData_Uint16Array_factory, 0x5707c5a2) \
+ V(Int32List, ., TypedData_Int32Array_factory, 0x2b96ec0e) \
+ V(Uint32List, ., TypedData_Uint32Array_factory, 0x0c1c0d62) \
+ V(Int64List, ., TypedData_Int64Array_factory, 0x279ab485) \
+ V(Uint64List, ., TypedData_Uint64Array_factory, 0x7bcb89c2) \
+ V(Float32List, ., TypedData_Float32Array_factory, 0x43506c09) \
+ V(Float64List, ., TypedData_Float64Array_factory, 0x1fde3eaf) \
+ V(Float32x4List, ., TypedData_Float32x4Array_factory, 0x4a4030d6) \
+ V(Int32x4List, ., TypedData_Int32x4Array_factory, 0x6dd02406) \
+ V(Float64x2List, ., TypedData_Float64x2Array_factory, 0x688e4e97) \
#define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
- V(_Int8List, [], Int8ArrayGetIndexed, Smi, 0x49767a2c) \
- V(_Int8List, []=, Int8ArraySetIndexed, Dynamic, 0x24f42cd0) \
- V(_Uint8List, [], Uint8ArrayGetIndexed, Smi, 0x088d86d4) \
- V(_Uint8List, []=, Uint8ArraySetIndexed, Dynamic, 0x12639541) \
- V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, Smi, 0x088d86d4) \
- V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, Dynamic, \
- 0x12639541) \
- V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, Smi, 0x088d86d4) \
- V(_Uint8ClampedList, []=, Uint8ClampedArraySetIndexed, Dynamic, 0x6790dba1) \
+ V(_Int8List, [], Int8ArrayGetIndexed, 0x49767a2c) \
+ V(_Int8List, []=, Int8ArraySetIndexed, 0x24f42cd0) \
+ V(_Uint8List, [], Uint8ArrayGetIndexed, 0x088d86d4) \
+ V(_Uint8List, []=, Uint8ArraySetIndexed, 0x12639541) \
+ V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 0x088d86d4) \
+ V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 0x12639541) \
+ V(_Uint8ClampedList, [], Uint8ClampedArrayGetIndexed, 0x088d86d4) \
+ V(_Uint8ClampedList, []=, Uint8ClampedArraySetIndexed, 0x6790dba1) \
V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed, \
- Smi, 0x088d86d4) \
+ 0x088d86d4) \
V(_ExternalUint8ClampedArray, []=, ExternalUint8ClampedArraySetIndexed, \
- Dynamic, 0x6790dba1) \
- V(_Int16List, [], Int16ArrayGetIndexed, Smi, 0x5ec64948) \
- V(_Int16List, []=, Int16ArraySetIndexed, Dynamic, 0x0e4e8221) \
- V(_Uint16List, [], Uint16ArrayGetIndexed, Smi, 0x5f49d093) \
- V(_Uint16List, []=, Uint16ArraySetIndexed, Dynamic, 0x2efbc90f) \
- V(_Int32List, [], Int32ArrayGetIndexed, Dynamic, 0x4bc0d3dd) \
- V(_Int32List, []=, Int32ArraySetIndexed, Dynamic, 0x1adf9823) \
- V(_Uint32List, [], Uint32ArrayGetIndexed, Dynamic, 0x188658ce) \
- V(_Uint32List, []=, Uint32ArraySetIndexed, Dynamic, 0x01f51a79) \
- V(_Int64List, [], Int64ArrayGetIndexed, Dynamic, 0x51eafb97) \
- V(_Int64List, []=, Int64ArraySetIndexed, Dynamic, 0x376181fb) \
- V(_Uint64List, [], Uint64ArrayGetIndexed, Dynamic, 0x4b2a1ba2) \
- V(_Uint64List, []=, Uint64ArraySetIndexed, Dynamic, 0x5f881bd4) \
- V(_Float64List, [], Float64ArrayGetIndexed, Double, 0x0a714486) \
- V(_Float64List, []=, Float64ArraySetIndexed, Dynamic, 0x04937367) \
- V(_Float32List, [], Float32ArrayGetIndexed, Double, 0x5ade301f) \
- V(_Float32List, []=, Float32ArraySetIndexed, Dynamic, 0x0d5c2e2b) \
- V(_Float32x4List, [], Float32x4ArrayGetIndexed, Float32x4, 0x128cddeb) \
- V(_Float32x4List, []=, Float32x4ArraySetIndexed, Dynamic, 0x7ad55c72) \
- V(_Int32x4List, [], Int32x4ArrayGetIndexed, Int32x4, 0x4b78af9c) \
- V(_Int32x4List, []=, Int32x4ArraySetIndexed, Dynamic, 0x31453dab) \
- V(_Float64x2List, [], Float64x2ArrayGetIndexed, Float64x2, 0x644a0be1) \
- V(_Float64x2List, []=, Float64x2ArraySetIndexed, Dynamic, 0x6b836b0b) \
- V(_TypedList, get:length, TypedDataLength, Smi, 0x2091c4d8) \
- V(_Float32x4, get:x, Float32x4ShuffleX, Double, 0x63d1a9fd) \
- V(_Float32x4, get:y, Float32x4ShuffleY, Double, 0x203523d9) \
- V(_Float32x4, get:z, Float32x4ShuffleZ, Double, 0x13190678) \
- V(_Float32x4, get:w, Float32x4ShuffleW, Double, 0x698a38de) \
- V(_Float32x4, *, Float32x4Mul, Float32x4, 0x5dec68b2) \
- V(_Float32x4, -, Float32x4Sub, Float32x4, 0x3ea14461) \
- V(_Float32x4, +, Float32x4Add, Float32x4, 0x7ffcf301) \
+ 0x6790dba1) \
+ V(_Int16List, [], Int16ArrayGetIndexed, 0x5ec64948) \
+ V(_Int16List, []=, Int16ArraySetIndexed, 0x0e4e8221) \
+ V(_Uint16List, [], Uint16ArrayGetIndexed, 0x5f49d093) \
+ V(_Uint16List, []=, Uint16ArraySetIndexed, 0x2efbc90f) \
+ V(_Int32List, [], Int32ArrayGetIndexed, 0x4bc0d3dd) \
+ V(_Int32List, []=, Int32ArraySetIndexed, 0x1adf9823) \
+ V(_Uint32List, [], Uint32ArrayGetIndexed, 0x188658ce) \
+ V(_Uint32List, []=, Uint32ArraySetIndexed, 0x01f51a79) \
+ V(_Int64List, [], Int64ArrayGetIndexed, 0x51eafb97) \
+ V(_Int64List, []=, Int64ArraySetIndexed, 0x376181fb) \
+ V(_Uint64List, [], Uint64ArrayGetIndexed, 0x4b2a1ba2) \
+ V(_Uint64List, []=, Uint64ArraySetIndexed, 0x5f881bd4) \
+ V(_Float64List, [], Float64ArrayGetIndexed, 0x0a714486) \
+ V(_Float64List, []=, Float64ArraySetIndexed, 0x04937367) \
+ V(_Float32List, [], Float32ArrayGetIndexed, 0x5ade301f) \
+ V(_Float32List, []=, Float32ArraySetIndexed, 0x0d5c2e2b) \
+ V(_Float32x4List, [], Float32x4ArrayGetIndexed, 0x128cddeb) \
+ V(_Float32x4List, []=, Float32x4ArraySetIndexed, 0x7ad55c72) \
+ V(_Int32x4List, [], Int32x4ArrayGetIndexed, 0x4b78af9c) \
+ V(_Int32x4List, []=, Int32x4ArraySetIndexed, 0x31453dab) \
+ V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0x644a0be1) \
+ V(_Float64x2List, []=, Float64x2ArraySetIndexed, 0x6b836b0b) \
+ V(_TypedList, get:length, TypedDataLength, 0x2091c4d8) \
+ V(_Float32x4, get:x, Float32x4ShuffleX, 0x63d1a9fd) \
+ V(_Float32x4, get:y, Float32x4ShuffleY, 0x203523d9) \
+ V(_Float32x4, get:z, Float32x4ShuffleZ, 0x13190678) \
+ V(_Float32x4, get:w, Float32x4ShuffleW, 0x698a38de) \
+ V(_Float32x4, *, Float32x4Mul, 0x5dec68b2) \
+ V(_Float32x4, -, Float32x4Sub, 0x3ea14461) \
+ V(_Float32x4, +, Float32x4Add, 0x7ffcf301) \
#define GRAPH_CORE_INTRINSICS_LIST(V) \
- V(_List, get:length, ObjectArrayLength, Smi, 0x25952390) \
- V(_List, [], ObjectArrayGetIndexed, Dynamic, 0x653da02e) \
- V(_List, []=, ObjectArraySetIndexed, Dynamic, 0x16b3d2b0) \
- V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, Dynamic, 0x50d64c75) \
- V(_ImmutableList, get:length, ImmutableArrayLength, Smi, 0x25952390) \
- V(_ImmutableList, [], ImmutableArrayGetIndexed, Dynamic, 0x653da02e) \
- V(_GrowableList, get:length, GrowableArrayLength, Smi, 0x18dd86b4) \
- V(_GrowableList, get:_capacity, GrowableArrayCapacity, Smi, 0x2e04be60) \
- V(_GrowableList, _setData, GrowableArraySetData, Dynamic, 0x3dbea348) \
- V(_GrowableList, _setLength, GrowableArraySetLength, Dynamic, 0x753e55da) \
- V(_GrowableList, [], GrowableArrayGetIndexed, Dynamic, 0x446fe1f0) \
- V(_GrowableList, []=, GrowableArraySetIndexed, Dynamic, 0x40a462ec) \
- V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, Dynamic, \
- 0x297083df) \
- V(_StringBase, get:length, StringBaseLength, Smi, 0x2a2d03d1) \
- V(_OneByteString, codeUnitAt, OneByteStringCodeUnitAt, Smi, 0x55a0a1f3) \
- V(_TwoByteString, codeUnitAt, TwoByteStringCodeUnitAt, Smi, 0x55a0a1f3) \
+ V(_List, get:length, ObjectArrayLength, 0x25952390) \
+ V(_List, [], ObjectArrayGetIndexed, 0x653da02e) \
+ V(_List, []=, ObjectArraySetIndexed, 0x16b3d2b0) \
+ V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, 0x50d64c75) \
+ V(_ImmutableList, get:length, ImmutableArrayLength, 0x25952390) \
+ V(_ImmutableList, [], ImmutableArrayGetIndexed, 0x653da02e) \
+ V(_GrowableList, get:length, GrowableArrayLength, 0x18dd86b4) \
+ V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x2e04be60) \
+ V(_GrowableList, _setData, GrowableArraySetData, 0x3dbea348) \
+ V(_GrowableList, _setLength, GrowableArraySetLength, 0x753e55da) \
+ V(_GrowableList, [], GrowableArrayGetIndexed, 0x446fe1f0) \
+ V(_GrowableList, []=, GrowableArraySetIndexed, 0x40a462ec) \
+ V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, 0x297083df) \
+ V(_StringBase, get:length, StringBaseLength, 0x2a2d03d1) \
+ V(_OneByteString, codeUnitAt, OneByteStringCodeUnitAt, 0x55a0a1f3) \
+ V(_TwoByteString, codeUnitAt, TwoByteStringCodeUnitAt, 0x55a0a1f3) \
V(_ExternalOneByteString, codeUnitAt, ExternalOneByteStringCodeUnitAt, \
- Smi, 0x55a0a1f3) \
+ 0x55a0a1f3) \
V(_ExternalTwoByteString, codeUnitAt, ExternalTwoByteStringCodeUnitAt, \
- Smi, 0x55a0a1f3) \
- V(_Double, unary-, DoubleFlipSignBit, Double, 0x6db4674f) \
- V(_Double, truncateToDouble, DoubleTruncate, Double, 0x2f27e5d3) \
- V(_Double, roundToDouble, DoubleRound, Double, 0x2f89c512) \
- V(_Double, floorToDouble, DoubleFloor, Double, 0x6aa87a5f) \
- V(_Double, ceilToDouble, DoubleCeil, Double, 0x1b045e9e) \
- V(_Double, _modulo, DoubleMod, Double, 0x5b8ceed7)
+ 0x55a0a1f3) \
+ V(_Double, unary-, DoubleFlipSignBit, 0x6db4674f) \
+ V(_Double, truncateToDouble, DoubleTruncate, 0x2f27e5d3) \
+ V(_Double, roundToDouble, DoubleRound, 0x2f89c512) \
+ V(_Double, floorToDouble, DoubleFloor, 0x6aa87a5f) \
+ V(_Double, ceilToDouble, DoubleCeil, 0x1b045e9e) \
+ V(_Double, _modulo, DoubleMod, 0x5b8ceed7)
#define GRAPH_INTRINSICS_LIST(V) \
@@ -356,17 +326,14 @@
GRAPH_MATH_LIB_INTRINSIC_LIST(V) \
#define DEVELOPER_LIB_INTRINSIC_LIST(V) \
- V(_UserTag, makeCurrent, UserTag_makeCurrent, Dynamic, 0x0b3066fd) \
- V(::, _getDefaultTag, UserTag_defaultTag, Dynamic, 0x69f3f1ad) \
- V(::, _getCurrentTag, Profiler_getCurrentTag, Dynamic, 0x05fa99d2) \
- V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, Dynamic, \
- 0x72f13f7a) \
+ V(_UserTag, makeCurrent, UserTag_makeCurrent, 0x0b3066fd) \
+ V(::, _getDefaultTag, UserTag_defaultTag, 0x69f3f1ad) \
+ V(::, _getCurrentTag, Profiler_getCurrentTag, 0x05fa99d2) \
+ V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 0x72f13f7a) \
#define ASYNC_LIB_INTRINSIC_LIST(V) \
- V(::, _clearAsyncThreadStackTrace, ClearAsyncThreadStackTrace, \
- Dynamic, 0x2edd4b25) \
- V(::, _setAsyncThreadStackTrace, SetAsyncThreadStackTrace, \
- Dynamic, 0x04f429a7)
+ V(::, _clearAsyncThreadStackTrace, ClearAsyncThreadStackTrace, 0x2edd4b25) \
+ V(::, _setAsyncThreadStackTrace, SetAsyncThreadStackTrace, 0x04f429a7) \
#define ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V) \
ASYNC_LIB_INTRINSIC_LIST(V) \
@@ -549,8 +516,7 @@
public:
enum Kind {
kUnknown,
-#define DEFINE_ENUM_LIST(class_name, function_name, enum_name, type, fp) \
- k##enum_name,
+#define DEFINE_ENUM_LIST(class_name, function_name, enum_name, fp) k##enum_name,
RECOGNIZED_LIST(DEFINE_ENUM_LIST)
#undef DEFINE_ENUM_LIST
kNumRecognizedMethods
@@ -560,7 +526,23 @@
static bool AlwaysInline(const Function& function);
static bool PolymorphicTarget(const Function& function);
static intptr_t NumArgsCheckedForStaticCall(const Function& function);
- static intptr_t ResultCid(const Function& function);
+
+ // Try to find an annotation of the form
+ // @pragma("vm:exact-result-type", int)
+ // @pragma("vm:exact-result-type", "dart:core#_Smi")
+ // and return the exact cid if found or kDynamicCid otherwise.
+ //
+ // See [result_type_pragma.md].
+ static intptr_t ResultCidFromPragma(const Object& function_or_field);
+
+ // Try to find an annotation of the form
+ // @pragma("vm:non-nullable-result-type")
+ // and returns true iff `false` was specified in the annotation.
+ //
+ // See [pragmas.md].
+ static bool HasNonNullableResultTypeFromPragma(
+ const Object& function_or_field);
+
static intptr_t MethodKindToReceiverCid(Kind kind);
static const char* KindToCString(Kind kind);
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 5e11b77..3ea0f09 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -143,12 +143,6 @@
"a sim* architecture.");
#endif // defined(USING_SIMULATOR) || defined(TARGET_ARCH_DBC)
-#if defined(TARGET_OS_WINDOWS)
- // TODO(34393): The interpreter currently relies on computed gotos, which
- // aren't supported on Windows.
- return strdup("--enable-interpreter is not supported on Windows.");
-#endif // defined(TARGET_OS_WINDOWS)
-
FLAG_use_field_guards = false;
}
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 031c7a3..e179fca 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1965,6 +1965,18 @@
return Api::ClassId(object) == kClosureCid;
}
+DART_EXPORT bool Dart_IsTearOff(Dart_Handle object) {
+ DARTSCOPE(Thread::Current());
+ API_TIMELINE_DURATION(T);
+ const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
+ if (obj.IsClosure()) {
+ const Closure& closure = Closure::Cast(obj);
+ const Function& func = Function::Handle(Z, closure.function());
+ return func.IsImplicitClosureFunction();
+ }
+ return false;
+}
+
DART_EXPORT bool Dart_IsTypedData(Dart_Handle handle) {
intptr_t cid = Api::ClassId(handle);
return RawObject::IsTypedDataClassId(cid) ||
@@ -5052,7 +5064,7 @@
"because it was not annotated with @pragma('vm:entry-point').\n"
"ERROR: See "
"https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/"
- "aot/entry_point_pragma.md",
+ "aot/entry_point_pragma.md\n",
String::Handle(klass.UserVisibleName()).ToCString());
UNREACHABLE();
}
@@ -5602,105 +5614,6 @@
return Api::Success();
}
-// --- Dart Front-End (Kernel) support ---
-
-DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate) {
-#if defined(DART_PRECOMPILED_RUNTIME)
- return false;
-#else
- Isolate* iso = reinterpret_cast<Isolate*>(isolate);
- return KernelIsolate::IsKernelIsolate(iso);
-#endif
-}
-
-DART_EXPORT bool Dart_KernelIsolateIsRunning() {
-#if defined(DART_PRECOMPILED_RUNTIME)
- return false;
-#else
- return KernelIsolate::IsRunning();
-#endif
-}
-
-DART_EXPORT Dart_Port Dart_KernelPort() {
-#if defined(DART_PRECOMPILED_RUNTIME)
- return false;
-#else
- return KernelIsolate::KernelPort();
-#endif
-}
-
-DART_EXPORT Dart_KernelCompilationResult
-Dart_CompileToKernel(const char* script_uri,
- const uint8_t* platform_kernel,
- intptr_t platform_kernel_size,
- bool incremental_compile,
- const char* package_config) {
- API_TIMELINE_DURATION(Thread::Current());
-
- Dart_KernelCompilationResult result;
-#if defined(DART_PRECOMPILED_RUNTIME)
- result.status = Dart_KernelCompilationStatus_Unknown;
- result.error = strdup("Dart_CompileToKernel is unsupported.");
-#else
- result = KernelIsolate::CompileToKernel(script_uri, platform_kernel,
- platform_kernel_size, 0, NULL,
- incremental_compile, package_config);
- if (result.status == Dart_KernelCompilationStatus_Ok) {
- Dart_KernelCompilationResult accept_result =
- KernelIsolate::AcceptCompilation();
- if (accept_result.status != Dart_KernelCompilationStatus_Ok) {
- FATAL1(
- "An error occurred in the CFE while accepting the most recent"
- " compilation results: %s",
- accept_result.error);
- }
- }
-#endif
- return result;
-}
-
-DART_EXPORT Dart_KernelCompilationResult
-Dart_CompileSourcesToKernel(const char* script_uri,
- const uint8_t* platform_kernel,
- intptr_t platform_kernel_size,
- int source_files_count,
- Dart_SourceFile sources[],
- bool incremental_compile,
- const char* package_config,
- const char* multiroot_filepaths,
- const char* multiroot_scheme) {
- Dart_KernelCompilationResult result;
-#if defined(DART_PRECOMPILED_RUNTIME)
- result.status = Dart_KernelCompilationStatus_Unknown;
- result.error = strdup("Dart_CompileSourcesToKernel is unsupported.");
-#else
- result = KernelIsolate::CompileToKernel(
- script_uri, platform_kernel, platform_kernel_size, source_files_count,
- sources, incremental_compile, package_config, multiroot_filepaths,
- multiroot_scheme);
- if (result.status == Dart_KernelCompilationStatus_Ok) {
- if (KernelIsolate::AcceptCompilation().status !=
- Dart_KernelCompilationStatus_Ok) {
- FATAL(
- "An error occurred in the CFE while accepting the most recent"
- " compilation results.");
- }
- }
-#endif
- return result;
-}
-
-DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies() {
- Dart_KernelCompilationResult result;
-#if defined(DART_PRECOMPILED_RUNTIME)
- result.status = Dart_KernelCompilationStatus_Unknown;
- result.error = strdup("Dart_KernelListDependencies is unsupported.");
-#else
- result = KernelIsolate::ListDependencies();
-#endif
- return result;
-}
-
// --- Service support ---
DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate) {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 1a3ef8a..3a3c425 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -861,6 +861,60 @@
EXPECT_STREQ(url, lib_url);
}
+TEST_CASE(DartAPI_IsTearOff) {
+ const char* kScriptChars =
+ "int getInt() { return 1; }\n"
+ "getTearOff() => getInt;\n"
+ "Function foo = () { print('baz'); };\n"
+ "class Baz {\n"
+ " static int foo() => 42;\n"
+ " getTearOff() => bar;\n"
+ " int bar() => 24;\n"
+ "}\n"
+ "Baz getBaz() => Baz();\n";
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ EXPECT_VALID(lib);
+
+ // Check tear-off of top-level static method.
+ Dart_Handle get_tear_off = Dart_GetField(lib, NewString("getTearOff"));
+ EXPECT_VALID(get_tear_off);
+ EXPECT(Dart_IsTearOff(get_tear_off));
+ Dart_Handle tear_off = Dart_InvokeClosure(get_tear_off, 0, NULL);
+ EXPECT_VALID(tear_off);
+ EXPECT(Dart_IsTearOff(tear_off));
+
+ // Check anonymous closures are not considered tear-offs.
+ Dart_Handle anonymous_closure = Dart_GetField(lib, NewString("foo"));
+ EXPECT_VALID(anonymous_closure);
+ EXPECT(!Dart_IsTearOff(anonymous_closure));
+
+ Dart_Handle baz_cls = Dart_GetClass(lib, NewString("Baz"));
+ EXPECT_VALID(baz_cls);
+
+ // Check tear-off for a static method in a class.
+ Dart_Handle closure =
+ Dart_GetStaticMethodClosure(lib, baz_cls, NewString("foo"));
+ EXPECT_VALID(closure);
+ EXPECT(Dart_IsTearOff(closure));
+
+ // Flutter will use Dart_IsTearOff in conjunction with Dart_ClosureFunction
+ // and Dart_FunctionIsStatic to prevent anonymous closures from being used to
+ // generate callback handles. We'll test that case here, just to be sure.
+ Dart_Handle function = Dart_ClosureFunction(closure);
+ EXPECT_VALID(function);
+ bool is_static = false;
+ Dart_Handle result = Dart_FunctionIsStatic(function, &is_static);
+ EXPECT_VALID(result);
+ EXPECT(is_static);
+
+ // Check tear-off for an instance method in a class.
+ Dart_Handle instance = Dart_Invoke(lib, NewString("getBaz"), 0, NULL);
+ EXPECT_VALID(instance);
+ closure = Dart_Invoke(instance, NewString("getTearOff"), 0, NULL);
+ EXPECT_VALID(closure);
+ EXPECT(Dart_IsTearOff(closure));
+}
+
TEST_CASE(DartAPI_FunctionIsStatic) {
const char* kScriptChars =
"int getInt() { return 1; }\n"
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index e348558..677be143 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -167,8 +167,8 @@
// Now Call the invoke stub which will invoke the dart function.
#if !defined(TARGET_ARCH_DBC)
- invokestub entrypoint = reinterpret_cast<invokestub>(
- StubCode::InvokeDartCode_entry()->EntryPoint());
+ invokestub entrypoint =
+ reinterpret_cast<invokestub>(StubCode::InvokeDartCode().EntryPoint());
#endif
const Code& code = Code::Handle(zone, function.CurrentCode());
ASSERT(!code.IsNull());
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 6823611..4fafda8 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -2037,7 +2037,7 @@
break;
}
if (async_stack_trace.CodeAtFrame(i) ==
- StubCode::AsynchronousGapMarker_entry()->code()) {
+ StubCode::AsynchronousGapMarker().raw()) {
stack_trace->AddMarker(ActivationFrame::kAsyncSuspensionMarker);
// The frame immediately below the asynchronous gap marker is the
// identical to the frame above the marker. Skip the frame to enhance
@@ -2251,7 +2251,7 @@
break;
}
if (async_stack_trace.CodeAtFrame(i) ==
- StubCode::AsynchronousGapMarker_entry()->code()) {
+ StubCode::AsynchronousGapMarker().raw()) {
stack_trace->AddMarker(ActivationFrame::kAsyncSuspensionMarker);
// The frame immediately below the asynchronous gap marker is the
// identical to the frame above the marker. Skip the frame to enhance
@@ -3722,7 +3722,7 @@
}
Thread* thread = Thread::Current();
thread->set_resume_pc(frame->pc());
- uword deopt_stub_pc = StubCode::DeoptForRewind_entry()->EntryPoint();
+ uword deopt_stub_pc = StubCode::DeoptForRewind().EntryPoint();
Exceptions::JumpToFrame(thread, deopt_stub_pc, frame->sp(), frame->fp(),
true /* clear lazy deopt at target */);
UNREACHABLE();
diff --git a/runtime/vm/debugger_arm.cc b/runtime/vm/debugger_arm.cc
index ee75cd7..3eafa74 100644
--- a/runtime/vm/debugger_arm.cc
+++ b/runtime/vm/debugger_arm.cc
@@ -25,10 +25,10 @@
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
- stub_target = StubCode::ICCallBreakpoint_entry()->code();
+ stub_target = StubCode::ICCallBreakpoint().raw();
break;
case RawPcDescriptors::kRuntimeCall:
- stub_target = StubCode::RuntimeCallBreakpoint_entry()->code();
+ stub_target = StubCode::RuntimeCallBreakpoint().raw();
break;
default:
UNREACHABLE();
diff --git a/runtime/vm/debugger_arm64.cc b/runtime/vm/debugger_arm64.cc
index 4d53e7c..48ed9c2 100644
--- a/runtime/vm/debugger_arm64.cc
+++ b/runtime/vm/debugger_arm64.cc
@@ -25,10 +25,10 @@
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
- stub_target = StubCode::ICCallBreakpoint_entry()->code();
+ stub_target = StubCode::ICCallBreakpoint().raw();
break;
case RawPcDescriptors::kRuntimeCall: {
- stub_target = StubCode::RuntimeCallBreakpoint_entry()->code();
+ stub_target = StubCode::RuntimeCallBreakpoint().raw();
break;
}
default:
diff --git a/runtime/vm/debugger_ia32.cc b/runtime/vm/debugger_ia32.cc
index 8dadc22..d74202c 100644
--- a/runtime/vm/debugger_ia32.cc
+++ b/runtime/vm/debugger_ia32.cc
@@ -33,12 +33,12 @@
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall: {
- stub_target = StubCode::ICCallBreakpoint_entry()->code();
+ stub_target = StubCode::ICCallBreakpoint().raw();
break;
}
case RawPcDescriptors::kRuntimeCall: {
saved_value_ = CodePatcher::GetStaticCallTargetAt(pc_, code);
- stub_target = StubCode::RuntimeCallBreakpoint_entry()->code();
+ stub_target = StubCode::RuntimeCallBreakpoint().raw();
break;
}
default:
diff --git a/runtime/vm/debugger_x64.cc b/runtime/vm/debugger_x64.cc
index a1f395c..39cf91c 100644
--- a/runtime/vm/debugger_x64.cc
+++ b/runtime/vm/debugger_x64.cc
@@ -27,10 +27,10 @@
switch (breakpoint_kind_) {
case RawPcDescriptors::kIcCall:
case RawPcDescriptors::kUnoptStaticCall:
- stub_target = StubCode::ICCallBreakpoint_entry()->code();
+ stub_target = StubCode::ICCallBreakpoint().raw();
break;
case RawPcDescriptors::kRuntimeCall:
- stub_target = StubCode::RuntimeCallBreakpoint_entry()->code();
+ stub_target = StubCode::RuntimeCallBreakpoint().raw();
break;
default:
UNREACHABLE();
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 7d082c7..7015a75 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -742,8 +742,8 @@
if (function.IsNull()) {
*reinterpret_cast<RawObject**>(dest_addr) =
deopt_context->is_lazy_deopt()
- ? StubCode::DeoptimizeLazyFromReturn_entry()->code()
- : StubCode::Deoptimize_entry()->code();
+ ? StubCode::DeoptimizeLazyFromReturn().raw()
+ : StubCode::Deoptimize().raw();
return;
}
@@ -753,7 +753,7 @@
// materialization to maintain the invariant that Dart frames always have
// a pc marker.
*reinterpret_cast<RawObject**>(dest_addr) =
- StubCode::FrameAwaitingMaterialization_entry()->code();
+ StubCode::FrameAwaitingMaterialization().raw();
deopt_context->DeferPcMarkerMaterialization(object_table_index_, dest_addr);
}
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 123870a..7a857cc 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -449,8 +449,7 @@
(*pending_deopts)[i].set_pc(program_counter);
// Jump to the deopt stub instead of the catch handler.
- program_counter =
- StubCode::DeoptimizeLazyFromThrow_entry()->EntryPoint();
+ program_counter = StubCode::DeoptimizeLazyFromThrow().EntryPoint();
if (FLAG_trace_deoptimization) {
THR_Print("Throwing to frame scheduled for lazy deopt fp=%" Pp "\n",
frame_pointer);
@@ -517,7 +516,7 @@
thread->set_active_exception(exception_object);
thread->set_active_stacktrace(stacktrace_object);
thread->set_resume_pc(remapped_pc);
- uword run_exception_pc = StubCode::RunExceptionHandler_entry()->EntryPoint();
+ uword run_exception_pc = StubCode::RunExceptionHandler().EntryPoint();
Exceptions::JumpToFrame(thread, run_exception_pc, stack_pointer,
frame_pointer, false /* do not clear deopt */);
}
@@ -564,8 +563,8 @@
// to set up the stacktrace object in kStackTraceObjectReg, and to
// continue execution at the given pc in the given frame.
typedef void (*ExcpHandler)(uword, uword, uword, Thread*);
- ExcpHandler func = reinterpret_cast<ExcpHandler>(
- StubCode::JumpToFrame_entry()->EntryPoint());
+ ExcpHandler func =
+ reinterpret_cast<ExcpHandler>(StubCode::JumpToFrame().EntryPoint());
// Unpoison the stack before we tear it down in the generated stub code.
uword current_sp = OSThread::GetCurrentStackPointer() - 1024;
diff --git a/runtime/vm/heap/compactor.cc b/runtime/vm/heap/compactor.cc
index 12815bf..859174e 100644
--- a/runtime/vm/heap/compactor.cc
+++ b/runtime/vm/heap/compactor.cc
@@ -13,6 +13,11 @@
namespace dart {
+DEFINE_FLAG(bool,
+ force_evacuation,
+ false,
+ "Force compaction to move every movable object");
+
static const intptr_t kBitVectorWordsPerBlock = 1;
static const intptr_t kBlockSize =
kObjectAlignment * kBitsPerWord * kBitVectorWordsPerBlock;
@@ -203,6 +208,26 @@
ASSERT(task_index == num_tasks);
}
+ if (FLAG_force_evacuation) {
+ // Inject empty pages at the beginning of each worker's list to ensure all
+ // objects move and all pages that used to have an object are released.
+ // This can be helpful for finding untracked pointers because it prevents
+ // an untracked pointer from getting lucky with its target not moving.
+ for (intptr_t task_index = 0; task_index < num_tasks; task_index++) {
+ const intptr_t pages_per_task = num_pages / num_tasks;
+ for (intptr_t j = 0; j < pages_per_task; j++) {
+ HeapPage* page = heap_->old_space()->AllocatePage(HeapPage::kData,
+ /* link */ false);
+ FreeListElement::AsElement(page->object_start(),
+ page->object_end() - page->object_start());
+
+ // The compactor slides down: add the empty pages to the beginning.
+ page->set_next(heads[task_index]);
+ heads[task_index] = page;
+ }
+ }
+ }
+
{
ThreadBarrier barrier(num_tasks + 1, heap_->barrier(),
heap_->barrier_done());
@@ -251,6 +276,7 @@
tails[task_index]->set_next(heads[task_index + 1]);
}
tails[num_tasks - 1]->set_next(NULL);
+ heap_->old_space()->pages_ = pages = heads[0];
heap_->old_space()->pages_tail_ = tails[num_tasks - 1];
delete[] heads;
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 18b8fc9..3145090 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -55,14 +55,14 @@
// code from the function.
if (FLAG_enable_interpreter && Function::HasBytecode(func)) {
func->StorePointer(&(func->ptr()->code_),
- StubCode::InterpretCall_entry()->code());
- uword entry_point = StubCode::InterpretCall_entry()->EntryPoint();
+ StubCode::InterpretCall().raw());
+ uword entry_point = StubCode::InterpretCall().EntryPoint();
func->ptr()->entry_point_ = entry_point;
func->ptr()->unchecked_entry_point_ = entry_point;
} else {
func->StorePointer(&(func->ptr()->code_),
- StubCode::LazyCompile_entry()->code());
- uword entry_point = StubCode::LazyCompile_entry()->EntryPoint();
+ StubCode::LazyCompile().raw());
+ uword entry_point = StubCode::LazyCompile().EntryPoint();
func->ptr()->entry_point_ = entry_point;
func->ptr()->unchecked_entry_point_ = entry_point;
}
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index e30089a..8e769bf4 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -288,7 +288,7 @@
return page_size >> kWordSizeLog2;
}
-HeapPage* PageSpace::AllocatePage(HeapPage::PageType type) {
+HeapPage* PageSpace::AllocatePage(HeapPage::PageType type, bool link) {
const bool is_exec = (type == HeapPage::kExecutable);
const intptr_t kVmNameSize = 128;
char vm_name[kVmNameSize];
@@ -301,31 +301,34 @@
}
MutexLocker ml(pages_lock_);
- if (!is_exec) {
- if (pages_ == NULL) {
- pages_ = page;
+ if (link) {
+ if (!is_exec) {
+ if (pages_ == NULL) {
+ pages_ = page;
+ } else {
+ pages_tail_->set_next(page);
+ }
+ pages_tail_ = page;
} else {
- pages_tail_->set_next(page);
- }
- pages_tail_ = page;
- } else {
- // Should not allocate executable pages when running from a precompiled
- // snapshot.
- ASSERT(Dart::vm_snapshot_kind() != Snapshot::kFullAOT);
+ // Should not allocate executable pages when running from a precompiled
+ // snapshot.
+ ASSERT(Dart::vm_snapshot_kind() != Snapshot::kFullAOT);
- if (exec_pages_ == NULL) {
- exec_pages_ = page;
- } else {
- if (FLAG_write_protect_code) {
- exec_pages_tail_->WriteProtect(false);
+ if (exec_pages_ == NULL) {
+ exec_pages_ = page;
+ } else {
+ if (FLAG_write_protect_code) {
+ exec_pages_tail_->WriteProtect(false);
+ }
+ exec_pages_tail_->set_next(page);
+ if (FLAG_write_protect_code) {
+ exec_pages_tail_->WriteProtect(true);
+ }
}
- exec_pages_tail_->set_next(page);
- if (FLAG_write_protect_code) {
- exec_pages_tail_->WriteProtect(true);
- }
+ exec_pages_tail_ = page;
}
- exec_pages_tail_ = page;
}
+
IncreaseCapacityInWordsLocked(kPageSizeInWords);
page->set_object_end(page->memory_->end());
return page;
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 95d8f19..4f93e24 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -436,7 +436,7 @@
bool is_locked);
// Makes bump block walkable; do not call concurrently with mutator.
void MakeIterable() const;
- HeapPage* AllocatePage(HeapPage::PageType type);
+ HeapPage* AllocatePage(HeapPage::PageType type, bool link = true);
void FreePage(HeapPage* page, HeapPage* previous_page);
HeapPage* AllocateLargePage(intptr_t size, HeapPage::PageType type);
void TruncateLargePage(HeapPage* page, intptr_t new_object_size_in_bytes);
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 5a48fb4..f61c467 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -268,8 +268,12 @@
}
// Append the direct-mapped RO data objects after the clustered snapshot.
+ offset_space_ = vm ? V8SnapshotProfileWriter::kVmData
+ : V8SnapshotProfileWriter::kIsolateData;
WriteROData(clustered_stream);
+ offset_space_ = vm ? V8SnapshotProfileWriter::kVmText
+ : V8SnapshotProfileWriter::kIsolateText;
WriteText(clustered_stream, vm);
}
@@ -278,14 +282,19 @@
// Heap page starts here.
+ intptr_t section_start = stream->Position();
+
stream->WriteWord(next_data_offset_); // Data length.
COMPILE_ASSERT(OS::kMaxPreferredCodeAlignment >= kObjectAlignment);
stream->Align(OS::kMaxPreferredCodeAlignment);
+ ASSERT(stream->Position() - section_start == Image::kHeaderSize);
+
// Heap page objects start here.
for (intptr_t i = 0; i < objects_.length(); i++) {
const Object& obj = *objects_[i].obj_;
+ AutoTraceImage(section_start, stream, "ROData");
NoSafepointScope no_safepoint;
uword start = reinterpret_cast<uword>(obj.raw()) - kHeapObjectTag;
@@ -370,10 +379,21 @@
ObjectStore* object_store = Isolate::Current()->object_store();
TypeTestingStubFinder tts;
+ intptr_t offset = Image::kHeaderSize;
for (intptr_t i = 0; i < instructions_.length(); i++) {
const Instructions& insns = *instructions_[i].insns_;
const Code& code = *instructions_[i].code_;
+ if (profile_writer_ != nullptr) {
+ ASSERT(offset_space_ != V8SnapshotProfileWriter::kSnapshot);
+ profile_writer_->SetObjectTypeAndName({offset_space_, offset},
+ "Instructions",
+ /*name=*/nullptr);
+ profile_writer_->AttributeBytesTo({offset_space_, offset},
+ insns.raw()->Size());
+ }
+ offset += insns.raw()->Size();
+
ASSERT(insns.raw()->Size() % sizeof(uint64_t) == 0);
// 1. Write from the header to the entry point.
@@ -595,6 +615,7 @@
NoSafepointScope no_safepoint;
for (intptr_t i = 0; i < instructions_.length(); i++) {
const Instructions& insns = *instructions_[i].insns_;
+ AutoTraceImage(0, &this->instructions_blob_stream_, "Instructions");
uword beginning = reinterpret_cast<uword>(insns.raw_ptr());
uword entry = beginning + Instructions::HeaderSize();
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index 16f83f7..33c0956 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -5,12 +5,15 @@
#ifndef RUNTIME_VM_IMAGE_SNAPSHOT_H_
#define RUNTIME_VM_IMAGE_SNAPSHOT_H_
+#include <utility>
+
#include "platform/assert.h"
#include "vm/allocation.h"
#include "vm/datastream.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
#include "vm/hash_map.h"
+#include "vm/v8_snapshot_writer.h"
namespace dart {
@@ -120,6 +123,14 @@
void DumpStatistics();
+ void SetProfileWriter(V8SnapshotProfileWriter* profile_writer) {
+ profile_writer_ = profile_writer;
+ }
+
+ void ClearProfileWriter() { profile_writer_ = nullptr; }
+
+ void TraceInstructions(const Instructions& instructions);
+
protected:
void WriteROData(WriteStream* stream);
virtual void WriteText(WriteStream* clustered_stream, bool vm) = 0;
@@ -162,10 +173,56 @@
ObjectOffsetMap shared_instructions_;
ObjectOffsetMap reuse_instructions_;
+ V8SnapshotProfileWriter::IdSpace offset_space_ =
+ V8SnapshotProfileWriter::kSnapshot;
+ V8SnapshotProfileWriter* profile_writer_ = nullptr;
+
+ template <class T>
+ friend class TraceImageObjectScope;
+
private:
DISALLOW_COPY_AND_ASSIGN(ImageWriter);
};
+#define AutoTraceImage(section_offset, stream, type_name) \
+ auto AutoTraceImagObjectScopeVar##__COUNTER__ = \
+ TraceImageObjectScope<std::remove_pointer<decltype(stream)>::type>( \
+ this, section_offset, stream, type_name);
+
+template <typename T>
+class TraceImageObjectScope {
+ public:
+ TraceImageObjectScope(ImageWriter* writer,
+ intptr_t section_offset,
+ const T* stream,
+ const char* type)
+ : writer_(writer),
+ stream_(stream),
+ section_offset_(section_offset),
+ start_offset_(stream_->Position() - section_offset) {
+ if (writer_->profile_writer_ != nullptr) {
+ ASSERT(writer_->offset_space_ != V8SnapshotProfileWriter::kSnapshot);
+ writer_->profile_writer_->SetObjectTypeAndName(
+ {writer_->offset_space_, start_offset_}, type, nullptr);
+ }
+ }
+
+ ~TraceImageObjectScope() {
+ if (writer_->profile_writer_ != nullptr) {
+ ASSERT(writer_->offset_space_ != V8SnapshotProfileWriter::kSnapshot);
+ writer_->profile_writer_->AttributeBytesTo(
+ {writer_->offset_space_, start_offset_},
+ stream_->Position() - section_offset_ - start_offset_);
+ }
+ }
+
+ private:
+ ImageWriter* writer_;
+ const T* stream_;
+ intptr_t section_offset_;
+ intptr_t start_offset_;
+};
+
class AssemblyImageWriter : public ImageWriter {
public:
AssemblyImageWriter(Thread* thread,
diff --git a/runtime/vm/instructions_arm64_test.cc b/runtime/vm/instructions_arm64_test.cc
index 89cca60..4a6528c 100644
--- a/runtime/vm/instructions_arm64_test.cc
+++ b/runtime/vm/instructions_arm64_test.cc
@@ -18,7 +18,7 @@
ASSEMBLER_TEST_GENERATE(Call, assembler) {
// Code accessing pp is generated, but not executed. Uninitialized pp is OK.
__ set_constant_pool_allowed(true);
- __ BranchLinkPatchable(*StubCode::InvokeDartCode_entry());
+ __ BranchLinkPatchable(StubCode::InvokeDartCode());
__ ret();
}
@@ -28,7 +28,7 @@
// before the end of the code buffer.
uword end = test->payload_start() + test->code().Size();
CallPattern call(end - Instr::kInstrSize, test->code());
- EXPECT_EQ(StubCode::InvokeDartCode_entry()->code(), call.TargetCode());
+ EXPECT_EQ(StubCode::InvokeDartCode().raw(), call.TargetCode());
}
} // namespace dart
diff --git a/runtime/vm/instructions_arm_test.cc b/runtime/vm/instructions_arm_test.cc
index 44749a7..e9fc409 100644
--- a/runtime/vm/instructions_arm_test.cc
+++ b/runtime/vm/instructions_arm_test.cc
@@ -18,7 +18,7 @@
ASSEMBLER_TEST_GENERATE(Call, assembler) {
// Code accessing pp is generated, but not executed. Uninitialized pp is OK.
__ set_constant_pool_allowed(true);
- __ BranchLinkPatchable(*StubCode::InvokeDartCode_entry());
+ __ BranchLinkPatchable(StubCode::InvokeDartCode());
__ Ret();
}
@@ -28,7 +28,7 @@
// before the end of the code buffer.
uword end = test->payload_start() + test->code().Size();
CallPattern call(end - Instr::kInstrSize, test->code());
- EXPECT_EQ(StubCode::InvokeDartCode_entry()->code(), call.TargetCode());
+ EXPECT_EQ(StubCode::InvokeDartCode().raw(), call.TargetCode());
}
} // namespace dart
diff --git a/runtime/vm/instructions_ia32_test.cc b/runtime/vm/instructions_ia32_test.cc
index 7aef6ca..9fcdb39 100644
--- a/runtime/vm/instructions_ia32_test.cc
+++ b/runtime/vm/instructions_ia32_test.cc
@@ -17,14 +17,14 @@
#define __ assembler->
ASSEMBLER_TEST_GENERATE(Call, assembler) {
- __ call(&StubCode::InvokeDartCode_entry()->label());
+ ExternalLabel label(StubCode::InvokeDartCode().EntryPoint());
+ __ call(&label);
__ ret();
}
ASSEMBLER_TEST_RUN(Call, test) {
CallPattern call(test->entry());
- EXPECT_EQ(StubCode::InvokeDartCode_entry()->EntryPoint(),
- call.TargetAddress());
+ EXPECT_EQ(StubCode::InvokeDartCode().EntryPoint(), call.TargetAddress());
}
} // namespace dart
diff --git a/runtime/vm/instructions_x64_test.cc b/runtime/vm/instructions_x64_test.cc
index 831d694..255b290 100644
--- a/runtime/vm/instructions_x64_test.cc
+++ b/runtime/vm/instructions_x64_test.cc
@@ -15,7 +15,7 @@
#define __ assembler->
ASSEMBLER_TEST_GENERATE(Call, assembler) {
- __ Call(*StubCode::InvokeDartCode_entry());
+ __ Call(StubCode::InvokeDartCode());
__ ret();
}
@@ -26,8 +26,8 @@
__ pushq(PP);
__ LoadPoolPointer();
prologue_code_size = assembler->CodeSize();
- __ JmpPatchable(*StubCode::InvokeDartCode_entry(), PP);
- __ JmpPatchable(*StubCode::AllocateArray_entry(), PP);
+ __ JmpPatchable(StubCode::InvokeDartCode(), PP);
+ __ JmpPatchable(StubCode::AllocateArray(), PP);
__ popq(PP);
__ ret();
}
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 09bee58..a921f60 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -6,7 +6,7 @@
#include <stdlib.h>
#include "vm/globals.h"
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_OS_WINDOWS)
+#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/interpreter.h"
@@ -31,7 +31,6 @@
trace_interpreter_after,
ULLONG_MAX,
"Trace interpreter execution after instruction count reached.");
-
DEFINE_FLAG(charp,
interpreter_trace_file,
NULL,
@@ -41,9 +40,6 @@
100 * MB,
"Maximum size in bytes of the interpreter trace file");
-#define LIKELY(cond) __builtin_expect((cond), 1)
-#define UNLIKELY(cond) __builtin_expect((cond), 0)
-
// InterpreterSetjmpBuffer are linked together, and the last created one
// is referenced by the Interpreter. When an exception is thrown, the exception
// runtime looks at where to jump and finds the corresponding
@@ -761,7 +757,7 @@
#endif
ASSERT(Function::HasCode(function));
RawCode* volatile code = function->ptr()->code_;
- ASSERT(code != StubCode::LazyCompile_entry()->code());
+ ASSERT(code != StubCode::LazyCompile().raw());
// TODO(regis): Once we share the same stack, try to invoke directly.
#if defined(DEBUG)
if (IsTracingExecution()) {
@@ -773,7 +769,7 @@
typedef RawObject* (*invokestub)(RawCode * code, RawArray * argdesc,
RawObject * *arg0, Thread * thread);
invokestub volatile entrypoint = reinterpret_cast<invokestub>(
- StubCode::InvokeDartCodeFromBytecode_entry()->EntryPoint());
+ StubCode::InvokeDartCodeFromBytecode().EntryPoint());
RawObject* volatile result;
Exit(thread, *FP, call_top + 1, *pc);
{
@@ -1286,6 +1282,7 @@
// Decode opcode and A part of the given value and dispatch to the
// corresponding bytecode handler.
+#ifdef DART_HAS_COMPUTED_GOTO
#define DISPATCH_OP(val) \
do { \
op = (val); \
@@ -1293,6 +1290,15 @@
TRACE_INSTRUCTION \
goto* dispatch[op & 0xFF]; \
} while (0)
+#else
+#define DISPATCH_OP(val) \
+ do { \
+ op = (val); \
+ rA = ((op >> 8) & 0xFF); \
+ TRACE_INSTRUCTION \
+ goto SwitchDispatch; \
+ } while (0)
+#endif
// Fetch next operation from PC, increment program counter and dispatch.
#define DISPATCH() DISPATCH_OP(*pc++)
@@ -1580,14 +1586,6 @@
intptr_t argc,
RawObject* const* argv,
Thread* thread) {
- // Dispatch used to interpret bytecode. Contains addresses of
- // labels of bytecode handlers. Handlers themselves are defined below.
- static const void* dispatch[] = {
-#define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
- KERNEL_BYTECODES_LIST(TARGET)
-#undef TARGET
- };
-
// Interpreter state (see constants_kbc.h for high-level overview).
uint32_t* pc; // Program Counter: points to the next op to execute.
RawObject** FP; // Frame Pointer.
@@ -1688,8 +1686,26 @@
Function& function_h = Function::Handle();
#endif
- // Enter the dispatch loop.
- DISPATCH();
+#ifdef DART_HAS_COMPUTED_GOTO
+ static const void* dispatch[] = {
+#define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
+ KERNEL_BYTECODES_LIST(TARGET)
+#undef TARGET
+ };
+ DISPATCH(); // Enter the dispatch loop.
+#else
+ DISPATCH(); // Enter the dispatch loop.
+SwitchDispatch:
+ switch (op & 0xFF) {
+#define TARGET(name, fmt, fmta, fmtb, fmtc) \
+ case KernelBytecode::k##name: \
+ goto bc##name;
+ KERNEL_BYTECODES_LIST(TARGET)
+#undef TARGET
+ default:
+ FATAL1("Undefined opcode: %d\n", op);
+ }
+#endif
// KernelBytecode handlers (see constants_kbc.h for bytecode descriptions).
{
@@ -3007,7 +3023,7 @@
fp_ = reinterpret_cast<RawObject**>(fp);
- if (pc == StubCode::RunExceptionHandler_entry()->EntryPoint()) {
+ if (pc == StubCode::RunExceptionHandler().EntryPoint()) {
// The RunExceptionHandler stub is a placeholder. We implement
// its behavior here.
RawObject* raw_exception = thread->active_exception();
@@ -3033,4 +3049,4 @@
} // namespace dart
-#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_OS_WINDOWS)
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/interpreter.h b/runtime/vm/interpreter.h
index 6150561..badbffd 100644
--- a/runtime/vm/interpreter.h
+++ b/runtime/vm/interpreter.h
@@ -83,7 +83,7 @@
uword get_pc() const { return pc_; }
enum IntrinsicId {
-#define V(test_class_name, test_function_name, enum_name, type, fp) \
+#define V(test_class_name, test_function_name, enum_name, fp) \
k##enum_name##Intrinsic,
ALL_INTRINSICS_LIST(V) GRAPH_INTRINSICS_LIST(V)
#undef V
diff --git a/runtime/vm/interpreter_unsupported.cc b/runtime/vm/interpreter_unsupported.cc
deleted file mode 100644
index 757e9b4..0000000
--- a/runtime/vm/interpreter_unsupported.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/globals.h"
-#if !defined(DART_PRECOMPILED_RUNTIME) && defined(TARGET_OS_WINDOWS)
-
-#include "vm/interpreter.h"
-
-#include "platform/assert.h"
-#include "vm/object.h"
-
-namespace dart {
-
-IntrinsicHandler Interpreter::intrinsics_[Interpreter::kIntrinsicCount];
-
-void Interpreter::InitOnce() {
- UNIMPLEMENTED();
-}
-
-Interpreter::Interpreter() {
- UNIMPLEMENTED();
-}
-
-Interpreter::~Interpreter() {
- UNIMPLEMENTED();
-}
-
-Interpreter* Interpreter::Current() {
- UNIMPLEMENTED();
- return NULL;
-}
-
-#if defined(DEBUG)
-bool Interpreter::IsTracingExecution() const {
- UNIMPLEMENTED();
- return false;
-}
-
-void Interpreter::TraceInstruction(uint32_t* pc) const {
- UNIMPLEMENTED();
-}
-#endif // defined(DEBUG)
-
-void Interpreter::Exit(Thread* thread,
- RawObject** base,
- RawObject** frame,
- uint32_t* pc) {
- UNIMPLEMENTED();
-}
-
-void Interpreter::CallRuntime(Thread* thread,
- RawObject** base,
- RawObject** exit_frame,
- uint32_t* pc,
- intptr_t argc_tag,
- RawObject** args,
- RawObject** result,
- uword target) {
- UNIMPLEMENTED();
-}
-
-bool Interpreter::InvokeCompiled(Thread* thread,
- RawFunction* function,
- RawObject** call_base,
- RawObject** call_top,
- uint32_t** pc,
- RawObject*** FP,
- RawObject*** SP) {
- UNIMPLEMENTED();
- return false;
-}
-
-bool Interpreter::ProcessInvocation(bool* invoked,
- Thread* thread,
- RawFunction* function,
- RawObject** call_base,
- RawObject** call_top,
- uint32_t** pc,
- RawObject*** FP,
- RawObject*** SP) {
- UNIMPLEMENTED();
- return false;
-}
-
-bool Interpreter::Invoke(Thread* thread,
- RawObject** call_base,
- RawObject** call_top,
- uint32_t** pc,
- RawObject*** FP,
- RawObject*** SP) {
- UNIMPLEMENTED();
- return false;
-}
-
-void Interpreter::InlineCacheMiss(int checked_args,
- Thread* thread,
- RawICData* icdata,
- RawObject** args,
- RawObject** top,
- uint32_t* pc,
- RawObject** FP,
- RawObject** SP) {
- UNIMPLEMENTED();
-}
-
-bool Interpreter::InstanceCall1(Thread* thread,
- RawICData* icdata,
- RawObject** call_base,
- RawObject** top,
- uint32_t** pc,
- RawObject*** FP,
- RawObject*** SP,
- bool optimized) {
- UNIMPLEMENTED();
- return false;
-}
-
-bool Interpreter::InstanceCall2(Thread* thread,
- RawICData* icdata,
- RawObject** call_base,
- RawObject** top,
- uint32_t** pc,
- RawObject*** FP,
- RawObject*** SP,
- bool optimized) {
- UNIMPLEMENTED();
- return false;
-}
-
-bool Interpreter::AssertAssignable(Thread* thread,
- uint32_t* pc,
- RawObject** FP,
- RawObject** call_top,
- RawObject** args,
- RawSubtypeTestCache* cache) {
- UNIMPLEMENTED();
- return false;
-}
-
-RawObject* Interpreter::Call(const Function& function,
- const Array& arguments_descriptor,
- const Array& arguments,
- Thread* thread) {
- UNIMPLEMENTED();
- return NULL;
-}
-
-RawObject* Interpreter::Call(RawFunction* function,
- RawArray* argdesc,
- intptr_t argc,
- RawObject* const* argv,
- Thread* thread) {
- UNIMPLEMENTED();
- return NULL;
-}
-
-void Interpreter::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
- UNIMPLEMENTED();
-}
-
-void Interpreter::VisitObjectPointers(ObjectPointerVisitor* visitor) {
- UNIMPLEMENTED();
-}
-
-} // namespace dart
-
-#endif // !defined(DART_PRECOMPILED_RUNTIME) && defined(TARGET_OS_WINDOWS)
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 94187e8..3c3f3d1 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -925,6 +925,8 @@
new Mutex(NOT_IN_PRODUCT("Isolate::kernel_data_lib_cache_mutex_"))),
kernel_data_class_cache_mutex_(
new Mutex(NOT_IN_PRODUCT("Isolate::kernel_data_class_cache_mutex_"))),
+ kernel_constants_mutex_(
+ new Mutex(NOT_IN_PRODUCT("Isolate::kernel_constants_mutex_"))),
message_handler_(NULL),
spawn_state_(NULL),
defer_finalization_count_(0),
@@ -1005,6 +1007,8 @@
constant_canonicalization_mutex_ = NULL;
delete megamorphic_lookup_mutex_;
megamorphic_lookup_mutex_ = NULL;
+ delete kernel_constants_mutex_;
+ kernel_constants_mutex_ = nullptr;
delete kernel_data_lib_cache_mutex_;
kernel_data_lib_cache_mutex_ = NULL;
delete kernel_data_class_cache_mutex_;
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index ebb648a..27fde4b 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -357,6 +357,10 @@
return kernel_data_class_cache_mutex_;
}
+ // Any access to constants arrays must be locked since mutator and
+ // background compiler can access the arrays at the same time.
+ Mutex* kernel_constants_mutex() const { return kernel_constants_mutex_; }
+
#if !defined(PRODUCT)
Debugger* debugger() const {
ASSERT(debugger_ != NULL);
@@ -959,6 +963,7 @@
Mutex* megamorphic_lookup_mutex_; // Protects megamorphic table lookup.
Mutex* kernel_data_lib_cache_mutex_;
Mutex* kernel_data_class_cache_mutex_;
+ Mutex* kernel_constants_mutex_;
MessageHandler* message_handler_;
IsolateSpawnState* spawn_state_;
intptr_t defer_finalization_count_;
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index 082bc48..35e6a7d 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -7,6 +7,7 @@
#include "include/dart_tools_api.h"
+#include "bin/kernel_isolate.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
#include "vm/hash_map.h"
diff --git a/runtime/vm/json_writer.cc b/runtime/vm/json_writer.cc
index 7c3aa7f..c3760a8 100644
--- a/runtime/vm/json_writer.cc
+++ b/runtime/vm/json_writer.cc
@@ -298,6 +298,10 @@
buffer_.AddChar(':');
}
+void JSONWriter::PrintNewline() {
+ buffer_.AddChar('\n');
+}
+
void JSONWriter::PrintCommaIfNeeded() {
if (NeedComma()) {
buffer_.AddChar(',');
diff --git a/runtime/vm/json_writer.h b/runtime/vm/json_writer.h
index b556869..c9d4375 100644
--- a/runtime/vm/json_writer.h
+++ b/runtime/vm/json_writer.h
@@ -74,6 +74,8 @@
void PrintPropertyName(const char* name);
+ void PrintNewline();
+
void AddEscapedUTF8String(const char* s);
void AddEscapedUTF8String(const char* s, intptr_t len);
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index a271351..ed610c5 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -8,6 +8,7 @@
#include "include/dart_api.h"
#include "include/dart_native_api.h"
+#include "bin/kernel_isolate.h"
#include "vm/allocation.h"
#include "vm/dart.h"
#include "vm/os_thread.h"
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index aab97e8a..b68203a 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -953,9 +953,6 @@
ReadVMAnnotations(annotation_count, &native_name_unused,
&is_potential_native_unused, &has_pragma_annotation);
}
- if (has_pragma_annotation) {
- toplevel_class.set_has_pragma(true);
- }
field_helper.SetJustRead(FieldHelper::kAnnotations);
field_helper.ReadUntilExcluding(FieldHelper::kType);
@@ -969,6 +966,7 @@
Field::NewTopLevel(name, is_final, field_helper.IsConst(), script_class,
field_helper.position_, field_helper.end_position_));
field.set_kernel_offset(field_offset);
+ field.set_has_pragma(has_pragma_annotation);
const AbstractType& type = T.BuildType(); // read type.
field.SetFieldType(type);
ReadInferredType(field, field_offset + library_kernel_offset_);
@@ -1344,9 +1342,6 @@
ReadVMAnnotations(annotation_count, &native_name_unused,
&is_potential_native_unused, &has_pragma_annotation);
}
- if (has_pragma_annotation) {
- klass.set_has_pragma(true);
- }
field_helper.SetJustRead(FieldHelper::kAnnotations);
field_helper.ReadUntilExcluding(FieldHelper::kType);
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index f0de736..7c2a30a 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -39,7 +39,7 @@
#define CHECK_STACK_ALIGNMENT \
{ \
uword (*func)() = reinterpret_cast<uword (*)()>( \
- StubCode::GetCStackPointer_entry()->EntryPoint()); \
+ StubCode::GetCStackPointer().EntryPoint()); \
uword current_sp = func(); \
ASSERT(Utils::IsAligned(current_sp, OS::ActivationFrameAlignment())); \
}
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index f6ac51b..ff77ded 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -296,8 +296,7 @@
reinterpret_cast<uword>(LinkNativeCall),
Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments)));
#endif
- ASSERT(current_trampoline.raw() ==
- StubCode::CallBootstrapNative_entry()->code());
+ ASSERT(current_trampoline.raw() == StubCode::CallBootstrapNative().raw());
}
#endif
@@ -333,7 +332,7 @@
} else {
Code& trampoline = Code::Handle(zone);
if (is_bootstrap_native) {
- trampoline = StubCode::CallBootstrapNative_entry()->code();
+ trampoline = StubCode::CallBootstrapNative().raw();
#if defined(USING_SIMULATOR)
patch_target_function = reinterpret_cast<NativeFunction>(
Simulator::RedirectExternalReference(
@@ -341,9 +340,9 @@
Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments));
#endif // defined USING_SIMULATOR
} else if (is_auto_scope) {
- trampoline = StubCode::CallAutoScopeNative_entry()->code();
+ trampoline = StubCode::CallAutoScopeNative().raw();
} else {
- trampoline = StubCode::CallNoScopeNative_entry()->code();
+ trampoline = StubCode::CallNoScopeNative().raw();
}
CodePatcher::PatchNativeCallAt(caller_frame->pc(), code,
patch_target_function, trampoline);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 34da421..c81689d 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2911,27 +2911,49 @@
return result.raw();
}
-bool Function::FindPragma(Isolate* I,
- const String& pragma_name,
- Object* options) const {
- if (!has_pragma()) return false;
+bool Library::FindPragma(Thread* T,
+ const Object& obj,
+ const String& pragma_name,
+ Object* options) const {
+ auto I = T->isolate();
+ auto Z = T->zone();
+ auto& lib = Library::Handle(Z);
+ if (obj.IsClass()) {
+ auto& klass = Class::Cast(obj);
+ if (!klass.has_pragma()) return false;
+ lib = klass.library();
+ } else if (obj.IsFunction()) {
+ auto& function = Function::Cast(obj);
+ if (!function.has_pragma()) return false;
+ lib = Class::Handle(Z, function.Owner()).library();
+ } else if (obj.IsField()) {
+ auto& field = Field::Cast(obj);
+ if (!field.has_pragma()) return false;
+ lib = Class::Handle(Z, field.Owner()).library();
+ } else {
+ UNREACHABLE();
+ }
- auto& klass = Class::Handle(Owner());
- auto& lib = Library::Handle(klass.library());
+ Object& metadata_obj = Object::Handle(Z, lib.GetMetadata(obj));
+ if (metadata_obj.IsUnwindError()) {
+ Report::LongJump(UnwindError::Cast(metadata_obj));
+ }
- auto& pragma_class =
- Class::Handle(Isolate::Current()->object_store()->pragma_class());
+ // If there is a compile-time error while evaluating the metadata, we will
+ // simply claim there was no @pramga annotation.
+ if (metadata_obj.IsNull() || metadata_obj.IsLanguageError()) {
+ return false;
+ }
+ ASSERT(metadata_obj.IsArray());
+
+ auto& metadata = Array::Cast(metadata_obj);
+ auto& pragma_class = Class::Handle(Z, I->object_store()->pragma_class());
auto& pragma_name_field =
- Field::Handle(pragma_class.LookupField(Symbols::name()));
+ Field::Handle(Z, pragma_class.LookupField(Symbols::name()));
auto& pragma_options_field =
- Field::Handle(pragma_class.LookupField(Symbols::options()));
+ Field::Handle(Z, pragma_class.LookupField(Symbols::options()));
- Array& metadata = Array::Handle();
- metadata ^= lib.GetMetadata(Function::Handle(raw()));
-
- if (metadata.IsNull()) return false;
-
- auto& pragma = Object::Handle();
+ auto& pragma = Object::Handle(Z);
for (intptr_t i = 0; i < metadata.Length(); ++i) {
pragma = metadata.At(i);
if (pragma.clazz() != pragma_class.raw() ||
@@ -3685,6 +3707,18 @@
CLASS_LIST_WITH_NULL(ADD_SET_FIELD)
#undef ADD_SET_FIELD
+
+#define ADD_SET_FIELD(clazz) \
+ field_name = Symbols::New(thread, "cid" #clazz "View"); \
+ field = Field::New(field_name, true, false, true, false, *this, \
+ Type::Handle(Type::IntType()), TokenPosition::kMinSource, \
+ TokenPosition::kMinSource); \
+ value = Smi::New(kTypedData##clazz##ViewCid); \
+ field.SetStaticValue(value, true); \
+ AddField(field);
+
+ CLASS_LIST_TYPED_DATA(ADD_SET_FIELD)
+#undef ADD_SET_FIELD
#undef CLASS_LIST_WITH_NULL
}
@@ -5857,10 +5891,10 @@
NoSafepointScope no_safepoint;
ASSERT(raw_ptr()->code_ != Code::null());
#if defined(DART_PRECOMPILED_RUNTIME)
- return raw_ptr()->code_ != StubCode::LazyCompile_entry()->code();
+ return raw_ptr()->code_ != StubCode::LazyCompile().raw();
#else
- return raw_ptr()->code_ != StubCode::LazyCompile_entry()->code() &&
- raw_ptr()->code_ != StubCode::InterpretCall_entry()->code();
+ return raw_ptr()->code_ != StubCode::LazyCompile().raw() &&
+ raw_ptr()->code_ != StubCode::InterpretCall().raw();
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
@@ -5914,7 +5948,7 @@
if (FLAG_enable_interpreter) {
// Set the code entry_point to InterpretCall stub.
- SetInstructions(Code::Handle(StubCode::InterpretCall_entry()->code()));
+ SetInstructions(StubCode::InterpretCall());
}
}
@@ -5931,10 +5965,10 @@
NoSafepointScope no_safepoint;
ASSERT(function->ptr()->code_ != Code::null());
#if defined(DART_PRECOMPILED_RUNTIME)
- return function->ptr()->code_ != StubCode::LazyCompile_entry()->code();
+ return function->ptr()->code_ != StubCode::LazyCompile().raw();
#else
- return function->ptr()->code_ != StubCode::LazyCompile_entry()->code() &&
- function->ptr()->code_ != StubCode::InterpretCall_entry()->code();
+ return function->ptr()->code_ != StubCode::LazyCompile().raw() &&
+ function->ptr()->code_ != StubCode::InterpretCall().raw();
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
@@ -5947,7 +5981,7 @@
StorePointer(&raw_ptr()->unoptimized_code_, Code::null());
StorePointer(&raw_ptr()->bytecode_, Bytecode::null());
- SetInstructions(Code::Handle(StubCode::LazyCompile_entry()->code()));
+ SetInstructions(StubCode::LazyCompile());
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
@@ -6008,10 +6042,10 @@
// Set the lazy compile or interpreter call stub code.
if (FLAG_enable_interpreter && HasBytecode()) {
TIR_Print("Switched to interpreter call stub for %s\n", ToCString());
- SetInstructions(Code::Handle(StubCode::InterpretCall_entry()->code()));
+ SetInstructions(StubCode::InterpretCall());
} else {
TIR_Print("Switched to lazy compile stub for %s\n", ToCString());
- SetInstructions(Code::Handle(StubCode::LazyCompile_entry()->code()));
+ SetInstructions(StubCode::LazyCompile());
}
return;
}
@@ -7413,8 +7447,7 @@
result.set_is_optimizable(is_native ? false : true);
result.set_is_background_optimizable(is_native ? false : true);
result.set_is_inlinable(true);
- result.SetInstructionsSafe(
- Code::Handle(StubCode::LazyCompile_entry()->code()));
+ result.SetInstructionsSafe(StubCode::LazyCompile());
if (kind == RawFunction::kClosureFunction ||
kind == RawFunction::kImplicitClosureFunction) {
ASSERT(space == Heap::kOld);
@@ -12467,7 +12500,7 @@
CHECK_FINGERPRINT3(func, class_name, function_name, dest, fp); \
}
-#define CHECK_FINGERPRINTS2(class_name, function_name, dest, type, fp) \
+#define CHECK_FINGERPRINTS2(class_name, function_name, dest, fp) \
CHECK_FINGERPRINTS(class_name, function_name, dest, fp)
all_libs.Add(&Library::ZoneHandle(Library::CoreLibrary()));
@@ -14993,8 +15026,7 @@
DEBUG_ASSERT(IsMutatorOrAtSafepoint());
ASSERT(IsFunctionCode());
ASSERT(instructions() == active_instructions());
- const Code& new_code =
- Code::Handle(StubCode::FixCallersTarget_entry()->code());
+ const Code& new_code = StubCode::FixCallersTarget();
SetActiveInstructions(Instructions::Handle(new_code.instructions()));
StoreNonPointer(&raw_ptr()->unchecked_entry_point_, raw_ptr()->entry_point_);
}
@@ -15004,8 +15036,7 @@
ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(IsAllocationStubCode());
ASSERT(instructions() == active_instructions());
- const Code& new_code =
- Code::Handle(StubCode::FixAllocationStubTarget_entry()->code());
+ const Code& new_code = StubCode::FixAllocationStubTarget();
SetActiveInstructions(Instructions::Handle(new_code.instructions()));
StoreNonPointer(&raw_ptr()->unchecked_entry_point_, raw_ptr()->entry_point_);
#else
@@ -22157,8 +22188,7 @@
// To account for gap frames.
frame_index += Smi::Value(stack_trace.PcOffsetAtFrame(i));
}
- } else if (code_object.raw() ==
- StubCode::AsynchronousGapMarker_entry()->code()) {
+ } else if (code_object.raw() == StubCode::AsynchronousGapMarker().raw()) {
buffer.AddString("<asynchronous suspension>\n");
// The frame immediately after the asynchronous gap marker is the
// identical to the frame above the marker. Skip the frame to enhance
@@ -22246,8 +22276,7 @@
// To account for gap frames.
frame_index += Smi::Value(stack_trace.PcOffsetAtFrame(i));
}
- } else if (code.raw() ==
- StubCode::AsynchronousGapMarker_entry()->code()) {
+ } else if (code.raw() == StubCode::AsynchronousGapMarker().raw()) {
buffer.AddString("<asynchronous suspension>\n");
// The frame immediately after the asynchronous gap marker is the
// identical to the frame above the marker. Skip the frame to enhance
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 5e72677..2e65d5d 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2234,6 +2234,9 @@
RawAbstractType* result_type() const { return raw_ptr()->result_type_; }
void set_result_type(const AbstractType& value) const;
+ // The parameters, starting with NumImplicitParameters() parameters which are
+ // only visible to the VM, but not to Dart users.
+ // Note that type checks exclude implicit parameters.
RawAbstractType* ParameterTypeAt(intptr_t index) const;
void SetParameterTypeAt(intptr_t index, const AbstractType& value) const;
RawArray* parameter_types() const { return raw_ptr()->parameter_types_; }
@@ -2280,8 +2283,6 @@
// Return true if any parent function of this function is generic.
bool HasGenericParent() const;
- bool FindPragma(Isolate* I, const String& pragma_name, Object* options) const;
-
// Not thread-safe; must be called in the main thread.
// Sets function's code and code's function.
void InstallOptimizedCode(const Code& code) const;
@@ -3825,6 +3826,18 @@
const Function& to_fun) const;
RawObject* GetMetadata(const Object& obj) const;
+ // Tries to finds a @pragma annotation on [object].
+ //
+ // If successful returns `true`. If an error happens during constant
+ // evaluation, returns `false.
+ //
+ // WARNING: If the isolate received an [UnwindError] this function will not
+ // return and rather unwinds until the enclosing setjmp() handler.
+ bool FindPragma(Thread* T,
+ const Object& object,
+ const String& pragma_name,
+ Object* options) const;
+
RawClass* toplevel_class() const { return raw_ptr()->toplevel_class_; }
void set_toplevel_class(const Class& value) const;
@@ -4443,6 +4456,7 @@
friend class Code;
friend class AssemblyImageWriter;
friend class BlobImageWriter;
+ friend class ImageWriter;
};
class LocalVarDescriptors : public Object {
diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc
index 70094af..1034547 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -269,7 +269,7 @@
}
void OS::Exit(int code) {
- UNIMPLEMENTED();
+ exit(code);
}
} // namespace dart
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index fbb891a..4cb44d8 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -622,8 +622,8 @@
#if !defined(TARGET_ARCH_DBC)
RawCode* marker = PCMarker(in_interpreted_frame);
- if (marker == StubCode::InvokeDartCode_entry()->code() ||
- marker == StubCode::InvokeDartCodeFromBytecode_entry()->code()) {
+ if (marker == StubCode::InvokeDartCode().raw() ||
+ marker == StubCode::InvokeDartCodeFromBytecode().raw()) {
// During the prologue of a function, CallerPC will return the caller's
// caller. For most frames, the missing PC will be added during profile
// processing. However, during this stack walk, it can cause us to fail
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index cdb5d63..3f9ef48 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -282,7 +282,9 @@
SNAPSHOT_WRITER_SUPPORT() \
HEAP_PROFILER_SUPPORT() \
friend class object##SerializationCluster; \
- friend class object##DeserializationCluster;
+ friend class object##DeserializationCluster; \
+ friend class Serializer; \
+ friend class Deserializer;
// RawObject is the base class of all raw objects; even though it carries the
// tags_ field not all raw objects are allocated in the heap and thus cannot
@@ -1142,6 +1144,7 @@
RawFunction* parent_function_; // Enclosing function of this sig. function.
RawType* signature_type_;
VISIT_TO(RawObject*, signature_type_);
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
friend class Function;
};
@@ -1155,6 +1158,7 @@
RawString* identifier_;
RawFunction* target_;
VISIT_TO(RawObject*, target_);
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
};
class RawField : public RawObject {
@@ -1340,6 +1344,7 @@
RawField* metadata_field_; // remembers the token pos of metadata if any,
// and the metadata values if computed.
VISIT_TO(RawObject*, metadata_field_);
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
};
class RawKernelProgramInfo : public RawObject {
@@ -1475,6 +1480,7 @@
RawExceptionHandlers* exception_handlers_;
RawPcDescriptors* pc_descriptors_;
VISIT_TO(RawObject*, pc_descriptors_);
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
intptr_t source_positions_binary_offset_;
@@ -1796,6 +1802,9 @@
// 'end' is the address just beyond the last descriptor, so step back.
return reinterpret_cast<RawObject**>(end - kWordSize);
}
+ RawObject** to_snapshot(Snapshot::Kind kind, intptr_t num_vars) {
+ return to(num_vars);
+ }
friend class Object;
friend class RawClosureData;
@@ -1818,6 +1827,7 @@
RawString* target_name_;
RawArray* args_descriptor_;
VISIT_TO(RawObject*, args_descriptor_);
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
};
class RawICData : public RawObject {
@@ -1867,6 +1877,7 @@
RawString* target_name_; // Name of target function.
RawArray* args_descriptor_; // Arguments descriptor.
VISIT_TO(RawObject*, args_descriptor_)
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
int32_t filled_entry_count_;
};
@@ -1902,6 +1913,8 @@
TokenPosition token_pos_; // Source position in script_.
bool report_after_token_; // Report message at or after the token.
int8_t kind_; // Of type Report::Kind.
+
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
};
class RawUnhandledException : public RawError {
@@ -1911,6 +1924,7 @@
RawInstance* exception_;
RawInstance* stacktrace_;
VISIT_TO(RawObject*, stacktrace_)
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
};
class RawUnwindError : public RawError {
@@ -2031,6 +2045,8 @@
TokenPosition token_pos_;
int8_t type_state_;
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
+
friend class CidRewriteVisitor;
friend class RawTypeArguments;
};
@@ -2042,6 +2058,7 @@
VISIT_FROM(RawObject*, type_)
RawAbstractType* type_; // The referenced type.
VISIT_TO(RawObject*, type_)
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
};
class RawTypeParameter : public RawAbstractType {
@@ -2059,6 +2076,8 @@
int16_t index_;
int8_t type_state_;
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
+
friend class CidRewriteVisitor;
};
@@ -2072,6 +2091,7 @@
RawSmi* hash_;
RawTypeParameter* type_parameter_; // For more detailed error reporting.
VISIT_TO(RawObject*, type_parameter_);
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
};
class RawMixinAppType : public RawAbstractType {
@@ -2103,6 +2123,8 @@
VISIT_TO(RawCompressed, hash_)
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
+
// Note that instantiator_type_arguments_, function_type_arguments_ and
// delayed_type_arguments_ are used to instantiate the signature of function_
// when this closure is involved in a type test. In other words, these fields
@@ -2277,6 +2299,7 @@
RawSmi* length_;
RawArray* data_;
VISIT_TO(RawCompressed, data_)
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
friend class SnapshotReader;
};
@@ -2425,6 +2448,7 @@
RawArray* code_array_; // Code object for each frame in the stack trace.
RawArray* pc_offset_array_; // Offset of PC for each frame.
VISIT_TO(RawObject*, pc_offset_array_)
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
// False for pre-allocated stack trace (used in OOM and Stack overflow).
bool expand_inlined_;
@@ -2458,6 +2482,7 @@
RawFunction* external_one_byte_sticky_function_;
RawFunction* external_two_byte_sticky_function_;
VISIT_TO(RawObject*, external_two_byte_sticky_function_)
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
intptr_t num_registers_;
@@ -2474,6 +2499,7 @@
RawObject* key_;
RawObject* value_;
VISIT_TO(RawObject*, value_)
+ RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
// Linked list is chaining all pending weak properties.
// Untyped to make it clear that it is not to be visited by GC.
diff --git a/runtime/vm/report.cc b/runtime/vm/report.cc
index f681530..980fedc 100644
--- a/runtime/vm/report.cc
+++ b/runtime/vm/report.cc
@@ -120,6 +120,14 @@
TokenPosition token_pos,
const char* format,
va_list args) {
+ // If an isolate is being killed a [UnwindError] will be propagated up the
+ // stack. In such a case we cannot wrap the unwind error in a new
+ // [LanguageError]. Instead we simply continue propagating the [UnwindError]
+ // upwards.
+ if (prev_error.IsUnwindError()) {
+ LongJump(prev_error);
+ UNREACHABLE();
+ }
const Error& error = Error::Handle(LanguageError::NewFormattedV(
prev_error, script, token_pos, Report::AtLocation, kError, Heap::kOld,
format, args));
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index f5676de..1ff2d59 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1408,8 +1408,7 @@
}
// Call site is not single target, switch to call using ICData.
- const Code& stub =
- Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code());
+ const Code& stub = StubCode::ICCallThroughCode();
ASSERT(!Isolate::Current()->compilation_allowed());
CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, ic_data,
stub);
@@ -1474,8 +1473,7 @@
}
// Patch to call through stub.
- const Code& stub =
- Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code());
+ const Code& stub = StubCode::ICCallThroughCode();
ASSERT(!Isolate::Current()->compilation_allowed());
CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, ic_data,
stub);
@@ -1559,8 +1557,7 @@
cache.set_entry_point(code.EntryPoint());
cache.set_lower_limit(lower);
cache.set_upper_limit(upper);
- const Code& stub =
- Code::Handle(zone, StubCode::SingleTargetCall_entry()->code());
+ const Code& stub = StubCode::SingleTargetCall();
CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, cache,
stub);
// Return the ICData. The miss stub will jump to continue in the IC call
@@ -1571,8 +1568,7 @@
}
// Patch to call through stub.
- const Code& stub =
- Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code());
+ const Code& stub = StubCode::ICCallThroughCode();
ASSERT(!Isolate::Current()->compilation_allowed());
CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code, ic_data,
stub);
@@ -1666,8 +1662,7 @@
ASSERT(caller_frame->IsDartFrame());
const Code& caller_code =
Code::Handle(zone, caller_frame->LookupDartCode());
- const Code& stub =
- Code::Handle(zone, StubCode::MegamorphicCall_entry()->code());
+ const Code& stub = StubCode::MegamorphicCall();
CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code,
cache, stub);
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index 0c6002c..2c7f573 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -41,9 +41,6 @@
ULLONG_MAX,
"Instruction address or instruction count to stop simulator at.");
-#define LIKELY(cond) __builtin_expect((cond), 1)
-#define UNLIKELY(cond) __builtin_expect((cond), 0)
-
// SimulatorSetjmpBuffer are linked together, and the last created one
// is referenced by the Simulator. When an exception is thrown, the exception
// runtime looks at where to jump and finds the corresponding
@@ -995,6 +992,7 @@
// Decode opcode and A part of the given value and dispatch to the
// corresponding bytecode handler.
+#ifdef DART_HAS_COMPUTED_GOTO
#define DISPATCH_OP(val) \
do { \
op = (val); \
@@ -1002,6 +1000,15 @@
TRACE_INSTRUCTION \
goto* dispatch[op & 0xFF]; \
} while (0)
+#else
+#define DISPATCH_OP(val) \
+ do { \
+ op = (val); \
+ rA = ((op >> 8) & 0xFF); \
+ TRACE_INSTRUCTION \
+ goto SwitchDispatch; \
+ } while (0)
+#endif
// Fetch next operation from PC, increment program counter and dispatch.
#define DISPATCH() DISPATCH_OP(*pc++)
@@ -1203,14 +1210,6 @@
const Array& arguments_descriptor,
const Array& arguments,
Thread* thread) {
- // Dispatch used to interpret bytecode. Contains addresses of
- // labels of bytecode handlers. Handlers themselves are defined below.
- static const void* dispatch[] = {
-#define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
- BYTECODES_LIST(TARGET)
-#undef TARGET
- };
-
// Interpreter state (see constants_dbc.h for high-level overview).
uint32_t* pc; // Program Counter: points to the next op to execute.
RawObject** FP; // Frame Pointer.
@@ -1287,8 +1286,26 @@
Function& function_h = Function::Handle();
#endif
- // Enter the dispatch loop.
- DISPATCH();
+#ifdef DART_HAS_COMPUTED_GOTO
+ static const void* dispatch[] = {
+#define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
+ BYTECODES_LIST(TARGET)
+#undef TARGET
+ };
+ DISPATCH(); // Enter the dispatch loop.
+#else
+ DISPATCH(); // Enter the dispatch loop.
+SwitchDispatch:
+ switch (op & 0xFF) {
+#define TARGET(name, fmt, fmta, fmtb, fmtc) \
+ case SimulatorBytecode::k##name: \
+ goto bc##name;
+ BYTECODES_LIST(TARGET)
+#undef TARGET
+ default:
+ FATAL1("Undefined opcode: %d\n", op);
+ }
+#endif
// Bytecode handlers (see constants_dbc.h for bytecode descriptions).
{
@@ -1374,9 +1391,9 @@
// Make the DRT_OptimizeInvokedFunction see a stub as its caller for
// consistency with the other architectures, and to avoid needing to
// generate a stackmap for the HotCheck pc.
- const StubEntry* stub = StubCode::OptimizeFunction_entry();
- FP[kPcMarkerSlotFromFp] = stub->code();
- pc = reinterpret_cast<uint32_t*>(stub->EntryPoint());
+ const Code& stub = StubCode::OptimizeFunction();
+ FP[kPcMarkerSlotFromFp] = stub.raw();
+ pc = reinterpret_cast<uint32_t*>(stub.EntryPoint());
Exit(thread, FP, FP + 3, pc);
NativeArguments args(thread, 1, /*argv=*/FP, /*retval=*/FP + 1);
@@ -3971,7 +3988,7 @@
fp_ = reinterpret_cast<RawObject**>(fp);
- if (pc == StubCode::RunExceptionHandler_entry()->EntryPoint()) {
+ if (pc == StubCode::RunExceptionHandler().EntryPoint()) {
// The RunExceptionHandler stub is a placeholder. We implement
// its behavior here.
RawObject* raw_exception = thread->active_exception();
diff --git a/runtime/vm/simulator_dbc.h b/runtime/vm/simulator_dbc.h
index 95a0a35..18aee10 100644
--- a/runtime/vm/simulator_dbc.h
+++ b/runtime/vm/simulator_dbc.h
@@ -67,7 +67,7 @@
uword get_pc() const { return reinterpret_cast<uword>(pc_); }
enum IntrinsicId {
-#define V(test_class_name, test_function_name, enum_name, type, fp) \
+#define V(test_class_name, test_function_name, enum_name, fp) \
k##enum_name##Intrinsic,
ALL_INTRINSICS_LIST(V) GRAPH_INTRINSICS_LIST(V)
#undef V
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 0ffe5da..85ba367 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -114,11 +114,11 @@
ASSERT(!is_interpreted());
uword raw_pc =
*reinterpret_cast<uword*>(sp() + (kSavedPcSlotFromSp * kWordSize));
- return raw_pc == StubCode::DeoptimizeLazyFromReturn_entry()->EntryPoint();
+ return raw_pc == StubCode::DeoptimizeLazyFromReturn().EntryPoint();
}
void MarkForLazyDeopt() {
ASSERT(!is_interpreted());
- set_pc(StubCode::DeoptimizeLazyFromReturn_entry()->EntryPoint());
+ set_pc(StubCode::DeoptimizeLazyFromReturn().EntryPoint());
}
void UnmarkForLazyDeopt() {
// If this frame was marked for lazy deopt, pc_ was computed to be the
@@ -126,8 +126,7 @@
// Write this value back into the frame.
ASSERT(!is_interpreted());
uword original_pc = pc();
- ASSERT(original_pc !=
- StubCode::DeoptimizeLazyFromReturn_entry()->EntryPoint());
+ ASSERT(original_pc != StubCode::DeoptimizeLazyFromReturn().EntryPoint());
set_pc(original_pc);
}
@@ -210,8 +209,8 @@
fp() + ((is_interpreted() ? kKBCSavedCallerPcSlotFromFp
: kSavedCallerPcSlotFromFp) *
kWordSize)));
- ASSERT(raw_pc != StubCode::DeoptimizeLazyFromThrow_entry()->EntryPoint());
- if (raw_pc == StubCode::DeoptimizeLazyFromReturn_entry()->EntryPoint()) {
+ ASSERT(raw_pc != StubCode::DeoptimizeLazyFromThrow().EntryPoint());
+ if (raw_pc == StubCode::DeoptimizeLazyFromReturn().EntryPoint()) {
return isolate()->FindPendingDeopt(GetCallerFp());
}
return raw_pc;
diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc
index a16b98d..24415e1 100644
--- a/runtime/vm/stack_trace.cc
+++ b/runtime/vm/stack_trace.cc
@@ -104,8 +104,7 @@
ASSERT(!async_pc_offset_array->IsNull());
// We start with the asynchronous gap marker.
ASSERT(async_code_array->At(0) != Code::null());
- ASSERT(async_code_array->At(0) ==
- StubCode::AsynchronousGapMarker_entry()->code());
+ ASSERT(async_code_array->At(0) == StubCode::AsynchronousGapMarker().raw());
const Object& code_object = Object::Handle(async_code_array->At(1));
if (code_object.IsCode()) {
*async_function = Code::Cast(code_object).function();
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index aad2c87..95e53c1 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -23,25 +23,12 @@
DECLARE_FLAG(bool, enable_interpreter);
-StubEntry* StubCode::entries_[kNumStubEntries] = {
-#define STUB_CODE_DECLARE(name) NULL,
+Code* StubCode::entries_[kNumStubEntries] = {
+#define STUB_CODE_DECLARE(name) nullptr,
VM_STUB_CODE_LIST(STUB_CODE_DECLARE)
#undef STUB_CODE_DECLARE
};
-StubEntry::StubEntry(const Code& code)
- : code_(code.raw()),
- entry_point_(code.EntryPoint()),
- monomorphic_entry_point_(code.MonomorphicEntryPoint()),
- size_(code.Size()),
- label_(code.EntryPoint()) {}
-
-// Visit all object pointers.
-void StubEntry::VisitObjectPointers(ObjectPointerVisitor* visitor) {
- ASSERT(visitor != NULL);
- visitor->VisitPointer(reinterpret_cast<RawObject**>(&code_));
-}
-
#if defined(DART_PRECOMPILED_RUNTIME)
void StubCode::Init() {
// Stubs will be loaded from the snapshot.
@@ -55,19 +42,17 @@
#else
#define STUB_CODE_GENERATE(name) \
- code ^= Generate("_stub_" #name, &object_pool_wrapper, \
- StubCode::Generate##name##Stub); \
- entries_[k##name##Index] = new StubEntry(code);
+ entries_[k##name##Index] = Code::ReadOnlyHandle(); \
+ *entries_[k##name##Index] = Generate("_stub_" #name, &object_pool_wrapper, \
+ StubCode::Generate##name##Stub);
#define STUB_CODE_SET_OBJECT_POOL(name) \
- code = entries_[k##name##Index]->code(); \
- code.set_object_pool(object_pool.raw());
+ entries_[k##name##Index]->set_object_pool(object_pool.raw());
void StubCode::Init() {
ObjectPoolWrapper object_pool_wrapper;
// Generate all the stubs.
- Code& code = Code::Handle();
VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
const ObjectPool& object_pool =
@@ -78,9 +63,7 @@
#undef STUB_CODE_GENERATE
#undef STUB_CODE_SET_OBJECT_POOL
-#define STUB_CODE_CLEANUP(name) \
- delete entries_[k##name##Index]; \
- entries_[k##name##Index] = NULL;
+#define STUB_CODE_CLEANUP(name) entries_[k##name##Index] = nullptr;
void StubCode::Cleanup() {
VM_STUB_CODE_LIST(STUB_CODE_CLEANUP);
@@ -117,7 +100,7 @@
bool StubCode::HasBeenInitialized() {
// Use AsynchronousGapMarker as canary.
- return StubCode::AsynchronousGapMarker_entry() != NULL;
+ return entries_[kAsynchronousGapMarkerIndex] != nullptr;
}
bool StubCode::InInvocationStub(uword pc, bool is_interpreted_frame) {
@@ -130,7 +113,7 @@
return Interpreter::IsEntryFrameMarker(pc);
}
{
- uword entry = StubCode::InvokeDartCodeFromBytecode_entry()->EntryPoint();
+ uword entry = StubCode::InvokeDartCodeFromBytecode().EntryPoint();
uword size = StubCode::InvokeDartCodeFromBytecodeSize();
if ((pc >= entry) && (pc < (entry + size))) {
return true;
@@ -138,7 +121,7 @@
}
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
- uword entry = StubCode::InvokeDartCode_entry()->EntryPoint();
+ uword entry = StubCode::InvokeDartCode().EntryPoint();
uword size = StubCode::InvokeDartCodeSize();
return (pc >= entry) && (pc < (entry + size));
#else
@@ -156,7 +139,7 @@
bool StubCode::InJumpToFrameStub(uword pc) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
- uword entry = StubCode::JumpToFrame_entry()->EntryPoint();
+ uword entry = StubCode::JumpToFrame().EntryPoint();
uword size = StubCode::JumpToFrameSize();
return (pc >= entry) && (pc < (entry + size));
#else
@@ -173,7 +156,7 @@
const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
ASSERT(error.IsNull());
if (cls.id() == kArrayCid) {
- return AllocateArray_entry()->code();
+ return AllocateArray().raw();
}
Code& stub = Code::Handle(zone, cls.allocation_stub());
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -274,35 +257,34 @@
}
#endif // !defined(TARGET_ARCH_DBC)
-const StubEntry* StubCode::UnoptimizedStaticCallEntry(
- intptr_t num_args_tested) {
+const Code& StubCode::UnoptimizedStaticCallEntry(intptr_t num_args_tested) {
// These stubs are not used by DBC.
#if !defined(TARGET_ARCH_DBC)
switch (num_args_tested) {
case 0:
- return ZeroArgsUnoptimizedStaticCall_entry();
+ return ZeroArgsUnoptimizedStaticCall();
case 1:
- return OneArgUnoptimizedStaticCall_entry();
+ return OneArgUnoptimizedStaticCall();
case 2:
- return TwoArgsUnoptimizedStaticCall_entry();
+ return TwoArgsUnoptimizedStaticCall();
default:
UNIMPLEMENTED();
- return NULL;
+ return Code::Handle();
}
#else
- return NULL;
+ return Code::Handle();
#endif
}
const char* StubCode::NameOfStub(uword entry_point) {
#define VM_STUB_CODE_TESTER(name) \
- if ((name##_entry() != NULL) && \
- (entry_point == name##_entry()->EntryPoint())) { \
+ if (entries_[k##name##Index] != nullptr && \
+ entries_[k##name##Index]->EntryPoint() == entry_point) { \
return "" #name; \
}
VM_STUB_CODE_LIST(VM_STUB_CODE_TESTER);
#undef VM_STUB_CODE_TESTER
- return NULL;
+ return nullptr;
}
} // namespace dart
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index ca61e06..637371b 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -118,32 +118,6 @@
// using Smi 0 instead of Object::null() is slightly more efficient, since a Smi
// does not require relocation.
-// class StubEntry is used to describe stub methods generated in dart to
-// abstract out common code executed from generated dart code.
-class StubEntry {
- public:
- explicit StubEntry(const Code& code);
- ~StubEntry() {}
-
- const ExternalLabel& label() const { return label_; }
- uword EntryPoint() const { return entry_point_; }
- uword MonomorphicEntryPoint() const { return monomorphic_entry_point_; }
- RawCode* code() const { return code_; }
- intptr_t Size() const { return size_; }
-
- // Visit all object pointers.
- void VisitObjectPointers(ObjectPointerVisitor* visitor);
-
- private:
- RawCode* code_;
- uword entry_point_;
- uword monomorphic_entry_point_;
- intptr_t size_;
- ExternalLabel label_;
-
- DISALLOW_COPY_AND_ASSIGN(StubEntry);
-};
-
// class StubCode is used to maintain the lifecycle of stubs.
class StubCode : public AllStatic {
public:
@@ -169,8 +143,8 @@
// Define the shared stub code accessors.
#define STUB_CODE_ACCESSOR(name) \
- static const StubEntry* name##_entry() { return entries_[k##name##Index]; } \
- static intptr_t name##Size() { return name##_entry()->Size(); }
+ static const Code& name() { return *entries_[k##name##Index]; } \
+ static intptr_t name##Size() { return name().Size(); }
VM_STUB_CODE_LIST(STUB_CODE_ACCESSOR);
#undef STUB_CODE_ACCESSOR
@@ -181,13 +155,15 @@
static void GenerateBuildMethodExtractorStub(Assembler* assembler);
#endif
- static const StubEntry* UnoptimizedStaticCallEntry(intptr_t num_args_tested);
+ static const Code& UnoptimizedStaticCallEntry(intptr_t num_args_tested);
static const intptr_t kNoInstantiator = 0;
static const intptr_t kInstantiationSizeInWords = 3;
- static StubEntry* EntryAt(intptr_t index) { return entries_[index]; }
- static void EntryAtPut(intptr_t index, StubEntry* entry) {
+ static const Code& EntryAt(intptr_t index) { return *entries_[index]; }
+ static void EntryAtPut(intptr_t index, Code* entry) {
+ ASSERT(entry->IsReadOnlyHandle());
+ ASSERT(entries_[index] == nullptr);
entries_[index] = entry;
}
static intptr_t NumEntries() { return kNumStubEntries; }
@@ -195,8 +171,6 @@
private:
friend class MegamorphicCacheTable;
- static const intptr_t kStubCodeSize = 4 * KB;
-
enum {
#define STUB_CODE_ENTRY(name) k##name##Index,
VM_STUB_CODE_LIST(STUB_CODE_ENTRY)
@@ -204,7 +178,7 @@
kNumStubEntries
};
- static StubEntry* entries_[kNumStubEntries];
+ static Code* entries_[kNumStubEntries];
#if !defined(DART_PRECOMPILED_RUNTIME)
#define STUB_CODE_GENERATE(name) \
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 7209ac5..2d04003 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -180,8 +180,7 @@
const intptr_t kReceiverOffset = compiler_frame_layout.param_end_from_fp + 1;
- const auto& context_allocation_stub =
- Code::ZoneHandle(StubCode::AllocateContext_entry()->code());
+ const auto& context_allocation_stub = StubCode::AllocateContext();
__ EnterStubFrame();
@@ -531,7 +530,7 @@
__ LoadObject(R1, Object::null_object());
// R1: null element type for raw Array.
// R2: smi-tagged argument count, may be zero.
- __ BranchLink(*StubCode::AllocateArray_entry());
+ __ BranchLink(StubCode::AllocateArray());
// R0: newly allocated array.
// R2: smi-tagged argument count, may be zero (was preserved by the stub).
__ Push(R0); // Array is in R0 and on top of stack.
@@ -2399,7 +2398,7 @@
__ Bind(&is_simple_case);
{
__ PushList(kRegsToSave);
- __ BranchLink(*StubCode::Subtype2TestCache_entry());
+ __ BranchLink(StubCode::Subtype2TestCache());
__ CompareObject(R1, Bool::True());
__ PopList(kRegsToSave);
__ BranchIf(EQUAL, &done); // Cache said: yes.
@@ -2409,7 +2408,7 @@
__ Bind(&is_complex_case);
{
__ PushList(kRegsToSave);
- __ BranchLink(*StubCode::Subtype6TestCache_entry());
+ __ BranchLink(StubCode::Subtype6TestCache());
__ CompareObject(R1, Bool::True());
__ PopList(kRegsToSave);
__ BranchIf(EQUAL, &done); // Cache said: yes.
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index f1ff4f6..384b31a 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -202,8 +202,7 @@
const intptr_t kReceiverOffset = compiler_frame_layout.param_end_from_fp + 1;
- const auto& context_allocation_stub =
- Code::ZoneHandle(StubCode::AllocateContext_entry()->code());
+ const auto& context_allocation_stub = StubCode::AllocateContext();
__ EnterStubFrame();
@@ -580,7 +579,7 @@
__ LoadObject(R1, Object::null_object());
// R1: null element type for raw Array.
// R2: smi-tagged argument count, may be zero.
- __ BranchLink(*StubCode::AllocateArray_entry());
+ __ BranchLink(StubCode::AllocateArray());
// R0: newly allocated array.
// R2: smi-tagged argument count, may be zero (was preserved by the stub).
__ Push(R0); // Array is in R0 and on top of stack.
@@ -2666,7 +2665,7 @@
__ Bind(&is_simple_case);
{
__ PushPair(kInstantiatorTypeArgumentsReg, kSubtypeTestCacheReg);
- __ BranchLink(*StubCode::Subtype2TestCache_entry());
+ __ BranchLink(StubCode::Subtype2TestCache());
__ CompareObject(R1, Bool::True());
__ PopPair(kInstantiatorTypeArgumentsReg, kSubtypeTestCacheReg);
__ BranchIf(EQUAL, &done); // Cache said: yes.
@@ -2676,7 +2675,7 @@
__ Bind(&is_complex_case);
{
__ PushPair(kInstantiatorTypeArgumentsReg, kSubtypeTestCacheReg);
- __ BranchLink(*StubCode::Subtype6TestCache_entry());
+ __ BranchLink(StubCode::Subtype6TestCache());
__ CompareObject(R1, Bool::True());
__ PopPair(kInstantiatorTypeArgumentsReg, kSubtypeTestCacheReg);
__ BranchIf(EQUAL, &done); // Cache said: yes.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index bab20db..93884e2 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -330,7 +330,7 @@
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ movl(ECX, raw_null); // Null element type for raw Array.
- __ Call(*StubCode::AllocateArray_entry());
+ __ Call(StubCode::AllocateArray());
__ SmiUntag(EDX);
// EAX: newly allocated array.
// EDX: length of the array (was preserved by the stub).
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 1ce8502..9033c2a 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -171,8 +171,7 @@
const intptr_t kReceiverOffset = compiler_frame_layout.param_end_from_fp + 1;
- const auto& context_allocation_stub =
- Code::ZoneHandle(StubCode::AllocateContext_entry()->code());
+ const auto& context_allocation_stub = StubCode::AllocateContext();
__ EnterStubFrame();
@@ -500,7 +499,7 @@
__ LoadObject(R12, Object::null_object());
// Allocate array to store arguments of caller.
__ movq(RBX, R12); // Null element type for raw Array.
- __ Call(*StubCode::AllocateArray_entry());
+ __ Call(StubCode::AllocateArray());
__ SmiUntag(R10);
// RAX: newly allocated array.
// R10: length of the array (was preserved by the stub).
@@ -2675,7 +2674,7 @@
__ Bind(&is_simple_case);
{
- __ Call(*StubCode::Subtype2TestCache_entry());
+ __ Call(StubCode::Subtype2TestCache());
__ CompareObject(R8, Bool::True());
__ BranchIf(EQUAL, &done); // Cache said: yes.
__ Jump(&call_runtime);
@@ -2683,7 +2682,7 @@
__ Bind(&is_complex_case);
{
- __ Call(*StubCode::Subtype6TestCache_entry());
+ __ Call(StubCode::Subtype6TestCache());
__ CompareObject(R8, Bool::True());
__ BranchIf(EQUAL, &done); // Cache said: yes.
// Fall through to runtime_call
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 87ac83d..38bfdf5 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -412,6 +412,7 @@
V(_UserTag, "_UserTag") \
V(Default, "Default") \
V(ClassID, "ClassID") \
+ V(getID, "getID") \
V(DartIsVM, "dart.isVM") \
V(stack, ":stack") \
V(stack_pointer, ":stack_pointer") \
@@ -456,6 +457,7 @@
V(DebugProcedureName, ":Eval") \
V(DebugClassName, "#DebugClass") \
V(vm_entry_point, "vm:entry-point") \
+ V(vm_non_nullable_result_type, "vm:non-nullable-result-type") \
V(vm_exact_result_type, "vm:exact-result-type") \
V(Get, "get") \
V(Set, "set") \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 740e8ef..65feb3b 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -213,7 +213,7 @@
defined(TARGET_ARCH_X64)
for (intptr_t i = 0; i < kNumberOfDartAvailableCpuRegs; ++i) {
write_barrier_wrappers_entry_points_[i] =
- StubCode::WriteBarrierWrappers_entry()->EntryPoint() +
+ StubCode::WriteBarrierWrappers().EntryPoint() +
i * kStoreBufferWrapperSize;
}
#endif
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 2041022..5b0ab13 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -85,41 +85,36 @@
#define CACHED_VM_STUBS_LIST(V)
#else
#define CACHED_VM_STUBS_LIST(V) \
- V(RawCode*, write_barrier_code_, StubCode::WriteBarrier_entry()->code(), \
+ V(RawCode*, write_barrier_code_, StubCode::WriteBarrier().raw(), NULL) \
+ V(RawCode*, array_write_barrier_code_, StubCode::ArrayWriteBarrier().raw(), \
NULL) \
- V(RawCode*, array_write_barrier_code_, \
- StubCode::ArrayWriteBarrier_entry()->code(), NULL) \
- V(RawCode*, fix_callers_target_code_, \
- StubCode::FixCallersTarget_entry()->code(), NULL) \
+ V(RawCode*, fix_callers_target_code_, StubCode::FixCallersTarget().raw(), \
+ NULL) \
V(RawCode*, fix_allocation_stub_code_, \
- StubCode::FixAllocationStubTarget_entry()->code(), NULL) \
- V(RawCode*, invoke_dart_code_stub_, \
- StubCode::InvokeDartCode_entry()->code(), NULL) \
+ StubCode::FixAllocationStubTarget().raw(), NULL) \
+ V(RawCode*, invoke_dart_code_stub_, StubCode::InvokeDartCode().raw(), NULL) \
V(RawCode*, invoke_dart_code_from_bytecode_stub_, \
- StubCode::InvokeDartCodeFromBytecode_entry()->code(), NULL) \
- V(RawCode*, call_to_runtime_stub_, StubCode::CallToRuntime_entry()->code(), \
- NULL) \
+ StubCode::InvokeDartCodeFromBytecode().raw(), NULL) \
+ V(RawCode*, call_to_runtime_stub_, StubCode::CallToRuntime().raw(), NULL) \
V(RawCode*, null_error_shared_without_fpu_regs_stub_, \
- StubCode::NullErrorSharedWithoutFPURegs_entry()->code(), NULL) \
+ StubCode::NullErrorSharedWithoutFPURegs().raw(), NULL) \
V(RawCode*, null_error_shared_with_fpu_regs_stub_, \
- StubCode::NullErrorSharedWithFPURegs_entry()->code(), NULL) \
+ StubCode::NullErrorSharedWithFPURegs().raw(), NULL) \
V(RawCode*, stack_overflow_shared_without_fpu_regs_stub_, \
- StubCode::StackOverflowSharedWithoutFPURegs_entry()->code(), NULL) \
+ StubCode::StackOverflowSharedWithoutFPURegs().raw(), NULL) \
V(RawCode*, stack_overflow_shared_with_fpu_regs_stub_, \
- StubCode::StackOverflowSharedWithFPURegs_entry()->code(), NULL) \
- V(RawCode*, monomorphic_miss_stub_, \
- StubCode::MonomorphicMiss_entry()->code(), NULL) \
+ StubCode::StackOverflowSharedWithFPURegs().raw(), NULL) \
+ V(RawCode*, monomorphic_miss_stub_, StubCode::MonomorphicMiss().raw(), NULL) \
V(RawCode*, ic_lookup_through_code_stub_, \
- StubCode::ICCallThroughCode_entry()->code(), NULL) \
- V(RawCode*, deoptimize_stub_, StubCode::Deoptimize_entry()->code(), NULL) \
+ StubCode::ICCallThroughCode().raw(), NULL) \
+ V(RawCode*, deoptimize_stub_, StubCode::Deoptimize().raw(), NULL) \
V(RawCode*, lazy_deopt_from_return_stub_, \
- StubCode::DeoptimizeLazyFromReturn_entry()->code(), NULL) \
+ StubCode::DeoptimizeLazyFromReturn().raw(), NULL) \
V(RawCode*, lazy_deopt_from_throw_stub_, \
- StubCode::DeoptimizeLazyFromThrow_entry()->code(), NULL) \
- V(RawCode*, slow_type_test_stub_, StubCode::SlowTypeTest_entry()->code(), \
- NULL) \
+ StubCode::DeoptimizeLazyFromThrow().raw(), NULL) \
+ V(RawCode*, slow_type_test_stub_, StubCode::SlowTypeTest().raw(), NULL) \
V(RawCode*, lazy_specialize_type_test_stub_, \
- StubCode::LazySpecializeTypeTest_entry()->code(), NULL)
+ StubCode::LazySpecializeTypeTest().raw(), NULL)
#endif
@@ -144,25 +139,25 @@
#define CACHED_VM_STUBS_ADDRESSES_LIST(V)
#else
#define CACHED_VM_STUBS_ADDRESSES_LIST(V) \
- V(uword, write_barrier_entry_point_, \
- StubCode::WriteBarrier_entry()->EntryPoint(), 0) \
+ V(uword, write_barrier_entry_point_, StubCode::WriteBarrier().EntryPoint(), \
+ 0) \
V(uword, array_write_barrier_entry_point_, \
- StubCode::ArrayWriteBarrier_entry()->EntryPoint(), 0) \
+ StubCode::ArrayWriteBarrier().EntryPoint(), 0) \
V(uword, call_to_runtime_entry_point_, \
- StubCode::CallToRuntime_entry()->EntryPoint(), 0) \
+ StubCode::CallToRuntime().EntryPoint(), 0) \
V(uword, null_error_shared_without_fpu_regs_entry_point_, \
- StubCode::NullErrorSharedWithoutFPURegs_entry()->EntryPoint(), 0) \
+ StubCode::NullErrorSharedWithoutFPURegs().EntryPoint(), 0) \
V(uword, null_error_shared_with_fpu_regs_entry_point_, \
- StubCode::NullErrorSharedWithFPURegs_entry()->EntryPoint(), 0) \
+ StubCode::NullErrorSharedWithFPURegs().EntryPoint(), 0) \
V(uword, stack_overflow_shared_without_fpu_regs_entry_point_, \
- StubCode::StackOverflowSharedWithoutFPURegs_entry()->EntryPoint(), 0) \
+ StubCode::StackOverflowSharedWithoutFPURegs().EntryPoint(), 0) \
V(uword, stack_overflow_shared_with_fpu_regs_entry_point_, \
- StubCode::StackOverflowSharedWithFPURegs_entry()->EntryPoint(), 0) \
+ StubCode::StackOverflowSharedWithFPURegs().EntryPoint(), 0) \
V(uword, megamorphic_call_checked_entry_, \
- StubCode::MegamorphicCall_entry()->EntryPoint(), 0) \
- V(uword, monomorphic_miss_entry_, \
- StubCode::MonomorphicMiss_entry()->EntryPoint(), 0) \
- V(uword, deoptimize_entry_, StubCode::Deoptimize_entry()->EntryPoint(), 0)
+ StubCode::MegamorphicCall().EntryPoint(), 0) \
+ V(uword, monomorphic_miss_entry_, StubCode::MonomorphicMiss().EntryPoint(), \
+ 0) \
+ V(uword, deoptimize_entry_, StubCode::Deoptimize().EntryPoint(), 0)
#endif
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index 1f849fd..ae8855e 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -105,21 +105,20 @@
if (type.raw() == Type::ObjectType() || type.raw() == Type::DynamicType() ||
type.raw() == Type::VoidType()) {
- return Code::InstructionsOf(StubCode::TopTypeTypeTest_entry()->code());
+ return StubCode::TopTypeTypeTest().instructions();
}
if (type.IsTypeRef()) {
- return Code::InstructionsOf(StubCode::TypeRefTypeTest_entry()->code());
+ return StubCode::TypeRefTypeTest().instructions();
}
if (type.IsType() || type.IsTypeParameter()) {
const bool should_specialize = !FLAG_precompiled_mode && lazy_specialize;
- return Code::InstructionsOf(
- should_specialize ? StubCode::LazySpecializeTypeTest_entry()->code()
- : StubCode::DefaultTypeTest_entry()->code());
+ return should_specialize ? StubCode::LazySpecializeTypeTest().instructions()
+ : StubCode::DefaultTypeTest().instructions();
} else {
ASSERT(type.IsBoundedType() || type.IsMixinAppType());
- return Code::InstructionsOf(StubCode::UnreachableTypeTest_entry()->code());
+ return StubCode::UnreachableTypeTest().instructions();
}
}
@@ -145,11 +144,11 @@
ASSERT(StubCode::HasBeenInitialized());
if (type.IsTypeRef()) {
- return Code::InstructionsOf(StubCode::TypeRefTypeTest_entry()->code());
+ return StubCode::TypeRefTypeTest().instructions();
}
if (type.raw() == Type::ObjectType() || type.raw() == Type::DynamicType()) {
- return Code::InstructionsOf(StubCode::TopTypeTypeTest_entry()->code());
+ return StubCode::TopTypeTypeTest().instructions();
}
if (type.IsCanonical()) {
@@ -168,14 +167,13 @@
array_.Add(instr_);
} else {
// Fall back to default.
- instr_ =
- Code::InstructionsOf(StubCode::DefaultTypeTest_entry()->code());
+ instr_ = StubCode::DefaultTypeTest().instructions();
}
#else
// In the precompiled runtime we cannot lazily create new optimized type
// testing stubs, so if we cannot find one, we'll just return the default
// one.
- instr_ = Code::InstructionsOf(StubCode::DefaultTypeTest_entry()->code());
+ instr_ = StubCode::DefaultTypeTest().instructions();
#endif // !defined(DART_PRECOMPILED_RUNTIME)
return instr_.raw();
}
@@ -199,23 +197,23 @@
RawInstructions* TypeTestingStubFinder::LookupByAddresss(
uword entry_point) const {
// First test the 4 common ones:
- code_ = StubCode::DefaultTypeTest_entry()->code();
+ code_ = StubCode::DefaultTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return code_.instructions();
}
- code_ = StubCode::LazySpecializeTypeTest_entry()->code();
+ code_ = StubCode::LazySpecializeTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return code_.instructions();
}
- code_ = StubCode::TopTypeTypeTest_entry()->code();
+ code_ = StubCode::TopTypeTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return code_.instructions();
}
- code_ = StubCode::TypeRefTypeTest_entry()->code();
+ code_ = StubCode::TypeRefTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return code_.instructions();
}
- code_ = StubCode::UnreachableTypeTest_entry()->code();
+ code_ = StubCode::UnreachableTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return code_.instructions();
}
@@ -227,23 +225,23 @@
const char* TypeTestingStubFinder::StubNameFromAddresss(
uword entry_point) const {
// First test the 4 common ones:
- code_ = StubCode::DefaultTypeTest_entry()->code();
+ code_ = StubCode::DefaultTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return "TypeTestingStub_Default";
}
- code_ = StubCode::LazySpecializeTypeTest_entry()->code();
+ code_ = StubCode::LazySpecializeTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return "TypeTestingStub_LazySpecialize";
}
- code_ = StubCode::TopTypeTypeTest_entry()->code();
+ code_ = StubCode::TopTypeTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return "TypeTestingStub_Top";
}
- code_ = StubCode::TypeRefTypeTest_entry()->code();
+ code_ = StubCode::TypeRefTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return "TypeTestingStub_Ref";
}
- code_ = StubCode::UnreachableTypeTest_entry()->code();
+ code_ = StubCode::UnreachableTypeTest().raw();
if (entry_point == code_.EntryPoint()) {
return "TypeTestingStub_Unreachable";
}
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 6c53746..e99f521 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -9,6 +9,7 @@
#include "platform/globals.h"
+#include "bin/kernel_isolate.h"
#include "vm/dart.h"
#include "vm/dart_api_state.h"
#include "vm/dart_entry.h"
diff --git a/runtime/vm/v8_snapshot_writer.cc b/runtime/vm/v8_snapshot_writer.cc
new file mode 100644
index 0000000..e945ca0
--- /dev/null
+++ b/runtime/vm/v8_snapshot_writer.cc
@@ -0,0 +1,290 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#if defined(DART_PRECOMPILER)
+
+#include "vm/v8_snapshot_writer.h"
+
+#include "vm/dart.h"
+#include "vm/os.h"
+
+namespace dart {
+
+const char* ZoneString(Zone* Z, const char* str) {
+ const intptr_t len = strlen(str) + 1;
+ char* dest = Z->Alloc<char>(len);
+ snprintf(dest, len, "%s", str);
+ return dest;
+}
+
+V8SnapshotProfileWriter::V8SnapshotProfileWriter(Zone* zone)
+ : zone_(zone),
+ node_types_(zone_),
+ edge_types_(zone_),
+ strings_(zone),
+ roots_(zone_, 100) {
+ node_types_.Insert({"Unknown", kUnknown});
+ node_types_.Insert({"ArtificialRoot", kArtificialRoot});
+
+ edge_types_.Insert({"context", kContext});
+ edge_types_.Insert({"element", kElement});
+ edge_types_.Insert({"property", kProperty});
+ edge_types_.Insert({"internal", kInternal});
+ edge_types_.Insert({"hidden", kHidden});
+ edge_types_.Insert({"shortcut", kShortcut});
+ edge_types_.Insert({"weak", kWeak});
+ edge_types_.Insert({"extra", kExtra});
+
+ strings_.Insert({"<unknown>", kUnknownString});
+ strings_.Insert({"<object>", kObjectString});
+ strings_.Insert({"<property>", kPropertyString});
+ strings_.Insert({"<artificial root>", kArtificialRootString});
+}
+
+void V8SnapshotProfileWriter::SetObjectTypeAndName(ObjectId object_id,
+ const char* type,
+ const char* name) {
+ ASSERT(type != nullptr);
+ NodeInfo* info = EnsureId(object_id);
+
+ if (!node_types_.HasKey(type)) {
+ node_types_.Insert({ZoneString(zone_, type), node_types_.Size()});
+ }
+
+ intptr_t type_id = node_types_.LookupValue(type);
+ ASSERT(info->type == kUnknown || info->type == type_id);
+ info->type = type_id;
+
+ if (name != nullptr) {
+ info->name = EnsureString(name);
+ } else {
+ info->name = EnsureString(type);
+ }
+}
+
+void V8SnapshotProfileWriter::AttributeBytesTo(ObjectId object_id,
+ size_t num_bytes) {
+ EnsureId(object_id)->self_size += num_bytes;
+}
+
+void V8SnapshotProfileWriter::AttributeReferenceTo(ObjectId object_id,
+ ObjectId to_object_id) {
+ EnsureId(to_object_id);
+ NodeInfo* info = EnsureId(object_id);
+
+#if defined(DEBUG)
+ // We should never add a reference twice.
+ for (intptr_t i = 0; i < info->edges->length(); ++i) {
+ ASSERT(info->edges->At(i).to_node != object_id);
+ }
+#endif
+
+ info->edges->Add(EdgeInfo{to_object_id});
+ ++edge_count_;
+}
+
+V8SnapshotProfileWriter::NodeInfo V8SnapshotProfileWriter::DefaultNode(
+ ObjectId object_id) {
+ return {
+ kUnknown,
+ kUnknownString,
+ object_id,
+ 0,
+ new (zone_) ZoneGrowableArray<EdgeInfo>(zone_, 0),
+ -1,
+ };
+}
+
+V8SnapshotProfileWriter::NodeInfo V8SnapshotProfileWriter::ArtificialRoot() {
+ return {
+ kArtificialRoot, kArtificialRootString, {kArtificial, 0}, 0, nullptr, 0,
+ };
+}
+
+V8SnapshotProfileWriter::NodeInfo* V8SnapshotProfileWriter::EnsureId(
+ ObjectId object_id) {
+ if (!nodes_.HasKey(object_id)) {
+ NodeInfo info = DefaultNode(object_id);
+ nodes_.Insert({object_id, info});
+ }
+ return &nodes_.Lookup(object_id)->value;
+}
+
+intptr_t V8SnapshotProfileWriter::EnsureString(const char* str) {
+ if (!strings_.HasKey(str)) {
+ strings_.Insert({ZoneString(zone_, str), strings_.Size()});
+ return strings_.Size() - 1;
+ }
+ return strings_.LookupValue(str);
+}
+
+void V8SnapshotProfileWriter::WriteNodeInfo(JSONWriter* writer,
+ const NodeInfo& info) {
+ writer->PrintValue(info.type);
+ writer->PrintValue(info.name);
+ writer->PrintValue(NodeIdFor(info.id));
+ writer->PrintValue(info.self_size);
+ // The artificial root has 'nullptr' edges, it actually points to all the
+ // roots.
+ writer->PrintValue64(info.edges != nullptr ? info.edges->length()
+ : roots_.length());
+ writer->PrintNewline();
+}
+
+void V8SnapshotProfileWriter::WriteEdgeInfo(JSONWriter* writer,
+ const EdgeInfo& info) {
+ writer->PrintValue64(kProperty); // type, not really used atm
+ writer->PrintValue64(
+ kPropertyString); // name_or_index, not really used either
+ writer->PrintValue64(nodes_.LookupValue(info.to_node).offset);
+ writer->PrintNewline();
+}
+
+void V8SnapshotProfileWriter::AddRoot(ObjectId object_id) {
+ EnsureId(object_id);
+ roots_.Add(object_id);
+}
+
+void V8SnapshotProfileWriter::WriteStringsTable(
+ JSONWriter* writer,
+ const DirectChainedHashMap<StringToIntMapTraits>& map) {
+ const char** strings = zone_->Alloc<const char*>(map.Size());
+ StringToIntMapTraits::Pair* pair = nullptr;
+ auto it = map.GetIterator();
+ while ((pair = it.Next()) != nullptr) {
+ ASSERT(pair->value >= 0 && pair->value < map.Size());
+ strings[pair->value] = pair->key;
+ }
+ for (intptr_t i = 0; i < map.Size(); ++i) {
+ writer->PrintValue(strings[i]);
+ writer->PrintNewline();
+ }
+}
+
+void V8SnapshotProfileWriter::Write(JSONWriter* writer) {
+ writer->OpenObject();
+
+ writer->OpenObject("snapshot");
+ {
+ writer->OpenObject("meta");
+
+ {
+ writer->OpenArray("node_fields");
+ writer->PrintValue("type");
+ writer->PrintValue("name");
+ writer->PrintValue("id");
+ writer->PrintValue("self_size");
+ writer->PrintValue("edge_count");
+ writer->CloseArray();
+ }
+
+ {
+ writer->OpenArray("node_types");
+ {
+ writer->OpenArray();
+ WriteStringsTable(writer, node_types_);
+ writer->CloseArray();
+ }
+ writer->CloseArray();
+ }
+
+ {
+ writer->OpenArray("edge_fields");
+ writer->PrintValue("type");
+ writer->PrintValue("name_or_index");
+ writer->PrintValue("to_node");
+ writer->CloseArray();
+ }
+
+ {
+ writer->OpenArray("edge_types");
+ {
+ writer->OpenArray();
+ WriteStringsTable(writer, edge_types_);
+ writer->CloseArray();
+ }
+ writer->CloseArray();
+ }
+
+ writer->CloseObject();
+
+ writer->PrintProperty64("node_count",
+ nodes_.Size() + 1 /* artificial root */);
+ writer->PrintProperty64("edge_count", edge_count_ + roots_.length());
+ }
+ writer->CloseObject();
+
+ {
+ writer->OpenArray("nodes");
+ // Write the artificial root node.
+ WriteNodeInfo(writer, ArtificialRoot());
+ intptr_t offset = kNumNodeFields;
+ ObjectIdToNodeInfoTraits::Pair* entry = nullptr;
+ auto it = nodes_.GetIterator();
+ while ((entry = it.Next()) != nullptr) {
+ ASSERT(entry->key == entry->value.id);
+ entry->value.offset = offset;
+ WriteNodeInfo(writer, entry->value);
+ offset += kNumNodeFields;
+ }
+ writer->CloseArray();
+ }
+
+ {
+ writer->OpenArray("edges");
+
+ // Write references from the artificial root to the actual roots.
+ for (ObjectId root : roots_) {
+ WriteEdgeInfo(writer, {root});
+ }
+
+ ObjectIdToNodeInfoTraits::Pair* entry = nullptr;
+ auto it = nodes_.GetIterator();
+ while ((entry = it.Next()) != nullptr) {
+ for (intptr_t i = 0; i < entry->value.edges->length(); ++i) {
+ WriteEdgeInfo(writer, entry->value.edges->At(i));
+ }
+ }
+
+ writer->CloseArray();
+ }
+
+ {
+ writer->OpenArray("strings");
+ WriteStringsTable(writer, strings_);
+ writer->CloseArray();
+ }
+
+ writer->CloseObject();
+}
+
+void V8SnapshotProfileWriter::Write(const char* filename) {
+ JSONWriter json;
+ Write(&json);
+
+ auto file_open = Dart::file_open_callback();
+ auto file_write = Dart::file_write_callback();
+ auto file_close = Dart::file_close_callback();
+ if ((file_open == nullptr) || (file_write == nullptr) ||
+ (file_close == nullptr)) {
+ OS::PrintErr("Could not access file callbacks to write snapshot profile.");
+ return;
+ }
+
+ auto file = file_open(filename, /*write=*/true);
+ if (file == nullptr) {
+ OS::PrintErr("Failed to open file %s\n", filename);
+ } else {
+ char* output = nullptr;
+ intptr_t output_length = 0;
+ json.Steal(&output, &output_length);
+ file_write(output, output_length, file);
+ free(output);
+ file_close(file);
+ }
+}
+
+} // namespace dart
+
+#endif
diff --git a/runtime/vm/v8_snapshot_writer.h b/runtime/vm/v8_snapshot_writer.h
new file mode 100644
index 0000000..c506b2e
--- /dev/null
+++ b/runtime/vm/v8_snapshot_writer.h
@@ -0,0 +1,201 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_VM_V8_SNAPSHOT_WRITER_H_
+#define RUNTIME_VM_V8_SNAPSHOT_WRITER_H_
+
+#include <utility>
+
+#include "platform/assert.h"
+#include "vm/allocation.h"
+#include "vm/hash_map.h"
+#include "vm/json_writer.h"
+
+namespace dart {
+
+struct StringToIntMapTraits {
+ typedef char const* Key;
+ typedef intptr_t Value;
+
+ struct Pair {
+ Key key;
+ Value value;
+ Pair() : key(nullptr), value(-1) {}
+ Pair(Key k, Value v) : key(k), value(v) {}
+ };
+
+ static Value ValueOf(Pair pair) { return pair.value; }
+
+ static Key KeyOf(Pair pair) { return pair.key; }
+
+ static size_t Hashcode(Key key) {
+ /// SAMIR_TODO
+ return 0;
+ }
+
+ static bool IsKeyEqual(Pair x, Key y) { return strcmp(x.key, y) == 0; }
+};
+
+class V8SnapshotProfileWriter : public ZoneAllocated {
+ public:
+ enum IdSpace {
+ kSnapshot = 0, // Can be VM or Isolate heap, they share ids.
+ kVmText = 1,
+ kIsolateText = 2,
+ kVmData = 3,
+ kIsolateData = 4,
+ kArtificial = 5, // Artificial objects (e.g. the global root).
+ kIdSpaceBits = 3,
+ };
+
+ typedef std::pair<IdSpace, intptr_t> ObjectId;
+
+#if !defined(DART_PRECOMPILER)
+ explicit V8SnapshotProfileWriter(Zone* zone) {}
+ virtual ~V8SnapshotProfileWriter() {}
+
+ void SetObjectTypeAndName(ObjectId object_id,
+ const char* type,
+ const char* name) {}
+ void AttributeBytesTo(ObjectId object_id, size_t num_bytes) {}
+ void AttributeReferenceTo(ObjectId object_id, ObjectId to_object_id) {}
+ void AddRoot(ObjectId object_id) {}
+#else
+ explicit V8SnapshotProfileWriter(Zone* zone);
+ virtual ~V8SnapshotProfileWriter() {}
+
+ // Records that the object referenced by 'object_id' has type 'type'. The
+ // 'type' for all 'Instance's should be 'Instance', not the user-visible type
+ // and use 'name' for the real type instead.
+ void SetObjectTypeAndName(ObjectId object_id,
+ const char* type,
+ const char* name);
+
+ // Charges 'num_bytes'-many bytes to 'object_id'. In a clustered snapshot,
+ // objects can have their data spread across multiple sections, so this can be
+ // called multiple times for the same object.
+ void AttributeBytesTo(ObjectId object_id, size_t num_bytes);
+
+ // Records that a reference to the object with id 'to_object_id' was written
+ // in order to serialize the object with id 'object_id'. This does not affect
+ // the number of bytes charged to 'object_id'.
+ void AttributeReferenceTo(ObjectId object_id, ObjectId to_object_id);
+
+ // Marks an object as being a root in the graph. Used for analysis of the
+ // graph.
+ void AddRoot(ObjectId object_id);
+
+ // Write to a file in the V8 Snapshot Profile (JSON/.heapsnapshot) format.
+ void Write(const char* file);
+
+ private:
+ static constexpr intptr_t kNumNodeFields = 5;
+ static constexpr intptr_t kNumEdgeFields = 3;
+
+ struct EdgeInfo {
+ // 'type' and 'name_or_index' aren't supported yet.
+ ObjectId to_node;
+ };
+
+ struct NodeInfo {
+ intptr_t type;
+ intptr_t name;
+ ObjectId id;
+ intptr_t self_size;
+ ZoneGrowableArray<EdgeInfo>* edges = nullptr;
+ // Populated during serialization.
+ intptr_t offset = -1;
+ // 'trace_node_id' isn't supported.
+ // 'edge_count' is computed on-demand.
+
+ // Used for testing sentinel in the hashtable.
+ bool operator!=(const NodeInfo& other) { return id != other.id; }
+ bool operator==(const NodeInfo& other) { return !(*this != other); }
+
+ NodeInfo(intptr_t type,
+ intptr_t name,
+ ObjectId id,
+ intptr_t self_size,
+ ZoneGrowableArray<EdgeInfo>* edges,
+ intptr_t offset)
+ : type(type),
+ name(name),
+ id(id),
+ self_size(self_size),
+ edges(edges),
+ offset(offset) {}
+ };
+
+ NodeInfo DefaultNode(ObjectId object_id);
+ static NodeInfo ArtificialRoot();
+
+ NodeInfo* EnsureId(ObjectId object_id);
+ intptr_t EnsureString(const char* str);
+ static intptr_t NodeIdFor(ObjectId id) {
+ return (id.second << kIdSpaceBits) | id.first;
+ }
+
+ enum ConstantStrings {
+ kUnknownString = 0,
+ kPropertyString = 1,
+ kObjectString = 2,
+ kArtificialRootString = 3,
+ };
+
+ enum ConstantEdgeTypes {
+ kContext = 0,
+ kElement = 1,
+ kProperty = 2,
+ kInternal = 3,
+ kHidden = 4,
+ kShortcut = 5,
+ kWeak = 6,
+ kExtra = 7,
+ };
+
+ enum ConstantNodeTypes {
+ kUnknown = 0,
+ kArtificialRoot = 1,
+ };
+
+ struct ObjectIdToNodeInfoTraits {
+ typedef ObjectId Key;
+ typedef NodeInfo Value;
+
+ struct Pair {
+ Key key;
+ Value value;
+ Pair()
+ : key{kSnapshot, -1}, value{0, 0, {kSnapshot, -1}, 0, nullptr, -1} {};
+ Pair(Key k, Value v) : key(k), value(v) {}
+ };
+
+ static Key KeyOf(const Pair& pair) { return pair.key; }
+
+ static Value ValueOf(const Pair& pair) { return pair.value; }
+
+ static size_t Hashcode(Key key) { return NodeIdFor(key); }
+
+ static bool IsKeyEqual(const Pair& x, Key y) { return x.key == y; }
+ };
+
+ Zone* zone_;
+ void Write(JSONWriter* writer);
+ void WriteNodeInfo(JSONWriter* writer, const NodeInfo& info);
+ void WriteEdgeInfo(JSONWriter* writer, const EdgeInfo& info);
+ void WriteStringsTable(JSONWriter* writer,
+ const DirectChainedHashMap<StringToIntMapTraits>& map);
+
+ DirectChainedHashMap<ObjectIdToNodeInfoTraits> nodes_;
+ DirectChainedHashMap<StringToIntMapTraits> node_types_;
+ DirectChainedHashMap<StringToIntMapTraits> edge_types_;
+ DirectChainedHashMap<StringToIntMapTraits> strings_;
+ ZoneGrowableArray<ObjectId> roots_;
+ size_t edge_count_ = 0;
+#endif
+};
+
+} // namespace dart
+
+#endif // RUNTIME_VM_V8_SNAPSHOT_WRITER_H_
diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni
index 50882d9..b0e7872 100644
--- a/runtime/vm/vm_sources.gni
+++ b/runtime/vm/vm_sources.gni
@@ -119,7 +119,6 @@
"instructions_x64.h",
"interpreter.cc",
"interpreter.h",
- "interpreter_unsupported.cc",
"isolate.cc",
"isolate.h",
"isolate_reload.cc",
@@ -278,9 +277,9 @@
"stack_frame.h",
"stack_frame_arm.h",
"stack_frame_arm64.h",
- "stack_frame_dbc",
+ "stack_frame_dbc.h",
"stack_frame_ia32.h",
- "stack_frame_kbc",
+ "stack_frame_kbc.h",
"stack_frame_x64.h",
"stack_trace.cc",
"stack_trace.h",
@@ -333,6 +332,8 @@
"unicode_data.cc",
"uri.cc",
"uri.h",
+ "v8_snapshot_writer.cc",
+ "v8_snapshot_writer.h",
"virtual_memory.cc",
"virtual_memory.h",
"virtual_memory_android.cc",
diff --git a/sdk/lib/_http/websocket_impl.dart b/sdk/lib/_http/websocket_impl.dart
index 330f9ea..e27ab20 100644
--- a/sdk/lib/_http/websocket_impl.dart
+++ b/sdk/lib/_http/websocket_impl.dart
@@ -732,12 +732,13 @@
void addFrame(int opcode, List<int> data) {
createFrame(
- opcode,
- data,
- webSocket._serverSide,
- _deflateHelper != null &&
- (opcode == _WebSocketOpcode.TEXT ||
- opcode == _WebSocketOpcode.BINARY)).forEach((e) {
+ opcode,
+ data,
+ webSocket._serverSide,
+ _deflateHelper != null &&
+ (opcode == _WebSocketOpcode.TEXT ||
+ opcode == _WebSocketOpcode.BINARY))
+ .forEach((e) {
_eventSink.add(e);
});
}
@@ -1204,9 +1205,7 @@
}
void addUtf8Text(List<int> bytes) {
- if (bytes is! List<int>) {
- throw new ArgumentError.value(bytes, "bytes", "Is not a list of bytes");
- }
+ ArgumentError.checkNotNull(bytes, "bytes");
_sink.add(new _EncodedString(bytes));
}
diff --git a/sdk/lib/_internal/js_runtime/lib/convert_patch.dart b/sdk/lib/_internal/js_runtime/lib/convert_patch.dart
index 2d234a4..afb5062 100644
--- a/sdk/lib/_internal/js_runtime/lib/convert_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/convert_patch.dart
@@ -496,3 +496,13 @@
return null;
}
}
+
+@patch
+int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
+ final to = endIndex;
+ for (var i = from; i < to; i++) {
+ final unit = units[i];
+ if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
+ }
+ return to - from;
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 14bf26d..0f14426 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -274,45 +274,42 @@
"because it is not included in a @MirrorsUsed annotation.");
}
-/// Helper to print the given method information to the console the first
-/// time it is called with it.
+/// Helper used to instrument calls when the compiler is invoked with
+/// `--experiment-call-instrumentation`.
+///
+/// By default, whenever a method is invoked for the first time, it prints an id
+/// and the method name to the console. This can be overriden by adding a top
+/// level `dartCallInstrumentation` hook in JavaScript.
@NoInline()
-void consoleTraceHelper(String method) {
- if (JS('bool', '!this.cache')) {
- JS('', 'this.cache = Object.create(null)');
- }
- if (JS('bool', '!this.cache[#]', method)) {
- JS('', 'console.log(#)', method);
- JS('', 'this.cache[#] = true', method);
- }
-}
-
-List _traceBuffer;
-
-/// Helper to send coverage information as a POST request to a server.
-@NoInline()
-void postTraceHelper(int id, String name) {
- // Note: we can't move this initialization to the declaration of
- // [_traceBuffer] because [postTraceHelper] is called very early on functions
- // that define constants, this happens before getters and setters are expanded
- // and before main starts executing. This initialization here allows us to
- // skip the lazy field initialization logic.
- if (_traceBuffer == null) _traceBuffer = JS('JSArray', '[]');
- if (JS('bool', '#.length == 0', _traceBuffer)) {
- JS(
- '',
- r'''
- window.setTimeout((function(buffer) {
- return function() {
- var xhr = new XMLHttpRequest();
- xhr.open("POST", "/coverage_uri_to_amend_by_server");
- xhr.send(JSON.stringify(buffer));
- buffer.length = 0;
- };
- })(#), 1000)''',
- _traceBuffer);
- }
- JS('', '#.push([#, #])', _traceBuffer, id, name);
+void traceHelper(dynamic /*int*/ id, dynamic /*String*/ qualifiedName) {
+ // Note: this method is written mostly in JavaScript to prevent a stack
+ // overflow. In particular, we use dynamic argument types because with with
+ // types, traceHelper would include type checks for the parameter types, those
+ // checks (intTypeCheck, stringTypeCheck) are themselves calls that end up
+ // invoking this traceHelper and produce a stack overflow. Similarly if we
+ // had Dart code below using, for example, string interpolation, we would
+ // include extra calls to the Dart runtime that could also trigger a stack
+ // overflow. This approach here is simpler than making the compiler smart
+ // about how to generate traceHelper calls more carefully.
+ JS(
+ '',
+ r'''
+ (function (id, name) {
+ var hook = self.dartCallInstrumentation;
+ if (typeof hook === "function") {
+ hook(id, name);
+ return;
+ }
+ if (!this.callInstrumentationCache) {
+ this.callInstrumentationCache = Object.create(null);
+ }
+ if (!this.callInstrumentationCache[id]) {
+ console.log(id, name);
+ this.callInstrumentationCache[id] = true;
+ }
+ })(#, #)''',
+ id,
+ qualifiedName);
}
class JSInvocationMirror implements Invocation {
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index c968cbd..b9d22c1 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -224,9 +224,6 @@
var result = computation();
if (result is Future<T>) {
return result;
- } else if (result is Future) {
- // TODO(lrn): Remove this case for Dart 2.0.
- return new _Future<T>.immediate(result);
} else {
return new _Future<T>.value(result);
}
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 798e63f..f77ca2c 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -1423,7 +1423,8 @@
* with a [RangeError].
*/
Future<T> elementAt(int index) {
- if (index is! int || index < 0) throw new ArgumentError(index);
+ ArgumentError.checkNotNull(index, "index");
+ RangeError.checkNotNegative(index, "index");
_Future<T> future = new _Future<T>();
StreamSubscription subscription;
int elementIndex = 0;
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 956de3b..51497e0 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -363,7 +363,7 @@
if (_cancelOnError) {
_state |= _STATE_WAIT_FOR_CANCEL;
_cancel();
- if (_cancelFuture is Future &&
+ if (_cancelFuture != null &&
!identical(_cancelFuture, Future._nullFuture)) {
_cancelFuture.whenComplete(sendError);
} else {
@@ -392,7 +392,7 @@
_cancel();
_state |= _STATE_WAIT_FOR_CANCEL;
- if (_cancelFuture is Future &&
+ if (_cancelFuture != null &&
!identical(_cancelFuture, Future._nullFuture)) {
_cancelFuture.whenComplete(sendDone);
} else {
diff --git a/sdk/lib/async/stream_pipe.dart b/sdk/lib/async/stream_pipe.dart
index 31d5bab..e526179 100644
--- a/sdk/lib/async/stream_pipe.dart
+++ b/sdk/lib/async/stream_pipe.dart
@@ -26,7 +26,7 @@
void _cancelAndError(StreamSubscription subscription, _Future future, error,
StackTrace stackTrace) {
var cancelFuture = subscription.cancel();
- if (cancelFuture is Future && !identical(cancelFuture, Future._nullFuture)) {
+ if (cancelFuture != null && !identical(cancelFuture, Future._nullFuture)) {
cancelFuture.whenComplete(() => future._completeError(error, stackTrace));
} else {
future._completeError(error, stackTrace);
@@ -57,7 +57,7 @@
before completing with a value. */
void _cancelAndValue(StreamSubscription subscription, _Future future, value) {
var cancelFuture = subscription.cancel();
- if (cancelFuture is Future && !identical(cancelFuture, Future._nullFuture)) {
+ if (cancelFuture != null && !identical(cancelFuture, Future._nullFuture)) {
cancelFuture.whenComplete(() => future._complete(value));
} else {
future._complete(value);
@@ -306,7 +306,7 @@
super(source) {
// This test is done early to avoid handling an async error
// in the _handleData method.
- if (count is! int) throw new ArgumentError(count);
+ ArgumentError.checkNotNull(count, "count");
}
StreamSubscription<T> _createSubscription(void onData(T data),
@@ -397,7 +397,8 @@
super(source) {
// This test is done early to avoid handling an async error
// in the _handleData method.
- if (count is! int || count < 0) throw new ArgumentError(count);
+ ArgumentError.checkNotNull(count, "count");
+ RangeError.checkNotNegative(count, "count");
}
StreamSubscription<T> _createSubscription(void onData(T data),
diff --git a/sdk/lib/async/timer.dart b/sdk/lib/async/timer.dart
index 186bbe6..aa2f088 100644
--- a/sdk/lib/async/timer.dart
+++ b/sdk/lib/async/timer.dart
@@ -89,6 +89,10 @@
/**
* Cancels the timer.
+ *
+ * Once a [Timer] has been canceled, the callback function will not be called
+ * by the timer. Calling [cancel] more than once on a [Timer] is allowed, and
+ * will have no further effect.
*/
void cancel();
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index dc84459..b7b5497 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.dart
@@ -199,7 +199,7 @@
}
E elementAt(int index) {
- if (index is! int) throw new ArgumentError.notNull("index");
+ ArgumentError.checkNotNull(index, "index");
RangeError.checkNotNegative(index, "index");
int elementIndex = 0;
for (E element in this) {
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index 4b50c6a..0c01350 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -486,15 +486,12 @@
}
void insert(int index, E element) {
+ ArgumentError.checkNotNull(index, "index");
RangeError.checkValueInInterval(index, 0, length, "index");
if (index == this.length) {
add(element);
return;
}
- // We are modifying the length just below the is-check. Without the check
- // Array.copy could throw an exception, leaving the list in a bad state
- // (with a length that has been increased, but without a new element).
- if (index is! int) throw new ArgumentError(index);
this.length++;
setRange(index + 1, this.length, this, index);
this[index] = element;
diff --git a/sdk/lib/collection/set.dart b/sdk/lib/collection/set.dart
index 0d986f9..c63bf30 100644
--- a/sdk/lib/collection/set.dart
+++ b/sdk/lib/collection/set.dart
@@ -276,7 +276,7 @@
}
E elementAt(int index) {
- if (index is! int) throw new ArgumentError.notNull("index");
+ ArgumentError.checkNotNull(index, "index");
RangeError.checkNotNegative(index, "index");
int elementIndex = 0;
for (E element in this) {
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 567c8b2..eb92e2b 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -412,16 +412,6 @@
_expectedUnits = 0;
_extraUnits = 0;
- int scanOneByteCharacters(List<int> units, int from) {
- final to = endIndex;
- final mask = _ONE_BYTE_LIMIT;
- for (var i = from; i < to; i++) {
- final unit = units[i];
- if ((unit & mask) != unit) return i - from;
- }
- return to - from;
- }
-
void addSingleBytes(int from, int to) {
assert(from >= startIndex && from <= endIndex);
assert(to >= startIndex && to <= endIndex);
@@ -484,7 +474,7 @@
}
while (i < endIndex) {
- var oneBytes = scanOneByteCharacters(codeUnits, i);
+ var oneBytes = _scanOneByteCharacters(codeUnits, i, endIndex);
if (oneBytes > 0) {
_isFirstCharacter = false;
addSingleBytes(i, i + oneBytes);
@@ -545,3 +535,10 @@
}
}
}
+
+// Returns the number of bytes in [units] starting at offset [from] which have
+// the leftmost bit set to 0.
+//
+// To increase performance of this critical method we have a special variant of
+// it implemented in the VM's patch files, which is why we make it external.
+external int _scanOneByteCharacters(List<int> units, int from, int endIndex);
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index 7e192c2..52bfc29 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -211,7 +211,7 @@
int get inMicroseconds => _duration;
/**
- * Returns `true` if this [Duration] is the same object as [other].
+ * Returns `true` if this [Duration] has the same value as [other].
*/
bool operator ==(dynamic other) =>
other is Duration && _duration == other.inMicroseconds;
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 1325dab..3436b58 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -638,7 +638,7 @@
* Some iterables may have more a efficient way to find the element.
*/
E elementAt(int index) {
- if (index is! int) throw new ArgumentError.notNull("index");
+ ArgumentError.checkNotNull(index, "index");
RangeError.checkNotNegative(index, "index");
int elementIndex = 0;
for (E element in this) {
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index f7cf182..4e78c2a 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -77,30 +77,31 @@
external factory List([int length]);
/**
- * Creates a fixed-length list of the given length, and initializes the
- * value at each position with [fill]:
- *
- * new List<int>.filled(3, 0); // [0, 0, 0]
+ * Creates a list of the given length with [fill] at each position.
*
* The [length] must be a non-negative integer.
*
+ * Example:
+ * ```dart
+ * new List<int>.filled(3, 0, growable: true); // [0, 0, 0]
+ * ```
+ *
+ * The created list is fixed-length if [growable] is false (the default)
+ * and growable if [growable] is true.
* If the list is growable, changing its length will not initialize new
- * entries with [fill]. After being created and filled, the list is
- * no different from any other growable or fixed-length list
- * created using [List].
+ * entries with [fill].
+ * After being created and filled, the list is no different from any other
+ * growable or fixed-length list created using [List].
*
- * All entries in the returned list point to the same provided [fill] value.
- * That all items in the list are the same object is
- * observable when the given value is a mutable object.
- *
+ * All elements of the returned list share the same [fill] value.
* ```
* var shared = new List.filled(3, []);
* shared[0].add(499);
* print(shared); // => [[499], [499], [499]]
* ```
*
- * You may use [List.generate] to create a new object for each position in
- * in the list.
+ * You can use [List.generate] to create a list with a new object at
+ * each position.
* ```
* var unique = new List.generate(3, (_) => []);
* unique[0].add(499);
diff --git a/sdk/lib/developer/extension.dart b/sdk/lib/developer/extension.dart
index ec316c7..c6f4cce 100644
--- a/sdk/lib/developer/extension.dart
+++ b/sdk/lib/developer/extension.dart
@@ -21,9 +21,7 @@
: _result = result,
_errorCode = null,
_errorDetail = null {
- if (_result is! String) {
- throw new ArgumentError.value(_result, "result", "Must be a String");
- }
+ ArgumentError.checkNotNull(_result, "result");
}
/// Creates an error response to a service protocol extension RPC.
@@ -37,10 +35,7 @@
_errorCode = errorCode,
_errorDetail = errorDetail {
_validateErrorCode(_errorCode);
- if (_errorDetail is! String) {
- throw new ArgumentError.value(
- _errorDetail, "errorDetail", "Must be a String");
- }
+ ArgumentError.checkNotNull(_errorDetail, "errorDetail");
}
/// Invalid method parameter(s) error code.
@@ -80,12 +75,8 @@
}
static _validateErrorCode(int errorCode) {
- if (errorCode is! int) {
- throw new ArgumentError.value(errorCode, "errorCode", "Must be an int");
- }
- if (errorCode == invalidParams) {
- return;
- }
+ ArgumentError.checkNotNull(errorCode, "errorCode");
+ if (errorCode == invalidParams) return;
if ((errorCode >= extensionErrorMin) && (errorCode <= extensionErrorMax)) {
return;
}
@@ -134,31 +125,22 @@
/// Because service extensions are isolate specific, clients using extensions
/// must always include an 'isolateId' parameter with each RPC.
void registerExtension(String method, ServiceExtensionHandler handler) {
- if (method is! String) {
- throw new ArgumentError.value(method, 'method', 'Must be a String');
- }
+ ArgumentError.checkNotNull(method, 'method');
if (!method.startsWith('ext.')) {
throw new ArgumentError.value(method, 'method', 'Must begin with ext.');
}
if (_lookupExtension(method) != null) {
throw new ArgumentError('Extension already registered: $method');
}
- if (handler is! ServiceExtensionHandler) {
- throw new ArgumentError.value(
- handler, 'handler', 'Must be a ServiceExtensionHandler');
- }
+ ArgumentError.checkNotNull(handler, 'handler');
_registerExtension(method, handler);
}
/// Post an event of [eventKind] with payload of [eventData] to the `Extension`
/// event stream.
void postEvent(String eventKind, Map eventData) {
- if (eventKind is! String) {
- throw new ArgumentError.value(eventKind, 'eventKind', 'Must be a String');
- }
- if (eventData is! Map) {
- throw new ArgumentError.value(eventData, 'eventData', 'Must be a Map');
- }
+ ArgumentError.checkNotNull(eventKind, 'eventKind');
+ ArgumentError.checkNotNull(eventData, 'eventData');
String eventDataAsString = json.encode(eventData);
_postEvent(eventKind, eventDataAsString);
}
diff --git a/sdk/lib/developer/profiler.dart b/sdk/lib/developer/profiler.dart
index 665cd27..05a9211 100644
--- a/sdk/lib/developer/profiler.dart
+++ b/sdk/lib/developer/profiler.dart
@@ -64,15 +64,9 @@
Gauge(String name, String description, this.min, this.max)
: super(name, description) {
- if (min is! double) {
- throw new ArgumentError('min must be a double');
- }
- if (max is! double) {
- throw new ArgumentError('max must be a double');
- }
- if (!(min < max)) {
- throw new ArgumentError('min must be less than max');
- }
+ ArgumentError.checkNotNull(min, 'min');
+ ArgumentError.checkNotNull(max, 'max');
+ if (!(min < max)) throw new ArgumentError('min must be less than max');
_value = min;
}
@@ -117,9 +111,7 @@
/// Register [Metric]s to make them visible to Observatory.
static void register(Metric metric) {
- if (metric is! Metric) {
- throw new ArgumentError('metric must be a Metric');
- }
+ ArgumentError.checkNotNull(metric, 'metric');
if (_metrics[metric.name] != null) {
throw new ArgumentError('Registered metrics have unique names');
}
@@ -128,9 +120,7 @@
/// Deregister [Metric]s to make them not visible to Observatory.
static void deregister(Metric metric) {
- if (metric is! Metric) {
- throw new ArgumentError('metric must be a Metric');
- }
+ ArgumentError.checkNotNull(metric, 'metric');
_metrics.remove(metric.name);
}
diff --git a/sdk/lib/developer/service.dart b/sdk/lib/developer/service.dart
index 9616963..a4d92b9 100644
--- a/sdk/lib/developer/service.dart
+++ b/sdk/lib/developer/service.dart
@@ -58,9 +58,7 @@
/// enable (true) or disable (false) the web server servicing requests.
static Future<ServiceProtocolInfo> controlWebServer(
{bool enable: false}) async {
- if (enable is! bool) {
- throw new ArgumentError.value(enable, 'enable', 'Must be a bool');
- }
+ ArgumentError.checkNotNull(enable, 'enable');
// Port to receive response from service isolate.
final RawReceivePort receivePort = new RawReceivePort();
final Completer<Uri> uriCompleter = new Completer<Uri>();
@@ -79,9 +77,7 @@
/// Returns null if the running Dart environment does not support the service
/// protocol.
static String getIsolateID(Isolate isolate) {
- if (isolate is! Isolate) {
- throw new ArgumentError.value(isolate, 'isolate', 'Must be an Isolate');
- }
+ ArgumentError.checkNotNull(isolate, 'isolate');
return _getIsolateIDFromSendPort(isolate.controlPort);
}
}
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index e838a1f..37ae997 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -100,22 +100,18 @@
/// a [Flow] event. This operation must be finished before
/// returning to the event queue.
static void startSync(String name, {Map arguments, Flow flow}) {
- if (_isProduct) {
- return;
- }
- if (name is! String) {
- throw new ArgumentError.value(name, 'name', 'Must be a String');
- }
+ if (_isProduct) return;
+ ArgumentError.checkNotNull(name, 'name');
if (!_isDartStreamEnabled()) {
// Push a null onto the stack and return.
_stack.add(null);
return;
}
var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock());
- if (arguments is Map) {
+ if (arguments != null) {
block._arguments = arguments;
}
- if (flow is Flow) {
+ if (flow != null) {
block.flow = flow;
}
_stack.add(block);
@@ -141,18 +137,14 @@
/// Emit an instant event.
static void instantSync(String name, {Map arguments}) {
- if (_isProduct) {
- return;
- }
- if (name is! String) {
- throw new ArgumentError.value(name, 'name', 'Must be a String');
- }
+ if (_isProduct) return;
+ ArgumentError.checkNotNull(name, 'name');
if (!_isDartStreamEnabled()) {
// Stream is disabled.
return;
}
Map instantArguments;
- if (arguments is Map) {
+ if (arguments != null) {
instantArguments = new Map.from(arguments);
}
_reportInstantEvent(
@@ -189,22 +181,16 @@
/// Create a task with an explicit [taskId]. This is useful if you are
/// passing a task from one isolate to another.
TimelineTask.withTaskId(int taskId) : _taskId = taskId {
- if (taskId is! int) {
- throw new ArgumentError.value(taskId, 'taskId', 'Must be an int');
- }
+ ArgumentError.checkNotNull(taskId, 'taskId');
}
/// Start a synchronous operation within this task named [name].
/// Optionally takes a [Map] of [arguments].
void start(String name, {Map arguments}) {
- if (_isProduct) {
- return;
- }
- if (name is! String) {
- throw new ArgumentError.value(name, 'name', 'Must be a String');
- }
+ if (_isProduct) return;
+ ArgumentError.checkNotNull(name, 'name');
var block = new _AsyncBlock._(name, _taskId);
- if (arguments is Map) {
+ if (arguments != null) {
block._arguments = arguments;
}
_stack.add(block);
@@ -213,14 +199,10 @@
/// Emit an instant event for this task.
void instant(String name, {Map arguments}) {
- if (_isProduct) {
- return;
- }
- if (name is! String) {
- throw new ArgumentError.value(name, 'name', 'Must be a String');
- }
+ if (_isProduct) return;
+ ArgumentError.checkNotNull(name, 'name');
Map instantArguments;
- if (arguments is Map) {
+ if (arguments != null) {
instantArguments = new Map.from(arguments);
}
_reportTaskEvent(_getTraceClock(), _taskId, 'n', 'Dart', name,
diff --git a/sdk/lib/internal/iterable.dart b/sdk/lib/internal/iterable.dart
index de62e02..10f0898 100644
--- a/sdk/lib/internal/iterable.dart
+++ b/sdk/lib/internal/iterable.dart
@@ -493,9 +493,8 @@
final int _takeCount;
factory TakeIterable(Iterable<E> iterable, int takeCount) {
- if (takeCount is! int || takeCount < 0) {
- throw new ArgumentError(takeCount);
- }
+ ArgumentError.checkNotNull(takeCount, "takeCount");
+ RangeError.checkNotNegative(takeCount, "takeCount");
if (iterable is EfficientLengthIterable) {
return new EfficientLengthTakeIterable<E>(iterable, takeCount);
}
@@ -621,9 +620,7 @@
}
int _checkCount(int count) {
- if (count is! int) {
- throw new ArgumentError.value(count, "count", "is not an integer");
- }
+ ArgumentError.checkNotNull(count, "count");
RangeError.checkNotNegative(count, "count");
return count;
}
diff --git a/sdk/lib/io/common.dart b/sdk/lib/io/common.dart
index 01476ea..77b7587 100644
--- a/sdk/lib/io/common.dart
+++ b/sdk/lib/io/common.dart
@@ -105,9 +105,7 @@
int j = start;
for (int i = 0; i < length; i++) {
int value = buffer[j];
- if (value is! int) {
- throw new ArgumentError("List element is not an integer at index $j");
- }
+ if (value == null) throw ArgumentError("List element is null at index $j");
newBuffer[i] = value;
j++;
}
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index 42d6865..faed892 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -9,9 +9,7 @@
Uint8List _rawPath;
_Directory(String path) {
- if (path is! String) {
- throw new ArgumentError('${Error.safeToString(path)} is not a String');
- }
+ ArgumentError.checkNotNull(path, 'path');
_path = path;
_rawPath = FileSystemEntity._toUtf8Array(_path);
}
@@ -192,8 +190,9 @@
}
Future<Directory> _delete({bool recursive: false}) {
- return _File._dispatchWithNamespace(_IOService.directoryDelete,
- [null, _rawPath, recursive]).then((response) {
+ return _File._dispatchWithNamespace(
+ _IOService.directoryDelete, [null, _rawPath, recursive])
+ .then((response) {
if (_isErrorResponse(response)) {
throw _exceptionOrErrorFromResponse(response, "Deletion failed");
}
@@ -252,8 +251,8 @@
result,
// FIXME(bkonyi): here we're using `path` directly, which might cause issues
// if it is not UTF-8 encoded.
- FileSystemEntity
- ._toUtf8Array(FileSystemEntity._ensureTrailingPathSeparators(path)),
+ FileSystemEntity._toUtf8Array(
+ FileSystemEntity._ensureTrailingPathSeparators(path)),
recursive,
followLinks);
return result;
@@ -369,8 +368,8 @@
return;
}
nextRunning = true;
- _IOService
- ._dispatch(_IOService.directoryListNext, [pointer]).then((result) {
+ _IOService._dispatch(_IOService.directoryListNext, [pointer])
+ .then((result) {
nextRunning = false;
if (result is List) {
next();
@@ -420,8 +419,8 @@
if (pointer == null) {
_cleanup();
} else {
- _IOService._dispatch(
- _IOService.directoryListStop, [pointer]).whenComplete(_cleanup);
+ _IOService._dispatch(_IOService.directoryListStop, [pointer])
+ .whenComplete(_cleanup);
}
}
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 05508cc..33c1352 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -207,17 +207,13 @@
Uint8List _rawPath;
_File(String path) {
- if (path is! String) {
- throw new ArgumentError('${Error.safeToString(path)} is not a String');
- }
+ ArgumentError.checkNotNull(path, 'path');
_path = path;
_rawPath = FileSystemEntity._toUtf8Array(path);
}
_File.fromRawPath(Uint8List rawPath) {
- if (rawPath == null) {
- throw new ArgumentError('rawPath cannot be null');
- }
+ ArgumentError.checkNotNull(rawPath, 'rawPath');
_rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawPath);
_path = FileSystemEntity._toStringFromUtf8Array(rawPath);
}
@@ -746,9 +742,7 @@
}
Future<List<int>> read(int bytes) {
- if (bytes is! int) {
- throw new ArgumentError(bytes);
- }
+ ArgumentError.checkNotNull(bytes, 'bytes');
return _dispatch(_IOService.fileRead, [null, bytes]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "read failed", path);
@@ -761,9 +755,7 @@
List<int> readSync(int bytes) {
_checkAvailable();
- if (bytes is! int) {
- throw new ArgumentError(bytes);
- }
+ ArgumentError.checkNotNull(bytes, 'bytes');
var result = _ops.read(bytes);
if (result is OSError) {
throw new FileSystemException("readSync failed", path, result);
@@ -815,9 +807,7 @@
}
Future<RandomAccessFile> writeByte(int value) {
- if (value is! int) {
- throw new ArgumentError(value);
- }
+ ArgumentError.checkNotNull(value, 'value');
return _dispatch(_IOService.fileWriteByte, [null, value]).then((response) {
if (_isErrorResponse(response)) {
throw _exceptionFromResponse(response, "writeByte failed", path);
@@ -829,9 +819,7 @@
int writeByteSync(int value) {
_checkAvailable();
- if (value is! int) {
- throw new ArgumentError(value);
- }
+ ArgumentError.checkNotNull(value, 'value');
var result = _ops.writeByte(value);
if (result is OSError) {
throw new FileSystemException("writeByte failed", path, result);
@@ -895,17 +883,13 @@
Future<RandomAccessFile> writeString(String string,
{Encoding encoding: utf8}) {
- if (encoding is! Encoding) {
- throw new ArgumentError(encoding);
- }
+ ArgumentError.checkNotNull(encoding, 'encoding');
var data = encoding.encode(string);
return writeFrom(data, 0, data.length);
}
void writeStringSync(String string, {Encoding encoding: utf8}) {
- if (encoding is! Encoding) {
- throw new ArgumentError(encoding);
- }
+ ArgumentError.checkNotNull(encoding, 'encoding');
var data = encoding.encode(string);
writeFromSync(data, 0, data.length);
}
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 2c995d0..17b05ce 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -165,8 +165,8 @@
if (Platform.isWindows) {
path = FileSystemEntity._trimTrailingPathSeparators(path);
}
- return _File._dispatchWithNamespace(_IOService.fileStat, [null, path]).then(
- (response) {
+ return _File._dispatchWithNamespace(_IOService.fileStat, [null, path])
+ .then((response) {
if (_isErrorResponse(response)) {
return FileStat._notFound;
}
@@ -846,7 +846,7 @@
// TODO(bkonyi): find a way to do this with raw paths.
static String _trimTrailingPathSeparators(String path) {
// Don't handle argument errors here.
- if (path is! String) return path;
+ if (path == null) return path;
if (Platform.isWindows) {
while (path.length > 1 &&
(path.endsWith(Platform.pathSeparator) || path.endsWith('/'))) {
@@ -863,7 +863,7 @@
// TODO(bkonyi): find a way to do this with raw paths.
static String _ensureTrailingPathSeparators(String path) {
// Don't handle argument errors here.
- if (path is! String) return path;
+ if (path == null) return path;
if (path.isEmpty) path = '.';
if (Platform.isWindows) {
while (!path.endsWith(Platform.pathSeparator) && !path.endsWith('/')) {
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 8b39682..b43c13a 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -162,10 +162,7 @@
Uint8List _rawPath;
_Link(String path) {
- if (path is! String) {
- throw new ArgumentError('${Error.safeToString(path)} '
- 'is not a String');
- }
+ ArgumentError.checkNotNull(path, 'path');
_path = path;
_rawPath = FileSystemEntity._toUtf8Array(path);
}
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 769eae4..a293b48 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -43,9 +43,7 @@
* cross-platform issues.
*/
void exit(int code) {
- if (code is! int) {
- throw new ArgumentError("Integer value for exit code expected");
- }
+ ArgumentError.checkNotNull(code, "code");
if (!_EmbedderConfig._mayExit) {
throw new UnsupportedError(
"This embedder disallows calling dart:io's exit()");
@@ -66,9 +64,7 @@
* exit code.
*/
void set exitCode(int code) {
- if (code is! int) {
- throw new ArgumentError("Integer value for exit code expected");
- }
+ ArgumentError.checkNotNull(code, "code");
_ProcessUtils._setExitCode(code);
}
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 101ea7b..b4c0132 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -581,21 +581,14 @@
if (host is! String && host is! InternetAddress) {
throw new ArgumentError("host is not a String or an InternetAddress");
}
- if (requestedPort is! int) {
- throw new ArgumentError("requestedPort is not an int");
- }
+ ArgumentError.checkNotNull(requestedPort, "requestedPort");
if (requestedPort < 0 || requestedPort > 65535) {
- throw new ArgumentError("requestedPort is not in the range 0..65535");
+ throw ArgumentError("requestedPort is not in the range 0..65535");
}
- if (requestClientCertificate is! bool) {
- throw new ArgumentError("requestClientCertificate is not a bool");
- }
- if (requireClientCertificate is! bool) {
- throw new ArgumentError("requireClientCertificate is not a bool");
- }
- if (onBadCertificate != null && onBadCertificate is! Function) {
- throw new ArgumentError("onBadCertificate is not null or a Function");
- }
+ ArgumentError.checkNotNull(
+ requestClientCertificate, "requestClientCertificate");
+ ArgumentError.checkNotNull(
+ requireClientCertificate, "requireClientCertificate");
}
int get port => _socket.port;
diff --git a/tests/co19_2/co19_2-analyzer.status b/tests/co19_2/co19_2-analyzer.status
index 5cb30f7..a13758c 100644
--- a/tests/co19_2/co19_2-analyzer.status
+++ b/tests/co19_2/co19_2-analyzer.status
@@ -8,42 +8,12 @@
Language/Classes/Abstract_Instance_Members/override_default_value_t03: MissingCompileTimeError # Issue 33995
Language/Classes/Abstract_Instance_Members/override_default_value_t04: MissingCompileTimeError # Issue 33995
Language/Classes/Abstract_Instance_Members/override_default_value_t05: MissingCompileTimeError # Issue 33995
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t01: MissingCompileTimeError # Issue 33995
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t02: MissingCompileTimeError # Issue 33995
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t04: MissingCompileTimeError # Issue 33995
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t05: MissingCompileTimeError # Issue 33995
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t06: MissingCompileTimeError # Issue 33995
-Language/Classes/Constructors/name_t01: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Constructors/name_t02: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Constructors/name_t03: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t01: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t02: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t03: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t04: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t05: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t06: MissingCompileTimeError # Legal, see #33235
Language/Classes/Getters/type_object_t01: CompileTimeError # Issue 33995
Language/Classes/Getters/type_object_t02: CompileTimeError # Issue 33995
Language/Classes/Instance_Methods/override_different_default_values_t01: MissingCompileTimeError # Issue 33995
Language/Classes/Instance_Methods/override_different_default_values_t02: MissingCompileTimeError # Issue 33995
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t01: MissingCompileTimeError # Issue 33995
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t02: MissingCompileTimeError # Issue 27476
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t04: MissingCompileTimeError # Issue 27476
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t05: MissingCompileTimeError # Issue 27476
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t06: MissingCompileTimeError # Issue 27476
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t07: MissingCompileTimeError # Issue 27476
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t09: MissingCompileTimeError # Issue 27476
-Language/Classes/Setters/instance_setter_t01: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t02: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t03: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t04: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t05: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t06: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/name_t06: CompileTimeError
-Language/Classes/Setters/name_t07: CompileTimeError
Language/Classes/Static_Methods/same_name_method_and_setter_t01: CompileTimeError # Invalid test, see #33237
Language/Classes/method_definition_t06: MissingCompileTimeError # Please triage this failure
-Language/Classes/mixins_t02: MissingCompileTimeError # This syntax is now allowed
Language/Enums/syntax_t08: CompileTimeError # Issue 33995
Language/Enums/syntax_t09: CompileTimeError # Issue 33995
Language/Errors_and_Warnings/static_warning_t01: CompileTimeError # issue #34319
@@ -117,6 +87,33 @@
Language/Statements/Return/no_expression_function_t16: CompileTimeError # issue #34319
Language/Statements/Return/no_expression_not_function_t01: CompileTimeError # issue #34319
Language/Types/Interface_Types/subtype_t30: CompileTimeError # Please triage this failure
+LanguageFeatures/Constant_update2018/CastOperator_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A02_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A03_t01/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A03_t02/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t04: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t05: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t07: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t08: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t05: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t03/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t04/none: CompileTimeError # This feature is not implemented yet
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t02: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t04: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l1_t04: CompileTimeError # Please triage this failure
@@ -134,11 +131,12 @@
LanguageFeatures/Instantiate-to-bound/class/static/class_l1_t04/none: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t03/none: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t04/none: CompileTimeError # Please triage this failure
+LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t05/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t07/none: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t08/none: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/class/static/class_l3_t02/none: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/class/static/class_l4_t01/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l1_t04/none: CompileTimeError # Please triage this failure
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_FutureOr_l1_t02/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t02/none: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/01: MissingCompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/02: MissingCompileTimeError # Please triage this failure
@@ -147,8 +145,6 @@
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/05: MissingCompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/06: MissingCompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/07: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t05: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t05/none: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t07/none: CompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/01: MissingCompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/02: MissingCompileTimeError # Please triage this failure
@@ -158,10 +154,52 @@
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/06: MissingCompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/07: MissingCompileTimeError # Please triage this failure
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t01/none: CompileTimeError # Please triage this failure
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t02/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t03/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t04/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t05/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t06/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t07: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t08: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t09: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t10: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t13: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t14: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t15: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t21: CompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/constant_set_literals_A03_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/constant_set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/non_constant_set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/non_constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/semantics_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/semantics_A05_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Simple-bounds/dynamic/class_typedef_l1_t02: CompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t01/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t02/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t03/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t05: MissingCompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t06: MissingCompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t07: MissingCompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_FutureOr_l1_t02: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_l1_t07: CompileTimeError
LanguageFeatures/Simple-bounds/static/typedef_l2_t02/none: CompileTimeError # Please triage this failure
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t06/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t07/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t08/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t09: MissingCompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t10: MissingCompileTimeError
LanguageFeatures/Super-bounded-types/static_analysis_A01_t02: CompileTimeError # Issue 32903
LanguageFeatures/Super-bounded-types/static_analysis_A01_t05: CompileTimeError # Issue 32903
LanguageFeatures/Super-bounded-types/static_analysis_A01_t08: CompileTimeError # Issue 32903
+LanguageFeatures/Super-mixins/covariance_t03: MissingCompileTimeError # Issue 35111
+LanguageFeatures/Super-mixins/covariance_t06: MissingCompileTimeError # Issue 35111
+LanguageFeatures/Super-mixins/covariance_t07: MissingCompileTimeError # Issue 35111
+LanguageFeatures/Super-mixins/super_invocation_t19: CompileTimeError # Issue 35090
LanguageFeatures/regression/33585_t01: MissingCompileTimeError # Please triage this failure
LanguageFeatures/regression/33585_t02: MissingCompileTimeError # Please triage this failure
LanguageFeatures/regression/33597_t01: MissingCompileTimeError # Please triage this failure
diff --git a/tests/co19_2/co19_2-dart2js.status b/tests/co19_2/co19_2-dart2js.status
index 9b8e576..6843d27 100644
--- a/tests/co19_2/co19_2-dart2js.status
+++ b/tests/co19_2/co19_2-dart2js.status
@@ -4,7 +4,6 @@
[ $compiler == dart2js ]
Language/Classes/Constructors/Generative_Constructors/execution_of_a_superinitializer_t01: RuntimeError
-Language/Classes/mixins_t02: MissingCompileTimeError # co19 issue 163
Language/Expressions/Assignment/null_aware_assignment_static_type_t01: RuntimeError
Language/Expressions/Await_Expressions/evaluation_throws_t03: RuntimeError
Language/Expressions/Booleans/Boolean_Conversion/definition_t01: RuntimeError
@@ -66,6 +65,35 @@
Language/Types/Interface_Types/subtype_t27: Pass, Crash # Issue 34389
Language/Types/Type_Declarations/Typedef/dynamic_param_type_t02: RuntimeError
Language/Variables/constant_initialization_t03: RuntimeError
+LanguageFeatures/Constant_update2018/CastOperator_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A02_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A03_t01/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A03_t02/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t04: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t05: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t07: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A02_t08: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t05: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t03/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t04/none: CompileTimeError # This feature is not implemented yet
LanguageFeatures/Instantiate-to-bound/FutureOr/dynamic/FutureOr_l1_t01: RuntimeError
LanguageFeatures/Instantiate-to-bound/FutureOr/dynamic/FutureOr_l1_t02: RuntimeError
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t02: CompileTimeError
@@ -74,6 +102,7 @@
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t07: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t08: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l3_t02: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/class/dynamic/class_typedef_l1_t02: RuntimeError
LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t03/01: Crash
LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t03/02: Crash
LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t03/none: Crash
@@ -83,18 +112,50 @@
LanguageFeatures/Instantiate-to-bound/class/static/class_l3_t02/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l1_t04/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t04/none: Crash, Pass
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_FutureOr_l1_t02: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_FutureOr_l1_t05: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l1_t05: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l1_t07: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t01: RuntimeError
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t05/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t06: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t07: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t08: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t09: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t10: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t11: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t12: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t13: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t14: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t15: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t16: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t20: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t21: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t07/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t01/none: CompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/constant_set_literals_A03_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/constant_set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/non_constant_set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/non_constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/semantics_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/semantics_A05_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/semantics_A05_t02: RuntimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
LanguageFeatures/Simple-bounds/dynamic/FutureOr_l1_t01: RuntimeError, Pass
LanguageFeatures/Simple-bounds/dynamic/class_FutureOr_l1_t02: CompileTimeError
+LanguageFeatures/Simple-bounds/dynamic/class_typedef_l1_t02: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/typedef_FutureOr_l1_t02: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/typedef_l1_t07: RuntimeError
LanguageFeatures/Simple-bounds/dynamic/typedef_l2_t01: RuntimeError
LanguageFeatures/Simple-bounds/dynamic/typedef_typedef_l1_t01: RuntimeError
LanguageFeatures/Simple-bounds/dynamic/typedef_typedef_l1_t02: RuntimeError
LanguageFeatures/Simple-bounds/dynamic/typedef_typedef_l1_t03: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/typedef_typedef_l1_t07: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/typedef_typedef_l1_t08: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/typedef_typedef_l1_t10: RuntimeError
LanguageFeatures/Simple-bounds/static/class_FutureOr_l1_t02: CompileTimeError
LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t03: CompileTimeError, Pass
LanguageFeatures/Subtyping/dynamic/generated/named_function_types_fail_arguments_binding_fail_A51_t03: RuntimeError
@@ -117,6 +178,7 @@
LanguageFeatures/Subtyping/dynamic/generated/positional_function_types_fail_global_variable_fail_A31_t01: RuntimeError
LanguageFeatures/Subtyping/dynamic/generated/positional_function_types_fail_global_variable_fail_A32_t01: RuntimeError
LanguageFeatures/Subtyping/dynamic/generated/positional_function_types_fail_return_value_fail_A31_t01: RuntimeError
+LanguageFeatures/Super-mixins/mixin_member_t06: RuntimeError
LanguageFeatures/regression/33585_t01: MissingCompileTimeError
LanguageFeatures/regression/33585_t02: MissingCompileTimeError
LanguageFeatures/regression/33597_t01: MissingCompileTimeError
@@ -1319,7 +1381,6 @@
LanguageFeatures/Instantiate-to-bound/check_types/typedef_param_t02: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l1_t02: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l1_t10: RuntimeError
-LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t02: RuntimeError
LanguageFeatures/Simple-bounds/dynamic/typedef_FutureOr_l1_t05: RuntimeError
LanguageFeatures/Simple-bounds/dynamic/typedef_l1_t05: RuntimeError
LanguageFeatures/Simple-bounds/dynamic/typedef_l1_t10: RuntimeError
@@ -3598,7 +3659,6 @@
LanguageFeatures/Instantiate-to-bound/function/function_ret_extends_Future_neg_assign_l1_t07: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l1_t02: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l1_t10: RuntimeError
-LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t02: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t02/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/01: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/02: MissingCompileTimeError
@@ -3607,7 +3667,6 @@
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/05: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/06: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/07: MissingCompileTimeError
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t05: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/01: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/02: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/03: MissingCompileTimeError
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index 7abc59e..d739194 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -2,8 +2,11 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-LibTest/io/FileSystemCreateEvent/isDirectory_A01_t06: Pass, Fail # https://github.com/dart-lang/co19/issues/186
LibTest/io/Stdin/readLineSync_A03_t02: Pass, Fail # https://github.com/dart-lang/co19/issues/184
+LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Slow # Does many calls
+LibTest/collection/ListMixin/ListMixin_class_A01_t02: Pass, Slow # Does many calls
+LibTest/core/List/List_class_A01_t02: Pass, Slow # Does many calls
+LibTest/io/RawDatagramSocket/close_A01_t01: Pass, RuntimeError # https://github.com/dart-lang/co19/issues/195
[ $compiler == dartkp ]
Language/Expressions/Instance_Creation/New/evaluation_t20: RuntimeError
@@ -31,8 +34,6 @@
LibTest/core/Uri/Uri.dataFromString_A01_t01: RuntimeError
LibTest/core/double/round_A01_t03: RuntimeError
LibTest/io/Cookie/Cookie_A01_t02: RuntimeError
-LibTest/io/Directory/renameSync_A02_t01: RuntimeError
-LibTest/io/Directory/rename_A02_t01: RuntimeError
LibTest/io/File/openRead_A01_t04: RuntimeError
LibTest/io/HttpClientRequest/addStream_A02_t02: RuntimeError
LibTest/io/HttpClientRequest/add_A03_t01: RuntimeError
@@ -76,14 +77,14 @@
Language/Statements/For/syntax_t20 tatements/For/syntax_t20: Crash # Assertion error: kernel_shadow_ast.dart: 'receiver == null': is not true.
[ $runtime == vm ]
-LibTest/io/FileSystemEntity/*: Skip # Temporary skip these tests
-LibTest/io/Link/rename_A02_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/174
LibTest/io/RawDatagramSocket/any_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
LibTest/io/RawDatagramSocket/any_A01_t03: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
LibTest/io/RawDatagramSocket/asBroadcastStream_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
LibTest/io/RawDatagramSocket/distinct_A01_t05: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
LibTest/io/RawDatagramSocket/lastWhere_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
LibTest/io/RawDatagramSocket/listen_A02_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
+LibTest/io/RawDatagramSocket/receive_A01_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
+LibTest/io/RawDatagramSocket/where_A01_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
LibTest/io/RawDatagramSocket/timeout_A02_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
LibTest/io/RawDatagramSocket/timeout_A06_t01: Pass, Fail # Next roll might fix it (see https://github.com/dart-lang/co19/commit/8b2e2be5bc3bb9fec41efec8ac6fc777e231d915)
LibTest/io/Stdin/first_A04_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/193
@@ -95,41 +96,12 @@
Language/Classes/Abstract_Instance_Members/override_default_value_t03: MissingCompileTimeError # Issue 34190
Language/Classes/Abstract_Instance_Members/override_default_value_t04: MissingCompileTimeError # Issue 34190
Language/Classes/Abstract_Instance_Members/override_default_value_t05: MissingCompileTimeError # Issue 34190
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t01: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t02: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t04: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t05: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t06: MissingCompileTimeError # Legal, see #33235
Language/Classes/Constructors/Generative_Constructors/initializers_t15: CompileTimeError
-Language/Classes/Constructors/name_t01: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Constructors/name_t02: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Constructors/name_t03: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t01: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t02: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t03: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t04: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t05: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Getters/instance_getter_t06: MissingCompileTimeError # Legal, see #33235
Language/Classes/Getters/type_object_t01: CompileTimeError
Language/Classes/Getters/type_object_t02: CompileTimeError
Language/Classes/Instance_Methods/Operators/return_type_t01: MissingCompileTimeError
Language/Classes/Instance_Methods/override_different_default_values_t01: MissingCompileTimeError # Issue 34190
Language/Classes/Instance_Methods/override_different_default_values_t02: MissingCompileTimeError # Issue 34190
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t01: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t02: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t04: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t05: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t06: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t07: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t09: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t01: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t02: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t03: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t04: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t05: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/instance_setter_t06: MissingCompileTimeError # Legal, see #33235
-Language/Classes/Setters/name_t06: CompileTimeError
-Language/Classes/Setters/name_t07: CompileTimeError
Language/Classes/Setters/return_type_not_void_t01: MissingCompileTimeError
Language/Classes/Setters/same_name_getter_different_type_t01: MissingCompileTimeError
Language/Classes/Setters/syntax_t04: MissingCompileTimeError
@@ -138,7 +110,6 @@
Language/Classes/Superclasses/wrong_superclass_t08: MissingCompileTimeError # Issue 30273
Language/Classes/Superinterfaces/wrong_type_t05: MissingCompileTimeError # Issue 30273
Language/Classes/method_definition_t06: MissingCompileTimeError # Legal
-Language/Classes/mixins_t02: MissingCompileTimeError # co19 issue 163
Language/Enums/syntax_t08: CompileTimeError
Language/Enums/syntax_t09: CompileTimeError
Language/Expressions/Assignable_Expressions/syntax_t01: CompileTimeError
@@ -217,6 +188,29 @@
Language/Statements/Continue/label_t07: MissingCompileTimeError # Issue 34206
Language/Statements/Try/catch_scope_t01: CompileTimeError
Language/Types/Interface_Types/subtype_t30: CompileTimeError
+LanguageFeatures/Constant_update2018/CastOperator_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A02_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A03_t01/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/CastOperator_A03_t02/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/NewOperators_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t05: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t02: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t03/none: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t04/none: CompileTimeError # This feature is not implemented yet
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t01: Crash
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t02: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t03: Crash
@@ -227,6 +221,7 @@
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t07: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t08: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l3_t02: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01: Crash
LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/01: Crash
LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/02: Crash
LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/03: Crash
@@ -250,7 +245,11 @@
LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l1_t04/none: Crash
LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t04/01: Crash, Pass
LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t04/none: Crash, Pass
+LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t08/01: Crash, Pass
+LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t08/02: Crash, Pass
+LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t08/none: Crash, Pass
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l1_t07: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_FutureOr_l1_t02/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t02/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/01: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/02: MissingCompileTimeError
@@ -259,8 +258,6 @@
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/05: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/06: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/07: MissingCompileTimeError
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t05: MissingCompileTimeError
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t05/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t07/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/01: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/02: MissingCompileTimeError
@@ -270,9 +267,38 @@
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/06: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/07: MissingCompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t01/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t06/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t15: CompileTimeError
+LanguageFeatures/Set-literals/constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/constant_set_literals_A03_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/constant_set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/exact_types_of_literals_A01_t03: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/non_constant_set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/non_constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/semantics_A04_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/semantics_A05_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/semantics_A05_t02: RuntimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
+LanguageFeatures/Set-literals/set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
LanguageFeatures/Simple-bounds/dynamic/class_FutureOr_l1_t02: CompileTimeError
LanguageFeatures/Simple-bounds/static/class_FutureOr_l1_t02: CompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t01/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t02/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t03/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t05: MissingCompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t06: MissingCompileTimeError
+LanguageFeatures/Simple-bounds/static/class_typedef_l1_t07: MissingCompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_FutureOr_l1_t02: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_l1_t07: CompileTimeError
LanguageFeatures/Simple-bounds/static/typedef_l2_t02/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t06/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t07/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t08/none: CompileTimeError
+LanguageFeatures/Simple-bounds/static/typedef_typedef_l1_t09: MissingCompileTimeError
+LanguageFeatures/Super-mixins/covariance_t03: MissingCompileTimeError # Issue 35111
+LanguageFeatures/Super-mixins/covariance_t06: MissingCompileTimeError # Issue 35111
+LanguageFeatures/Super-mixins/covariance_t07: MissingCompileTimeError # Issue 35111
LanguageFeatures/regression/33585_t01: MissingCompileTimeError
LanguageFeatures/regression/33585_t02: MissingCompileTimeError
LanguageFeatures/regression/33597_t01: MissingCompileTimeError
@@ -284,6 +310,11 @@
LanguageFeatures/regression/34803_t02: Crash
LibTest/async/Future/Future_A01_t01: CompileTimeError
+[ $arch == simdbc64 && $compiler == dartk ]
+LibTest/collection/ListBase/ListBase_class_A01_t02: Crash # Issue http://dartbug.com/35242
+LibTest/collection/ListMixin/ListMixin_class_A01_t02: Crash # Issue http://dartbug.com/35242
+LibTest/core/List/List_class_A01_t02: Crash # Issue http://dartbug.com/35242
+
[ $arch == simdbc64 && $system == macos && ($compiler == dartk || $compiler == dartkb) ]
LanguageFeatures/Subtyping/static/generated/function_type_function_arguments_binding_A04_t02: Crash, Pass
LibTest/io/Directory/watch_A01_t02: RuntimeError, Pass
@@ -296,7 +327,6 @@
LibTest/io/Stdout/writeCharCode_A01_t03: Timeout, Pass
[ $arch == simdbc64 && ($compiler == dartk || $compiler == dartkb) ]
-LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l1_t04/none: CompileTimeError
LibTest/collection/ListBase/ListBase_class_A01_t02: Timeout, Pass
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Timeout, Pass
LibTest/io/Link/renameSync_A02_t01: RuntimeError, Pass
@@ -388,6 +418,9 @@
LibTest/isolate/Isolate/spawn_A06_t03: Crash, Pass
[ $runtime == vm && $system == macos && ($compiler == dartk || $compiler == dartkb) ]
+LibTest/collection/ListBase/ListBase_class_A01_t02: Timeout, Pass, Slow # https://github.com/dart-lang/co19/issues/198
+LibTest/collection/ListMixin/ListMixin_class_A01_t02: Timeout, Pass, Slow # https://github.com/dart-lang/co19/issues/198
+LibTest/core/List/List_class_A01_t02: Timeout, Pass, Slow # https://github.com/dart-lang/co19/issues/198
LibTest/io/Directory/watch_A01_t02: RuntimeError, Pass
LibTest/io/Directory/watch_A02_t01: RuntimeError, Pass
LibTest/io/FileSystemCreateEvent/isDirectory_A01_t03: RuntimeError, Pass
@@ -397,11 +430,10 @@
LibTest/io/FileSystemCreateEvent/type_A01_t01: RuntimeError, Pass
LibTest/io/FileSystemCreateEvent/type_A01_t02: RuntimeError, Pass
LibTest/io/FileSystemCreateEvent/type_A01_t03: RuntimeError, Pass, Timeout
-LibTest/io/FileSystemDeleteEvent/isDirectory_A01_t01: RuntimeError, Timeout
+LibTest/io/FileSystemDeleteEvent/isDirectory_A01_t07: RuntimeError
LibTest/io/FileSystemDeleteEvent/path_A01_t02: RuntimeError, Pass
LibTest/io/FileSystemDeleteEvent/path_A01_t03: RuntimeError, Pass
LibTest/io/FileSystemDeleteEvent/type_A01_t03: RuntimeError, Pass
-LibTest/io/FileSystemEntity/isWatchSupported_A01_t01: RuntimeError
LibTest/io/FileSystemModifyEvent/contentChanged_A01_t01: Fail, Timeout
LibTest/io/FileSystemModifyEvent/contentChanged_A01_t02: Timeout, Pass
LibTest/io/FileSystemModifyEvent/isDirectory_A01_t01: Timeout, Pass
@@ -538,16 +570,7 @@
LibTest/math/atan_A01_t01: RuntimeError
LibTest/math/cos_A01_t01: RuntimeError
-[ $runtime == vm && $system != macos ]
-LibTest/io/FileSystemDeleteEvent/isDirectory_A01_t07: Fail # Issue 35032
-
[ $runtime == vm && $system != macos && ($compiler == dartk || $compiler == dartkb) ]
-LibTest/io/Directory/listSync_A01_t02: RuntimeError
-LibTest/io/Directory/listSync_A01_t03: RuntimeError
-LibTest/io/Directory/listSync_A01_t04: RuntimeError
-LibTest/io/Directory/list_A01_t02: RuntimeError
-LibTest/io/Directory/list_A01_t03: RuntimeError
-LibTest/io/Directory/list_A01_t04: RuntimeError
LibTest/io/InternetAddress/lookup_A02_t01: RuntimeError
LibTest/io/InternetAddress/lookup_A03_t01: RuntimeError
LibTest/io/InternetAddress/lookup_A03_t02: RuntimeError
@@ -561,12 +584,24 @@
Language/Mixins/Mixin_Application/syntax_t16: CompileTimeError
Language/Statements/Assert/execution_t08: RuntimeError
Language/Types/Function_Types/call_t01: RuntimeError
+LanguageFeatures/Instantiate-to-bound/class/dynamic/class_typedef_l1_t02: RuntimeError
LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t04/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t08/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l1_t04/none: DartkCrash
-LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t02: RuntimeError
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t05/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l1_t04/none: CompileTimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_FutureOr_l1_t02: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t06: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t11: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t12: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t13: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t14: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t15: RuntimeError
+LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t16: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/class_typedef_l1_t02: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/typedef_FutureOr_l1_t02: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/typedef_l1_t07: RuntimeError
LanguageFeatures/Simple-bounds/dynamic/typedef_l2_t02: RuntimeError
+LanguageFeatures/Simple-bounds/dynamic/typedef_typedef_l1_t07: RuntimeError
LanguageFeatures/regression/33701_t01: MissingCompileTimeError
LanguageFeatures/regression/34803_t01: DartkCrash
LanguageFeatures/regression/34803_t02: DartkCrash
@@ -611,11 +646,11 @@
LibTest/core/int/isOdd_A01_t01: RuntimeError
LibTest/io/Cookie/Cookie_A01_t04: RuntimeError
LibTest/io/Directory/watch_A01_t01: Fail, Pass
-LibTest/io/Directory/watch_A02_t01: Timeout
+LibTest/io/Directory/watch_A02_t01: Fail
LibTest/io/FileSystemCreateEvent/isDirectory_A01_t01: Fail, Pass
LibTest/io/FileSystemCreateEvent/isDirectory_A01_t02: Fail, Pass
LibTest/io/FileSystemCreateEvent/path_A01_t01: Fail, Pass
-LibTest/io/FileSystemEntity/identical_A01_t06: Pass, RuntimeError # Issue 183 (co19)
+LibTest/io/FileSystemEntity/identical_A01_t06: Fail
LibTest/io/FileSystemModifyEvent/isDirectory_A01_t02: Fail
LibTest/io/FileSystemModifyEvent/path_A01_t01: Fail
LibTest/io/FileSystemModifyEvent/type_A01_t02: Fail
@@ -669,6 +704,7 @@
LibTest/io/WebSocket/connect_A01_t02: RuntimeError
LibTest/isolate/Isolate/pause_A01_t01: Timeout, Pass
LibTest/isolate/Isolate/pause_A01_t02: Timeout, Pass
+LibTest/isolate/Isolate/ping_A02_t01: Timeout, Pass
LibTest/isolate/Isolate/ping_A03_t01: RuntimeError, Pass
LibTest/isolate/Isolate/ping_A03_t02: RuntimeError, Pass
LibTest/isolate/ReceivePort/firstWhere_A01_t01: RuntimeError
@@ -885,8 +921,6 @@
Language/Types/Type_Declarations/Typedef/dynamic_param_type_t02: RuntimeError
Language/Variables/constant_initialization_t03: RuntimeError
Language/Variables/constant_variable_t09: RuntimeError
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t05: CompileTimeError
-LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t05/none: CompileTimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l1_t02: RuntimeError
LanguageFeatures/Instantiate-to-bound/typedef/dynamic/typedef_l2_t01: RuntimeError
LibTest/async/Future/asStream_A01_t02: RuntimeError
@@ -1020,8 +1054,6 @@
LibTest/io/Directory/delete_A02_t05: RuntimeError
LibTest/io/Directory/existsSync_A02_t02: RuntimeError
LibTest/io/Directory/exists_A02_t02: RuntimeError
-LibTest/io/Directory/renameSync_A02_t01: RuntimeError
-LibTest/io/Directory/rename_A02_t01: RuntimeError
LibTest/io/Directory/statSync_A01_t05: RuntimeError
LibTest/io/Directory/stat_A01_t05: RuntimeError
LibTest/io/File/openRead_A01_t04: RuntimeError
@@ -1040,7 +1072,6 @@
LibTest/io/FileSystemEntity/isDirectorySync_A01_t03: RuntimeError
LibTest/io/FileSystemEntity/isDirectory_A01_t03: RuntimeError
LibTest/io/FileSystemEntity/isFileSync_A01_t03: RuntimeError
-LibTest/io/FileSystemEntity/isFile_A01_t01: RuntimeError
LibTest/io/FileSystemEntity/isFile_A01_t03: RuntimeError
LibTest/io/FileSystemModifyEvent/path_A01_t01: RuntimeError
LibTest/io/HttpClient/addCredentials_A03_t01: RuntimeError
diff --git a/tests/compiler/dart2js/analyses/analysis_helper.dart b/tests/compiler/dart2js/analyses/analysis_helper.dart
index cbfbbb8b..c5f2dd0 100644
--- a/tests/compiler/dart2js/analyses/analysis_helper.dart
+++ b/tests/compiler/dart2js/analyses/analysis_helper.dart
@@ -11,9 +11,9 @@
import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/diagnostics/messages.dart';
import 'package:compiler/src/diagnostics/source_span.dart';
-import 'package:compiler/src/library_loader.dart';
import 'package:compiler/src/ir/static_type.dart';
import 'package:compiler/src/ir/util.dart';
+import 'package:compiler/src/kernel/loader.dart';
import 'package:compiler/src/util/uri_extras.dart';
import 'package:expect/expect.dart';
import 'package:kernel/ast.dart' as ir;
@@ -57,10 +57,9 @@
librariesSpecificationUri: librariesSpecificationUri,
packageConfig: packageConfig,
options: options);
- LoadedLibraries loadedLibraries =
- await compiler.libraryLoader.loadLibraries(entryPoint);
- new DynamicVisitor(compiler.reporter, loadedLibraries.component,
- allowedListPath, analyzedUrisFilter)
+ KernelResult result = await compiler.kernelLoader.load(entryPoint);
+ new DynamicVisitor(compiler.reporter, result.component, allowedListPath,
+ analyzedUrisFilter)
.run(verbose: verbose, generate: generate);
});
}
diff --git a/tests/compiler/dart2js/analyses/dart2js_allowed.json b/tests/compiler/dart2js/analyses/dart2js_allowed.json
index ea21856..920dc49 100644
--- a/tests/compiler/dart2js/analyses/dart2js_allowed.json
+++ b/tests/compiler/dart2js/analyses/dart2js_allowed.json
@@ -195,9 +195,6 @@
"Dynamic access of 'names'.": 1,
"Dynamic access of 'isNonLeaf'.": 1
},
- "pkg/compiler/lib/src/universe/world_builder.dart": {
- "Dynamic access of 'cls'.": 1
- },
"pkg/compiler/lib/src/elements/names.dart": {
"Dynamic access of 'library'.": 1
},
diff --git a/tests/compiler/dart2js/analyses/static_type_visitor_test.dart b/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
index 09d8882..00403a7 100644
--- a/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
+++ b/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
@@ -5,7 +5,7 @@
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/ir/static_type.dart';
-import 'package:compiler/src/library_loader.dart';
+import 'package:compiler/src/kernel/loader.dart';
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/class_hierarchy.dart' as ir;
import 'package:kernel/core_types.dart' as ir;
@@ -21,9 +21,9 @@
asyncTest(() async {
Compiler compiler =
await compilerFor(memorySourceFiles: {'main.dart': source});
- LoadedLibraries loadedLibraries = await compiler.libraryLoader
- .loadLibraries(Uri.parse('memory:main.dart'));
- ir.Component component = loadedLibraries.component;
+ KernelResult result =
+ await compiler.kernelLoader.load(Uri.parse('memory:main.dart'));
+ ir.Component component = result.component;
StaticTypeVisitor visitor = new Visitor(component);
component.accept(visitor);
});
diff --git a/tests/compiler/dart2js/deferred/load_mapping_test.dart b/tests/compiler/dart2js/deferred/load_mapping_test.dart
index 6736599..74c0c43 100644
--- a/tests/compiler/dart2js/deferred/load_mapping_test.dart
+++ b/tests/compiler/dart2js/deferred/load_mapping_test.dart
@@ -19,7 +19,8 @@
CompilerImpl compiler = result.compiler;
JClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
// Ensure a mapping file is output.
- Expect.isNotNull(collector.getOutput("deferred_map.json", OutputType.info));
+ Expect.isNotNull(
+ collector.getOutput("deferred_map.json", OutputType.deferredMap));
Map mapping = closedWorld.outputUnitData
.computeDeferredMap(compiler.options, closedWorld.elementEnvironment);
diff --git a/tests/compiler/dart2js/end_to_end/dill_loader_test.dart b/tests/compiler/dart2js/end_to_end/dill_loader_test.dart
index 3b3c0e6..56bf3e6 100644
--- a/tests/compiler/dart2js/end_to_end/dill_loader_test.dart
+++ b/tests/compiler/dart2js/end_to_end/dill_loader_test.dart
@@ -9,7 +9,7 @@
import 'package:compiler/src/elements/entities.dart'
show LibraryEntity, ClassEntity;
import 'package:compiler/src/kernel/dart2js_target.dart';
-import 'package:compiler/src/library_loader.dart';
+import 'package:compiler/src/kernel/loader.dart';
import 'package:expect/expect.dart';
import 'package:front_end/src/api_prototype/front_end.dart';
import 'package:front_end/src/compute_platform_binaries_location.dart'
@@ -44,9 +44,8 @@
diagnosticHandler: diagnostics,
outputProvider: output);
await compiler.setupSdk();
- LoadedLibraries loadedLibraries =
- await compiler.libraryLoader.loadLibraries(entryPoint);
- compiler.frontendStrategy.registerLoadedLibraries(loadedLibraries);
+ KernelResult result = await compiler.kernelLoader.load(entryPoint);
+ compiler.frontendStrategy.registerLoadedLibraries(result);
Expect.equals(0, diagnostics.errors.length);
Expect.equals(0, diagnostics.warnings.length);
diff --git a/tests/compiler/dart2js/end_to_end/exit_code_test.dart b/tests/compiler/dart2js/end_to_end/exit_code_test.dart
index 8c7624f..52657e0 100644
--- a/tests/compiler/dart2js/end_to_end/exit_code_test.dart
+++ b/tests/compiler/dart2js/end_to_end/exit_code_test.dart
@@ -21,7 +21,6 @@
import 'package:compiler/src/apiimpl.dart' as apiimpl;
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/js_backend/js_backend.dart';
-import 'package:compiler/src/library_loader.dart';
import 'package:compiler/src/null_compiler_output.dart';
import 'package:compiler/src/options.dart' show CompilerOptions;
import 'package:compiler/src/types/types.dart';
@@ -60,11 +59,6 @@
return super.run(uri);
}
- void processLoadedLibraries(LoadedLibraries loadedLibraries) {
- test('Compiler.processLoadedLibraries');
- super.processLoadedLibraries(loadedLibraries);
- }
-
test(String marker) {
if (marker == testMarker) {
switch (testType) {
@@ -239,7 +233,6 @@
final tests = {
'Compiler': beforeRun,
'Compiler.run': beforeRun,
- 'Compiler.processLoadedLibraries': beforeRun,
'Compiler.withCurrentElement': duringRun,
'Compiler.codegen': duringRun,
};
diff --git a/tests/compiler/dart2js/helpers/memory_compiler.dart b/tests/compiler/dart2js/helpers/memory_compiler.dart
index 079ac0b..6062660 100644
--- a/tests/compiler/dart2js/helpers/memory_compiler.dart
+++ b/tests/compiler/dart2js/helpers/memory_compiler.dart
@@ -94,7 +94,7 @@
}
bool isSuccess = await compiler.run(entryPoint);
fe.InitializedCompilerState compilerState = kernelInitializedCompilerState =
- compiler.libraryLoader.initializedCompilerState;
+ compiler.kernelLoader.initializedCompilerState;
return new CompilationResult(compiler,
isSuccess: isSuccess, kernelInitializedCompilerState: compilerState);
}
diff --git a/tests/compiler/dart2js/helpers/text_helpers.dart b/tests/compiler/dart2js/helpers/text_helpers.dart
index ce1254c..e9723d2 100644
--- a/tests/compiler/dart2js/helpers/text_helpers.dart
+++ b/tests/compiler/dart2js/helpers/text_helpers.dart
@@ -6,40 +6,68 @@
/// of the [windowSize] lines before and after are printed and the mismatch line
/// number is returned. If identical, nothing is printed and `null` is returned.
int checkEqualContentAndShowDiff(String text1, String text2,
- {int windowSize: 20}) {
+ {int windowSize: 20,
+ bool Function(int, List<String>, List<String>) filter}) {
List<String> lines1 = text1.split('\n');
List<String> lines2 = text2.split('\n');
for (int i = 0; i < lines1.length && i < lines2.length; i++) {
if (i >= lines1.length || i >= lines2.length || lines1[i] != lines2[i]) {
- for (int j = i - windowSize; j < i + windowSize; j++) {
- if (j < 0) continue;
- String line1 = 0 <= j && j < lines1.length ? lines1[j] : null;
- String line2 = 0 <= j && j < lines2.length ? lines2[j] : null;
- if (line1 == line2) {
- print(' $j $line1');
- } else {
- String text = line1 == null ? '<eof>' : line1;
- String newText = line2 == null ? '<eof>' : line2;
- print('- $j ${text}');
- print('+ $j ${newText}');
- if (text.length > 80 && newText.length > 80) {
- assert(text != newText);
- StringBuffer diff = new StringBuffer();
- diff.write(' $j ');
- for (int k = 0; k < text.length && k < newText.length; k++) {
- int char1 = k < text.length ? text.codeUnitAt(k) : null;
- int char2 = k < newText.length ? newText.codeUnitAt(k) : null;
- if (char1 != char2) {
- diff.write('^');
- } else {
- diff.write(' ');
- }
- }
- print(diff);
+ if (filter != null && filter(i, lines1, lines2)) {
+ String line1 = 0 <= i && i < lines1.length ? lines1[i] : null;
+ String line2 = 0 <= i && i < lines2.length ? lines2[i] : null;
+ String text = line1 == null ? '<eof>' : line1;
+ String newText = line2 == null ? '<eof>' : line2;
+ print('(skipped) - $i ${text}');
+ print('(skipped) + $i ${newText}');
+ } else {
+ List<String> pendingLines = <String>[];
+
+ void flushPendingLines() {
+ if (pendingLines.isNotEmpty) {
+ print(pendingLines.join('\n'));
+ pendingLines.clear();
}
}
+
+ for (int j = i - windowSize; j < i + windowSize; j++) {
+ if (j < 0) continue;
+ String line1 = 0 <= j && j < lines1.length ? lines1[j] : null;
+ String line2 = 0 <= j && j < lines2.length ? lines2[j] : null;
+ if (line1 == line2) {
+ flushPendingLines();
+ if (line1 != null) {
+ print(' $j $line1');
+ }
+ } else {
+ String text = line1 == null ? '<eof>' : line1;
+ String newText = line2 == null ? '<eof>' : line2;
+
+ if (text.length > 80 && newText.length > 80) {
+ flushPendingLines();
+ print('- $j ${text}');
+ print('+ $j ${newText}');
+ assert(text != newText);
+ StringBuffer diff = new StringBuffer();
+ diff.write(' $j ');
+ for (int k = 0; k < text.length && k < newText.length; k++) {
+ int char1 = k < text.length ? text.codeUnitAt(k) : null;
+ int char2 = k < newText.length ? newText.codeUnitAt(k) : null;
+ if (char1 != char2) {
+ diff.write('^');
+ } else {
+ diff.write(' ');
+ }
+ }
+ print(diff);
+ } else {
+ print('- $j ${text}');
+ pendingLines.add('+ $j ${newText}');
+ }
+ }
+ }
+ flushPendingLines();
+ return i;
}
- return i;
}
}
return null;
diff --git a/tests/compiler/dart2js/impact/data/effectively_final.dart b/tests/compiler/dart2js/impact/data/effectively_final.dart
new file mode 100644
index 0000000..305ca2b
--- /dev/null
+++ b/tests/compiler/dart2js/impact/data/effectively_final.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*element: main:
+ static=[
+ effectivelyFinalList(0),
+ effectivelyFinalPromoted(0),
+ effectivelyFinalPromotedInvalid(0),
+ notEffectivelyFinalList(0)]
+*/
+main() {
+ effectivelyFinalList();
+ notEffectivelyFinalList();
+ effectivelyFinalPromoted();
+ effectivelyFinalPromotedInvalid();
+}
+
+/*element: effectivelyFinalList:
+ dynamic=[
+ List.add(1),
+ List.length,
+ List.length=,
+ int.+],
+ type=[
+ inst:JSDouble,
+ inst:JSInt,
+ inst:JSNull,
+ inst:JSNumber,
+ inst:JSPositiveInt,
+ inst:JSUInt31,
+ inst:JSUInt32,
+ inst:List<dynamic>]
+*/
+effectivelyFinalList() {
+ dynamic c = [];
+ c.add(null);
+ c.length + 1;
+ c.length = 1;
+}
+
+/*element: notEffectivelyFinalList:
+ dynamic=[
+ +,
+ add(1),
+ call(1),
+ length,
+ length=],
+ type=[
+ inst:JSDouble,
+ inst:JSInt,
+ inst:JSNull,
+ inst:JSNumber,
+ inst:JSPositiveInt,
+ inst:JSUInt31,
+ inst:JSUInt32,
+ inst:List<dynamic>]
+*/
+notEffectivelyFinalList() {
+ dynamic c = [];
+ c.add(null);
+ c.length + 1;
+ c.length = 1;
+ c = null;
+}
+
+/*element: _method1:type=[inst:JSNull]*/
+num _method1() => null;
+
+/*element: effectivelyFinalPromoted:
+ dynamic=[int.+,num.+],
+ static=[_method1(0)],
+ type=[
+ inst:JSBool,
+ inst:JSDouble,
+ inst:JSInt,
+ inst:JSNumber,
+ inst:JSPositiveInt,
+ inst:JSUInt31,
+ inst:JSUInt32,
+ is:int]
+*/
+effectivelyFinalPromoted() {
+ dynamic c = _method1();
+ c + 0;
+ if (c is int) {
+ c + 1;
+ }
+}
+
+/*element: _method2:type=[inst:JSNull]*/
+String _method2() => null;
+
+/*element: effectivelyFinalPromotedInvalid:
+ dynamic=[String.+,int.+],
+ static=[_method2(0)],
+ type=[
+ inst:JSBool,
+ inst:JSDouble,
+ inst:JSInt,
+ inst:JSNumber,
+ inst:JSPositiveInt,
+ inst:JSString,
+ inst:JSUInt31,
+ inst:JSUInt32,
+ is:int]
+*/
+effectivelyFinalPromotedInvalid() {
+ dynamic c = _method2();
+ c + '';
+ if (c is int) {
+ c + 1;
+ }
+}
diff --git a/tests/compiler/dart2js/impact/data/runtime_type_strong.dart b/tests/compiler/dart2js/impact/data/runtime_type_strong.dart
index 63d2dea..32fa0a7 100644
--- a/tests/compiler/dart2js/impact/data/runtime_type_strong.dart
+++ b/tests/compiler/dart2js/impact/data/runtime_type_strong.dart
@@ -5,7 +5,7 @@
/*element: Class1a.:static=[Object.(0)]*/
class Class1a<T> {
/*element: Class1a.==:
- dynamic=[Class1a.runtimeType,Object.runtimeType,Type.==],
+ dynamic=[<Class1a.runtimeType,Object.runtimeType,Type.==],
runtimeType=[equals:Class1a<Class1a.T>/dynamic]
*/
bool operator ==(other) {
@@ -16,7 +16,7 @@
/*element: Class1b.:static=[Class1a.(0)]*/
class Class1b<T> extends Class1a<T> {
/*element: Class1b.==:
- dynamic=[Class1b.runtimeType,Object.runtimeType,Type.==],
+ dynamic=[<Class1b.runtimeType,Object.runtimeType,Type.==],
runtimeType=[equals:dynamic/Class1b<Class1b.T>]
*/
bool operator ==(other) {
@@ -27,7 +27,7 @@
/*element: Class1c.:static=[Object.(0)]*/
class Class1c<T> implements Class1a<T> {
/*element: Class1c.==:
- dynamic=[Class1c.runtimeType,Object.==,Object.runtimeType,Type.==],
+ dynamic=[<Class1c.runtimeType,Object.==,Object.runtimeType,Type.==],
runtimeType=[equals:Class1c<Class1c.T>/dynamic],
type=[inst:JSNull]
*/
@@ -39,7 +39,7 @@
/*element: Class1d.:static=[Object.(0)]*/
class Class1d<T> implements Class1a<T> {
/*element: Class1d.==:
- dynamic=[Class1d.runtimeType,Object.==,Object.runtimeType,Type.==],
+ dynamic=[<Class1d.runtimeType,Object.==,Object.runtimeType,Type.==],
runtimeType=[equals:dynamic/Class1d<Class1d.T>],
type=[inst:JSNull]
*/
diff --git a/tests/compiler/dart2js/impact/data/this.dart b/tests/compiler/dart2js/impact/data/this.dart
new file mode 100644
index 0000000..2579dda
--- /dev/null
+++ b/tests/compiler/dart2js/impact/data/this.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*element: Class.:static=[Object.(0)]*/
+class Class {
+ /*element: Class.field1:type=[inst:JSNull]*/
+ var field1;
+
+ /*element: Class.field2:type=[inst:JSNull]*/
+ var field2;
+
+ /*element: Class.method1:dynamic=[<Class.method2(0)]*/
+ method1() {
+ method2();
+ }
+
+ /*element: Class.method2:dynamic=[<Class.field1=,<Class.field2]*/
+ method2() {
+ field1 = field2;
+ }
+}
+
+/*element: Subclass.:static=[Class.(0)]*/
+class Subclass extends Class {
+ /*element: Subclass.field1:type=[inst:JSNull]*/
+ var field1;
+ /*element: Subclass.field2:type=[inst:JSNull]*/
+ var field2;
+
+ /*element: Subclass.method1:*/
+ method1() {}
+
+ /*element: Subclass.method2:dynamic=[<Subclass.method3(0)]*/
+ method2() {
+ method3();
+ }
+
+ method3() {}
+}
+
+/*element: Subtype.:static=[Object.(0)]*/
+class Subtype implements Class {
+ /*element: Subtype.field1:type=[inst:JSNull]*/
+ var field1;
+ /*element: Subtype.field2:type=[inst:JSNull]*/
+ var field2;
+
+ method1() {}
+
+ method2() {
+ method4();
+ }
+
+ method4() {
+ method2();
+ }
+}
+
+/*element: main:
+ dynamic=[Class.method1(0)],
+ static=[Class.(0),Subclass.(0),Subtype.(0)]
+*/
+main() {
+ var c = new Class();
+ c = new Subclass();
+ c = new Subtype();
+ c.method1();
+}
diff --git a/tests/compiler/dart2js/inference/data/locals_notrust.dart b/tests/compiler/dart2js/inference/data/locals_notrust.dart
index 35f518a..fbd9b464 100644
--- a/tests/compiler/dart2js/inference/data/locals_notrust.dart
+++ b/tests/compiler/dart2js/inference/data/locals_notrust.dart
@@ -35,6 +35,7 @@
/*element: _dontTrustFunctions:[exact=JSBool]*/
_dontTrustFunctions(int Function(int) /*[null|subclass=Closure]*/ f) {
dynamic c = f(0);
+ c = f(0);
return c == 0;
}
diff --git a/tests/compiler/dart2js/inference/data/locals_trust.dart b/tests/compiler/dart2js/inference/data/locals_trust.dart
index c179e96..b937783 100644
--- a/tests/compiler/dart2js/inference/data/locals_trust.dart
+++ b/tests/compiler/dart2js/inference/data/locals_trust.dart
@@ -34,6 +34,7 @@
/*element: _dontTrustFunctions:[exact=JSBool]*/
_dontTrustFunctions(int Function(int) /*[null|subclass=Closure]*/ f) {
dynamic c = f(0);
+ c = f(0);
return c == 0;
}
diff --git a/tests/compiler/dart2js/inference/data/null.dart b/tests/compiler/dart2js/inference/data/null.dart
new file mode 100644
index 0000000..b91c581
--- /dev/null
+++ b/tests/compiler/dart2js/inference/data/null.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*element: main:[null]*/
+main() {
+ ifThenNullCheck(0);
+ ifThenNullCheck(null);
+ ifThenElseNullCheck(0);
+ ifThenElseNullCheck(null);
+ ifNotThenNullCheck(0);
+ ifNotThenNullCheck(null);
+ ifNotThenElseNullCheck(0);
+ ifNotThenElseNullCheck(null);
+ ifThenNotNullComplexCheck(0, 0);
+ ifThenNotNullComplexCheck(null, null);
+ ifThenElseNotNullComplexCheck(0, 0);
+ ifThenElseNotNullComplexCheck(null, null);
+ ifThenNotNullGradualCheck1(0, 0);
+ ifThenNotNullGradualCheck1(null, 0);
+ ifThenNotNullGradualCheck2(0, 0);
+ ifThenNotNullGradualCheck2(null, 0);
+}
+
+/*element: ifThenNullCheck:[exact=JSUInt31]*/
+ifThenNullCheck(int /*[null|exact=JSUInt31]*/ value) {
+ if (value == null) {
+ return 0;
+ }
+ return value;
+}
+
+/*element: ifThenElseNullCheck:[exact=JSUInt31]*/
+ifThenElseNullCheck(int /*[null|exact=JSUInt31]*/ value) {
+ if (value == null) {
+ return 0;
+ } else {
+ return value;
+ }
+}
+
+/*element: ifNotThenNullCheck:[exact=JSUInt31]*/
+ifNotThenNullCheck(int /*[null|exact=JSUInt31]*/ value) {
+ if (value != null) {
+ return value;
+ }
+ return 0;
+}
+
+/*element: ifNotThenElseNullCheck:[exact=JSUInt31]*/
+ifNotThenElseNullCheck(int /*[null|exact=JSUInt31]*/ value) {
+ if (value != null) {
+ return value;
+ } else {
+ return 0;
+ }
+}
+
+/*element: ifThenNotNullComplexCheck:[null|exact=JSUInt31]*/
+ifThenNotNullComplexCheck(
+ int /*[null|exact=JSUInt31]*/ a, int /*[null|exact=JSUInt31]*/ b) {
+ if (a != null && a /*invoke: [exact=JSUInt31]*/ != b) {
+ return a;
+ }
+ return 0;
+}
+
+/*element: ifThenElseNotNullComplexCheck:[null|exact=JSUInt31]*/
+ifThenElseNotNullComplexCheck(
+ int /*[null|exact=JSUInt31]*/ a, int /*[null|exact=JSUInt31]*/ b) {
+ if (a != null && a /*invoke: [exact=JSUInt31]*/ != b) {
+ return a;
+ }
+ return a;
+}
+
+/*element: ifThenNotNullGradualCheck1:[exact=JSUInt31]*/
+ifThenNotNullGradualCheck1(
+ int /*[null|exact=JSUInt31]*/ a, int /*[exact=JSUInt31]*/ b) {
+ if (a /*invoke: [null|exact=JSUInt31]*/ != b) {
+ if (a != null) {
+ return a;
+ }
+ }
+ return 0;
+}
+
+/*element: ifThenNotNullGradualCheck2:[exact=JSUInt31]*/
+ifThenNotNullGradualCheck2(
+ int /*[null|exact=JSUInt31]*/ a, int /*[exact=JSUInt31]*/ b) {
+ if (a != null) {
+ if (a /*invoke: [exact=JSUInt31]*/ != b) {
+ return a;
+ }
+ }
+ return 0;
+}
diff --git a/tests/compiler/dart2js/js/js_spec_string_test.dart b/tests/compiler/dart2js/js/js_spec_string_test.dart
index 4f301af..1e7080d 100644
--- a/tests/compiler/dart2js/js/js_spec_string_test.dart
+++ b/tests/compiler/dart2js/js/js_spec_string_test.dart
@@ -5,7 +5,7 @@
// Unit test of the [NativeBehavior.processSpecString] method.
import 'package:expect/expect.dart';
-import 'package:compiler/src/native/native.dart';
+import 'package:compiler/src/native/behavior.dart';
import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/diagnostics/messages.dart';
import 'package:compiler/src/universe/side_effects.dart' show SideEffects;
diff --git a/tests/compiler/dart2js/js/js_throw_behavior_test.dart b/tests/compiler/dart2js/js/js_throw_behavior_test.dart
index e0b75b9..22fb733 100644
--- a/tests/compiler/dart2js/js/js_throw_behavior_test.dart
+++ b/tests/compiler/dart2js/js/js_throw_behavior_test.dart
@@ -3,7 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:expect/expect.dart';
-import 'package:compiler/src/native/native.dart';
+import 'package:compiler/src/native/behavior.dart';
+import 'package:compiler/src/native/js.dart';
import 'package:compiler/src/js/js.dart' as js;
void test(String source, NativeThrowBehavior expectedThrowBehavior) {
diff --git a/tests/compiler/dart2js/model/open_world_test.dart b/tests/compiler/dart2js/model/open_world_test.dart
new file mode 100644
index 0000000..b315b5c
--- /dev/null
+++ b/tests/compiler/dart2js/model/open_world_test.dart
@@ -0,0 +1,434 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/common_elements.dart';
+import 'package:compiler/src/elements/entities.dart';
+import 'package:compiler/src/ir/static_type.dart';
+import 'package:compiler/src/js_backend/native_data.dart';
+import 'package:compiler/src/universe/resolution_world_builder.dart';
+import 'package:compiler/src/universe/world_builder.dart';
+import '../helpers/memory_compiler.dart';
+
+main() {
+ asyncTest(() async {
+ await runTest();
+ });
+}
+
+runTest() async {
+ String classes = '''
+@JS()
+library lib;
+
+import 'package:js/js.dart';
+
+class A {}
+class A1 extends A {}
+class A2 extends A1 {}
+
+class B implements A {}
+class B1 extends B {}
+
+class C {}
+class C0 {}
+class C1 = C with A;
+class C2 extends C1 {}
+class C3 = C with C0, A;
+class C4 = C with A, C0;
+
+@JS()
+class D {}
+
+@JS()
+class D1 extends D {}
+
+''';
+
+ CommonElements commonElements;
+ NativeBasicData nativeBasicData;
+ ResolutionWorldBuilderImpl world;
+
+ List<ClassEntity> allClasses;
+
+ ClassEntity A;
+ ClassEntity A1;
+ ClassEntity A2;
+ ClassEntity B;
+ ClassEntity B1;
+ ClassEntity C;
+ ClassEntity C0;
+ ClassEntity C1;
+ ClassEntity C2;
+ ClassEntity C3;
+ ClassEntity C4;
+ ClassEntity D;
+ ClassEntity D1;
+
+ List<ClassRelation> allRelations = ClassRelation.values;
+ List<ClassRelation> notExact = [
+ ClassRelation.thisExpression,
+ ClassRelation.subtype
+ ];
+ List<ClassRelation> subtype = [ClassRelation.subtype];
+
+ run(List<String> liveClasses) async {
+ String source = '''
+$classes
+main() {
+${liveClasses.map((c) => ' new $c();').join('\n')}
+}
+''';
+ print('------------------------------------------------------------------');
+ print(source);
+ CompilationResult result =
+ await runCompiler(memorySourceFiles: {'main.dart': source});
+ Expect.isTrue(result.isSuccess);
+ Compiler compiler = result.compiler;
+ commonElements = compiler.frontendStrategy.commonElements;
+ ElementEnvironment elementEnvironment =
+ compiler.frontendStrategy.elementEnvironment;
+ nativeBasicData = compiler.frontendStrategy.nativeBasicData;
+ world = compiler.resolutionWorldBuilder;
+
+ ClassEntity findClass(String name) {
+ ClassEntity cls =
+ elementEnvironment.lookupClass(elementEnvironment.mainLibrary, name);
+ Expect.isNotNull(cls, 'Class $name not found.');
+ return cls;
+ }
+
+ allClasses = [
+ A = findClass('A'),
+ A1 = findClass('A1'),
+ A2 = findClass('A2'),
+ B = findClass('B'),
+ B1 = findClass('B1'),
+ C = findClass('C'),
+ C0 = findClass('C0'),
+ C1 = findClass('C1'),
+ C2 = findClass('C2'),
+ C3 = findClass('C3'),
+ C4 = findClass('C4'),
+ D = findClass('D'),
+ D1 = findClass('D1'),
+ ];
+ }
+
+ void check(
+ Map<ClassEntity, Map<ClassEntity, List<ClassRelation>>> expectedResults) {
+ for (ClassEntity cls in allClasses) {
+ for (ClassEntity memberHoldingClass in allClasses) {
+ Map<ClassEntity, List<ClassRelation>> memberResults =
+ expectedResults[memberHoldingClass] ?? {};
+ for (ClassRelation relation in allRelations) {
+ List<ClassRelation> expectRelations = memberResults[cls];
+ bool expectedResult =
+ expectRelations != null && expectRelations.contains(relation);
+ StrongModeConstraint constraint = new StrongModeConstraint(
+ commonElements, nativeBasicData, cls, relation);
+ Expect.equals(
+ expectedResult,
+ world.isInheritedInClass(
+ memberHoldingClass, constraint.cls, constraint.relation),
+ "Unexpected results for member of $memberHoldingClass on a "
+ "receiver $constraint (cls=$cls, relation=$relation)");
+ }
+ }
+ }
+ }
+
+ await run([]);
+ check({});
+
+ await run(['A']);
+ check({
+ A: {A: allRelations},
+ });
+
+ await run(['A1']);
+ check({
+ A: {
+ A: notExact,
+ A1: allRelations,
+ },
+ A1: {
+ A: notExact,
+ A1: allRelations,
+ },
+ });
+
+ await run(['A', 'A1']);
+ check({
+ A: {
+ A: allRelations,
+ A1: allRelations,
+ },
+ A1: {
+ A: notExact,
+ A1: allRelations,
+ },
+ });
+
+ await run(['A2']);
+ check({
+ A: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ A1: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ A2: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ });
+
+ await run(['A', 'A2']);
+ check({
+ A: {
+ A: allRelations,
+ A1: notExact,
+ A2: allRelations,
+ },
+ A1: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ A2: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ });
+
+ await run(['A1', 'A2']);
+ check({
+ A: {
+ A: notExact,
+ A1: allRelations,
+ A2: allRelations,
+ },
+ A1: {
+ A: notExact,
+ A1: allRelations,
+ A2: allRelations,
+ },
+ A2: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ });
+
+ await run(['B']);
+ check({
+ B: {
+ A: subtype,
+ B: allRelations,
+ },
+ });
+
+ await run(['B1']);
+ check({
+ B: {
+ A: subtype,
+ B: notExact,
+ B1: allRelations,
+ },
+ B1: {
+ A: subtype,
+ B: notExact,
+ B1: allRelations,
+ },
+ });
+
+ await run(['A', 'A2', 'B']);
+ check({
+ A: {
+ A: allRelations,
+ A1: notExact,
+ A2: allRelations,
+ },
+ A1: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ A2: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ B: {A: subtype, B: allRelations},
+ });
+
+ await run(['C']);
+ check({
+ C: {
+ C: allRelations,
+ },
+ });
+
+ await run(['C1']);
+ check({
+ A: {
+ A: notExact,
+ C: notExact,
+ C1: allRelations,
+ },
+ C: {
+ A: notExact,
+ C: notExact,
+ C1: allRelations,
+ },
+ C1: {
+ A: notExact,
+ C: notExact,
+ C1: allRelations,
+ },
+ });
+
+ await run(['C2']);
+ check({
+ A: {
+ A: notExact,
+ C: notExact,
+ C1: notExact,
+ C2: allRelations,
+ },
+ C: {
+ A: notExact,
+ C: notExact,
+ C1: notExact,
+ C2: allRelations,
+ },
+ C1: {
+ A: notExact,
+ C: notExact,
+ C1: notExact,
+ C2: allRelations,
+ },
+ C2: {
+ A: notExact,
+ C: notExact,
+ C1: notExact,
+ C2: allRelations,
+ },
+ });
+
+ await run(['C3']);
+ check({
+ A: {
+ A: notExact,
+ C: notExact,
+ C0: notExact,
+ C3: allRelations,
+ },
+ C: {
+ A: notExact,
+ C: notExact,
+ C0: notExact,
+ C3: allRelations,
+ },
+ C0: {
+ A: notExact,
+ C: notExact,
+ C0: notExact,
+ C3: allRelations,
+ },
+ C3: {
+ A: notExact,
+ C: notExact,
+ C0: notExact,
+ C3: allRelations,
+ },
+ });
+
+ await run(['C4']);
+ check({
+ A: {
+ A: notExact,
+ C: notExact,
+ C0: notExact,
+ C4: allRelations,
+ },
+ C: {
+ A: notExact,
+ C: notExact,
+ C0: notExact,
+ C4: allRelations,
+ },
+ C0: {
+ A: notExact,
+ C: notExact,
+ C0: notExact,
+ C4: allRelations,
+ },
+ C4: {
+ A: notExact,
+ C: notExact,
+ C0: notExact,
+ C4: allRelations,
+ },
+ });
+
+ await run(['A2', 'C1']);
+ check({
+ A: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ C: notExact,
+ C1: allRelations,
+ },
+ A1: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ A2: {
+ A: notExact,
+ A1: notExact,
+ A2: allRelations,
+ },
+ C: {
+ A: notExact,
+ C: notExact,
+ C1: allRelations,
+ },
+ C1: {
+ A: notExact,
+ C: notExact,
+ C1: allRelations,
+ },
+ });
+
+ await run(['D']);
+ check({
+ D: {
+ D: allRelations,
+ D1: allRelations,
+ },
+ });
+ await run(['D1']);
+ check({
+ D: {
+ D: allRelations,
+ D1: allRelations,
+ },
+ D1: {
+ D: allRelations,
+ D1: allRelations,
+ },
+ });
+}
diff --git a/tests/compiler/dart2js/rti/data/runtime_type_to_string6.dart b/tests/compiler/dart2js/rti/data/runtime_type_to_string6.dart
index fb64484..eeb633c 100644
--- a/tests/compiler/dart2js/rti/data/runtime_type_to_string6.dart
+++ b/tests/compiler/dart2js/rti/data/runtime_type_to_string6.dart
@@ -24,4 +24,5 @@
dynamic cls1 = new Class1<int>();
print('${cls1.runtimeType}');
new Class2<int>();
+ cls1 = null;
}
diff --git a/tests/compiler/dart2js/serialization/serialization_test.dart b/tests/compiler/dart2js/serialization/serialization_test.dart
index 72af9ba..6c5a1cb 100644
--- a/tests/compiler/dart2js/serialization/serialization_test.dart
+++ b/tests/compiler/dart2js/serialization/serialization_test.dart
@@ -4,6 +4,7 @@
import 'dart:io';
import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/serialization/strategies.dart';
import 'package:expect/expect.dart';
import 'serialization_test_helper.dart';
@@ -49,6 +50,8 @@
if (shouldContinue) continued = true;
testCount++;
List<String> testOptions = options.toList();
+ testOptions.add(Flags.dumpInfo);
+ testOptions.add('--out=out.js');
if (onTest != null) {
onTest(entity.uri);
}
diff --git a/tests/compiler/dart2js/serialization/serialization_test_helper.dart b/tests/compiler/dart2js/serialization/serialization_test_helper.dart
index 12be8dc..ad0ddfd 100644
--- a/tests/compiler/dart2js/serialization/serialization_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/serialization_test_helper.dart
@@ -11,6 +11,13 @@
import '../helpers/memory_compiler.dart';
import '../helpers/text_helpers.dart';
+/// Entries in dump info that naturally differ between compilations.
+const List<String> dumpInfoExceptions = [
+ '"compilationMoment":',
+ '"compilationDuration":',
+ '"toJsonDuration":'
+];
+
runTest(
{Uri entryPoint,
Map<String, String> memorySourceFiles: const <String, String>{},
@@ -28,7 +35,7 @@
options: options,
outputProvider: collector1,
beforeRun: (Compiler compiler) {
- compiler.libraryLoader.forceSerialization = true;
+ compiler.kernelLoader.forceSerialization = true;
});
Expect.isTrue(result1.isSuccess);
@@ -41,7 +48,7 @@
options: options,
outputProvider: collector2,
beforeRun: (Compiler compiler) {
- compiler.libraryLoader.forceSerialization = true;
+ compiler.kernelLoader.forceSerialization = true;
compiler.stopAfterTypeInference = true;
});
Expect.isTrue(result.isSuccess);
@@ -62,10 +69,26 @@
Map<String, String> newFileMap = newOutput[outputType];
Expect.setEquals(fileMap.keys, newFileMap.keys,
"File mismatch for output type $outputType.");
-
fileMap.forEach((String fileName, String code) {
String newCode = newFileMap[fileName];
- int failureLine = checkEqualContentAndShowDiff(code, newCode);
+ bool Function(int, List<String>, List<String>) filter;
+ if (outputType == OutputType.dumpInfo) {
+ filter = (int index, List<String> lines1, List<String> lines2) {
+ if (index <= lines1.length && index <= lines2.length) {
+ String line1 = lines1[index];
+ String line2 = lines2[index];
+ for (String exception in dumpInfoExceptions) {
+ if (line1.trim().startsWith(exception) &&
+ line2.trim().startsWith(exception)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+ }
+ int failureLine =
+ checkEqualContentAndShowDiff(code, newCode, filter: filter);
Expect.isNull(
failureLine,
"Output mismatch at line $failureLine in "
diff --git a/tests/compiler/dart2js/static_type/data/effectively_final.dart b/tests/compiler/dart2js/static_type/data/effectively_final.dart
index 5d13f32..58bd022 100644
--- a/tests/compiler/dart2js/static_type/data/effectively_final.dart
+++ b/tests/compiler/dart2js/static_type/data/effectively_final.dart
@@ -11,12 +11,14 @@
effectivelyFinalList() {
dynamic c = [];
- /*dynamic*/ c. /*invoke: dynamic*/ add(null);
+ /*List<dynamic>*/ c. /*invoke: void*/ add(null);
+ /*List<dynamic>*/ c.length /*invoke: int*/ + 1;
}
notEffectivelyFinalList() {
dynamic c = [];
/*dynamic*/ c. /*invoke: dynamic*/ add(null);
+ /*dynamic*/ c.length /*invoke: dynamic*/ + 1;
c = null;
}
@@ -24,8 +26,8 @@
effectivelyFinalPromoted() {
dynamic c = _method1();
- /*dynamic*/ c /*invoke: dynamic*/ + 0;
- if (/*dynamic*/ c is int) {
+ /*num*/ c /*invoke: num*/ + 0;
+ if (/*num*/ c is int) {
/*int*/ c /*invoke: int*/ + 1;
}
}
@@ -34,8 +36,8 @@
effectivelyFinalPromotedInvalid() {
dynamic c = _method2();
- /*dynamic*/ c /*invoke: dynamic*/ + '';
- if (/*dynamic*/ c is int) {
+ /*String*/ c /*invoke: String*/ + '';
+ if (/*String*/ c is int) {
/*int*/ c /*invoke: int*/ + 1;
}
}
diff --git a/tests/compiler/dart2js/static_type/data/generic_method.dart b/tests/compiler/dart2js/static_type/data/generic_method.dart
index 97f839c..0af8ea4 100644
--- a/tests/compiler/dart2js/static_type/data/generic_method.dart
+++ b/tests/compiler/dart2js/static_type/data/generic_method.dart
@@ -2,22 +2,33 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-class Class {
+class Class1 {
T method<T>(T t) => t;
}
+class Class2<T> {
+ @pragma('dart2js:noInline')
+ S method<S extends T>() => null;
+}
+
main() {
genericMethod1(null);
genericMethod2(null);
+ genericMethod3();
}
genericMethod1(c) {
- if (/*dynamic*/ c is Class) {
- /*Class*/ c. /*invoke: String*/ method('').length;
+ if (/*dynamic*/ c is Class1) {
+ /*Class1*/ c. /*invoke: String*/ method('').length;
}
}
genericMethod2(c) {
- if (/*dynamic*/ c is! Class) return;
+ if (/*dynamic*/ c is! Class1) return;
/*dynamic*/ c. /*invoke: dynamic*/ method('').length;
}
+
+genericMethod3() {
+ dynamic c = new Class2<int>();
+ /*Class2<int>*/ c. /*invoke: int*/ method();
+}
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index d705379..e8bc0cb 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -408,14 +408,6 @@
[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
*: SkipByDesign # Deprecating all Dart1 modes of execution
-# Sections for dartk and dartkp.
-#
-# Note: these sections are normalized so we can update them with automated
-# tools. Please add any new status lines affecting those two compilers in the
-# existing sections, if possible keep the alphabetic ordering. If we are missing
-# a section you need, please reach out to sigmund@ to see the best way to add
-# them.
-# ===== Skip dartk and darkp in !$strong mode ====
[ !$strong && ($compiler == dartk || $compiler == dartkb || $compiler == dartkp) ]
*: SkipByDesign
diff --git a/tests/language_2/cascade_2_test.dart b/tests/language_2/cascade_2_test.dart
index 1742f48..11b2974 100644
--- a/tests/language_2/cascade_2_test.dart
+++ b/tests/language_2/cascade_2_test.dart
@@ -29,6 +29,14 @@
Expect.equals(b, b.path1[2]);
Expect.equals(2, b.path2.length); // NPE.
+
+ // Regression test for dartdevc comma expressions (js_ast printer did not
+ // generate parentheses around the comma expression).
+ var expectedList = [3, 2, 1];
+ for (var actual in expectedList.toList()..sort()) {
+ Expect.equals(
+ expectedList.removeLast(), actual, "list items should be sorted");
+ }
}
class Element {
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index cbbe9b5..b514980 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -3,12 +3,6 @@
# BSD-style license that can be found in the LICENSE file.
# Sections in this file should contain "$compiler == dartk" or
# "$compiler == dartkp".
-#
-# Note: Sections in this file are normalized so we can update them with
-# automated tools. Please add any new status lines affecting those two compilers
-# in the existing sections, if possible keep the alphabetic ordering. If we are
-# missing a section you need, please reach out to sigmund@ to see the best way
-# to add them.
[ $compiler == app_jitk ]
assertion_initializer_const_error2_test/cc01: MissingCompileTimeError
diff --git a/tests/language_2/set_literals/const_set_literal_test.dart b/tests/language_2/set_literals/const_set_literal_test.dart
index 4dc9eb0..f236d9b 100644
--- a/tests/language_2/set_literals/const_set_literal_test.dart
+++ b/tests/language_2/set_literals/const_set_literal_test.dart
@@ -4,6 +4,8 @@
// SharedOptions=--enable-experiment=set-literals
+import 'dart:async';
+
import "package:expect/expect.dart";
void main() {
diff --git a/tests/language_2/set_literals/invalid_set_literal_test.dart b/tests/language_2/set_literals/invalid_set_literal_test.dart
index f116a42..18b1a67 100644
--- a/tests/language_2/set_literals/invalid_set_literal_test.dart
+++ b/tests/language_2/set_literals/invalid_set_literal_test.dart
@@ -4,7 +4,7 @@
// SharedOptions=--enable-experiment=set-literals
-import "dart:collection" show LinkedHashSet;
+import "dart:collection" show HashSet, LinkedHashSet;
import "package:expect/expect.dart";
diff --git a/tests/language_2/set_literals/set_literal_test.dart b/tests/language_2/set_literals/set_literal_test.dart
index 03e9b0b..460d1b6 100644
--- a/tests/language_2/set_literals/set_literal_test.dart
+++ b/tests/language_2/set_literals/set_literal_test.dart
@@ -4,6 +4,7 @@
// SharedOptions=--enable-experiment=set-literals
+import 'dart:async';
import "dart:collection" show LinkedHashSet;
import "package:expect/expect.dart";
@@ -22,7 +23,7 @@
Object setContext<T>(Set<T> object) => object;
Object iterableContext<T>(Iterable<T> object) => object;
Object foSetContext<T>(FutureOr<Set<T>> object) => object;
- cbject foIterableContext<T>(FutureOr<Iterable<T>> object) => object;
+ Object foIterableContext<T>(FutureOr<Iterable<T>> object) => object;
Object sContext(S object) => object;
Object iContext(I object) => object;
@@ -113,8 +114,8 @@
Expect.equals(0, set.first.length);
set = {{1}, {}}; // Set<Object>
- Expect.type<Set<Object>>(x);
- Expect.notType<Set<Set<Object>>>(x);
+ Expect.type<Set<Object>>(set);
+ Expect.notType<Set<Set<Object>>>(set);
// Trailing comma.
Iterable<Object> i;
@@ -124,7 +125,8 @@
o = {1, 2, 3,};
Expect.type<Set<int>>(o);
- Expect.equals(3, o.length);
+ set = o;
+ Expect.equals(3, set.length);
}
class Equality {
@@ -132,6 +134,6 @@
final String name;
const Equality(this.id, this.name);
int get hashCode => id;
- bool operator==(Object other) => other is Equality && id = other.id;
+ bool operator==(Object other) => other is Equality && id == other.id;
String toString() => "$id:$name";
}
diff --git a/tests/language_2/static_const_field_reserved_name_test.dart b/tests/language_2/static_const_field_reserved_name_test.dart
index 8c892a1..1de0168 100644
--- a/tests/language_2/static_const_field_reserved_name_test.dart
+++ b/tests/language_2/static_const_field_reserved_name_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test for testing redefinition of reserved names as static const fields.
-// Bug #587.
+// Issue https://github.com/dart-archive/dev_compiler/issues/587
import "package:expect/expect.dart";
@@ -17,6 +17,19 @@
}
}
+class Foo {
+ int get foo => 42;
+ static final baz = new Foo();
+}
+
+class Bar extends Foo {
+ get foo => 123;
+ Bar.baz();
+}
+
void main() {
StaticConstFieldReservedNameTest.testMain();
+
+ // Regression test for https://github.com/dart-lang/sdk/issues/33621
+ Expect.equals(Bar.baz().foo, 123);
}
diff --git a/tests/lib_2/lib_2_dartdevc.status b/tests/lib_2/lib_2_dartdevc.status
index 610f4b9..55192e7 100644
--- a/tests/lib_2/lib_2_dartdevc.status
+++ b/tests/lib_2/lib_2_dartdevc.status
@@ -9,10 +9,6 @@
[ $compiler == dartdevk ]
async/slow_consumer_test: CompileTimeError
-convert/chunked_conversion_utf82_test: RuntimeError
-convert/chunked_conversion_utf86_test: RuntimeError
-convert/chunked_conversion_utf87_test: RuntimeError
-convert/utf82_test: RuntimeError
html/debugger_test: CompileTimeError
[ $runtime == chrome && ($compiler == dartdevc || $compiler == dartdevk) ]
@@ -43,8 +39,7 @@
convert/chunked_conversion_utf88_test: Slow, Pass
convert/json_utf8_chunk_test: Slow, Pass
convert/streamed_conversion_json_utf8_encode_test: Pass, Timeout # Issue 29922
-convert/streamed_conversion_utf8_decode_test: Slow, Pass
-convert/streamed_conversion_utf8_encode_test: Pass, Timeout # Issue 29922
+convert/streamed_conversion_utf8_decode_test: Slow, Pass, Timeout # Issue 29922
convert/utf85_test: Slow, Pass
html/async_spawnuri_test: RuntimeError # Issue 29922
html/async_test: RuntimeError # Issue 29922
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index 081f26e..b636d47 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -3,12 +3,6 @@
# BSD-style license that can be found in the LICENSE file.
# Sections in this file should contain "$compiler == dartk" or
# "$compiler == dartkp".
-#
-# Note: Sections in this file are normalized so we can update them with
-# automated tools. Please add any new status lines affecting those two compilers
-# in the existing sections, if possible keep the alphabetic ordering. If we are
-# missing a section you need, please reach out to sigmund@ to see the best way
-# to add them.
convert/streamed_conversion_json_utf8_decode_test: Pass, Slow # Uses --verify_before_gc --verify_after_gc --old_gen_growth_rate=1 flags
@@ -129,6 +123,7 @@
mirrors/other_declarations_location_test: Crash # Issue 33325 (assertion error, TypeParameter not having position).
[ $mode == debug && $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
+async/timer_regress22626_test: Skip # Timing dependent
isolate/message3_test/constList_identical: Skip # Timeout
[ $runtime == vm && $checked && $strong && ($compiler == dartk || $compiler == dartkb) ]
diff --git a/tests/standalone_2/fragmentation_test.dart b/tests/standalone_2/fragmentation_test.dart
index 19d1d95..b083ec1 100644
--- a/tests/standalone_2/fragmentation_test.dart
+++ b/tests/standalone_2/fragmentation_test.dart
@@ -13,9 +13,11 @@
// VMOptions=--no_concurrent_mark --no_concurrent_sweep
// VMOptions=--no_concurrent_mark --concurrent_sweep
// VMOptions=--no_concurrent_mark --use_compactor
+// VMOptions=--no_concurrent_mark --use_compactor --force_evacuation
// VMOptions=--concurrent_mark --no_concurrent_sweep
// VMOptions=--concurrent_mark --concurrent_sweep
// VMOptions=--concurrent_mark --use_compactor
+// VMOptions=--concurrent_mark --use_compactor --force_evacuation
main() {
final List<List> arrays = [];
diff --git a/tests/standalone_2/io/http_loopback_test.dart b/tests/standalone_2/io/http_loopback_test.dart
index f2b9db6..2667091 100644
--- a/tests/standalone_2/io/http_loopback_test.dart
+++ b/tests/standalone_2/io/http_loopback_test.dart
@@ -2,57 +2,64 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:async";
import "dart:io";
import "package:expect/expect.dart";
RawServerSocket server;
RawSocket client;
-serverListen(RawSocket serverSide) {
- serveData(RawSocketEvent event) {
- serverSide.shutdown(SocketDirection.send);
- }
+/// Creates a callback that listens for incomming connections.
+/// If [remotePorts] is not null then callback would add remote port of each
+/// new connection to the given list.
+makeListener([List<int> remotePorts]) {
+ return (RawSocket serverSide) {
+ serveData(RawSocketEvent event) {
+ serverSide.shutdown(SocketDirection.send);
+ }
- serverSide.listen(serveData);
+ remotePorts?.add(serverSide.remotePort);
+ serverSide.listen(serveData);
+ };
}
-IPv4ToIPv6FailureTest() async {
- server = await RawServerSocket.bind(InternetAddress.loopbackIPv6, 0);
- server.listen(serverListen);
+/// Verify that you can't connect to loopback via mismatching protocol, e.g.
+/// if the server is listening to IPv4 then you can't connect via IPv6.
+Future<void> failureTest(
+ InternetAddress serverAddr, InternetAddress clientAddr) async {
+ final remotePorts = <int>[];
+ server = await RawServerSocket.bind(serverAddr, 0);
+ server.listen(makeListener(remotePorts));
+
+ bool success = false;
try {
- client = await RawSocket.connect(InternetAddress.loopbackIPv4, server.port);
+ client = await RawSocket.connect(clientAddr, server.port);
+ final clientPort = client.port;
+
+ // We might actually succeed in connecting somewhere (e.g. to another test
+ // which by chance started listening to the same port).
+ // To make this test more robust we add a check that verifies that we did
+ // not connect to our server by checking if clientPort is within
+ // the list of remotePorts observed by the server. It should not be there.
+ await Future.delayed(Duration(seconds: 2));
+ success = !remotePorts.contains(clientPort);
await client.close();
- Expect.fail('Unexpected connection to IPv6 server!');
} on SocketException catch (e) {
- // We shouldn't be able to connect to the IPv6 loopback adapter using the
- // IPv4 loopback address.
+ // We expect that we fail to connect to IPv4 server via IPv6 client and
+ // vice versa.
+ success = true;
} catch (e) {
Expect.fail('Unexpected exception: $e');
} finally {
+ Expect.isTrue(success,
+ 'Unexpected connection to $serverAddr via $clientAddr address!');
await server.close();
}
}
-IPv6ToIPv4FailureTest() async {
- server = await RawServerSocket.bind(InternetAddress.loopbackIPv4, 0);
- server.listen(serverListen);
- try {
- client = await RawSocket.connect(InternetAddress.loopbackIPv6, server.port);
- await client.close();
- Expect.fail('Unexpected connection to IPv4 server!');
- } on SocketException catch (e) {
- // We shouldn't be able to connect to the IPv4 loopback adapter using the
- // IPv6 loopback address.
- } catch (e) {
- Expect.fail('Unexpected exception: $e');
- } finally {
- await server.close();
- }
-}
-
-loopbackSuccessTest(InternetAddress address) async {
+Future<void> successTest(InternetAddress address) async {
server = await RawServerSocket.bind(address, 0);
- server.listen(serverListen);
+ server.listen(makeListener());
bool testFailure = false;
try {
client = await RawSocket.connect(address, server.port);
@@ -66,8 +73,8 @@
}
main() async {
- await IPv4ToIPv6FailureTest();
- await IPv6ToIPv4FailureTest();
- await loopbackSuccessTest(InternetAddress.loopbackIPv4);
- await loopbackSuccessTest(InternetAddress.loopbackIPv6);
+ await failureTest(InternetAddress.loopbackIPv4, InternetAddress.loopbackIPv6);
+ await failureTest(InternetAddress.loopbackIPv6, InternetAddress.loopbackIPv4);
+ await successTest(InternetAddress.loopbackIPv4);
+ await successTest(InternetAddress.loopbackIPv6);
}
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index b1220e5..2935167 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -3,13 +3,8 @@
# BSD-style license that can be found in the LICENSE file.
# Sections in this file should contain "$compiler == dartk" or
# "$compiler == dartkp".
-#
-# Note: Sections in this file are normalized so we can update them with
-# automated tools. Please add any new status lines affecting those two compilers
-# in the existing sections, if possible keep the alphabetic ordering. If we are
-# missing a section you need, please reach out to sigmund@ to see the best way
-# to add them.
+fragmentation_test: Pass, Slow # GC heavy
io/process_sync_test: Pass, Slow # Spawns synchronously subprocesses in sequence.
[ $builder_tag == asan ]
diff --git a/tools/approve_results.dart b/tools/approve_results.dart
index 75d54fb..d8adccd 100755
--- a/tools/approve_results.dart
+++ b/tools/approve_results.dart
@@ -358,10 +358,10 @@
// Stop if this is a dry run.
if (options["no"]) {
- if (unapprovedBots.length == 1) {
+ if (unapprovedTests.length == 1) {
print("1 test has a changed result and needs approval");
} else {
- print("${unapprovedBots.length} "
+ print("${unapprovedTests.length} "
"tests have changed results and need approval");
}
return;
diff --git a/tools/bots/flutter/analyze_flutter.sh b/tools/bots/flutter/analyze_flutter.sh
index c54f461..0685c0e 100755
--- a/tools/bots/flutter/analyze_flutter.sh
+++ b/tools/bots/flutter/analyze_flutter.sh
@@ -6,8 +6,9 @@
# Runs flutter's analyzer related tests with a locally built SDK.
set -e
-dart=$(pwd)/tools/sdks/dart-sdk/bin/dart
-sdk=$(pwd)/out/ReleaseX64/dart-sdk
+checkout=$(pwd)
+dart=$checkout/tools/sdks/dart-sdk/bin/dart
+sdk=$checkout/out/ReleaseX64/dart-sdk
tmpdir=$(mktemp -d)
cleanup() {
rm -rf "$tmpdir"
@@ -20,6 +21,13 @@
cd flutter
bin/flutter config --no-analytics
+
+pinned_dart_sdk=$(cat bin/cache/dart-sdk/revision)
+patch=$checkout/tools/patches/flutter-engine/${pinned_dart_sdk}.flutter.patch
+if [ -e "$patch" ]; then
+ git apply $patch
+fi
+
bin/flutter update-packages
$dart dev/bots/analyze.dart --dart-sdk $sdk
diff --git a/tools/patches/flutter-engine/apply.sh b/tools/patches/flutter-engine/apply.sh
index e2ac1df..b449af1 100755
--- a/tools/patches/flutter-engine/apply.sh
+++ b/tools/patches/flutter-engine/apply.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
#
# Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -32,11 +32,55 @@
(cd flutter && git apply ../$patch)
need_runhooks=true
fi
+
patch=src/third_party/dart/tools/patches/flutter-engine/${pinned_dart_sdk}.patch
if [ -e "$patch" ]; then
(cd src/flutter && git apply ../../$patch)
need_runhooks=true
fi
+
if [ $need_runhooks = true ]; then
+ # Check if .gclient configuration specifies a cache_dir. Local caches are used
+ # by bots to reduce amount of Git traffic. .gclient configuration file
+ # is a well-formed Python source so use Python load_source to parse it.
+ # If cache_dir is specified then we need to force update the git cache,
+ # otherwise git fetch below might fail to find tags and commits we are
+ # referencing.
+ # Normally gclient sync would update the cache - but we are bypassing
+ # it here.
+ git_cache=$(python -c 'import imp; config = imp.load_source("config", ".gclient"); print getattr(config, "cache_dir", "")')
+
+ # DEPS file might have been patched with new version of packages that
+ # Dart SDK depends on. Get information about dependencies from the
+ # DEPS file and forcefully update checkouts of those dependencies.
+ gclient revinfo | grep 'src/third_party/dart/' | while read -r line; do
+ # revinfo would produce lines in the following format:
+ # path: git-url@tag-or-hash
+ # Where no spaces occur inside path, git-url or tag-or-hash.
+ # To extract path and tag-or-hash we replace ': ' and '@' with ' '
+ # and then create array from the resulting string which splits it
+ # by whitespace.
+ line="${line/: / }"
+ line="${line/@/ }"
+ line=(${line})
+ dependency_path=${line[0]}
+ dependency_tag_or_hash=${line[2]}
+
+ # Inside dependency compare HEAD to specified tag-or-hash by rev-parse'ing
+ # them and comparing resulting hashes.
+ # Note: tag^0 forces rev-parse to return commit hash rather then the hash of
+ # the tag object itself.
+ pushd ${dependency_path} > /dev/null
+ if [ $(git rev-parse HEAD) != $(git rev-parse ${dependency_tag_or_hash}^0) ]; then
+ echo "${dependency_path} requires update to match DEPS file"
+ if [ "$git_cache" != "" ]; then
+ echo "--- Forcing update of the git_cache ${git_cache}"
+ git cache fetch -c ${git_cache} --all -v
+ fi
+ git fetch origin
+ git checkout ${dependency_tag_or_hash}
+ fi
+ popd > /dev/null
+ done
gclient runhooks
fi
diff --git a/tools/patches/flutter-engine/f9ebf2129732fd2b606286fdf58e500384b8a0bc.flutter.patch b/tools/patches/flutter-engine/f9ebf2129732fd2b606286fdf58e500384b8a0bc.flutter.patch
new file mode 100644
index 0000000..e4dcd66
--- /dev/null
+++ b/tools/patches/flutter-engine/f9ebf2129732fd2b606286fdf58e500384b8a0bc.flutter.patch
@@ -0,0 +1,52 @@
+diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml
+index 9dee6de4a12..8063988556d 100644
+--- a/dev/devicelab/pubspec.yaml
++++ b/dev/devicelab/pubspec.yaml
+@@ -5,7 +5,7 @@ homepage: https://github.com/flutter/flutter
+
+ environment:
+ # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
+- sdk: ">=2.0.0-dev.68.0 <3.0.0"
++ sdk: ">=2.1.0-dev.5.0 <3.0.0"
+
+ dependencies:
+ args: 1.5.1
+diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml
+index 81564e6a2b4..9f85ed7ab4d 100644
+--- a/packages/flutter/pubspec.yaml
++++ b/packages/flutter/pubspec.yaml
+@@ -5,7 +5,7 @@ homepage: http://flutter.io
+
+ environment:
+ # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
+- sdk: ">=2.0.0-dev.68.0 <3.0.0"
++ sdk: ">=2.1.0-dev.5.0 <3.0.0"
+
+ dependencies:
+ # To update these, use "flutter update-packages --force-upgrade".
+diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml
+index aa930cbdf49..531d24b7187 100644
+--- a/packages/flutter_test/pubspec.yaml
++++ b/packages/flutter_test/pubspec.yaml
+@@ -2,7 +2,7 @@ name: flutter_test
+
+ environment:
+ # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
+- sdk: ">=2.0.0-dev.68.0 <3.0.0"
++ sdk: ">=2.1.0-dev.5.0 <3.0.0"
+
+ dependencies:
+ # To update these, use "flutter update-packages --force-upgrade".
+diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml
+index 5f89d0f18ea..a869162b0e8 100644
+--- a/packages/flutter_tools/pubspec.yaml
++++ b/packages/flutter_tools/pubspec.yaml
+@@ -5,7 +5,7 @@ author: Flutter Authors <flutter-dev@googlegroups.com>
+
+ environment:
+ # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
+- sdk: ">=2.0.0-dev.68.0 <3.0.0"
++ sdk: ">=2.1.0-dev.5.0 <3.0.0"
+
+ dependencies:
+ # To update these, use "flutter update-packages --force-upgrade".
diff --git a/tools/patches/flutter-engine/f9ebf2129732fd2b606286fdf58e500384b8a0bc.patch b/tools/patches/flutter-engine/f9ebf2129732fd2b606286fdf58e500384b8a0bc.patch
index c9a4d7d..0d76138 100644
--- a/tools/patches/flutter-engine/f9ebf2129732fd2b606286fdf58e500384b8a0bc.patch
+++ b/tools/patches/flutter-engine/f9ebf2129732fd2b606286fdf58e500384b8a0bc.patch
@@ -1,3 +1,16 @@
+diff --git a/DEPS b/DEPS
+index bb8bca813..701871f79 100644
+--- a/DEPS
++++ b/DEPS
+@@ -47,7 +47,7 @@ vars = {
+ 'dart_convert_tag': '2.0.2',
+ 'dart_crypto_tag': '2.0.6',
+ 'dart_csslib_tag': '0.14.4+1',
+- 'dart_dart2js_info_tag': '0.5.13',
++ 'dart_dart2js_info_tag': '0.5.15',
+ 'dart_dart_style_tag': '1.2.0',
+ 'dart_dartdoc_tag': 'v0.24.1',
+ 'dart_fixnum_tag': '0.10.8',
diff --git a/lib/snapshot/BUILD.gn b/lib/snapshot/BUILD.gn
index ef06063a2..fa18ebfbf 100644
--- a/lib/snapshot/BUILD.gn
diff --git a/tools/testing/dart/android.dart b/tools/testing/dart/android.dart
index 20e5fca..5cb232a 100644
--- a/tools/testing/dart/android.dart
+++ b/tools/testing/dart/android.dart
@@ -393,6 +393,9 @@
* Helper to list all adb devices available.
*/
class AdbHelper {
+ // This particular device seems to be flakily going offline / having problems.
+ static const blackListedDeviceIds = const <String>['06ada00c003b6f92'];
+
static RegExp _deviceLineRegexp =
new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true);
@@ -405,6 +408,7 @@
return _deviceLineRegexp
.allMatches(result.stdout as String)
.map((Match m) => m.group(1))
+ .where((String deviceId) => !blackListedDeviceIds.contains(deviceId))
.toList();
});
}
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 8fe7756..d1c68fb 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -622,7 +622,7 @@
commands.add(
computeDartBootstrapCommand(tempDir, arguments, environmentOverrides));
- if (previewDart2) {
+ if (previewDart2 && !_configuration.keepGeneratedFiles) {
commands.add(computeRemoveKernelFileCommand(
tempDir, arguments, environmentOverrides));
}
@@ -630,8 +630,10 @@
if (!_configuration.useBlobs) {
commands.add(
computeAssembleCommand(tempDir, arguments, environmentOverrides));
- commands.add(computeRemoveAssemblyCommand(
- tempDir, arguments, environmentOverrides));
+ if (!_configuration.keepGeneratedFiles) {
+ commands.add(computeRemoveAssemblyCommand(
+ tempDir, arguments, environmentOverrides));
+ }
}
return new CommandArtifact(
diff --git a/tools/testing/dart/configuration.dart b/tools/testing/dart/configuration.dart
index 3568239..53f95df 100644
--- a/tools/testing/dart/configuration.dart
+++ b/tools/testing/dart/configuration.dart
@@ -26,7 +26,6 @@
this.progress,
this.selectors,
this.testList,
- this.appendLogs,
this.repeat,
this.batch,
this.batchDart2JS,
@@ -34,6 +33,7 @@
this.isVerbose,
this.listTests,
this.listStatusFiles,
+ this.noStatus,
this.printTiming,
this.printReport,
this.reportInJson,
@@ -41,8 +41,6 @@
this.skipCompilation,
this.useKernelBytecode,
this.writeDebugLog,
- this.writeTestOutcomeLog,
- this.writeResultLog,
this.writeResults,
this.writeLogs,
this.drtPath,
@@ -78,7 +76,6 @@
// Boolean flags.
- final bool appendLogs;
final bool batch;
final bool batchDart2JS;
final bool copyCoreDumps;
@@ -86,6 +83,7 @@
final bool isVerbose;
final bool listTests;
final bool listStatusFiles;
+ final bool noStatus;
final bool printTiming;
final bool printReport;
final bool reportInJson;
@@ -93,8 +91,6 @@
final bool skipCompilation;
final bool useKernelBytecode;
final bool writeDebugLog;
- final bool writeTestOutcomeLog;
- final bool writeResultLog;
final bool writeResults;
final bool writeLogs;
final bool printPassingStdout;
@@ -116,6 +112,7 @@
bool get useAnalyzerCfe => configuration.useAnalyzerCfe;
bool get useAnalyzerFastaParser => configuration.useAnalyzerFastaParser;
bool get useBlobs => configuration.useBlobs;
+ bool get keepGeneratedFiles => configuration.keepGeneratedFiles;
bool get useSdk => configuration.useSdk;
bool get useFastStartup => configuration.useFastStartup;
bool get useEnableAsserts => configuration.enableAsserts;
diff --git a/tools/testing/dart/options.dart b/tools/testing/dart/options.dart
index 7ebecad..3bea2d7 100644
--- a/tools/testing/dart/options.dart
+++ b/tools/testing/dart/options.dart
@@ -191,6 +191,8 @@
new _Option.bool(
'use_blobs', 'Use mmap instead of shared libraries for precompilation.',
hide: true),
+ new _Option.bool('keep_generated_files', 'Keep any generated files.',
+ abbr: 'k'),
new _Option.int('timeout', 'Timeout in seconds.', abbr: 't'),
new _Option(
'progress',
@@ -223,6 +225,12 @@
new _Option.bool('list_status_files',
'List status files for test-suites. Do not run any test suites.',
hide: true),
+ new _Option.bool(
+ 'no_status',
+ 'Do not use status files for test expectations. Use Skip '
+ 'and Slow from status files. Return exit code 0 if tests '
+ 'run and return results.',
+ hide: true),
new _Option.bool('report_in_json',
'When listing with --list, output result summary in JSON.',
hide: true),
@@ -243,20 +251,9 @@
new _Option.bool('noBatch', 'Do not run tests in batch mode.', hide: true),
new _Option.bool('dart2js_batch', 'Run dart2js tests in batch mode.',
hide: true),
- new _Option.bool(
- 'append_logs', 'Do not delete old logs but rather append to them.',
- hide: true),
new _Option.bool('write_debug_log',
'Don\'t write debug messages to stdout but rather to a logfile.',
hide: true),
- new _Option.bool('write_test_outcome_log',
- 'Write test outcomes to a "${TestUtils.testOutcomeFileName}" file.',
- hide: true),
- new _Option.bool(
- 'write_result_log',
- 'Write test results to a "${TestUtils.resultLogFileName}" json file '
- 'located at the debug_output_directory.',
- hide: true),
new _Option.bool(
'write_results',
'Write results to a "${TestUtils.resultsFileName}" json file '
@@ -335,7 +332,6 @@
/// For printing out reproducing command lines, we don't want to add these
/// options.
static final _blacklistedOptions = [
- 'append_logs',
'build_directory',
'debug_output_directory',
'chrome',
@@ -358,8 +354,6 @@
'verbose',
'write_logs',
'write_debug_log',
- 'write_test_outcome_log',
- 'write_result_log',
'write_results',
].toSet();
@@ -656,6 +650,7 @@
useAnalyzerFastaParser:
data["analyzer_use_fasta_parser"] as bool,
useBlobs: data["use_blobs"] as bool,
+ keepGeneratedFiles: data["keep_generated_files"] as bool,
useSdk: data["use_sdk"] as bool,
useFastStartup: data["fast_startup"] as bool,
useDart2JSWithKernel: data["dart2js_with_kernel"] as bool,
@@ -674,7 +669,6 @@
progress: Progress.find(data["progress"] as String),
selectors: selectors,
testList: data["test_list_contents"] as List<String>,
- appendLogs: data["append_logs"] as bool,
repeat: data["repeat"] as int,
batch: !(data["noBatch"] as bool),
batchDart2JS: data["dart2js_batch"] as bool,
@@ -682,6 +676,7 @@
isVerbose: data["verbose"] as bool,
listTests: data["list"] as bool,
listStatusFiles: data["list_status_files"] as bool,
+ noStatus: data["no_status"] as bool,
printTiming: data["time"] as bool,
printReport: data["report"] as bool,
reportInJson: data["report_in_json"] as bool,
@@ -689,8 +684,6 @@
skipCompilation: data["skip_compilation"] as bool,
useKernelBytecode: compiler == Compiler.dartkb,
writeDebugLog: data["write_debug_log"] as bool,
- writeTestOutcomeLog: data["write_test_outcome_log"] as bool,
- writeResultLog: data["write_result_log"] as bool,
writeResults: data["write_results"] as bool,
writeLogs: data["write_logs"] as bool,
drtPath: data["drt"] as String,
diff --git a/tools/testing/dart/test_configurations.dart b/tools/testing/dart/test_configurations.dart
index 17bb379..00e5ebf 100644
--- a/tools/testing/dart/test_configurations.dart
+++ b/tools/testing/dart/test_configurations.dart
@@ -60,25 +60,10 @@
var printTiming = firstConf.printTiming;
var listTests = firstConf.listTests;
var listStatusFiles = firstConf.listStatusFiles;
-
var reportInJson = firstConf.reportInJson;
Browser.resetBrowserConfiguration = firstConf.resetBrowser;
-
- if (!firstConf.appendLogs) {
- var files = [
- new File(TestUtils.flakyFileName),
- new File(TestUtils.testOutcomeFileName)
- ];
- for (var file in files) {
- if (file.existsSync()) {
- file.deleteSync();
- }
- }
- }
-
- DebugLogger.init(firstConf.writeDebugLog ? TestUtils.debugLogFilePath : null,
- append: firstConf.appendLogs);
+ DebugLogger.init(firstConf.writeDebugLog ? TestUtils.debugLogFilePath : null);
// Print the configurations being run by this execution of
// test.dart. However, don't do it if the silent progress indicator
@@ -182,7 +167,9 @@
}
DebugLogger.close();
- TestUtils.deleteTempSnapshotDirectory(configurations[0]);
+ if (!firstConf.keepGeneratedFiles) {
+ TestUtils.deleteTempSnapshotDirectory(configurations[0]);
+ }
}
var eventListener = <EventListener>[];
@@ -202,7 +189,6 @@
eventListener.add(new StatusFileUpdatePrinter());
}
eventListener.add(new SummaryPrinter());
- eventListener.add(new FlakyLogWriter());
if (printFailures) {
// The buildbot has it's own failure summary since it needs to wrap it
// into '@@@'-annotated sections.
@@ -223,14 +209,6 @@
}
}
- if (firstConf.writeTestOutcomeLog) {
- eventListener.add(new TestOutcomeLogWriter());
- }
-
- if (firstConf.writeResultLog) {
- eventListener.add(new ResultLogWriter(firstConf.outputDirectory));
- }
-
if (firstConf.writeResults) {
eventListener.add(new ResultWriter(firstConf, startTime, startStopwatch));
}
@@ -244,7 +222,9 @@
if (listTests) {
eventListener.add(new SummaryPrinter(jsonOnly: reportInJson));
} else {
- eventListener.add(new ExitCodeSetter());
+ if (!firstConf.noStatus) {
+ eventListener.add(new ExitCodeSetter());
+ }
eventListener.add(new IgnoredTestMonitor());
}
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index 99dd4f9..43dce69 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -120,104 +120,6 @@
}
}
-class FlakyLogWriter extends EventListener {
- void done(TestCase test) {
- if (test.isFlaky && test.result != Expectation.pass) {
- var buf = new StringBuffer();
- for (var l in _buildFailureOutput(test)) {
- buf.write("$l\n");
- }
- _appendToFlakyFile(buf.toString());
- }
- }
-
- void _appendToFlakyFile(String msg) {
- var file = new File(TestUtils.flakyFileName);
- var fd = file.openSync(mode: FileMode.append);
- fd.writeStringSync(msg);
- fd.closeSync();
- }
-}
-
-class TestOutcomeLogWriter extends EventListener {
- /*
- * The ".test-outcome.log" file contains one line for every executed test.
- * Such a line is an encoded JSON data structure of the following form:
- * The durations are double values in milliseconds.
- *
- * {
- * name: 'co19/LibTest/math/x',
- * configuration: {
- * mode : 'release',
- * compiler : 'dart2js',
- * ....
- * },
- * test_result: {
- * outcome: 'RuntimeError',
- * expected_outcomes: ['Pass', 'Fail'],
- * duration: 2600.64,
- * command_results: [
- * {
- * name: 'dart2js',
- * duration: 2400.44,
- * },
- * {
- * name: 'ff',
- * duration: 200.2,
- * },
- * ],
- * }
- * },
- */
- IOSink _sink;
-
- void done(TestCase test) {
- var name = test.displayName;
- var outcome = '${test.lastCommandOutput.result(test)}';
- var expectations =
- test.expectedOutcomes.map((expectation) => "$expectation").toList();
-
- var commandResults = [];
- double totalDuration = 0.0;
- for (var command in test.commands) {
- var output = test.commandOutputs[command];
- if (output != null) {
- double duration = output.time.inMicroseconds / 1000.0;
- totalDuration += duration;
- commandResults.add({
- 'name': command.displayName,
- 'duration': duration,
- });
- }
- }
- _writeTestOutcomeRecord({
- 'name': name,
- 'configuration': test.configuration.toSummaryMap(),
- 'test_result': {
- 'outcome': outcome,
- 'expected_outcomes': expectations,
- 'duration': totalDuration,
- 'command_results': commandResults,
- },
- });
- }
-
- void allDone() {
- if (_sink != null) _sink.close();
- }
-
- void _writeTestOutcomeRecord(Map record) {
- // TODO(mkroghj) change the location of this file
- // to be in the debug_output_directory
- // if the current location is not used.
- if (_sink == null) {
- _sink = new File(TestUtils.testOutcomeFileName)
- .openWrite(mode: FileMode.append);
- }
- _sink.write("${jsonEncode(record)}\n");
- }
-}
-
class UnexpectedCrashLogger extends EventListener {
final archivedBinaries = <String, String>{};
@@ -772,89 +674,6 @@
}
}
-class ResultLogWriter extends EventListener {
- Map<String, Map> _configurations = {};
- List<Map> _results = [];
- String _outputDirectory;
-
- ResultLogWriter(this._outputDirectory);
-
- void allTestsKnown() {
- // Write an empty result log file, that will be overwritten if any tests
- // are actually run, when the allDone event handler is invoked.
- writeToFile({}, []);
- }
-
- void done(TestCase test) {
- // We try to find an existing configuration, so as to not duplicate this
- // for each test.
- var thisConf = test.configuration.toSummaryMap();
- String key = _configurations.keys.firstWhere(
- (key) => identical(_configurations[key], thisConf), orElse: () {
- var newKey = "conf${_configurations.length + 1}";
- _configurations[newKey] = thisConf;
- return newKey;
- });
- var commands = test.commands.map((command) {
- var output = test.commandOutputs[command];
- if (output == null) {
- return {'name': command.displayName};
- }
- return {
- 'name': command.displayName,
- 'exitCode': output.exitCode,
- 'timeout': output.hasTimedOut,
- 'duration': output.time.inMilliseconds
- };
- }).toList();
-
- // Compute inlined expectations.
- var inlineExpectations = <String>[];
- if (test.hasStaticWarning) {
- inlineExpectations.add("static-type-warning");
- }
- if (test.hasRuntimeError) {
- inlineExpectations.add("runtime-error");
- }
- if (test.hasSyntaxError) {
- inlineExpectations.add("syntax-error");
- }
- if (test.hasCompileError) {
- inlineExpectations.add("compile-time-error");
- }
- if (test.hasCompileErrorIfChecked) {
- inlineExpectations.add("checked-compile-time-error");
- }
- if (test.isNegativeIfChecked) {
- inlineExpectations.add("dynamic-type-error");
- }
- _results.add({
- 'configuration': key,
- 'name': test.displayName,
- 'result': test.lastCommandOutput.result(test).toString(),
- 'test_expectation': inlineExpectations,
- 'flaky': test.isFlaky,
- 'negative': test.isNegative,
- 'commands': commands
- });
- }
-
- void allDone() {
- writeToFile(_configurations, _results);
- }
-
- void writeToFile(Map<String, Map> configurations, List<Map> results) {
- if (_outputDirectory != null) {
- var path = new Path(_outputDirectory);
- var file =
- new File(path.append(TestUtils.resultLogFileName).toNativePath());
- file.createSync(recursive: true);
- file.writeAsStringSync(
- jsonEncode({'configurations': configurations, 'results': results}));
- }
- }
-}
-
/// Writes a results.json file with a line for each test.
/// Each line is a json map with the test name and result and expected result.
/// Also writes a run.json file with a json map containing the configuration
diff --git a/tools/testing/dart/utils.dart b/tools/testing/dart/utils.dart
index a8378cf..0da3dbf 100644
--- a/tools/testing/dart/utils.dart
+++ b/tools/testing/dart/utils.dart
@@ -37,10 +37,9 @@
/**
* If [path] was null, the DebugLogger will write messages to stdout.
*/
- static void init(Path path, {bool append: false}) {
+ static void init(Path path) {
if (path != null) {
- var mode = append ? FileMode.append : FileMode.write;
- _sink = new File(path.toNativePath()).openWrite(mode: mode);
+ _sink = new File(path.toNativePath()).openWrite(mode: FileMode.append);
}
}
@@ -462,21 +461,6 @@
static final debugLogFilePath = new Path(".debug.log");
- /// If a flaky test failed, information about it (test name, stdin, stdout)
- /// is written to this file.
- ///
- /// This is useful for debugging flaky tests. When running on a buildbot, the
- /// file can be made visible in the waterfall UI.
- static const flakyFileName = ".flaky.log";
-
- /// If test.py was invoked with '--write-test-outcome-log' it will write
- /// test outcomes to this file.
- static const testOutcomeFileName = ".test-outcome.log";
-
- /// If test.py was invoked with '--write-result-log' it will write
- /// test outcomes to this file in the '--output-directory'.
- static const resultLogFileName = "result.log";
-
/// If test.py was invoked with '--write-results' it will write
/// test outcomes to this file in the '--output-directory'.
static const resultsFileName = "results.json";