Version 1.17.0-dev.4.0
Merge branch 'fa1a40c4ee6fc8d28f6902dcd5a55d6b8308b055' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4daba9f..1476317 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,9 @@
## 1.17.0
### Core library changes
+* `dart:convert`
+ * Deprecate `ChunkedConverter` which was erroneously added in 1.16.
+
* `dart:core`
* `Uri.replace` supports iterables as values for the query parameters.
* `Uri.parseIPv6Address` returns a `Uint8List`.
@@ -25,6 +28,9 @@
* A bug has been fixed in which a lockfile was considered up-to-date when it
actually wasn't.
+ * A bug has been fixed in which `pub get --offline` would crash when a
+ prerelease version was selected.
+
## 1.16.0 - 2016-04-26
### Core library changes
diff --git a/DEPS b/DEPS
index 1339596..7753d5f 100644
--- a/DEPS
+++ b/DEPS
@@ -49,7 +49,7 @@
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
"dart_style_tag": "@0.2.4",
"dartdoc_tag" : "@v0.9.0",
- "dev_compiler_rev": "@a0557e2f76fc85a6e71fe8391d1beda69905a548",
+ "dev_compiler_rev": "@1f00327fdf8fe11ab8e9b3d5b0fc958025ede592",
"fixnum_tag": "@0.10.5",
"func_rev": "@8d4aea75c21be2179cb00dc2b94a71414653094e",
"glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
@@ -62,7 +62,7 @@
"intl_rev": "@a8b480b9c436f6c0ec16730804c914bdb4e30d53",
"jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_tag": "@2.0.0",
- "linter_rev": "@ecfaed3ea52ea2b5a7d9e0a7db94cf1f92208280",
+ "linter_rev": "@8e1873ba689fbb0064cbd27c238c898106938dcd",
"logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
"markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
"matcher_tag": "@0.12.0",
@@ -74,12 +74,12 @@
"observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
"package_config_rev": "@0.1.3",
"path_tag": "@1.3.6",
- "plugin_tag": "@0.1.0",
+ "plugin_tag": "@0.2.0",
"ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
"pool_tag": "@1.2.1",
"protobuf_tag": "@0.5.1+1",
"pub_cache_tag": "@v0.1.0",
- "pub_rev": "@0b96a97d61673cea04f69eb47b2ef2b5b37337d3",
+ "pub_rev": "@488ab539770512a234f0a01b74882dcbb3f1a4da",
"pub_semver_tag": "@1.2.1",
"quiver_tag": "@0.21.4",
"resource_rev":"@a49101ba2deb29c728acba6fb86000a8f730f4b1",
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index 25a0c0d..886d65b 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -1807,9 +1807,9 @@
\item \label{requiredParams}
If two members override each other, it is a static warning 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 a static warning if the overriding member has fewer positional parameters than the the overridden one (\ref{instanceMethods}).
+If two members override each other, it is a static warning 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 a static warning if the overriding member does not have all the named parameters that the the overridden one has (\ref{instanceMethods}).
+If two members override each other, it is a static warning if the overriding member does not have all the named parameters that the overridden one has (\ref{instanceMethods}).
\item Setters, getters and operators never have optional parameters of any kind; it's a compile-time error (\ref{operators}, \ref{getters}, \ref{setters}).
\item It is a compile-time error if a member has the same name as its enclosing class (\ref{classes}).
\item A class has an implicit interface (\ref{classes}).
@@ -1839,7 +1839,7 @@
% 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 the \IMPLEMENTS{} clause of the class.
+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.
% and any superinterfaces specified by interface injection (\ref{interfaceInjection}). \Q{The latter needs to be worded carefully - when do interface injection clauses execute and in what scope?}
\begin{grammar}
@@ -2815,7 +2815,7 @@
\LMLabel{stringInterpolation}
\LMHash{}
-It is possible to embed expressions within non-raw string literals, such that the these expressions are evaluated, and the resulting values are converted into strings and concatenated with the enclosing string. This process is known as {\em string interpolation}.
+It is possible to embed expressions within non-raw string literals, such that these expressions are evaluated, and the resulting values are converted into strings and concatenated with the enclosing string. This process is known as {\em string interpolation}.
\begin{grammar}
{\bf stringInterpolation:}`\$' IDENTIFIER\_NO\_DOLLAR;
@@ -3059,7 +3059,7 @@
}
\LMHash{}
-If the object being thrown is an instance of class \code{Error} or a subclass thereof, its \code{stackTrace} getter will return the stack trace current at the point where the the object was first thrown.
+If the object being thrown is an instance of class \code{Error} or a subclass thereof, its \code{stackTrace} getter will return the stack trace current at the point where the object was first thrown.
\LMHash{}
The static type of a throw expression is $\bot$.
@@ -5683,7 +5683,7 @@
\LMHash{}
It is a static warning if the static type of $c$ may not be assigned to \cd{bool}.
-%A for statement of the form \code{ \FOR{} ($d$ ; $c$; $e$) $s$} is equivalent to the the following code:
+%A for statement of the form \code{ \FOR{} ($d$ ; $c$; $e$) $s$} is equivalent to the following code:
%\code{
%\{$d$;
@@ -6306,7 +6306,7 @@
\end{grammar}
\LMHash{}
-Let $s_b$ be a \BREAK{} statement. If $s_b$ is of the form \code{\BREAK{} $L$;}, then let $s_E$ be the the innermost labeled statement with label $L$ enclosing $s_b$. If $s_b$ is of the form \code{\BREAK{};}, then let $s_E$ be the the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}), \SWITCH{} (\ref{switch}) or \WHILE{} (\ref{while}) statement enclosing $s_b$. It is a compile-time error if no such statement $s_E$ exists within the innermost function in which $s_b$ occurs. Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose $s_b$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$. Executing $s_b$ first executes $f_1, \ldots, f_n$ in innermost-clause-first order and then terminates $s_E$.
+Let $s_b$ be a \BREAK{} statement. If $s_b$ is of the form \code{\BREAK{} $L$;}, then let $s_E$ be the innermost labeled statement with label $L$ enclosing $s_b$. If $s_b$ is of the form \code{\BREAK{};}, then let $s_E$ be the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}), \SWITCH{} (\ref{switch}) or \WHILE{} (\ref{while}) statement enclosing $s_b$. It is a compile-time error if no such statement $s_E$ exists within the innermost function in which $s_b$ occurs. Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose $s_b$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$. Executing $s_b$ first executes $f_1, \ldots, f_n$ in innermost-clause-first order and then terminates $s_E$.
\LMHash{}
If $s_E$ is an asynchronous for loop (\ref{asynchronousFor-in}), its associated stream subscription is canceled. Furthermore, let $a_k$ be the set of asynchronous for loops and yield-each statements (\ref{yieldEach}) enclosing $s_b$ that are enclosed in $s_E , 1 \le k \le m$, where $a_k$ is enclosed in $a_{k+1}$. The stream subscriptions associated with $a_j$ are canceled, $1 \le j \le m$, innermost first, so that $a_j$ is canceled before $a_{j+1}$.
@@ -6326,7 +6326,7 @@
\end{grammar}
\LMHash{}
- Let $s_c$ be a \CONTINUE{} statement. If $s_c$ is of the form \code{\CONTINUE{} $L$;}, then let $s_E$ be the the innermost labeled \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement or case clause with label $L$ enclosing $s_c$. If $s_c$ is of the form \code{\CONTINUE{};} then let $s_E$ be the the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement enclosing $s_c$. It is a compile-time error if no such statement or case clause $s_E$ exists within the innermost function in which $s_c$ occurs. Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose $s_c$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$. Executing $s_c$ first executes $f_1, \ldots, f_n$ in innermost-clause-first order. Then, if $s_E$ is a case clause, control is transferred to the case clause. Otherwise, $s_E$ is necessarily a loop and execution resumes after the last statement in the loop body.
+ Let $s_c$ be a \CONTINUE{} statement. If $s_c$ is of the form \code{\CONTINUE{} $L$;}, then let $s_E$ be the innermost labeled \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement or case clause with label $L$ enclosing $s_c$. If $s_c$ is of the form \code{\CONTINUE{};} then let $s_E$ be the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}) or \WHILE{} (\ref{while}) statement enclosing $s_c$. It is a compile-time error if no such statement or case clause $s_E$ exists within the innermost function in which $s_c$ occurs. Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose $s_c$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$. Executing $s_c$ first executes $f_1, \ldots, f_n$ in innermost-clause-first order. Then, if $s_E$ is a case clause, control is transferred to the case clause. Otherwise, $s_E$ is necessarily a loop and execution resumes after the last statement in the loop body.
\commentary{
In a while loop, that would be the boolean expression before the body. In a do loop, it would be the boolean expression after the body. In a for loop, it would be the increment clause. In other words, execution continues to the next iteration of the loop.
@@ -6980,7 +6980,7 @@
}
\LMHash{}
-Otherwise, any relative URI is interpreted as relative to the the location of the current library. All further interpretation of URIs is implementation dependent.
+Otherwise, any relative URI is interpreted as relative to the location of the current library. All further interpretation of URIs is implementation dependent.
\commentary{This means it is dependent on the embedder.}
diff --git a/pkg/analysis_server/benchmark/integration/input_converter.dart b/pkg/analysis_server/benchmark/integration/input_converter.dart
index d743d6c..14ffd96 100644
--- a/pkg/analysis_server/benchmark/integration/input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/input_converter.dart
@@ -271,8 +271,7 @@
* into a series of operations to be sent to the analysis server.
* The input stream can be either an instrumenation or log file.
*/
-class InputConverter
- extends ChunkedConverter<String, Operation, String, Operation> {
+class InputConverter extends Converter<String, Operation> {
final Logger logger = new Logger('InputConverter');
diff --git a/pkg/analysis_server/lib/src/channel/channel.dart b/pkg/analysis_server/lib/src/channel/channel.dart
index bee6f35..21bd3ca 100644
--- a/pkg/analysis_server/lib/src/channel/channel.dart
+++ b/pkg/analysis_server/lib/src/channel/channel.dart
@@ -85,8 +85,7 @@
* Instances of the class [JsonStreamDecoder] convert JSON strings to JSON
* maps.
*/
-class JsonStreamDecoder extends
- ChunkedConverter<String, Map, String, Map> {
+class JsonStreamDecoder extends Converter<String, Map> {
@override
Map convert(String text) => JSON.decode(text);
@@ -99,8 +98,7 @@
* Instances of the class [NotificationConverter] convert JSON maps to
* [Notification]s.
*/
-class NotificationConverter extends
- ChunkedConverter<Map, Notification, Map, Notification> {
+class NotificationConverter extends Converter<Map, Notification> {
@override
Notification convert(Map json) => new Notification.fromJson(json);
@@ -112,8 +110,7 @@
/**
* Instances of the class [ResponseConverter] convert JSON maps to [Response]s.
*/
-class ResponseConverter extends
- ChunkedConverter<Map, Response, Map, Response> {
+class ResponseConverter extends Converter<Map, Response> {
@override
Response convert(Map json) => new Response.fromJson(json);
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 181eeac..44c3595 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -611,7 +611,7 @@
p.optionsProcessed(info.context, options);
} catch (e, stacktrace) {
AnalysisEngine.instance.logger.logError(
- 'Error processing .analysis_options',
+ 'Error processing analysis options',
new CaughtException(e, stacktrace));
}
});
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index 91ecb32..049ef3e 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -109,48 +109,49 @@
* The extension point that allows plugins to register file patterns that will
* cause files to be analyzed.
*/
- ExtensionPoint analyzedFilePatternsExtensionPoint;
+ ExtensionPoint<List<String>> analyzedFilePatternsExtensionPoint;
/**
* The extension point that allows plugins to register assist contributors.
*/
- ExtensionPoint assistContributorExtensionPoint;
+ ExtensionPoint<AssistContributor> assistContributorExtensionPoint;
/**
* The extension point that allows plugins to register completion
* contributors.
*/
- ExtensionPoint completionContributorExtensionPoint;
+ ExtensionPoint<CompletionContributorFactory>
+ completionContributorExtensionPoint;
/**
* The extension point that allows plugins to register domains with the
* server.
*/
- ExtensionPoint domainExtensionPoint;
+ ExtensionPoint<RequestHandlerFactory> domainExtensionPoint;
/**
* The extension point that allows plugins to register fix contributors with
* the server.
*/
- ExtensionPoint fixContributorExtensionPoint;
+ ExtensionPoint<FixContributor> fixContributorExtensionPoint;
/**
* The extension point that allows plugins to register navigation
* contributors.
*/
- ExtensionPoint navigationContributorExtensionPoint;
+ ExtensionPoint<NavigationContributor> navigationContributorExtensionPoint;
/**
* The extension point that allows plugins to register occurrences
* contributors.
*/
- ExtensionPoint occurrencesContributorExtensionPoint;
+ ExtensionPoint<OccurrencesContributor> occurrencesContributorExtensionPoint;
/**
* The extension point that allows plugins to get access to the `analysis`
* domain.
*/
- ExtensionPoint setAnalysisDomainExtensionPoint;
+ ExtensionPoint<SetAnalysisDomain> setAnalysisDomainExtensionPoint;
/**
* Initialize a newly created plugin.
@@ -230,28 +231,33 @@
@override
void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
- setAnalysisDomainExtensionPoint = registerExtensionPoint(
- SET_ANALISYS_DOMAIN_EXTENSION_POINT,
- _validateSetAnalysisDomainFunction);
- analyzedFilePatternsExtensionPoint = registerExtensionPoint(
- ANALYZED_FILE_PATTERNS_EXTENSION_POINT,
- _validateAnalyzedFilePatternsExtension);
- assistContributorExtensionPoint = registerExtensionPoint(
- ASSIST_CONTRIBUTOR_EXTENSION_POINT,
- _validateAssistContributorExtension);
- completionContributorExtensionPoint = registerExtensionPoint(
- COMPLETION_CONTRIBUTOR_EXTENSION_POINT,
- _validateCompletionContributorExtension);
- domainExtensionPoint = registerExtensionPoint(
- DOMAIN_EXTENSION_POINT, _validateDomainExtension);
- fixContributorExtensionPoint = registerExtensionPoint(
- FIX_CONTRIBUTOR_EXTENSION_POINT, _validateFixContributorExtension);
- navigationContributorExtensionPoint = registerExtensionPoint(
- NAVIGATION_CONTRIBUTOR_EXTENSION_POINT,
- _validateNavigationContributorExtension);
- occurrencesContributorExtensionPoint = registerExtensionPoint(
- OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT,
- _validateOccurrencesContributorExtension);
+ analyzedFilePatternsExtensionPoint = new ExtensionPoint<List<String>>(
+ this, ANALYZED_FILE_PATTERNS_EXTENSION_POINT, null);
+ registerExtensionPoint(analyzedFilePatternsExtensionPoint);
+ assistContributorExtensionPoint = new ExtensionPoint<AssistContributor>(
+ this, ASSIST_CONTRIBUTOR_EXTENSION_POINT, null);
+ registerExtensionPoint(assistContributorExtensionPoint);
+ completionContributorExtensionPoint =
+ new ExtensionPoint<CompletionContributorFactory>(
+ this, COMPLETION_CONTRIBUTOR_EXTENSION_POINT, null);
+ registerExtensionPoint(completionContributorExtensionPoint);
+ domainExtensionPoint = new ExtensionPoint<RequestHandlerFactory>(
+ this, DOMAIN_EXTENSION_POINT, null);
+ registerExtensionPoint(domainExtensionPoint);
+ fixContributorExtensionPoint = new ExtensionPoint<FixContributor>(
+ this, FIX_CONTRIBUTOR_EXTENSION_POINT, null);
+ registerExtensionPoint(fixContributorExtensionPoint);
+ navigationContributorExtensionPoint =
+ new ExtensionPoint<NavigationContributor>(
+ this, NAVIGATION_CONTRIBUTOR_EXTENSION_POINT, null);
+ registerExtensionPoint(navigationContributorExtensionPoint);
+ occurrencesContributorExtensionPoint =
+ new ExtensionPoint<OccurrencesContributor>(
+ this, OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT, null);
+ registerExtensionPoint(occurrencesContributorExtensionPoint);
+ setAnalysisDomainExtensionPoint = new ExtensionPoint<SetAnalysisDomain>(
+ this, SET_ANALISYS_DOMAIN_EXTENSION_POINT, null);
+ registerExtensionPoint(setAnalysisDomainExtensionPoint);
}
@override
@@ -263,7 +269,8 @@
'**/*.${AnalysisEngine.SUFFIX_DART}',
'**/*.${AnalysisEngine.SUFFIX_HTML}',
'**/*.${AnalysisEngine.SUFFIX_HTM}',
- '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}'
+ '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}',
+ '**/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}'
];
registerExtension(ANALYZED_FILE_PATTERNS_EXTENSION_POINT_ID, patterns);
//
@@ -307,111 +314,4 @@
registerExtension(
FIX_CONTRIBUTOR_EXTENSION_POINT_ID, new DefaultFixContributor());
}
-
- /**
- * Return `true` if the list being used as an [extension] contains any
- * elements that are not strings.
- */
- bool _containsNonString(List extension) {
- for (Object element in extension) {
- if (element is! String) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid list of analyzed file patterns.
- */
- void _validateAnalyzedFilePatternsExtension(Object extension) {
- if (extension is! List || _containsNonString(extension)) {
- String id = analyzedFilePatternsExtensionPoint.uniqueIdentifier;
- throw new ExtensionError('Extensions to $id must be a List of Strings');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid assist contributor.
- */
- void _validateAssistContributorExtension(Object extension) {
- if (extension is! AssistContributor) {
- String id = assistContributorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be an AssistContributor');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid completion contributor.
- */
- void _validateCompletionContributorExtension(Object extension) {
- if (extension is! CompletionContributorFactory) {
- String id = completionContributorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be an CompletionContributorFactory');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid domain.
- */
- void _validateDomainExtension(Object extension) {
- if (extension is! RequestHandlerFactory) {
- String id = domainExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be a RequestHandlerFactory');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid fix contributor.
- */
- void _validateFixContributorExtension(Object extension) {
- if (extension is! FixContributor) {
- String id = fixContributorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError('Extensions to $id must be a FixContributor');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid navigation contributor.
- */
- void _validateNavigationContributorExtension(Object extension) {
- if (extension is! NavigationContributor) {
- String id = navigationContributorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be an NavigationContributor');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid occurrences contributor.
- */
- void _validateOccurrencesContributorExtension(Object extension) {
- if (extension is! OccurrencesContributor) {
- String id = occurrencesContributorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be an OccurrencesContributor');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid analysis domain receiver.
- */
- void _validateSetAnalysisDomainFunction(Object extension) {
- if (extension is! SetAnalysisDomain) {
- String id = setAnalysisDomainExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be a SetAnalysisDomain function');
- }
- }
}
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
index 97a162e..b25375ad 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
@@ -20,7 +20,7 @@
const int DART_RELEVANCE_COMMON_USAGE = 1200;
const int DART_RELEVANCE_DEFAULT = 1000;
const int DART_RELEVANCE_HIGH = 2000;
-const int DART_RELEVANCE_INCREMENT = 20;
+const int DART_RELEVANCE_INCREMENT = 100;
const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
const int DART_RELEVANCE_INHERITED_FIELD = 1058;
const int DART_RELEVANCE_INHERITED_METHOD = 1057;
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
index cf34c94..8338c92 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
@@ -50,7 +50,7 @@
* The extension point that allows plugins to register Dart specific
* completion contributor factories.
*/
- ExtensionPoint _contributorExtensionPoint;
+ ExtensionPoint<DartCompletionContributorFactory> _contributorExtensionPoint;
/**
* Return a list containing all of the Dart specific completion contributors.
@@ -64,9 +64,10 @@
@override
void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
- _contributorExtensionPoint = registerExtensionPoint(
- CONTRIBUTOR_EXTENSION_POINT,
- _validateDartCompletionContributorExtension);
+ _contributorExtensionPoint =
+ new ExtensionPoint<DartCompletionContributorFactory>(
+ this, CONTRIBUTOR_EXTENSION_POINT, null);
+ registerExtensionPoint(_contributorExtensionPoint);
}
@override
@@ -119,16 +120,4 @@
registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
() => new VariableNameContributor());
}
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid Dart specific completion contributor.
- */
- void _validateDartCompletionContributorExtension(Object extension) {
- if (extension is! DartCompletionContributorFactory) {
- String id = _contributorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be a DartCompletionContributorFactory');
- }
- }
}
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 6ccf8ae..ae8c50f 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -313,7 +313,7 @@
* If this flag is `true`, then single analysis context should be used for
* analysis of multiple analysis roots, special files that could otherwise
* cause creating additional contexts, such as `pubspec.yaml`, or `.packages`,
- * or `.analysis_options` are ignored.
+ * or analysis options are ignored.
*/
bool useSingleContextManager = false;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 833b0ec..6b328b2 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -265,7 +265,7 @@
// Actual: if (x i^)
// Parsed: if (x) i^
_addSuggestion(Keyword.IS, DART_RELEVANCE_HIGH);
- } else if (entity == node.thenStatement) {
+ } else if (entity == node.thenStatement || entity == node.elseStatement) {
_addStatementKeywords(node);
} else if (entity == node.condition) {
_addExpressionKeywords(node);
@@ -502,6 +502,9 @@
if (_inSwitch(node)) {
_addSuggestions([Keyword.BREAK]);
}
+ if (_isEntityAfterIfWithoutElse(node)) {
+ _addSuggestions([Keyword.ELSE]);
+ }
_addSuggestions([
Keyword.ASSERT,
Keyword.CONST,
@@ -584,6 +587,30 @@
bool _inWhileLoop(AstNode node) =>
node.getAncestor((p) => p is WhileStatement) != null;
+ bool _isEntityAfterIfWithoutElse(AstNode node) {
+ Block block = node?.getAncestor((n) => n is Block);
+ if (block == null) {
+ return false;
+ }
+ Object entity = this.entity;
+ if (entity is Statement) {
+ int entityIndex = block.statements.indexOf(entity);
+ if (entityIndex > 0) {
+ Statement prevStatement = block.statements[entityIndex - 1];
+ return prevStatement is IfStatement &&
+ prevStatement.elseStatement == null;
+ }
+ }
+ if (entity is Token) {
+ for (Statement statement in block.statements) {
+ if (statement.endToken.next == entity) {
+ return statement is IfStatement && statement.elseStatement == null;
+ }
+ }
+ }
+ return false;
+ }
+
static bool _isNextTokenSynthetic(Object entity, TokenType type) {
if (entity is AstNode) {
Token token = entity.beginToken;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index d9778a5..7687117 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -256,6 +256,13 @@
_addLocalSuggestion_includeTypeNameSuggestions(
declaration.name, NO_RETURN_TYPE, protocol.ElementKind.ENUM,
isDeprecated: _isDeprecated(declaration));
+ for (EnumConstantDeclaration enumConstant in declaration.constants) {
+ if (!enumConstant.isSynthetic) {
+ _addLocalSuggestion_includeReturnValueSuggestions_enumConstant(
+ enumConstant, declaration,
+ isDeprecated: _isDeprecated(declaration));
+ }
+ }
}
}
@@ -419,6 +426,42 @@
}
}
+ void _addLocalSuggestion_enumConstant(
+ EnumConstantDeclaration constantDeclaration,
+ EnumDeclaration enumDeclaration,
+ {bool isAbstract: false,
+ bool isDeprecated: false,
+ ClassDeclaration classDecl,
+ int relevance: DART_RELEVANCE_DEFAULT}) {
+ String completion =
+ '${enumDeclaration.name.name}.${constantDeclaration.name.name}';
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ CompletionSuggestionKind.INVOCATION,
+ isDeprecated ? DART_RELEVANCE_LOW : relevance,
+ completion,
+ completion.length,
+ 0,
+ isDeprecated,
+ false,
+ returnType: enumDeclaration.name.name);
+
+ suggestionMap.putIfAbsent(suggestion.completion, () => suggestion);
+ int flags = protocol.Element.makeFlags(
+ isAbstract: isAbstract,
+ isDeprecated: isDeprecated,
+ isPrivate: Identifier.isPrivateName(constantDeclaration.name.name));
+ suggestion.element = new protocol.Element(
+ protocol.ElementKind.ENUM_CONSTANT,
+ constantDeclaration.name.name,
+ flags,
+ location: new Location(
+ request.source.fullName,
+ constantDeclaration.name.offset,
+ constantDeclaration.name.length,
+ 0,
+ 0));
+ }
+
void _addLocalSuggestion_includeReturnValueSuggestions(
SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
{bool isAbstract: false,
@@ -438,6 +481,22 @@
}
}
+ void _addLocalSuggestion_includeReturnValueSuggestions_enumConstant(
+ EnumConstantDeclaration constantDeclaration,
+ EnumDeclaration enumDeclaration,
+ {bool isAbstract: false,
+ bool isDeprecated: false,
+ int relevance: DART_RELEVANCE_DEFAULT}) {
+ relevance = optype.returnValueSuggestionsFilter(
+ enumDeclaration.element.type, relevance);
+ if (relevance != null) {
+ _addLocalSuggestion_enumConstant(constantDeclaration, enumDeclaration,
+ isAbstract: isAbstract,
+ isDeprecated: isDeprecated,
+ relevance: relevance);
+ }
+ }
+
void _addLocalSuggestion_includeTypeNameSuggestions(
SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
{bool isAbstract: false,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
index 3ddc75d..3a5608c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
@@ -641,6 +641,16 @@
optype.includeReturnValueSuggestions = true;
optype.returnValueSuggestionsFilter = (DartType dartType, int relevance) {
DartType type = node.element?.type;
+ bool isEnum = type != null &&
+ type.element is ClassElement &&
+ (type.element as ClassElement).isEnum;
+ if (isEnum) {
+ if (type == dartType) {
+ return relevance + DART_RELEVANCE_INCREMENT;
+ } else {
+ return null;
+ }
+ }
if (type != null &&
dartType != null &&
!type.isDynamic &&
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 49d616d..20ca00f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -70,6 +70,7 @@
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS ||
+ errorCode == StaticWarningCode.FUNCTION_WITHOUT_CALL ||
errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER ||
errorCode ==
CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE ||
@@ -154,6 +155,8 @@
const FixKind('CREATE_LOCAL_VARIABLE', 50, "Create local variable '{0}'");
static const CREATE_METHOD =
const FixKind('CREATE_METHOD', 50, "Create method '{0}'");
+ static const CREATE_MISSING_METHOD_CALL =
+ const FixKind('CREATE_MISSING_METHOD_CALL', 49, "Create method 'call'.");
static const CREATE_MISSING_OVERRIDES = const FixKind(
'CREATE_MISSING_OVERRIDES', 49, "Create {0} missing override(s)");
static const CREATE_NO_SUCH_METHOD = const FixKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index f855a29..117884d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -245,6 +245,9 @@
_addFix_createConstructor_insteadOfSyntheticDefault();
_addFix_addMissingParameter();
}
+ if (errorCode == StaticWarningCode.FUNCTION_WITHOUT_CALL) {
+ _addFix_addMissingMethodCall();
+ }
if (errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR) {
_addFix_createConstructor_named();
}
@@ -415,6 +418,32 @@
}
}
+ void _addFix_addMissingMethodCall() {
+ ClassDeclaration targetClass = node.parent as ClassDeclaration;
+ // prepare SourceBuilder
+ int insertOffset = targetClass.end - 1;
+ SourceBuilder sb = new SourceBuilder(file, insertOffset);
+ // prepare environment
+ String prefix = utils.getIndent(1);
+ String prefix2 = utils.getIndent(2);
+ // start method
+ sb.append(prefix);
+ sb.append('call() {');
+ // TO-DO
+ sb.append(eol);
+ sb.append(prefix2);
+ sb.append('// TODO: implement call');
+ sb.append(eol);
+ // close method
+ sb.append(prefix);
+ sb.append('}');
+ sb.append(eol);
+ // add proposal
+ exitPosition = new Position(file, insertOffset);
+ _insertBuilder(sb, unitElement);
+ _addFix(DartFixKind.CREATE_MISSING_METHOD_CALL, []);
+ }
+
void _addFix_addMissingParameter() {
if (node is ArgumentList && node.parent is MethodInvocation) {
ArgumentList argumentList = node;
diff --git a/pkg/analysis_server/lib/src/single_context_manager.dart b/pkg/analysis_server/lib/src/single_context_manager.dart
index 0a8c9f1..058d77e 100644
--- a/pkg/analysis_server/lib/src/single_context_manager.dart
+++ b/pkg/analysis_server/lib/src/single_context_manager.dart
@@ -22,7 +22,7 @@
* Implementation of [ContextManager] that supports only one [AnalysisContext].
* So, sources from all analysis roots are added to this single context. All
* features that could otherwise cause creating additional contexts, such as
- * presence of `pubspec.yaml` or `.packages` files, or `.analysis_options` files
+ * presence of `pubspec.yaml` or `.packages` files, or analysis options files
* are ignored.
*/
class SingleContextManager implements ContextManager {
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index dff1fd7..03722a1 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -9,10 +9,10 @@
analyzer: ^0.27.0
args: '>=0.13.0 <0.14.0'
dart_style: '>=0.2.0 <0.3.0'
- linter: ^0.1.10
+ linter: ^0.1.16
logging: any
path: any
- plugin: <0.2.0
+ plugin: ^0.2.0
watcher: any
yaml: any
dev_dependencies:
diff --git a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
index e8cf7c4..b2d1add 100644
--- a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
@@ -2,7 +2,7 @@
// 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 test.analysis.notification.analysis_options;
+library test.analysis.notification_analysis_options_test;
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/constants.dart';
@@ -18,11 +18,12 @@
main() {
initializeTestEnvironment();
- defineReflectiveTests(AnalysisOptionsFileNotificationTest);
+ defineReflectiveTests(NewAnalysisOptionsFileNotificationTest);
+ defineReflectiveTests(OldAnalysisOptionsFileNotificationTest);
}
-@reflectiveTest
-class AnalysisOptionsFileNotificationTest extends AbstractAnalysisTest {
+abstract class AnalysisOptionsFileNotificationTest
+ extends AbstractAnalysisTest {
Map<String, List<AnalysisError>> filesErrors = {};
final testSource = '''
@@ -36,7 +37,7 @@
List<AnalysisError> get optionsFileErrors => filesErrors[optionsFilePath];
- String get optionsFilePath => '$projectPath/.analysis_options';
+ String get optionsFilePath;
AnalysisContext get testContext => server.getContainingContext(testFile);
@@ -306,3 +307,15 @@
}
}
}
+
+@reflectiveTest
+class NewAnalysisOptionsFileNotificationTest
+ extends AnalysisOptionsFileNotificationTest {
+ String get optionsFilePath => '$projectPath/analysis_options.yaml';
+}
+
+@reflectiveTest
+class OldAnalysisOptionsFileNotificationTest
+ extends AnalysisOptionsFileNotificationTest {
+ String get optionsFilePath => '$projectPath/.analysis_options';
+}
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 8527528e..c238d59 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -471,7 +471,28 @@
});
}
- test_setAnalysisSubscriptions_fileInIgnoredFolder() async {
+ test_setAnalysisSubscriptions_fileInIgnoredFolder_newOptions() async {
+ String path = '/project/samples/sample.dart';
+ resourceProvider.newFile(path, '');
+ resourceProvider.newFile(
+ '/project/analysis_options.yaml',
+ r'''
+analyzer:
+ exclude:
+ - 'samples/**'
+''');
+ server.setAnalysisRoots('0', ['/project'], [], {});
+ server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
+ AnalysisService.NAVIGATION: new Set<String>.from([path])
+ });
+ // the file is excluded, so no navigation notification
+ await server.onAnalysisComplete;
+ expect(channel.notificationsReceived.any((notification) {
+ return notification.event == ANALYSIS_NAVIGATION;
+ }), isFalse);
+ }
+
+ test_setAnalysisSubscriptions_fileInIgnoredFolder_oldOptions() async {
String path = '/project/samples/sample.dart';
resourceProvider.newFile(path, '');
resourceProvider.newFile(
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 9f00603..db85fcd 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -35,352 +35,12 @@
main() {
initializeTestEnvironment();
defineReflectiveTests(AbstractContextManagerTest);
+ defineReflectiveTests(ContextManagerWithNewOptionsTest);
+ defineReflectiveTests(ContextManagerWithOldOptionsTest);
}
@reflectiveTest
-class AbstractContextManagerTest {
- /**
- * The name of the 'bin' directory.
- */
- static const String BIN_NAME = 'bin';
-
- /**
- * The name of the 'example' directory.
- */
- static const String EXAMPLE_NAME = 'example';
-
- /**
- * The name of the 'lib' directory.
- */
- static const String LIB_NAME = 'lib';
-
- /**
- * The name of the 'src' directory.
- */
- static const String SRC_NAME = 'src';
-
- /**
- * The name of the 'test' directory.
- */
- static const String TEST_NAME = 'test';
-
- ContextManagerImpl manager;
-
- TestContextManagerCallbacks callbacks;
-
- MemoryResourceProvider resourceProvider;
-
- MockPackageMapProvider packageMapProvider;
-
- UriResolver packageResolver = null;
-
- UriResolver embeddedUriResolver = null;
-
- String projPath = '/my/proj';
-
- AnalysisError missing_required_param = new AnalysisError(
- new TestSource(), 0, 1, HintCode.MISSING_REQUIRED_PARAM, [
- ['x']
- ]);
-
- AnalysisError missing_return =
- new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
- ['x']
- ]);
-
- AnalysisError invalid_assignment_error =
- new AnalysisError(new TestSource(), 0, 1, HintCode.INVALID_ASSIGNMENT, [
- ['x'],
- ['y']
- ]);
-
- AnalysisError unused_local_variable = new AnalysisError(
- new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
- ['x']
- ]);
-
- List<Glob> get analysisFilesGlobs {
- List<String> patterns = <String>[
- '**/*.${AnalysisEngine.SUFFIX_DART}',
- '**/*.${AnalysisEngine.SUFFIX_HTML}',
- '**/*.${AnalysisEngine.SUFFIX_HTM}',
- '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}'
- ];
- return patterns
- .map((pattern) => new Glob(JavaFile.pathContext.separator, pattern))
- .toList();
- }
-
- List<ErrorProcessor> get errorProcessors => callbacks.currentContext
- .getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
-
- List<Linter> get lints => getLints(callbacks.currentContext);
-
- AnalysisOptions get options => callbacks.currentContext.analysisOptions;
-
- Map<String, List<Folder>> get _currentPackageMap => _packageMap(projPath);
-
- void deleteFile(List<String> pathComponents) {
- String filePath = posix.joinAll(pathComponents);
- resourceProvider.deleteFile(filePath);
- }
-
- ErrorProcessor getProcessor(AnalysisError error) =>
- ErrorProcessor.getProcessor(callbacks.currentContext, error);
-
- String newFile(List<String> pathComponents, [String content = '']) {
- String filePath = posix.joinAll(pathComponents);
- resourceProvider.newFile(filePath, content);
- return filePath;
- }
-
- String newFolder(List<String> pathComponents) {
- String folderPath = posix.joinAll(pathComponents);
- resourceProvider.newFolder(folderPath);
- return folderPath;
- }
-
- void processRequiredPlugins() {
- List<Plugin> plugins = <Plugin>[];
- plugins.addAll(AnalysisEngine.instance.requiredPlugins);
- plugins.add(AnalysisEngine.instance.commandLinePlugin);
- plugins.add(AnalysisEngine.instance.optionsPlugin);
- plugins.add(linterPlugin);
- ExtensionManager manager = new ExtensionManager();
- manager.processPlugins(plugins);
- }
-
- EmbedderUriResolver provideEmbeddedUriResolver(Folder folder) =>
- embeddedUriResolver;
-
- UriResolver providePackageResolver(Folder folder) => packageResolver;
-
- void setUp() {
- processRequiredPlugins();
- resourceProvider = new MemoryResourceProvider();
- packageMapProvider = new MockPackageMapProvider();
- DartSdkManager sdkManager = new DartSdkManager((_) {
- return new MockSdk();
- });
- manager = new ContextManagerImpl(
- resourceProvider,
- sdkManager,
- providePackageResolver,
- provideEmbeddedUriResolver,
- packageMapProvider,
- analysisFilesGlobs,
- InstrumentationService.NULL_SERVICE,
- new AnalysisOptionsImpl());
- callbacks = new TestContextManagerCallbacks(resourceProvider);
- manager.callbacks = callbacks;
- resourceProvider.newFolder(projPath);
- }
-
- test_analysis_options_file_delete() async {
- // Setup .analysis_options
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-embedded_libs:
- "dart:foobar": "../sdk_ext/entry.dart"
-analyzer:
- language:
- enableGenericMethods: true
- errors:
- unused_local_variable: false
-linter:
- rules:
- - camel_case_types
-''');
-
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- await pumpEventQueue();
-
- // Verify options were set.
- expect(errorProcessors, hasLength(1));
- expect(lints, hasLength(1));
- expect(options.enableGenericMethods, isTrue);
-
- // Remove options.
- deleteFile([projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE]);
- await pumpEventQueue();
-
- // Verify defaults restored.
- expect(errorProcessors, isEmpty);
- expect(lints, isEmpty);
- expect(options.enableGenericMethods, isFalse);
- }
-
- test_analysis_options_file_delete_with_embedder() async {
- // Setup _embedder.yaml.
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile(
- [libPath, '_embedder.yaml'],
- r'''
-analyzer:
- strong-mode: true
- errors:
- missing_return: false
-linter:
- rules:
- - avoid_as
-''');
-
- // Setup .packages file
- newFile(
- [projPath, '.packages'],
- r'''
-test_pack:lib/''');
-
- // Setup .analysis_options
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- language:
- enableGenericMethods: true
- errors:
- unused_local_variable: false
-linter:
- rules:
- - camel_case_types
-''');
-
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- await pumpEventQueue();
-
- // Verify options were set.
- expect(options.enableGenericMethods, isTrue);
- expect(options.strongMode, isTrue);
- expect(errorProcessors, hasLength(2));
- expect(lints, hasLength(2));
-
- // Remove options.
- deleteFile([projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE]);
- await pumpEventQueue();
-
- // Verify defaults restored.
- expect(options.enableGenericMethods, isFalse);
- expect(lints, hasLength(1));
- expect(lints.first, new isInstanceOf<AvoidAs>());
- expect(errorProcessors, hasLength(1));
- expect(getProcessor(missing_return).severity, isNull);
- }
-
- test_analysis_options_parse_failure() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile([libPath, 'main.dart']);
- String sdkExtPath = newFolder([projPath, 'sdk_ext']);
- newFile([sdkExtPath, 'entry.dart']);
- String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
- newFile([sdkExtSrcPath, 'part.dart']);
- // Setup analysis options file with ignore list.
- newFile(
- [projPath, '.analysis_options'],
- r'''
-;
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
- // No error means success.
- }
-
- test_configed_options() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile([projPath, 'test', 'test.dart']);
- newFile(
- [projPath, 'pubspec.yaml'],
- r'''
-dependencies:
- test_pack: any
-analyzer:
- configuration: test_pack/config
-''');
-
- // Setup .packages file
- newFile(
- [projPath, '.packages'],
- r'''
-test_pack:lib/''');
-
- // Setup config.yaml.
- newFile(
- [libPath, 'config', 'config.yaml'],
- r'''
-analyzer:
- strong-mode: true
- language:
- enableSuperMixins: true
- errors:
- missing_return: false
-linter:
- rules:
- - avoid_as
-''');
-
- // Setup .analysis_options
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - 'test/**'
- language:
- enableGenericMethods: true
- enableAsync: false
- errors:
- unused_local_variable: false
-linter:
- rules:
- - camel_case_types
-''');
-
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- await pumpEventQueue();
-
- // Confirm that one context was created.
- var contexts =
- manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
- expect(contexts, isNotNull);
- expect(contexts, hasLength(1));
-
- var context = contexts.first;
-
- // Verify options.
- // * from `config.yaml`:
- expect(context.analysisOptions.strongMode, isTrue);
- expect(context.analysisOptions.enableSuperMixins, isTrue);
- expect(context.analysisOptions.enableAsync, isFalse);
- // * from `.analysis_options`:
- expect(context.analysisOptions.enableGenericMethods, isTrue);
-
- // * verify tests are excluded
- expect(callbacks.currentContextFilePaths[projPath].keys,
- unorderedEquals(['/my/proj/.analysis_options']));
-
- // Verify filter setup.
- expect(errorProcessors, hasLength(2));
-
- // * (config.)
- expect(getProcessor(missing_return).severity, isNull);
-
- // * (options.)
- expect(getProcessor(unused_local_variable).severity, isNull);
-
- // Verify lints.
- var lintNames = lints.map((lint) => lint.name);
- expect(
- lintNames,
- unorderedEquals(
- ['avoid_as' /* config */, 'camel_case_types' /* options */]));
- }
-
+class AbstractContextManagerTest extends ContextManagerTest {
void test_contextsInAnalysisRoot_nestedContext() {
String subProjPath = posix.join(projPath, 'subproj');
Folder subProjFolder = resourceProvider.newFolder(subProjPath);
@@ -408,7 +68,7 @@
test_embedder_added() async {
// Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
newFile([libPath, 'main.dart']);
newFile([libPath, 'nope.dart']);
String embedderPath = newFolder([projPath, 'embedder']);
@@ -459,227 +119,9 @@
expect(contexts.first.sourceFactory.forUri('dart:typed_data'), isNotNull);
}
- test_embedder_and_configed_options() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- String sdkExtPath = newFolder([projPath, 'sdk_ext']);
- newFile([projPath, 'test', 'test.dart']);
- newFile([sdkExtPath, 'entry.dart']);
-
- // Setup pubspec with configuration.
- newFile(
- [projPath, 'pubspec.yaml'],
- r'''
-dependencies:
- test_pack: any
-analyzer:
- configuration: test_pack/config
-''');
-
- // Setup _embedder.yaml.
- newFile(
- [libPath, '_embedder.yaml'],
- r'''
-embedded_libs:
- "dart:foobar": "../sdk_ext/entry.dart"
-analyzer:
- strong-mode: true
- language:
- enableSuperMixins: true
- errors:
- missing_return: false
-linter:
- rules:
- - avoid_as
-''');
-
- // Setup .packages file
- newFile(
- [projPath, '.packages'],
- r'''
-test_pack:lib/''');
-
- // Setup .analysis_options
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - 'test/**'
- language:
- enableGenericMethods: true
- enableAsync: false
- errors:
- unused_local_variable: false
-linter:
- rules:
- - camel_case_types
-''');
-
- // Setup config.yaml.
- newFile(
- [libPath, 'config', 'config.yaml'],
- r'''
-analyzer:
- errors:
- missing_required_param: error
-linter:
- rules:
- - always_specify_types
-''');
-
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- await pumpEventQueue();
-
- // Confirm that one context was created.
- var contexts =
- manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
- expect(contexts, isNotNull);
- expect(contexts, hasLength(1));
- var context = contexts[0];
-
- // Verify options.
- // * from `_embedder.yaml`:
- expect(context.analysisOptions.strongMode, isTrue);
- expect(context.analysisOptions.enableSuperMixins, isTrue);
- expect(context.analysisOptions.enableAsync, isFalse);
- // * from `.analysis_options`:
- expect(context.analysisOptions.enableGenericMethods, isTrue);
-
- // * verify tests are excluded
- expect(
- callbacks.currentContextFilePaths[projPath].keys,
- unorderedEquals(
- ['/my/proj/sdk_ext/entry.dart', '/my/proj/.analysis_options']));
-
- // Verify filter setup.
- expect(errorProcessors, hasLength(3));
-
- // * (embedder.)
- expect(getProcessor(missing_return).severity, isNull);
-
- // * (config.)
- expect(getProcessor(missing_required_param).severity, ErrorSeverity.ERROR);
-
- // * (options.)
- expect(getProcessor(unused_local_variable).severity, isNull);
-
- // Verify lints.
- var lintNames = lints.map((lint) => lint.name);
-
- expect(
- lintNames,
- unorderedEquals([
- 'avoid_as' /* embedder */,
- 'always_specify_types' /* config*/,
- 'camel_case_types' /* options */
- ]));
-
- // Sanity check embedder libs.
- var source = context.sourceFactory.forUri('dart:foobar');
- expect(source, isNotNull);
- expect(source.fullName,
- '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
- }
-
- test_embedder_options() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- String sdkExtPath = newFolder([projPath, 'sdk_ext']);
- newFile([projPath, 'test', 'test.dart']);
- newFile([sdkExtPath, 'entry.dart']);
- // Setup _embedder.yaml.
- newFile(
- [libPath, '_embedder.yaml'],
- r'''
-embedded_libs:
- "dart:foobar": "../sdk_ext/entry.dart"
-analyzer:
- strong-mode: true
- language:
- enableSuperMixins: true
- errors:
- missing_return: false
-linter:
- rules:
- - avoid_as
-''');
- // Setup .packages file
- newFile(
- [projPath, '.packages'],
- r'''
-test_pack:lib/''');
-
- // Setup .analysis_options
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - 'test/**'
- language:
- enableGenericMethods: true
- enableAsync: false
- errors:
- unused_local_variable: false
-linter:
- rules:
- - camel_case_types
-''');
-
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- await pumpEventQueue();
-
- // Confirm that one context was created.
- var contexts =
- manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
- expect(contexts, isNotNull);
- expect(contexts, hasLength(1));
- var context = contexts[0];
-
- // Verify options.
- // * from `_embedder.yaml`:
- expect(context.analysisOptions.strongMode, isTrue);
- expect(context.analysisOptions.enableSuperMixins, isTrue);
- expect(context.analysisOptions.enableAsync, isFalse);
- // * from `.analysis_options`:
- expect(context.analysisOptions.enableGenericMethods, isTrue);
-
- // * verify tests are excluded
- expect(
- callbacks.currentContextFilePaths[projPath].keys,
- unorderedEquals(
- ['/my/proj/sdk_ext/entry.dart', '/my/proj/.analysis_options']));
-
- // Verify filter setup.
- expect(errorProcessors, hasLength(2));
-
- // * (embedder.)
- expect(getProcessor(missing_return).severity, isNull);
-
- // * (options.)
- expect(getProcessor(unused_local_variable).severity, isNull);
-
- // Verify lints.
- var lintNames = lints.map((lint) => lint.name);
-
- expect(
- lintNames,
- unorderedEquals(
- ['avoid_as' /* embedder */, 'camel_case_types' /* options */]));
-
- // Sanity check embedder libs.
- var source = context.sourceFactory.forUri('dart:foobar');
- expect(source, isNotNull);
- expect(source.fullName,
- '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
- }
-
test_embedder_packagespec() async {
// Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
newFile([libPath, 'main.dart']);
newFile([libPath, 'nope.dart']);
String sdkExtPath = newFolder([projPath, 'sdk_ext']);
@@ -721,77 +163,6 @@
expect(context.sourceFactory.forUri('dart:typed_data'), isNotNull);
}
- test_error_filter_analysis_option() async {
- // Create files.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- errors:
- unused_local_variable: ignore
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
- // Verify filter setup.
- expect(errorProcessors, hasLength(1));
- expect(getProcessor(unused_local_variable).severity, isNull);
- }
-
- test_error_filter_analysis_option_multiple_filters() async {
- // Create files.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- errors:
- invalid_assignment: ignore
- unused_local_variable: error
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
- // Verify filter setup.
- expect(errorProcessors, hasLength(2));
-
- expect(getProcessor(invalid_assignment_error).severity, isNull);
- expect(getProcessor(unused_local_variable).severity, ErrorSeverity.ERROR);
- }
-
- test_error_filter_analysis_option_synonyms() async {
- // Create files.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- errors:
- unused_local_variable: ignore
- ambiguous_import: false
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
- // Verify filter setup.
- expect(errorProcessors, isNotNull);
- expect(errorProcessors, hasLength(2));
- }
-
- test_error_filter_analysis_option_unpsecified() async {
- // Create files.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
-# errors:
-# unused_local_variable: ignore
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
- // Verify filter setup.
- expect(errorProcessors, isEmpty);
- }
-
test_ignoreFilesInPackagesFolder() {
// create a context with a pubspec.yaml file
String pubspecPath = posix.join(projPath, 'pubspec.yaml');
@@ -860,7 +231,7 @@
rootInfo, ['sdk_ext/**', 'lib/ignoreme.dart']);
// Start creating files.
newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
- String libPath = newFolder([projPath, LIB_NAME]);
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
newFile([libPath, 'main.dart']);
newFile([libPath, 'ignoreme.dart']);
String sdkExtPath = newFolder([projPath, 'sdk_ext']);
@@ -878,145 +249,6 @@
expect(files[0], equals('/my/proj/lib/main.dart'));
}
- test_path_filter_analysis_option() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile([libPath, 'main.dart']);
- newFile([libPath, 'nope.dart']);
- String sdkExtPath = newFolder([projPath, 'sdk_ext']);
- newFile([sdkExtPath, 'entry.dart']);
- String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
- newFile([sdkExtSrcPath, 'part.dart']);
- // Setup analysis options file with ignore list.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - lib/nope.dart
- - 'sdk_ext/**'
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- // Verify that analysis options was parsed and the ignore patterns applied.
- Map<String, int> fileTimestamps =
- callbacks.currentContextFilePaths[projPath];
- expect(fileTimestamps, isNotEmpty);
- List<String> files = fileTimestamps.keys.toList();
- expect(
- files,
- unorderedEquals(
- ['/my/proj/lib/main.dart', '/my/proj/.analysis_options']));
- }
-
- test_path_filter_child_contexts_option() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile([libPath, 'main.dart']);
- newFile(
- [libPath, 'pubspec.yaml'],
- r'''
-name: foobar
-''');
- String otherLibPath = newFolder([projPath, 'other_lib']);
- newFile([otherLibPath, 'entry.dart']);
- newFile(
- [otherLibPath, 'pubspec.yaml'],
- r'''
-name: other_lib
-''');
- // Setup analysis options file with ignore list that ignores the 'other_lib'
- // directory by name.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - 'other_lib'
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- // Verify that the context in other_lib wasn't created and that the
- // context in lib was created.
- var contexts =
- manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
- expect(contexts.length, 2);
- expect(contexts[0].name, equals('/my/proj'));
- expect(contexts[1].name, equals('/my/proj/lib'));
- }
-
- test_path_filter_recursive_wildcard_child_contexts_option() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile([libPath, 'main.dart']);
- newFile(
- [libPath, 'pubspec.yaml'],
- r'''
- name: foobar
- ''');
- String otherLibPath = newFolder([projPath, 'other_lib']);
- newFile([otherLibPath, 'entry.dart']);
- newFile(
- [otherLibPath, 'pubspec.yaml'],
- r'''
- name: other_lib
- ''');
- // Setup analysis options file with ignore list that ignores 'other_lib'
- // and all descendants.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - 'other_lib/**'
- ''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- // Verify that the context in other_lib wasn't created and that the
- // context in lib was created.
- var contexts =
- manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
- expect(contexts.length, 2);
- expect(contexts[0].name, equals('/my/proj'));
- expect(contexts[1].name, equals('/my/proj/lib'));
- }
-
- test_path_filter_wildcard_child_contexts_option() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile([libPath, 'main.dart']);
- newFile(
- [libPath, 'pubspec.yaml'],
- r'''
-name: foobar
-''');
- String otherLibPath = newFolder([projPath, 'other_lib']);
- newFile([otherLibPath, 'entry.dart']);
- newFile(
- [otherLibPath, 'pubspec.yaml'],
- r'''
-name: other_lib
-''');
- // Setup analysis options file with ignore list that ignores 'other_lib'
- // and all immediate children.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - 'other_lib/*'
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- // Verify that the context in other_lib wasn't created and that the
- // context in lib was created.
- var contexts =
- manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
- expect(contexts.length, 2);
- expect(contexts[0].name, equals('/my/proj'));
- expect(contexts[1].name, equals('/my/proj/lib'));
- }
-
test_refresh_folder_with_packagespec() {
// create a context with a .packages file
String packagespecFile = posix.join(projPath, '.packages');
@@ -1129,7 +361,7 @@
test_sdk_ext_packagespec() async {
// Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
newFile([libPath, 'main.dart']);
newFile([libPath, 'nope.dart']);
String sdkExtPath = newFolder([projPath, 'sdk_ext']);
@@ -1199,8 +431,8 @@
}
void test_setRoots_addFolderWithNestedPackageSpec() {
- String examplePath = newFolder([projPath, EXAMPLE_NAME]);
- String libPath = newFolder([projPath, LIB_NAME]);
+ String examplePath = newFolder([projPath, ContextManagerTest.EXAMPLE_NAME]);
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
newFile([projPath, ContextManagerImpl.PACKAGE_SPEC_NAME]);
newFile([libPath, 'main.dart']);
@@ -1228,8 +460,8 @@
}
void test_setRoots_addFolderWithNestedPubspec() {
- String examplePath = newFolder([projPath, EXAMPLE_NAME]);
- String libPath = newFolder([projPath, LIB_NAME]);
+ String examplePath = newFolder([projPath, ContextManagerTest.EXAMPLE_NAME]);
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
newFile([libPath, 'main.dart']);
@@ -1269,7 +501,7 @@
String packagespecPath = posix.join(projPath, '.packages');
resourceProvider.newFile(packagespecPath,
'unittest:file:///home/somebody/.pub/cache/unittest-0.9.9/lib/');
- String libPath = newFolder([projPath, LIB_NAME]);
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
File mainFile =
resourceProvider.newFile(posix.join(libPath, 'main.dart'), '');
Source source = mainFile.createSource();
@@ -1324,10 +556,10 @@
}
void test_setRoots_addFolderWithPubspecAndLib() {
- String binPath = newFolder([projPath, BIN_NAME]);
- String libPath = newFolder([projPath, LIB_NAME]);
- String srcPath = newFolder([libPath, SRC_NAME]);
- String testPath = newFolder([projPath, TEST_NAME]);
+ String binPath = newFolder([projPath, ContextManagerTest.BIN_NAME]);
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ String srcPath = newFolder([libPath, ContextManagerTest.SRC_NAME]);
+ String testPath = newFolder([projPath, ContextManagerTest.TEST_NAME]);
newFile([projPath, ContextManagerImpl.PUBSPEC_NAME]);
String appPath = newFile([binPath, 'app.dart']);
@@ -1584,77 +816,6 @@
callbacks.assertContextFiles(project, [fileA, fileB]);
}
- void test_setRoots_nested_excludedByOuter() {
- String project = '/project';
- String projectPubspec = '$project/pubspec.yaml';
- String example = '$project/example';
- String examplePubspec = '$example/pubspec.yaml';
- // create files
- resourceProvider.newFile(projectPubspec, 'name: project');
- resourceProvider.newFile(examplePubspec, 'name: example');
- newFile(
- [project, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - 'example'
-''');
- manager
- .setRoots(<String>[project, example], <String>[], <String, String>{});
- // verify
- {
- ContextInfo rootInfo = manager.rootInfo;
- expect(rootInfo.children, hasLength(1));
- {
- ContextInfo projectInfo = rootInfo.children[0];
- expect(projectInfo.folder.path, project);
- expect(projectInfo.children, hasLength(1));
- {
- ContextInfo exampleInfo = projectInfo.children[0];
- expect(exampleInfo.folder.path, example);
- expect(exampleInfo.children, isEmpty);
- }
- }
- }
- expect(callbacks.currentContextPaths, hasLength(2));
- expect(callbacks.currentContextPaths, unorderedEquals([project, example]));
- }
-
- void test_setRoots_nested_excludedByOuter_deep() {
- String a = '/a';
- String c = '$a/b/c';
- String aPubspec = '$a/pubspec.yaml';
- String cPubspec = '$c/pubspec.yaml';
- // create files
- resourceProvider.newFile(aPubspec, 'name: aaa');
- resourceProvider.newFile(cPubspec, 'name: ccc');
- newFile(
- [a, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- exclude:
- - 'b**'
-''');
- manager.setRoots(<String>[a, c], <String>[], <String, String>{});
- // verify
- {
- ContextInfo rootInfo = manager.rootInfo;
- expect(rootInfo.children, hasLength(1));
- {
- ContextInfo aInfo = rootInfo.children[0];
- expect(aInfo.folder.path, a);
- expect(aInfo.children, hasLength(1));
- {
- ContextInfo cInfo = aInfo.children[0];
- expect(cInfo.folder.path, c);
- expect(cInfo.children, isEmpty);
- }
- }
- }
- expect(callbacks.currentContextPaths, hasLength(2));
- expect(callbacks.currentContextPaths, unorderedEquals([a, c]));
- }
-
void test_setRoots_nested_includedByOuter_innerFirst() {
String project = '/project';
String projectPubspec = '$project/pubspec.yaml';
@@ -1953,25 +1114,6 @@
callbacks.assertContextFiles(project, [fileA]);
}
- test_strong_mode_analysis_option() async {
- // Create files.
- newFile(
- [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
- r'''
-analyzer:
- strong-mode: true
-''');
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile([libPath, 'main.dart']);
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- // Verify that analysis options was parsed and strong-mode set.
- Map<String, int> fileTimestamps =
- callbacks.currentContextFilePaths[projPath];
- expect(fileTimestamps, isNotEmpty);
- expect(callbacks.currentContext.analysisOptions.strongMode, true);
- }
-
test_watch_addDummyLink() {
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// empty folder initially
@@ -2560,6 +1702,902 @@
}
}
+abstract class ContextManagerTest {
+ /**
+ * The name of the 'bin' directory.
+ */
+ static const String BIN_NAME = 'bin';
+
+ /**
+ * The name of the 'example' directory.
+ */
+ static const String EXAMPLE_NAME = 'example';
+
+ /**
+ * The name of the 'lib' directory.
+ */
+ static const String LIB_NAME = 'lib';
+
+ /**
+ * The name of the 'src' directory.
+ */
+ static const String SRC_NAME = 'src';
+
+ /**
+ * The name of the 'test' directory.
+ */
+ static const String TEST_NAME = 'test';
+
+ ContextManagerImpl manager;
+
+ TestContextManagerCallbacks callbacks;
+
+ MemoryResourceProvider resourceProvider;
+
+ MockPackageMapProvider packageMapProvider;
+
+ UriResolver packageResolver = null;
+
+ UriResolver embeddedUriResolver = null;
+
+ String projPath = '/my/proj';
+
+ AnalysisError missing_required_param = new AnalysisError(
+ new TestSource(), 0, 1, HintCode.MISSING_REQUIRED_PARAM, [
+ ['x']
+ ]);
+
+ AnalysisError missing_return =
+ new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
+ ['x']
+ ]);
+
+ AnalysisError invalid_assignment_error =
+ new AnalysisError(new TestSource(), 0, 1, HintCode.INVALID_ASSIGNMENT, [
+ ['x'],
+ ['y']
+ ]);
+
+ AnalysisError unused_local_variable = new AnalysisError(
+ new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
+ ['x']
+ ]);
+
+ List<Glob> get analysisFilesGlobs {
+ List<String> patterns = <String>[
+ '**/*.${AnalysisEngine.SUFFIX_DART}',
+ '**/*.${AnalysisEngine.SUFFIX_HTML}',
+ '**/*.${AnalysisEngine.SUFFIX_HTM}',
+ '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}',
+ '**/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}'
+ ];
+ return patterns
+ .map((pattern) => new Glob(JavaFile.pathContext.separator, pattern))
+ .toList();
+ }
+
+ List<ErrorProcessor> get errorProcessors => callbacks.currentContext
+ .getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
+
+ List<Linter> get lints => getLints(callbacks.currentContext);
+
+ AnalysisOptions get options => callbacks.currentContext.analysisOptions;
+
+ Map<String, List<Folder>> get _currentPackageMap => _packageMap(projPath);
+
+ void deleteFile(List<String> pathComponents) {
+ String filePath = posix.joinAll(pathComponents);
+ resourceProvider.deleteFile(filePath);
+ }
+
+ ErrorProcessor getProcessor(AnalysisError error) =>
+ ErrorProcessor.getProcessor(callbacks.currentContext, error);
+
+ String newFile(List<String> pathComponents, [String content = '']) {
+ String filePath = posix.joinAll(pathComponents);
+ resourceProvider.newFile(filePath, content);
+ return filePath;
+ }
+
+ String newFolder(List<String> pathComponents) {
+ String folderPath = posix.joinAll(pathComponents);
+ resourceProvider.newFolder(folderPath);
+ return folderPath;
+ }
+
+ void processRequiredPlugins() {
+ List<Plugin> plugins = <Plugin>[];
+ plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+ plugins.add(AnalysisEngine.instance.commandLinePlugin);
+ plugins.add(AnalysisEngine.instance.optionsPlugin);
+ plugins.add(linterPlugin);
+ ExtensionManager manager = new ExtensionManager();
+ manager.processPlugins(plugins);
+ }
+
+ EmbedderUriResolver provideEmbeddedUriResolver(Folder folder) =>
+ embeddedUriResolver;
+
+ UriResolver providePackageResolver(Folder folder) => packageResolver;
+
+ void setUp() {
+ processRequiredPlugins();
+ resourceProvider = new MemoryResourceProvider();
+ packageMapProvider = new MockPackageMapProvider();
+ DartSdkManager sdkManager = new DartSdkManager((_) {
+ return new MockSdk();
+ });
+ manager = new ContextManagerImpl(
+ resourceProvider,
+ sdkManager,
+ providePackageResolver,
+ provideEmbeddedUriResolver,
+ packageMapProvider,
+ analysisFilesGlobs,
+ InstrumentationService.NULL_SERVICE,
+ new AnalysisOptionsImpl());
+ callbacks = new TestContextManagerCallbacks(resourceProvider);
+ manager.callbacks = callbacks;
+ resourceProvider.newFolder(projPath);
+ }
+
+ /**
+ * Verify that package URI's for source files in [path] will be resolved
+ * using a package root matching [expectation].
+ */
+ void _checkPackageRoot(String path, expectation) {
+ // TODO(brianwilkerson) Figure out how to test this. Possibly by comparing
+ // the contents of the package map (although that approach doesn't work at
+ // the moment).
+// FolderDisposition disposition = callbacks.currentContextDispositions[path];
+// expect(disposition.packageRoot, expectation);
+ // TODO(paulberry): we should also verify that the package map itself is
+ // correct. See dartbug.com/23909.
+ }
+
+ Map<String, List<Folder>> _packageMap(String contextPath) {
+ Folder folder = resourceProvider.getFolder(contextPath);
+ return manager.folderMap[folder]?.sourceFactory?.packageMap;
+ }
+}
+
+@reflectiveTest
+class ContextManagerWithNewOptionsTest extends ContextManagerWithOptionsTest {
+ String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
+}
+
+@reflectiveTest
+class ContextManagerWithOldOptionsTest extends ContextManagerWithOptionsTest {
+ String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+}
+
+abstract class ContextManagerWithOptionsTest extends ContextManagerTest {
+ String get optionsFileName;
+
+ test_analysis_options_file_delete() async {
+ // Setup analysis options
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+embedded_libs:
+ "dart:foobar": "../sdk_ext/entry.dart"
+analyzer:
+ language:
+ enableGenericMethods: true
+ errors:
+ unused_local_variable: false
+linter:
+ rules:
+ - camel_case_types
+''');
+
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ await pumpEventQueue();
+
+ // Verify options were set.
+ expect(errorProcessors, hasLength(1));
+ expect(lints, hasLength(1));
+ expect(options.enableGenericMethods, isTrue);
+
+ // Remove options.
+ deleteFile([projPath, optionsFileName]);
+ await pumpEventQueue();
+
+ // Verify defaults restored.
+ expect(errorProcessors, isEmpty);
+ expect(lints, isEmpty);
+ expect(options.enableGenericMethods, isFalse);
+ }
+
+ test_analysis_options_file_delete_with_embedder() async {
+ // Setup _embedder.yaml.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ newFile(
+ [libPath, '_embedder.yaml'],
+ r'''
+analyzer:
+ strong-mode: true
+ errors:
+ missing_return: false
+linter:
+ rules:
+ - avoid_as
+''');
+
+ // Setup .packages file
+ newFile(
+ [projPath, '.packages'],
+ r'''
+test_pack:lib/''');
+
+ // Setup analysis options
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ language:
+ enableGenericMethods: true
+ errors:
+ unused_local_variable: false
+linter:
+ rules:
+ - camel_case_types
+''');
+
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ await pumpEventQueue();
+
+ // Verify options were set.
+ expect(options.enableGenericMethods, isTrue);
+ expect(options.strongMode, isTrue);
+ expect(errorProcessors, hasLength(2));
+ expect(lints, hasLength(2));
+
+ // Remove options.
+ deleteFile([projPath, optionsFileName]);
+ await pumpEventQueue();
+
+ // Verify defaults restored.
+ expect(options.enableGenericMethods, isFalse);
+ expect(lints, hasLength(1));
+ expect(lints.first, new isInstanceOf<AvoidAs>());
+ expect(errorProcessors, hasLength(1));
+ expect(getProcessor(missing_return).severity, isNull);
+ }
+
+ test_analysis_options_parse_failure() async {
+ // Create files.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+ newFile([sdkExtPath, 'entry.dart']);
+ String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
+ newFile([sdkExtSrcPath, 'part.dart']);
+ // Setup analysis options file with ignore list.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+;
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+ // No error means success.
+ }
+
+ test_configed_options() async {
+ // Create files.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ newFile([projPath, 'test', 'test.dart']);
+ newFile(
+ [projPath, 'pubspec.yaml'],
+ r'''
+dependencies:
+ test_pack: any
+analyzer:
+ configuration: test_pack/config
+''');
+
+ // Setup .packages file
+ newFile(
+ [projPath, '.packages'],
+ r'''
+test_pack:lib/''');
+
+ // Setup config.yaml.
+ newFile(
+ [libPath, 'config', 'config.yaml'],
+ r'''
+analyzer:
+ strong-mode: true
+ language:
+ enableSuperMixins: true
+ errors:
+ missing_return: false
+linter:
+ rules:
+ - avoid_as
+''');
+
+ // Setup analysis options
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - 'test/**'
+ language:
+ enableGenericMethods: true
+ enableAsync: false
+ errors:
+ unused_local_variable: false
+linter:
+ rules:
+ - camel_case_types
+''');
+
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ await pumpEventQueue();
+
+ // Confirm that one context was created.
+ var contexts =
+ manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+ expect(contexts, isNotNull);
+ expect(contexts, hasLength(1));
+
+ var context = contexts.first;
+
+ // Verify options.
+ // * from `config.yaml`:
+ expect(context.analysisOptions.strongMode, isTrue);
+ expect(context.analysisOptions.enableSuperMixins, isTrue);
+ expect(context.analysisOptions.enableAsync, isFalse);
+ // * from analysis options:
+ expect(context.analysisOptions.enableGenericMethods, isTrue);
+
+ // * verify tests are excluded
+ expect(callbacks.currentContextFilePaths[projPath].keys,
+ unorderedEquals(['/my/proj/$optionsFileName']));
+
+ // Verify filter setup.
+ expect(errorProcessors, hasLength(2));
+
+ // * (config.)
+ expect(getProcessor(missing_return).severity, isNull);
+
+ // * (options.)
+ expect(getProcessor(unused_local_variable).severity, isNull);
+
+ // Verify lints.
+ var lintNames = lints.map((lint) => lint.name);
+ expect(
+ lintNames,
+ unorderedEquals(
+ ['avoid_as' /* config */, 'camel_case_types' /* options */]));
+ }
+
+ test_embedder_and_configed_options() async {
+ // Create files.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+ newFile([projPath, 'test', 'test.dart']);
+ newFile([sdkExtPath, 'entry.dart']);
+
+ // Setup pubspec with configuration.
+ newFile(
+ [projPath, 'pubspec.yaml'],
+ r'''
+dependencies:
+ test_pack: any
+analyzer:
+ configuration: test_pack/config
+''');
+
+ // Setup _embedder.yaml.
+ newFile(
+ [libPath, '_embedder.yaml'],
+ r'''
+embedded_libs:
+ "dart:foobar": "../sdk_ext/entry.dart"
+analyzer:
+ strong-mode: true
+ language:
+ enableSuperMixins: true
+ errors:
+ missing_return: false
+linter:
+ rules:
+ - avoid_as
+''');
+
+ // Setup .packages file
+ newFile(
+ [projPath, '.packages'],
+ r'''
+test_pack:lib/''');
+
+ // Setup analysis options
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - 'test/**'
+ language:
+ enableGenericMethods: true
+ enableAsync: false
+ errors:
+ unused_local_variable: false
+linter:
+ rules:
+ - camel_case_types
+''');
+
+ // Setup config.yaml.
+ newFile(
+ [libPath, 'config', 'config.yaml'],
+ r'''
+analyzer:
+ errors:
+ missing_required_param: error
+linter:
+ rules:
+ - always_specify_types
+''');
+
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ await pumpEventQueue();
+
+ // Confirm that one context was created.
+ var contexts =
+ manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+ expect(contexts, isNotNull);
+ expect(contexts, hasLength(1));
+ var context = contexts[0];
+
+ // Verify options.
+ // * from `_embedder.yaml`:
+ expect(context.analysisOptions.strongMode, isTrue);
+ expect(context.analysisOptions.enableSuperMixins, isTrue);
+ expect(context.analysisOptions.enableAsync, isFalse);
+ // * from analysis options:
+ expect(context.analysisOptions.enableGenericMethods, isTrue);
+
+ // * verify tests are excluded
+ expect(
+ callbacks.currentContextFilePaths[projPath].keys,
+ unorderedEquals(
+ ['/my/proj/sdk_ext/entry.dart', '/my/proj/$optionsFileName']));
+
+ // Verify filter setup.
+ expect(errorProcessors, hasLength(3));
+
+ // * (embedder.)
+ expect(getProcessor(missing_return).severity, isNull);
+
+ // * (config.)
+ expect(getProcessor(missing_required_param).severity, ErrorSeverity.ERROR);
+
+ // * (options.)
+ expect(getProcessor(unused_local_variable).severity, isNull);
+
+ // Verify lints.
+ var lintNames = lints.map((lint) => lint.name);
+
+ expect(
+ lintNames,
+ unorderedEquals([
+ 'avoid_as' /* embedder */,
+ 'always_specify_types' /* config*/,
+ 'camel_case_types' /* options */
+ ]));
+
+ // Sanity check embedder libs.
+ var source = context.sourceFactory.forUri('dart:foobar');
+ expect(source, isNotNull);
+ expect(source.fullName,
+ '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
+ }
+
+ test_embedder_options() async {
+ // Create files.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+ newFile([projPath, 'test', 'test.dart']);
+ newFile([sdkExtPath, 'entry.dart']);
+ // Setup _embedder.yaml.
+ newFile(
+ [libPath, '_embedder.yaml'],
+ r'''
+embedded_libs:
+ "dart:foobar": "../sdk_ext/entry.dart"
+analyzer:
+ strong-mode: true
+ language:
+ enableSuperMixins: true
+ errors:
+ missing_return: false
+linter:
+ rules:
+ - avoid_as
+''');
+ // Setup .packages file
+ newFile(
+ [projPath, '.packages'],
+ r'''
+test_pack:lib/''');
+
+ // Setup analysis options
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - 'test/**'
+ language:
+ enableGenericMethods: true
+ enableAsync: false
+ errors:
+ unused_local_variable: false
+linter:
+ rules:
+ - camel_case_types
+''');
+
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ await pumpEventQueue();
+
+ // Confirm that one context was created.
+ var contexts =
+ manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+ expect(contexts, isNotNull);
+ expect(contexts, hasLength(1));
+ var context = contexts[0];
+
+ // Verify options.
+ // * from `_embedder.yaml`:
+ expect(context.analysisOptions.strongMode, isTrue);
+ expect(context.analysisOptions.enableSuperMixins, isTrue);
+ expect(context.analysisOptions.enableAsync, isFalse);
+ // * from analysis options:
+ expect(context.analysisOptions.enableGenericMethods, isTrue);
+
+ // * verify tests are excluded
+ expect(
+ callbacks.currentContextFilePaths[projPath].keys,
+ unorderedEquals(
+ ['/my/proj/sdk_ext/entry.dart', '/my/proj/$optionsFileName']));
+
+ // Verify filter setup.
+ expect(errorProcessors, hasLength(2));
+
+ // * (embedder.)
+ expect(getProcessor(missing_return).severity, isNull);
+
+ // * (options.)
+ expect(getProcessor(unused_local_variable).severity, isNull);
+
+ // Verify lints.
+ var lintNames = lints.map((lint) => lint.name);
+
+ expect(
+ lintNames,
+ unorderedEquals(
+ ['avoid_as' /* embedder */, 'camel_case_types' /* options */]));
+
+ // Sanity check embedder libs.
+ var source = context.sourceFactory.forUri('dart:foobar');
+ expect(source, isNotNull);
+ expect(source.fullName,
+ '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
+ }
+
+ test_error_filter_analysis_option() async {
+ // Create files.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ errors:
+ unused_local_variable: ignore
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+ // Verify filter setup.
+ expect(errorProcessors, hasLength(1));
+ expect(getProcessor(unused_local_variable).severity, isNull);
+ }
+
+ test_error_filter_analysis_option_multiple_filters() async {
+ // Create files.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ errors:
+ invalid_assignment: ignore
+ unused_local_variable: error
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+ // Verify filter setup.
+ expect(errorProcessors, hasLength(2));
+
+ expect(getProcessor(invalid_assignment_error).severity, isNull);
+ expect(getProcessor(unused_local_variable).severity, ErrorSeverity.ERROR);
+ }
+
+ test_error_filter_analysis_option_synonyms() async {
+ // Create files.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ errors:
+ unused_local_variable: ignore
+ ambiguous_import: false
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+ // Verify filter setup.
+ expect(errorProcessors, isNotNull);
+ expect(errorProcessors, hasLength(2));
+ }
+
+ test_error_filter_analysis_option_unpsecified() async {
+ // Create files.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+# errors:
+# unused_local_variable: ignore
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+ // Verify filter setup.
+ expect(errorProcessors, isEmpty);
+ }
+
+ test_path_filter_analysis_option() async {
+ // Create files.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile([libPath, 'nope.dart']);
+ String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+ newFile([sdkExtPath, 'entry.dart']);
+ String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
+ newFile([sdkExtSrcPath, 'part.dart']);
+ // Setup analysis options file with ignore list.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - lib/nope.dart
+ - 'sdk_ext/**'
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Verify that analysis options was parsed and the ignore patterns applied.
+ Map<String, int> fileTimestamps =
+ callbacks.currentContextFilePaths[projPath];
+ expect(fileTimestamps, isNotEmpty);
+ List<String> files = fileTimestamps.keys.toList();
+ expect(
+ files,
+ unorderedEquals(
+ ['/my/proj/lib/main.dart', '/my/proj/$optionsFileName']));
+ }
+
+ test_path_filter_child_contexts_option() async {
+ // Create files.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile(
+ [libPath, 'pubspec.yaml'],
+ r'''
+name: foobar
+''');
+ String otherLibPath = newFolder([projPath, 'other_lib']);
+ newFile([otherLibPath, 'entry.dart']);
+ newFile(
+ [otherLibPath, 'pubspec.yaml'],
+ r'''
+name: other_lib
+''');
+ // Setup analysis options file with ignore list that ignores the 'other_lib'
+ // directory by name.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - 'other_lib'
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Verify that the context in other_lib wasn't created and that the
+ // context in lib was created.
+ var contexts =
+ manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+ expect(contexts.length, 2);
+ expect(contexts[0].name, equals('/my/proj'));
+ expect(contexts[1].name, equals('/my/proj/lib'));
+ }
+
+ test_path_filter_recursive_wildcard_child_contexts_option() async {
+ // Create files.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile(
+ [libPath, 'pubspec.yaml'],
+ r'''
+ name: foobar
+ ''');
+ String otherLibPath = newFolder([projPath, 'other_lib']);
+ newFile([otherLibPath, 'entry.dart']);
+ newFile(
+ [otherLibPath, 'pubspec.yaml'],
+ r'''
+ name: other_lib
+ ''');
+ // Setup analysis options file with ignore list that ignores 'other_lib'
+ // and all descendants.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - 'other_lib/**'
+ ''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Verify that the context in other_lib wasn't created and that the
+ // context in lib was created.
+ var contexts =
+ manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+ expect(contexts.length, 2);
+ expect(contexts[0].name, equals('/my/proj'));
+ expect(contexts[1].name, equals('/my/proj/lib'));
+ }
+
+ test_path_filter_wildcard_child_contexts_option() async {
+ // Create files.
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile(
+ [libPath, 'pubspec.yaml'],
+ r'''
+name: foobar
+''');
+ String otherLibPath = newFolder([projPath, 'other_lib']);
+ newFile([otherLibPath, 'entry.dart']);
+ newFile(
+ [otherLibPath, 'pubspec.yaml'],
+ r'''
+name: other_lib
+''');
+ // Setup analysis options file with ignore list that ignores 'other_lib'
+ // and all immediate children.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - 'other_lib/*'
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Verify that the context in other_lib wasn't created and that the
+ // context in lib was created.
+ var contexts =
+ manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+ expect(contexts.length, 2);
+ expect(contexts[0].name, equals('/my/proj'));
+ expect(contexts[1].name, equals('/my/proj/lib'));
+ }
+
+ void test_setRoots_nested_excludedByOuter() {
+ String project = '/project';
+ String projectPubspec = '$project/pubspec.yaml';
+ String example = '$project/example';
+ String examplePubspec = '$example/pubspec.yaml';
+ // create files
+ resourceProvider.newFile(projectPubspec, 'name: project');
+ resourceProvider.newFile(examplePubspec, 'name: example');
+ newFile(
+ [project, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - 'example'
+''');
+ manager
+ .setRoots(<String>[project, example], <String>[], <String, String>{});
+ // verify
+ {
+ ContextInfo rootInfo = manager.rootInfo;
+ expect(rootInfo.children, hasLength(1));
+ {
+ ContextInfo projectInfo = rootInfo.children[0];
+ expect(projectInfo.folder.path, project);
+ expect(projectInfo.children, hasLength(1));
+ {
+ ContextInfo exampleInfo = projectInfo.children[0];
+ expect(exampleInfo.folder.path, example);
+ expect(exampleInfo.children, isEmpty);
+ }
+ }
+ }
+ expect(callbacks.currentContextPaths, hasLength(2));
+ expect(callbacks.currentContextPaths, unorderedEquals([project, example]));
+ }
+
+ void test_setRoots_nested_excludedByOuter_deep() {
+ String a = '/a';
+ String c = '$a/b/c';
+ String aPubspec = '$a/pubspec.yaml';
+ String cPubspec = '$c/pubspec.yaml';
+ // create files
+ resourceProvider.newFile(aPubspec, 'name: aaa');
+ resourceProvider.newFile(cPubspec, 'name: ccc');
+ newFile(
+ [a, optionsFileName],
+ r'''
+analyzer:
+ exclude:
+ - 'b**'
+''');
+ manager.setRoots(<String>[a, c], <String>[], <String, String>{});
+ // verify
+ {
+ ContextInfo rootInfo = manager.rootInfo;
+ expect(rootInfo.children, hasLength(1));
+ {
+ ContextInfo aInfo = rootInfo.children[0];
+ expect(aInfo.folder.path, a);
+ expect(aInfo.children, hasLength(1));
+ {
+ ContextInfo cInfo = aInfo.children[0];
+ expect(cInfo.folder.path, c);
+ expect(cInfo.children, isEmpty);
+ }
+ }
+ }
+ expect(callbacks.currentContextPaths, hasLength(2));
+ expect(callbacks.currentContextPaths, unorderedEquals([a, c]));
+ }
+
+ test_strong_mode_analysis_option() async {
+ // Create files.
+ newFile(
+ [projPath, optionsFileName],
+ r'''
+analyzer:
+ strong-mode: true
+''');
+ String libPath = newFolder([projPath, ContextManagerTest.LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Verify that analysis options was parsed and strong-mode set.
+ Map<String, int> fileTimestamps =
+ callbacks.currentContextFilePaths[projPath];
+ expect(fileTimestamps, isNotEmpty);
+ expect(callbacks.currentContext.analysisOptions.strongMode, true);
+ }
+}
+
class TestContextManagerCallbacks extends ContextManagerCallbacks {
/**
* Source of timestamps stored in [currentContextFilePaths].
diff --git a/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart b/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
index 33ad500..4c55f82 100644
--- a/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/analysis_options_test.dart
@@ -2,9 +2,10 @@
// 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 test.integration.analysis.analysis_options;
+library test.integration.analysis.analysis_options_test;
import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
@@ -18,8 +19,35 @@
@reflectiveTest
class OptionsIntegrationTest extends AbstractAnalysisServerIntegrationTest {
- test_option_warning() async {
- String options = sourcePath('.analysis_options');
+ test_option_warning_newOptionFile() async {
+ String options = sourcePath(AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
+ writeFile(
+ options,
+ '''
+linter:
+ rules:
+ - camel_case_typo # :)
+''');
+
+ standardAnalysisSetup();
+
+ await analysisFinished;
+
+ expect(currentAnalysisErrors[options], isList);
+ List<AnalysisError> errors = currentAnalysisErrors[options];
+ expect(errors, hasLength(1));
+ AnalysisError error = errors[0];
+ expect(error.location.file, options);
+ expect(error.severity, AnalysisErrorSeverity.WARNING);
+ expect(error.type, AnalysisErrorType.STATIC_WARNING);
+ expect(error.location.offset, 23);
+ expect(error.location.length, 'camel_case_typo'.length);
+ expect(error.location.startLine, 3);
+ expect(error.location.startColumn, 7);
+ }
+
+ test_option_warning_oldOptionFile() async {
+ String options = sourcePath(AnalysisEngine.ANALYSIS_OPTIONS_FILE);
writeFile(
options,
'''
diff --git a/pkg/analysis_server/test/integration/analysis/lint_test.dart b/pkg/analysis_server/test/integration/analysis/lint_test.dart
index e75120c..a1cfeb6 100644
--- a/pkg/analysis_server/test/integration/analysis/lint_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/lint_test.dart
@@ -5,6 +5,7 @@
library test.integration.analysis.lint;
import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
@@ -29,14 +30,43 @@
await analysisFinished;
expect(currentAnalysisErrors[source], isList);
- // Should be empty without .analysis_options.
+ // Should be empty without an analysis options file.
List<AnalysisError> errors = currentAnalysisErrors[source];
expect(errors, hasLength(0));
}
- test_simple_lint() async {
+ test_simple_lint_newOptionsFile() async {
writeFile(
- sourcePath('.analysis_options'),
+ sourcePath(AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE),
+ '''
+linter:
+ rules:
+ - camel_case_types
+''');
+
+ String source = sourcePath('test.dart');
+ writeFile(
+ source,
+ '''
+class a { // lint: not CamelCase
+}''');
+
+ standardAnalysisSetup();
+
+ await analysisFinished;
+
+ expect(currentAnalysisErrors[source], isList);
+ List<AnalysisError> errors = currentAnalysisErrors[source];
+ expect(errors, hasLength(1));
+ AnalysisError error = errors[0];
+ expect(error.location.file, source);
+ expect(error.severity, AnalysisErrorSeverity.INFO);
+ expect(error.type, AnalysisErrorType.LINT);
+ }
+
+ test_simple_lint_oldOptionsFile() async {
+ writeFile(
+ sourcePath(AnalysisEngine.ANALYSIS_OPTIONS_FILE),
'''
linter:
rules:
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index 2dddbf9..04d3d0e 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -24,7 +24,7 @@
import 'package:unittest/unittest.dart';
/**
- * Answer the absolute path the the SDK relative to the currently running
+ * Answer the absolute path the SDK relative to the currently running
* script or throw an exception if it cannot be found.
*/
String get sdkPath {
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index 08c83de..0bf8a6d 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -216,9 +216,10 @@
}
CompletionSuggestion assertSuggestEnumConst(String completion,
- {bool isDeprecated: false}) {
+ {int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
CompletionSuggestion suggestion =
- assertSuggest(completion, isDeprecated: isDeprecated);
+ assertSuggest(completion, relevance: relevance, isDeprecated: isDeprecated);
+ expect(suggestion.completion, completion);
expect(suggestion.isDeprecated, isDeprecated);
expect(suggestion.element.kind, protocol.ElementKind.ENUM_CONSTANT);
return suggestion;
diff --git a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index a52a862..e51ed5f 100644
--- a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -870,6 +870,34 @@
pseudoKeywords: ['await', 'yield', 'yield*']);
}
+ test_if_after_else() async {
+ addTestSource('main() { if (true) {} else ^ }');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS,
+ relevance: DART_RELEVANCE_KEYWORD);
+ }
+
+ test_if_afterThen_nextCloseCurlyBrace0() async {
+ addTestSource('main() { if (true) {} ^ }');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS.toList()..add(Keyword.ELSE),
+ relevance: DART_RELEVANCE_KEYWORD);
+ }
+
+ test_if_afterThen_nextCloseCurlyBrace1() async {
+ addTestSource('main() { if (true) {} e^ }');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS.toList()..add(Keyword.ELSE),
+ relevance: DART_RELEVANCE_KEYWORD);
+ }
+
+ test_if_afterThen_nextStatement0() async {
+ addTestSource('main() { if (true) {} ^ print(0); }');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS.toList()..add(Keyword.ELSE),
+ relevance: DART_RELEVANCE_KEYWORD);
+ }
+
test_if_condition_isKeyword() async {
addTestSource('main() { if (v i^) {} }');
await computeSuggestions();
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index ef90952..5740cad 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -355,21 +355,19 @@
expect(replacementLength, 0);
assertSuggestTopLevelVar('a', 'A',
relevance:
- DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
assertSuggestTopLevelVar('b', 'B',
relevance:
- DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
assertSuggestTopLevelVar('c', 'C',
relevance:
- DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE + DART_RELEVANCE_INCREMENT);
assertSuggestTopLevelVar('d', 'D',
relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
assertSuggestTopLevelVar('e', 'E',
relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
}
-
-
test_AsExpression_type() async {
// SimpleIdentifier TypeName AsExpression
addTestSource('''
@@ -1929,6 +1927,8 @@
addTestSource('enum E { one, two } main() {^}');
await computeSuggestions();
assertSuggestEnum('E');
+ assertSuggestEnumConst('E.one');
+ assertSuggestEnumConst('E.two');
assertNotSuggested('one');
assertNotSuggested('two');
}
@@ -1937,10 +1937,38 @@
addTestSource('@deprecated enum E { one, two } main() {^}');
await computeSuggestions();
assertSuggestEnum('E', isDeprecated: true);
+ assertSuggestEnumConst('E.one', isDeprecated: true);
+ assertSuggestEnumConst('E.two', isDeprecated: true);
assertNotSuggested('one');
assertNotSuggested('two');
}
+ test_enum_filter() async {
+ // SimpleIdentifier NamedExpression ArgumentList
+ // InstanceCreationExpression
+ addTestSource('''
+ enum E { one, two }
+ enum F { three, four }
+ class A {}
+ class B {
+ B({E someE});
+ }
+ A a = new A();
+ B b = new B(someE: ^);
+ ''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestEnumConst('E.one',
+ relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+ assertSuggestEnumConst('E.two',
+ relevance: DART_RELEVANCE_DEFAULT + DART_RELEVANCE_INCREMENT);
+ assertNotSuggested('a');
+ assertNotSuggested('F.three');
+ assertNotSuggested('F.four');
+ }
+
test_ExpressionStatement_identifier() async {
// SimpleIdentifier ExpressionStatement Block
addSource(
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index d793539..4ec437f 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -2254,6 +2254,22 @@
''');
}
+ test_createMissingMethodCall() async {
+ resolveTestUnit('''
+class C implements Function {
+}
+''');
+ await assertHasFix(
+ DartFixKind.CREATE_MISSING_METHOD_CALL,
+ '''
+class C implements Function {
+ call() {
+ // TODO: implement call
+ }
+}
+''');
+ }
+
test_createMissingOverrides_field_untyped() async {
resolveTestUnit('''
class A {
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index d7e871c..3e049b7 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.27.4
+
+* Added support for 'analysis_options.yaml' files as an alternative to '.analysis_options' files.
+
## 0.27.1
* Moved the public and private API's for the element model into their proper places.
* Added back support for auto-processing of plugins.
diff --git a/pkg/analyzer/README.md b/pkg/analyzer/README.md
index 18dd9b2..6915a58 100644
--- a/pkg/analyzer/README.md
+++ b/pkg/analyzer/README.md
@@ -15,22 +15,19 @@
## Configuring the analyzer
-Both `dartanalyzer` and Dart Analysis Server can be configured
-with a `.analysis_options` file. This YAML file can control which files
-and paths are analyzed, which lints are applied, and more.
+Both `dartanalyzer` and Dart Analysis Server can be configured with either an
+`analysis_options.yaml` or `.analysis_options` file. This YAML file can control
+which files and paths are analyzed, which lints are applied, and more.
-If you are embedding the analyzer library in your project, you are
-responsible for finding the `.analysis_options` file, parsing it,
-and configuring the analyzer.
+If you are embedding the analyzer library in your project, you are responsible
+for finding the analysis options file, parsing it, and configuring the analyzer.
-The `.analysis_options` file should live
-at the root of your project (for example, next to your `pubspec.yaml`).
-Different embedders of analyzer, such as `dartanalyzer` or Dart Analysis Server,
-may choose to find the file in various different ways. Consult their
-documentation to learn more.
+The analysis options file should live at the root of your project (for example,
+next to your `pubspec.yaml`). Different embedders of analyzer, such as
+`dartanalyzer` or Dart Analysis Server, may choose to find the file in various
+different ways. Consult their documentation to learn more.
-Here is an example file that instructs the analyzer
-to ignore two files:
+Here is an example file that instructs the analyzer to ignore two files:
```yaml
analyzer:
diff --git a/pkg/analyzer/doc/tasks.html b/pkg/analyzer/doc/tasks.html
index 4fdabc9..b8b2e568 100644
--- a/pkg/analyzer/doc/tasks.html
+++ b/pkg/analyzer/doc/tasks.html
@@ -44,6 +44,7 @@
CONSTANT_EXPRESSION_RESOLVED [shape=box]
CONSTANT_VALUE -> ComputeConstantValueTask
CONSTANT_VALUE -> EvaluateUnitConstantsTask
+ CONSTANT_VALUE -> VerifyUnitTask
CONSTANT_VALUE [shape=box]
CONTAINING_LIBRARIES -> DartErrorsTask
CONTAINING_LIBRARIES [shape=box]
@@ -78,6 +79,8 @@
ComputeLibraryCycleTask -> LIBRARY_CYCLE_DEPENDENCIES
ComputeLibraryCycleTask -> LIBRARY_CYCLE_UNITS
ComputePropagableVariableDependenciesTask -> PROPAGABLE_VARIABLE_DEPENDENCIES
+ ComputeRequiredConstantsTask -> PENDING_ERRORS
+ ComputeRequiredConstantsTask -> REQUIRED_CONSTANTS
ContainingLibrariesTask -> CONTAINING_LIBRARIES
DART_ERRORS -> LibraryErrorsReadyTask
DART_ERRORS [shape=box]
@@ -195,6 +198,8 @@
PARSED_UNIT [shape=box]
PARSE_ERRORS -> dartErrorsForSource
PARSE_ERRORS [shape=box]
+ PENDING_ERRORS -> VerifyUnitTask
+ PENDING_ERRORS [shape=box]
PROPAGABLE_VARIABLES_IN_UNIT -> PropagateVariableTypesInUnitTask
PROPAGABLE_VARIABLES_IN_UNIT [shape=box]
PROPAGABLE_VARIABLE_DEPENDENCIES -> PropagateVariableTypeTask
@@ -237,6 +242,9 @@
REFERENCED_SOURCES -> BuildDirectiveElementsTask
REFERENCED_SOURCES -> VerifyUnitTask
REFERENCED_SOURCES [shape=box]
+ REQUIRED_CONSTANTS -> VerifyUnitTask
+ REQUIRED_CONSTANTS [shape=box]
+ RESOLVED_UNIT -> ComputeRequiredConstantsTask
RESOLVED_UNIT -> GenerateHintsTask
RESOLVED_UNIT -> GenerateLintsTask
RESOLVED_UNIT -> ReadyResolvedUnitTask
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index c33b26d..7b645cc 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -598,13 +598,14 @@
* returns `true`, or `null` if there is no such ancestor. Note that this node
* will never be returned.
*/
- AstNode getAncestor(Predicate<AstNode> predicate);
+ AstNode/*=E*/ getAncestor/*<E extends AstNode>*/(
+ Predicate<AstNode> predicate);
/**
* Return the value of the property with the given [name], or `null` if this
* node does not have a property with the given name.
*/
- Object getProperty(String name);
+ Object/*=E*/ getProperty/*<E>*/(String name);
/**
* Set the value of the property with the given [name] to the given [value].
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 1a73457..e7091ab 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -757,7 +757,8 @@
* [predicate] returns `true`, or `null` if there is no such ancestor. Note
* that this element will never be returned.
*/
- Element getAncestor(Predicate<Element> predicate);
+ Element/*=E*/ getAncestor/*<E extends Element >*/(
+ Predicate<Element> predicate);
/**
* Return a display name for the given element that includes the path to the
@@ -852,6 +853,13 @@
* required.
*/
bool get isRequired;
+
+ /**
+ * Return a representation of the value of this annotation, forcing the value
+ * to be computed if it had not previously been computed, or `null` if the
+ * value of this annotation could not be computed because of errors.
+ */
+ DartObject computeConstantValue();
}
/**
@@ -2001,4 +2009,12 @@
* 'var').
*/
DartType get type;
+
+ /**
+ * Return a representation of the value of this variable, forcing the value
+ * to be computed if it had not previously been computed, or `null` if either
+ * this variable was not declared with the 'const' modifier or if the value of
+ * this variable could not be computed because of errors.
+ */
+ DartObject computeConstantValue();
}
diff --git a/pkg/analyzer/lib/source/analysis_options_provider.dart b/pkg/analyzer/lib/source/analysis_options_provider.dart
index 3b6e330..2acab1d 100644
--- a/pkg/analyzer/lib/source/analysis_options_provider.dart
+++ b/pkg/analyzer/lib/source/analysis_options_provider.dart
@@ -12,14 +12,19 @@
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';
-/// Provide the options found in the `.analysis_options` file.
+/// Provide the options found in the analysis options file.
class AnalysisOptionsProvider {
- /// Provide the options found in [root]/[ANALYSIS_OPTIONS_FILE].
+ /// Provide the options found in either [root]/[ANALYSIS_OPTIONS_FILE] or
+ /// [root]/[ANALYSIS_OPTIONS_YAML_FILE].
/// Return an empty options map if the file does not exist.
Map<String, YamlNode> getOptions(Folder root, {bool crawlUp: false}) {
Resource resource;
for (Folder folder = root; folder != null; folder = folder.parent) {
resource = folder.getChild(AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+ if (resource.exists) {
+ break;
+ }
+ resource = folder.getChild(AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
if (resource.exists || !crawlUp) {
break;
}
diff --git a/pkg/analyzer/lib/source/config.dart b/pkg/analyzer/lib/source/config.dart
index 376c189..0ca954a 100644
--- a/pkg/analyzer/lib/source/config.dart
+++ b/pkg/analyzer/lib/source/config.dart
@@ -19,8 +19,7 @@
/// Return configuration associated with this [context], or `null` if there is
/// none.
AnalysisConfiguration getConfiguration(AnalysisContext context) =>
- context.getConfigurationData(ANALYSIS_CONFIGURATION)
- as AnalysisConfiguration;
+ context.getConfigurationData(ANALYSIS_CONFIGURATION);
/// Associate this [config] with the given [context].
void setConfiguration(AnalysisContext context, AnalysisConfiguration config) {
@@ -47,6 +46,7 @@
class AnalysisConfigurationDescriptor {
/// The name of the package hosting the configuration.
String package;
+
/// The name of the configuration "pragma".
String pragma;
diff --git a/pkg/analyzer/lib/source/error_processor.dart b/pkg/analyzer/lib/source/error_processor.dart
index ddd0679..1fd9577 100644
--- a/pkg/analyzer/lib/source/error_processor.dart
+++ b/pkg/analyzer/lib/source/error_processor.dart
@@ -96,8 +96,7 @@
// Let the user configure how specific errors are processed.
List<ErrorProcessor> processors =
- context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS)
- as List<ErrorProcessor>;
+ context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
// Give strong mode a chance to upgrade it.
if (context.analysisOptions.strongMode) {
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index c5641a9..7dbe398 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -179,7 +179,7 @@
if (entry == null) {
return result.defaultValue;
}
- return entry.getValue(result) as Object/*=V*/;
+ return entry.getValue(result);
}
/**
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 7540c0f..f5464b1 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -1016,7 +1016,7 @@
@override
Object/*=V*/ getResult/*<V>*/(
AnalysisTarget target, ResultDescriptor/*<V>*/ result) {
- return _cache.getValue(target, result) as Object/*=V*/;
+ return _cache.getValue(target, result);
}
@override
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
index 32792df..dcd413a 100644
--- a/pkg/analyzer/lib/src/context/source.dart
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -4,6 +4,8 @@
library analyzer.src.context.source;
+import 'dart:collection';
+
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/source/package_map_resolver.dart';
@@ -48,6 +50,12 @@
LocalSourcePredicate _localSourcePredicate = LocalSourcePredicate.NOT_SDK;
/**
+ * Cache of mapping of absolute [Uri]s to [Source]s.
+ */
+ final HashMap<Uri, Source> _absoluteUriToSourceCache =
+ new HashMap<Uri, Source>();
+
+ /**
* Initialize a newly created source factory with the given absolute URI
* [resolvers] and optional [packages] resolution helper.
*/
@@ -310,13 +318,14 @@
}
}
- for (UriResolver resolver in resolvers) {
- Source result = resolver.resolveAbsolute(containedUri, actualUri);
- if (result != null) {
- return result;
+ return _absoluteUriToSourceCache.putIfAbsent(containedUri, () {
+ for (UriResolver resolver in resolvers) {
+ Source result = resolver.resolveAbsolute(containedUri, actualUri);
+ if (result != null) {
+ return result;
+ }
}
- }
-
- return null;
+ return null;
+ });
}
}
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index e5509f1..2ed3515 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -895,21 +895,22 @@
}
@override
- AstNode getAncestor(Predicate<AstNode> predicate) {
+ AstNode/*=E*/ getAncestor/*<E extends AstNode>*/(
+ Predicate<AstNode> predicate) {
// TODO(brianwilkerson) It is a bug that this method can return `this`.
AstNode node = this;
while (node != null && !predicate(node)) {
node = node.parent;
}
- return node;
+ return node as AstNode/*=E*/;
}
@override
- Object getProperty(String name) {
+ Object/*=E*/ getProperty/*<E>*/(String name) {
if (_propertyMap == null) {
return null;
}
- return _propertyMap[name];
+ return _propertyMap[name] as Object/*=E*/;
}
@override
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index cde4825..e3e379f 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -2317,7 +2317,7 @@
Object key = entry.key.accept(this);
Object value = entry.value.accept(this);
if (key is String && !identical(value, NOT_A_CONSTANT)) {
- map[(key as String)] = value;
+ map[key] = value;
} else {
return NOT_A_CONSTANT;
}
@@ -5611,7 +5611,9 @@
bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
FunctionExpressionInvocation toNode =
this._toNode as FunctionExpressionInvocation;
- if (_and(_isEqualNodes(node.function, toNode.function),
+ if (_and(
+ _isEqualNodes(node.function, toNode.function),
+ _isEqualNodes(node.typeArguments, toNode.typeArguments),
_isEqualNodes(node.argumentList, toNode.argumentList))) {
toNode.propagatedElement = node.propagatedElement;
toNode.propagatedInvokeType = node.propagatedInvokeType;
@@ -5876,6 +5878,7 @@
if (_and(
_isEqualNodes(node.target, toNode.target),
_isEqualTokens(node.operator, toNode.operator),
+ _isEqualNodes(node.typeArguments, toNode.typeArguments),
_isEqualNodes(node.methodName, toNode.methodName),
_isEqualNodes(node.argumentList, toNode.argumentList))) {
toNode.propagatedInvokeType = node.propagatedInvokeType;
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index bcac6b1..ddcad2b 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -27,6 +27,8 @@
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/task/dart.dart';
/**
* For AST nodes that could be in both the getter and setter contexts
@@ -59,7 +61,14 @@
/**
* A concrete implementation of a [ClassElement].
*/
-class ClassElementImpl extends ElementImpl implements ClassElement {
+class ClassElementImpl extends ElementImpl
+ with TypeParameterizedElementMixin
+ implements ClassElement {
+ /**
+ * The unlinked representation of the class in the summary.
+ */
+ final UnlinkedClass _unlinkedClass;
+
/**
* A list containing all of the accessors (getters and setters) contained in
* this class.
@@ -128,17 +137,29 @@
* Initialize a newly created class element to have the given [name] at the
* given [offset] in the file that contains the declaration of this element.
*/
- ClassElementImpl(String name, int offset) : super(name, offset);
+ ClassElementImpl(String name, int offset)
+ : _unlinkedClass = null,
+ super(name, offset);
/**
* Initialize a newly created class element to have the given [name].
*/
- ClassElementImpl.forNode(Identifier name) : super.forNode(name);
+ ClassElementImpl.forNode(Identifier name)
+ : _unlinkedClass = null,
+ super.forNode(name);
+
+ /**
+ * Initialize using the given serialized information.
+ */
+ ClassElementImpl.forSerialized(
+ this._unlinkedClass, CompilationUnitElementImpl enclosingUnit)
+ : super.forSerialized(enclosingUnit);
/**
* Set whether this class is abstract.
*/
void set abstract(bool isAbstract) {
+ assert(_unlinkedClass == null);
setModifier(Modifier.ABSTRACT, isAbstract);
}
@@ -163,6 +184,22 @@
}
@override
+ int get codeLength {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass.codeRange?.length;
+ }
+ return super.codeLength;
+ }
+
+ @override
+ int get codeOffset {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass.codeRange?.offset;
+ }
+ return super.codeOffset;
+ }
+
+ @override
List<ConstructorElement> get constructors {
if (!isMixinApplication) {
assert(_constructors != null);
@@ -184,6 +221,29 @@
this._constructors = constructors;
}
+ @override
+ String get displayName => name;
+
+ @override
+ SourceRange get docRange {
+ if (_unlinkedClass != null) {
+ UnlinkedDocumentationComment comment =
+ _unlinkedClass.documentationComment;
+ return comment != null
+ ? new SourceRange(comment.offset, comment.length)
+ : null;
+ }
+ return super.docRange;
+ }
+
+ @override
+ String get documentationComment {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass?.documentationComment?.text;
+ }
+ return super.documentationComment;
+ }
+
/**
* Return `true` if [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] should
* be reported for this class.
@@ -228,6 +288,9 @@
return !nearestNonMixinClass.constructors.any(isSuperConstructorAccessible);
}
+ @override
+ TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
+
/**
* Set whether this class is defined by an enum declaration.
*/
@@ -310,13 +373,23 @@
}
@override
- bool get isAbstract => hasModifier(Modifier.ABSTRACT);
+ bool get isAbstract {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass.isAbstract;
+ }
+ return hasModifier(Modifier.ABSTRACT);
+ }
@override
bool get isEnum => hasModifier(Modifier.ENUM);
@override
- bool get isMixinApplication => hasModifier(Modifier.MIXIN_APPLICATION);
+ bool get isMixinApplication {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass.isMixinApplication;
+ }
+ return hasModifier(Modifier.MIXIN_APPLICATION);
+ }
@override
bool get isOrInheritsProxy =>
@@ -354,6 +427,16 @@
ElementKind get kind => ElementKind.CLASS;
@override
+ List<ElementAnnotation> get metadata {
+ if (_unlinkedClass != null) {
+ return _metadata ??= _unlinkedClass.annotations
+ .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+ .toList();
+ }
+ return super.metadata;
+ }
+
+ @override
List<MethodElement> get methods => _methods;
/**
@@ -370,17 +453,40 @@
* Set whether this class is a mixin application.
*/
void set mixinApplication(bool isMixinApplication) {
+ assert(_unlinkedClass == null);
setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
}
@override
- List<TypeParameterElement> get typeParameters => _typeParameters;
+ String get name {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass.name;
+ }
+ return super.name;
+ }
+
+ @override
+ int get nameOffset {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass.nameOffset;
+ }
+ return super.nameOffset;
+ }
+
+ @override
+ List<TypeParameterElement> get typeParameters {
+ if (_unlinkedClass != null) {
+ return super.typeParameters;
+ }
+ return _typeParameters;
+ }
/**
* Set the type parameters defined for this class to the given
* [typeParameters].
*/
void set typeParameters(List<TypeParameterElement> typeParameters) {
+ assert(_unlinkedClass == null);
for (TypeParameterElement typeParameter in typeParameters) {
(typeParameter as TypeParameterElementImpl).enclosingElement = this;
}
@@ -388,6 +494,10 @@
}
@override
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
+ _unlinkedClass.typeParameters;
+
+ @override
ConstructorElement get unnamedConstructor {
for (ConstructorElement element in constructors) {
String name = element.displayName;
@@ -921,6 +1031,7 @@
*/
static ClassElementImpl getImpl(ClassElement classElement) {
if (classElement is ClassElementHandle) {
+ classElement.ensureActualElementComplete();
return getImpl(classElement.actualElement);
}
return classElement as ClassElementImpl;
@@ -933,6 +1044,22 @@
class CompilationUnitElementImpl extends UriReferencedElementImpl
implements CompilationUnitElement {
/**
+ * The context in which this unit is resynthesized, or `null` if the
+ * element is not resynthesized a summary.
+ */
+ final ResynthesizerContext resynthesizerContext;
+
+ /**
+ * The unlinked representation of the unit in the summary.
+ */
+ final UnlinkedUnit _unlinkedUnit;
+
+ /**
+ * The unlinked representation of the part in the summary.
+ */
+ final UnlinkedPart _unlinkedPart;
+
+ /**
* The source that corresponds to this compilation unit.
*/
@override
@@ -997,7 +1124,26 @@
* Initialize a newly created compilation unit element to have the given
* [name].
*/
- CompilationUnitElementImpl(String name) : super(name, -1);
+ CompilationUnitElementImpl(String name)
+ : resynthesizerContext = null,
+ _unlinkedUnit = null,
+ _unlinkedPart = null,
+ super(name, -1);
+
+ /**
+ * Initialize using the given serialized information.
+ */
+ CompilationUnitElementImpl.forSerialized(
+ LibraryElementImpl enclosingLibrary,
+ this.resynthesizerContext,
+ this._unlinkedUnit,
+ this._unlinkedPart,
+ String name)
+ : super.forSerialized(null) {
+ _enclosingElement = enclosingLibrary;
+ _name = name;
+ _nameOffset = -1;
+ }
@override
List<PropertyAccessorElement> get accessors => _accessors;
@@ -1014,10 +1160,31 @@
}
@override
+ int get codeLength {
+ if (_unlinkedUnit != null) {
+ return _unlinkedUnit.codeRange?.length;
+ }
+ return super.codeLength;
+ }
+
+ @override
+ int get codeOffset {
+ if (_unlinkedUnit != null) {
+ return _unlinkedUnit.codeRange?.offset;
+ }
+ return super.codeOffset;
+ }
+
+ @override
LibraryElement get enclosingElement =>
super.enclosingElement as LibraryElement;
@override
+ CompilationUnitElementImpl get enclosingUnit {
+ return this;
+ }
+
+ @override
List<ClassElement> get enums => _enums;
/**
@@ -1067,6 +1234,18 @@
ElementKind get kind => ElementKind.COMPILATION_UNIT;
@override
+ List<ElementAnnotation> get metadata {
+ if (_unlinkedPart != null) {
+ CompilationUnitElementImpl definingUnit =
+ library.definingCompilationUnit as CompilationUnitElementImpl;
+ return _metadata ??= _unlinkedPart.annotations
+ .map(definingUnit.resynthesizerContext.buildAnnotation)
+ .toList();
+ }
+ return super.metadata;
+ }
+
+ @override
List<TopLevelVariableElement> get topLevelVariables => _variables;
/**
@@ -1143,9 +1322,9 @@
*/
List<ElementAnnotation> getAnnotations(int offset) {
if (annotationMap == null) {
- return ElementAnnotation.EMPTY_LIST;
+ return const <ElementAnnotation>[];
}
- return annotationMap[offset] ?? ElementAnnotation.EMPTY_LIST;
+ return annotationMap[offset] ?? const <ElementAnnotation>[];
}
@override
@@ -1264,11 +1443,6 @@
*/
class ConstFieldElementImpl extends FieldElementImpl with ConstVariableElement {
/**
- * The result of evaluating this variable's initializer.
- */
- EvaluationResultImpl _result;
-
- /**
* Initialize a newly created synthetic field element to have the given
* [name] and [offset].
*/
@@ -1278,17 +1452,6 @@
* Initialize a newly created field element to have the given [name].
*/
ConstFieldElementImpl.forNode(Identifier name) : super.forNode(name);
-
- @override
- DartObject get constantValue => _result?.value;
-
- @override
- EvaluationResultImpl get evaluationResult => _result;
-
- @override
- void set evaluationResult(EvaluationResultImpl result) {
- this._result = result;
- }
}
/**
@@ -1298,11 +1461,6 @@
class ConstLocalVariableElementImpl extends LocalVariableElementImpl
with ConstVariableElement {
/**
- * The result of evaluating this variable's initializer.
- */
- EvaluationResultImpl _result;
-
- /**
* Initialize a newly created local variable element to have the given [name]
* and [offset].
*/
@@ -1313,16 +1471,12 @@
*/
ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
- @override
- DartObject get constantValue => _result?.value;
-
- @override
- EvaluationResultImpl get evaluationResult => _result;
-
- @override
- void set evaluationResult(EvaluationResultImpl result) {
- this._result = result;
- }
+ /**
+ * Initialize using the given serialized information.
+ */
+ ConstLocalVariableElementImpl.forSerialized(UnlinkedVariable unlinkedVariable,
+ ExecutableElementImpl enclosingExecutable)
+ : super.forSerialized(unlinkedVariable, enclosingExecutable);
}
/**
@@ -1370,9 +1524,17 @@
ConstructorElementImpl.forNode(Identifier name) : super.forNode(name);
/**
+ * Initialize using the given serialized information.
+ */
+ ConstructorElementImpl.forSerialized(
+ UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
+ : super.forSerialized(serializedExecutable, enclosingClass);
+
+ /**
* Set whether this constructor represents a 'const' constructor.
*/
void set const2(bool isConst) {
+ assert(serializedExecutable == null);
setModifier(Modifier.CONST, isConst);
}
@@ -1383,11 +1545,17 @@
* Set whether this constructor represents a factory method.
*/
void set factory(bool isFactory) {
+ assert(serializedExecutable == null);
setModifier(Modifier.FACTORY, isFactory);
}
@override
- bool get isConst => hasModifier(Modifier.CONST);
+ bool get isConst {
+ if (serializedExecutable != null) {
+ return serializedExecutable.isConst;
+ }
+ return hasModifier(Modifier.CONST);
+ }
@override
bool get isDefaultConstructor {
@@ -1407,7 +1575,12 @@
}
@override
- bool get isFactory => hasModifier(Modifier.FACTORY);
+ bool get isFactory {
+ if (serializedExecutable != null) {
+ return serializedExecutable.isFactory;
+ }
+ return hasModifier(Modifier.FACTORY);
+ }
@override
bool get isStatic => false;
@@ -1454,11 +1627,6 @@
class ConstTopLevelVariableElementImpl extends TopLevelVariableElementImpl
with ConstVariableElement {
/**
- * The result of evaluating this variable's initializer.
- */
- EvaluationResultImpl _result;
-
- /**
* Initialize a newly created synthetic top-level variable element to have the
* given [name] and [offset].
*/
@@ -1471,17 +1639,6 @@
*/
ConstTopLevelVariableElementImpl.forNode(Identifier name)
: super.forNode(name);
-
- @override
- DartObject get constantValue => _result?.value;
-
- @override
- EvaluationResultImpl get evaluationResult => _result;
-
- @override
- void set evaluationResult(EvaluationResultImpl result) {
- this._result = result;
- }
}
/**
@@ -1495,7 +1652,7 @@
*
* This class is not intended to be part of the public API for analyzer.
*/
-abstract class ConstVariableElement {
+abstract class ConstVariableElement implements ConstantEvaluationTarget {
/**
* If this element represents a constant variable, and it has an initializer,
* a copy of the initializer for the constant. Otherwise `null`.
@@ -1506,6 +1663,22 @@
* initializers.
*/
Expression constantInitializer;
+
+ @override
+ EvaluationResultImpl evaluationResult;
+
+ /**
+ * Return a representation of the value of this variable, forcing the value
+ * to be computed if it had not previously been computed, or `null` if either
+ * this variable was not declared with the 'const' modifier or if the value of
+ * this variable could not be computed because of errors.
+ */
+ DartObject computeConstantValue() {
+ if (evaluationResult == null) {
+ context?.computeResult(this, CONSTANT_VALUE);
+ }
+ return evaluationResult?.value;
+ }
}
/**
@@ -1514,11 +1687,6 @@
class DefaultFieldFormalParameterElementImpl
extends FieldFormalParameterElementImpl with ConstVariableElement {
/**
- * The result of evaluating this variable's initializer.
- */
- EvaluationResultImpl _result;
-
- /**
* Initialize a newly created parameter element to have the given [name] and
* [nameOffset].
*/
@@ -1530,17 +1698,6 @@
*/
DefaultFieldFormalParameterElementImpl.forNode(Identifier name)
: super.forNode(name);
-
- @override
- DartObject get constantValue => _result?.value;
-
- @override
- EvaluationResultImpl get evaluationResult => _result;
-
- @override
- void set evaluationResult(EvaluationResultImpl result) {
- this._result = result;
- }
}
/**
@@ -1549,11 +1706,6 @@
class DefaultParameterElementImpl extends ParameterElementImpl
with ConstVariableElement {
/**
- * The result of evaluating this variable's initializer.
- */
- EvaluationResultImpl _result;
-
- /**
* Initialize a newly created parameter element to have the given [name] and
* [nameOffset].
*/
@@ -1565,15 +1717,30 @@
*/
DefaultParameterElementImpl.forNode(Identifier name) : super.forNode(name);
- @override
- DartObject get constantValue => _result?.value;
+ /**
+ * Initialize using the given serialized information.
+ */
+ DefaultParameterElementImpl.forSerialized(
+ UnlinkedParam unlinkedParam, ExecutableElementImpl enclosingExecutable)
+ : super.forSerialized(unlinkedParam, enclosingExecutable);
@override
- EvaluationResultImpl get evaluationResult => _result;
+ Expression get constantInitializer {
+ if (_unlinkedParam != null) {
+ UnlinkedConst defaultValue = _unlinkedParam.defaultValue;
+ if (defaultValue == null) {
+ return null;
+ }
+ return super.constantInitializer ??=
+ enclosingUnit.resynthesizerContext.buildExpression(defaultValue);
+ }
+ return super.constantInitializer;
+ }
@override
- void set evaluationResult(EvaluationResultImpl result) {
- this._result = result;
+ void set constantInitializer(Expression initializer) {
+ assert(_unlinkedParam == null);
+ super.constantInitializer = initializer;
}
@override
@@ -1772,6 +1939,14 @@
Source get source => compilationUnit.source;
@override
+ DartObject computeConstantValue() {
+ if (evaluationResult == null) {
+ context?.computeResult(this, CONSTANT_VALUE);
+ }
+ return constantValue;
+ }
+
+ @override
String toString() => '@$element';
}
@@ -1813,7 +1988,7 @@
/**
* A list containing all of the metadata associated with this element.
*/
- List<ElementAnnotation> metadata = ElementAnnotation.EMPTY_LIST;
+ List<ElementAnnotation> _metadata;
/**
* A cached copy of the calculated hashCode for this element.
@@ -1867,6 +2042,11 @@
: this(name == null ? "" : name.name, name == null ? -1 : name.offset);
/**
+ * Initialize from serialized information.
+ */
+ ElementImpl.forSerialized(this._enclosingElement);
+
+ /**
* The length of the element's code, or `null` if the element is synthetic.
*/
int get codeLength => _codeLength;
@@ -1903,6 +2083,7 @@
* The documentation comment source for this element.
*/
void set documentationComment(String doc) {
+ assert(!isResynthesized);
_docComment = doc?.replaceAll('\r\n', '\n');
}
@@ -1919,6 +2100,14 @@
_updateCaches();
}
+ /**
+ * Return the enclosing unit element (which might be the same as `this`), or
+ * `null` if this element is not contained in any compilation unit.
+ */
+ CompilationUnitElementImpl get enclosingUnit {
+ return _enclosingElement?.enclosingUnit;
+ }
+
@override
int get hashCode {
// TODO: We might want to re-visit this optimization in the future.
@@ -1997,6 +2186,11 @@
return false;
}
+ /**
+ * Return `true` if this element is resynthesized from a summary.
+ */
+ bool get isResynthesized => enclosingUnit?.resynthesizerContext != null;
+
@override
bool get isSynthetic => hasModifier(Modifier.SYNTHETIC);
@@ -2015,6 +2209,15 @@
return _cachedLocation;
}
+ List<ElementAnnotation> get metadata {
+ return _metadata ?? const <ElementAnnotation>[];
+ }
+
+ void set metadata(List<ElementAnnotation> metadata) {
+ assert(!isResynthesized);
+ _metadata = metadata;
+ }
+
@override
String get name => _name;
@@ -2121,12 +2324,13 @@
}
@override
- Element getAncestor(Predicate<Element> predicate) {
+ Element/*=E*/ getAncestor/*<E extends Element >*/(
+ Predicate<Element> predicate) {
Element ancestor = _enclosingElement;
while (ancestor != null && !predicate(ancestor)) {
ancestor = ancestor.enclosingElement;
}
- return ancestor;
+ return ancestor as Element/*=E*/;
}
/**
@@ -2171,7 +2375,7 @@
@override
bool isAccessibleIn(LibraryElement library) {
- if (Identifier.isPrivateName(_name)) {
+ if (Identifier.isPrivateName(name)) {
return library == this.library;
}
return true;
@@ -2192,6 +2396,7 @@
* Set the code range for this element.
*/
void setCodeRange(int offset, int length) {
+ assert(!isResynthesized);
_codeOffset = offset;
_codeLength = length;
}
@@ -2200,6 +2405,7 @@
* Set the documentation comment source range for this element.
*/
void setDocRange(int offset, int length) {
+ assert(!isResynthesized);
_docRangeOffset = offset;
_docRangeLength = length;
}
@@ -2411,6 +2617,11 @@
abstract class ExecutableElementImpl extends ElementImpl
implements ExecutableElement {
/**
+ * The unlinked representation of the executable in the summary.
+ */
+ final UnlinkedExecutable serializedExecutable;
+
+ /**
* A list containing all of the functions defined within this executable
* element.
*/
@@ -2452,24 +2663,81 @@
* Initialize a newly created executable element to have the given [name] and
* [offset].
*/
- ExecutableElementImpl(String name, int offset) : super(name, offset);
+ ExecutableElementImpl(String name, int offset)
+ : serializedExecutable = null,
+ super(name, offset);
/**
* Initialize a newly created executable element to have the given [name].
*/
- ExecutableElementImpl.forNode(Identifier name) : super.forNode(name);
+ ExecutableElementImpl.forNode(Identifier name)
+ : serializedExecutable = null,
+ super.forNode(name);
+
+ /**
+ * Initialize using the given serialized information.
+ */
+ ExecutableElementImpl.forSerialized(
+ this.serializedExecutable, ElementImpl enclosingElement)
+ : super.forSerialized(enclosingElement);
/**
* Set whether this executable element's body is asynchronous.
*/
void set asynchronous(bool isAsynchronous) {
+ assert(serializedExecutable == null);
setModifier(Modifier.ASYNCHRONOUS, isAsynchronous);
}
+ @override
+ int get codeLength {
+ if (serializedExecutable != null) {
+ return serializedExecutable.codeRange?.length;
+ }
+ return super.codeLength;
+ }
+
+ @override
+ int get codeOffset {
+ if (serializedExecutable != null) {
+ return serializedExecutable.codeRange?.offset;
+ }
+ return super.codeOffset;
+ }
+
+ @override
+ String get displayName {
+ if (serializedExecutable != null) {
+ return serializedExecutable.name;
+ }
+ return super.displayName;
+ }
+
+ @override
+ SourceRange get docRange {
+ if (serializedExecutable != null) {
+ UnlinkedDocumentationComment comment =
+ serializedExecutable.documentationComment;
+ return comment != null
+ ? new SourceRange(comment.offset, comment.length)
+ : null;
+ }
+ return super.docRange;
+ }
+
+ @override
+ String get documentationComment {
+ if (serializedExecutable != null) {
+ return serializedExecutable?.documentationComment?.text;
+ }
+ return super.documentationComment;
+ }
+
/**
* Set whether this executable element is external.
*/
void set external(bool isExternal) {
+ assert(serializedExecutable == null);
setModifier(Modifier.EXTERNAL, isExternal);
}
@@ -2491,36 +2759,64 @@
* Set whether this method's body is a generator.
*/
void set generator(bool isGenerator) {
+ assert(serializedExecutable == null);
setModifier(Modifier.GENERATOR, isGenerator);
}
@override
- bool get hasImplicitReturnType => hasModifier(Modifier.IMPLICIT_TYPE);
+ bool get hasImplicitReturnType {
+ if (serializedExecutable != null) {
+ return serializedExecutable.returnType == null &&
+ serializedExecutable.kind != UnlinkedExecutableKind.constructor;
+ }
+ return hasModifier(Modifier.IMPLICIT_TYPE);
+ }
/**
* Set whether this executable element has an implicit return type.
*/
void set hasImplicitReturnType(bool hasImplicitReturnType) {
+ assert(serializedExecutable == null);
setModifier(Modifier.IMPLICIT_TYPE, hasImplicitReturnType);
}
@override
- bool get isAbstract => hasModifier(Modifier.ABSTRACT);
+ bool get isAbstract {
+ if (serializedExecutable != null) {
+ return serializedExecutable.isAbstract;
+ }
+ return hasModifier(Modifier.ABSTRACT);
+ }
@override
- bool get isAsynchronous => hasModifier(Modifier.ASYNCHRONOUS);
+ bool get isAsynchronous {
+ if (serializedExecutable != null) {
+ return serializedExecutable.isAsynchronous;
+ }
+ return hasModifier(Modifier.ASYNCHRONOUS);
+ }
@override
- bool get isExternal => hasModifier(Modifier.EXTERNAL);
+ bool get isExternal {
+ if (serializedExecutable != null) {
+ return serializedExecutable.isExternal;
+ }
+ return hasModifier(Modifier.EXTERNAL);
+ }
@override
- bool get isGenerator => hasModifier(Modifier.GENERATOR);
+ bool get isGenerator {
+ if (serializedExecutable != null) {
+ return serializedExecutable.isGenerator;
+ }
+ return hasModifier(Modifier.GENERATOR);
+ }
@override
bool get isOperator => false;
@override
- bool get isSynchronous => !hasModifier(Modifier.ASYNCHRONOUS);
+ bool get isSynchronous => !isAsynchronous;
@override
List<LabelElement> get labels => _labels;
@@ -2551,6 +2847,32 @@
}
@override
+ List<ElementAnnotation> get metadata {
+ if (serializedExecutable != null) {
+ return _metadata ??= serializedExecutable.annotations
+ .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+ .toList();
+ }
+ return super.metadata;
+ }
+
+ @override
+ String get name {
+ if (serializedExecutable != null) {
+ return serializedExecutable.name;
+ }
+ return super.name;
+ }
+
+ @override
+ int get nameOffset {
+ if (serializedExecutable != null) {
+ return serializedExecutable.nameOffset;
+ }
+ return super.nameOffset;
+ }
+
+ @override
List<ParameterElement> get parameters => _parameters;
/**
@@ -2830,6 +3152,13 @@
FunctionElementImpl.forOffset(int nameOffset) : super("", nameOffset);
/**
+ * Initialize using the given serialized information.
+ */
+ FunctionElementImpl.forSerialized(
+ UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement)
+ : super.forSerialized(serializedExecutable, enclosingElement);
+
+ /**
* Synthesize an unnamed function element that takes [parameters] and returns
* [returnType].
*/
@@ -2920,8 +3249,14 @@
* A concrete implementation of a [FunctionTypeAliasElement].
*/
class FunctionTypeAliasElementImpl extends ElementImpl
+ with TypeParameterizedElementMixin
implements FunctionTypeAliasElement {
/**
+ * The unlinked representation of the type in the summary.
+ */
+ final UnlinkedTypedef _unlinkedTypedef;
+
+ /**
* A list containing all of the parameters defined by this type alias.
*/
List<ParameterElement> _parameters = ParameterElement.EMPTY_LIST;
@@ -2949,21 +3284,103 @@
* contains the declaration of this element
*/
FunctionTypeAliasElementImpl(String name, int nameOffset)
- : super(name, nameOffset);
+ : _unlinkedTypedef = null,
+ super(name, nameOffset);
/**
* Initialize a newly created type alias element to have the given [name].
*/
- FunctionTypeAliasElementImpl.forNode(Identifier name) : super.forNode(name);
+ FunctionTypeAliasElementImpl.forNode(Identifier name)
+ : _unlinkedTypedef = null,
+ super.forNode(name);
+
+ /**
+ * Initialize using the given serialized information.
+ */
+ FunctionTypeAliasElementImpl.forSerialized(
+ this._unlinkedTypedef, CompilationUnitElementImpl enclosingUnit)
+ : super.forSerialized(enclosingUnit);
+
+ @override
+ int get codeLength {
+ if (_unlinkedTypedef != null) {
+ return _unlinkedTypedef.codeRange?.length;
+ }
+ return super.codeLength;
+ }
+
+ @override
+ int get codeOffset {
+ if (_unlinkedTypedef != null) {
+ return _unlinkedTypedef.codeRange?.offset;
+ }
+ return super.codeOffset;
+ }
+
+ @override
+ String get displayName => name;
+
+ @override
+ SourceRange get docRange {
+ if (_unlinkedTypedef != null) {
+ UnlinkedDocumentationComment comment =
+ _unlinkedTypedef.documentationComment;
+ return comment != null
+ ? new SourceRange(comment.offset, comment.length)
+ : null;
+ }
+ return super.docRange;
+ }
+
+ @override
+ String get documentationComment {
+ if (_unlinkedTypedef != null) {
+ return _unlinkedTypedef?.documentationComment?.text;
+ }
+ return super.documentationComment;
+ }
@override
CompilationUnitElement get enclosingElement =>
super.enclosingElement as CompilationUnitElement;
@override
+ TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
+
+ @override
+ CompilationUnitElementImpl get enclosingUnit =>
+ _enclosingElement as CompilationUnitElementImpl;
+
+ @override
ElementKind get kind => ElementKind.FUNCTION_TYPE_ALIAS;
@override
+ List<ElementAnnotation> get metadata {
+ if (_unlinkedTypedef != null) {
+ return _metadata ??= _unlinkedTypedef.annotations
+ .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+ .toList();
+ }
+ return super.metadata;
+ }
+
+ @override
+ String get name {
+ if (_unlinkedTypedef != null) {
+ return _unlinkedTypedef.name;
+ }
+ return super.name;
+ }
+
+ @override
+ int get nameOffset {
+ if (_unlinkedTypedef != null) {
+ return _unlinkedTypedef.nameOffset;
+ }
+ return super.nameOffset;
+ }
+
+ @override
List<ParameterElement> get parameters => _parameters;
/**
@@ -2979,13 +3396,19 @@
}
@override
- List<TypeParameterElement> get typeParameters => _typeParameters;
+ List<TypeParameterElement> get typeParameters {
+ if (_unlinkedTypedef != null) {
+ return super.typeParameters;
+ }
+ return _typeParameters;
+ }
/**
* Set the type parameters defined for this type to the given
* [typeParameters].
*/
void set typeParameters(List<TypeParameterElement> typeParameters) {
+ assert(_unlinkedTypedef == null);
for (TypeParameterElement typeParameter in typeParameters) {
(typeParameter as TypeParameterElementImpl).enclosingElement = this;
}
@@ -2993,6 +3416,10 @@
}
@override
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
+ _unlinkedTypedef.typeParameters;
+
+ @override
accept(ElementVisitor visitor) => visitor.visitFunctionTypeAliasElement(this);
@override
@@ -3450,6 +3877,13 @@
}
@override
+ bool get isResynthesized {
+ CompilationUnitElement definingUnit = _definingCompilationUnit;
+ return definingUnit is CompilationUnitElementImpl &&
+ definingUnit.resynthesizerContext != null;
+ }
+
+ @override
ElementKind get kind => ElementKind.LIBRARY;
@override
@@ -3692,7 +4126,7 @@
// represents a new back edge. It would be sufficient to invalidate the
// cycle information for all nodes that are between the target and the
// node in the topological order. For simplicity, we simply invalidate
- // all nodes which are reachable from the the source node.
+ // all nodes which are reachable from the source node.
// Note that in the invalidation phase, we do not cut off when we encounter
// a node with no library cycle information, since we do not know whether
// we are in the case where invalidation has already been performed, or we
@@ -3801,7 +4235,7 @@
/**
* A concrete implementation of a [LocalVariableElement].
*/
-class LocalVariableElementImpl extends VariableElementImpl
+class LocalVariableElementImpl extends NonParameterVariableElementImpl
implements LocalVariableElement {
/**
* The offset to the beginning of the visible range for this element.
@@ -3825,6 +4259,13 @@
*/
LocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
+ /**
+ * Initialize using the given serialized information.
+ */
+ LocalVariableElementImpl.forSerialized(UnlinkedVariable unlinkedVariable,
+ ExecutableElementImpl enclosingExecutable)
+ : super.forSerialized(unlinkedVariable, enclosingExecutable);
+
@override
String get identifier {
int enclosingOffset =
@@ -3890,9 +4331,17 @@
MethodElementImpl.forNode(Identifier name) : super.forNode(name);
/**
+ * Initialize using the given serialized information.
+ */
+ MethodElementImpl.forSerialized(
+ UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
+ : super.forSerialized(serializedExecutable, enclosingClass);
+
+ /**
* Set whether this method is abstract.
*/
void set abstract(bool isAbstract) {
+ assert(serializedExecutable == null);
setModifier(Modifier.ABSTRACT, isAbstract);
}
@@ -3922,7 +4371,12 @@
}
@override
- bool get isStatic => hasModifier(Modifier.STATIC);
+ bool get isStatic {
+ if (serializedExecutable != null) {
+ return serializedExecutable.isStatic;
+ }
+ return hasModifier(Modifier.STATIC);
+ }
@override
ElementKind get kind => ElementKind.METHOD;
@@ -3940,6 +4394,7 @@
* Set whether this method is static.
*/
void set static(bool isStatic) {
+ assert(serializedExecutable == null);
setModifier(Modifier.STATIC, isStatic);
}
@@ -4177,7 +4632,7 @@
ElementLocation get location => null;
@override
- List<ElementAnnotation> get metadata => ElementAnnotation.EMPTY_LIST;
+ List<ElementAnnotation> get metadata => const <ElementAnnotation>[];
@override
String get name => _name;
@@ -4207,7 +4662,9 @@
AstNode computeNode() => null;
@override
- Element getAncestor(Predicate<Element> predicate) => null;
+ Element/*=E*/ getAncestor/*<E extends Element >*/(
+ Predicate<Element> predicate) =>
+ null;
@override
String getExtendedDisplayName(String shortName) {
@@ -4346,12 +4803,133 @@
}
/**
+ * A [VariableElementImpl], which is not a parameter.
+ */
+abstract class NonParameterVariableElementImpl extends VariableElementImpl {
+ /**
+ * The unlinked representation of the variable in the summary.
+ */
+ final UnlinkedVariable _unlinkedVariable;
+
+ /**
+ * Initialize a newly created variable element to have the given [name] and
+ * [offset].
+ */
+ NonParameterVariableElementImpl(String name, int offset)
+ : _unlinkedVariable = null,
+ super(name, offset);
+
+ /**
+ * Initialize a newly created variable element to have the given [name].
+ */
+ NonParameterVariableElementImpl.forNode(Identifier name)
+ : _unlinkedVariable = null,
+ super.forNode(name);
+
+ /**
+ * Initialize using the given serialized information.
+ */
+ NonParameterVariableElementImpl.forSerialized(
+ this._unlinkedVariable, ElementImpl enclosingElement)
+ : super.forSerialized(enclosingElement);
+
+ @override
+ int get codeLength {
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.codeRange?.length;
+ }
+ return super.codeLength;
+ }
+
+ @override
+ int get codeOffset {
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.codeRange?.offset;
+ }
+ return super.codeOffset;
+ }
+
+ @override
+ void set const3(bool isConst) {
+ assert(_unlinkedVariable == null);
+ super.const3 = isConst;
+ }
+
+ @override
+ void set final2(bool isFinal) {
+ assert(_unlinkedVariable == null);
+ super.final2 = isFinal;
+ }
+
+ @override
+ bool get hasImplicitType {
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.type == null;
+ }
+ return super.hasImplicitType;
+ }
+
+ @override
+ void set hasImplicitType(bool hasImplicitType) {
+ assert(_unlinkedVariable == null);
+ super.hasImplicitType = hasImplicitType;
+ }
+
+ @override
+ bool get isConst {
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.isConst;
+ }
+ return super.isConst;
+ }
+
+ @override
+ bool get isFinal {
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.isFinal;
+ }
+ return super.isFinal;
+ }
+
+ @override
+ List<ElementAnnotation> get metadata {
+ if (_unlinkedVariable != null) {
+ return _metadata ??= _unlinkedVariable.annotations
+ .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+ .toList();
+ }
+ return super.metadata;
+ }
+
+ @override
+ String get name {
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.name;
+ }
+ return super.name;
+ }
+
+ @override
+ int get nameOffset {
+ if (_unlinkedVariable != null) {
+ return _unlinkedVariable.nameOffset;
+ }
+ return super.nameOffset;
+ }
+}
+
+/**
* A concrete implementation of a [ParameterElement].
*/
class ParameterElementImpl extends VariableElementImpl
with ParameterElementMixin
implements ParameterElement {
/**
+ * The unlinked representation of the parameter in the summary.
+ */
+ final UnlinkedParam _unlinkedParam;
+
+ /**
* A list containing all of the parameters defined by this parameter element.
* There will only be parameters if this parameter is a function typed
* parameter.
@@ -4390,12 +4968,23 @@
* Initialize a newly created parameter element to have the given [name] and
* [nameOffset].
*/
- ParameterElementImpl(String name, int nameOffset) : super(name, nameOffset);
+ ParameterElementImpl(String name, int nameOffset)
+ : _unlinkedParam = null,
+ super(name, nameOffset);
/**
* Initialize a newly created parameter element to have the given [name].
*/
- ParameterElementImpl.forNode(Identifier name) : super.forNode(name);
+ ParameterElementImpl.forNode(Identifier name)
+ : _unlinkedParam = null,
+ super.forNode(name);
+
+ /**
+ * Initialize using the given serialized information.
+ */
+ ParameterElementImpl.forSerialized(
+ this._unlinkedParam, ElementImpl enclosingExecutable)
+ : super.forSerialized(enclosingExecutable);
/**
* Creates a synthetic parameter with [name], [type] and [kind].
@@ -4410,16 +4999,83 @@
}
@override
- String get defaultValueCode => _defaultValueCode;
+ int get codeLength {
+ if (_unlinkedParam != null) {
+ return _unlinkedParam.codeRange?.length;
+ }
+ return super.codeLength;
+ }
+
+ @override
+ int get codeOffset {
+ if (_unlinkedParam != null) {
+ return _unlinkedParam.codeRange?.offset;
+ }
+ return super.codeOffset;
+ }
+
+ @override
+ void set const3(bool isConst) {
+ assert(_unlinkedParam == null);
+ super.const3 = isConst;
+ }
+
+ @override
+ String get defaultValueCode {
+ if (_unlinkedParam != null) {
+ if (_unlinkedParam.defaultValue == null) {
+ return null;
+ }
+ return _unlinkedParam.defaultValueCode;
+ }
+ return _defaultValueCode;
+ }
/**
* Set Dart code of the default value.
*/
void set defaultValueCode(String defaultValueCode) {
+ assert(_unlinkedParam == null);
this._defaultValueCode = StringUtilities.intern(defaultValueCode);
}
@override
+ void set final2(bool isFinal) {
+ assert(_unlinkedParam == null);
+ super.final2 = isFinal;
+ }
+
+ @override
+ bool get hasImplicitType {
+ if (_unlinkedParam != null) {
+ return _unlinkedParam.type == null;
+ }
+ return super.hasImplicitType;
+ }
+
+ @override
+ void set hasImplicitType(bool hasImplicitType) {
+ assert(_unlinkedParam == null);
+ super.hasImplicitType = hasImplicitType;
+ }
+
+ @override
+ bool get isConst {
+ if (_unlinkedParam != null) {
+ return false;
+ }
+ return super.isConst;
+ }
+
+ @override
+ bool get isFinal {
+ if (_unlinkedParam != null) {
+ return false;
+ }
+ return super.isFinal;
+ }
+
+ @override
bool get isInitializingFormal => false;
@override
@@ -4432,6 +5088,38 @@
ElementKind get kind => ElementKind.PARAMETER;
@override
+ List<ElementAnnotation> get metadata {
+ if (_unlinkedParam != null) {
+ if (_unlinkedParam.annotations.isEmpty) {
+ return const <ElementAnnotation>[];
+ }
+ return _metadata ??= _unlinkedParam.annotations
+ .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+ .toList();
+ }
+ return super.metadata;
+ }
+
+ @override
+ String get name {
+ if (_unlinkedParam != null) {
+ return _unlinkedParam.name;
+ }
+ return super.name;
+ }
+
+ @override
+ int get nameOffset {
+ if (_unlinkedParam != null) {
+ if (isSynthetic) {
+ return -1;
+ }
+ return _unlinkedParam.nameOffset;
+ }
+ return super.nameOffset;
+ }
+
+ @override
List<ParameterElement> get parameters => _parameters;
/**
@@ -4461,6 +5149,13 @@
@override
SourceRange get visibleRange {
+ if (_unlinkedParam != null) {
+ if (_unlinkedParam.visibleLength == 0) {
+ return null;
+ }
+ return new SourceRange(
+ _unlinkedParam.visibleOffset, _unlinkedParam.visibleLength);
+ }
if (_visibleRangeLength < 0) {
return null;
}
@@ -4509,6 +5204,7 @@
* [offset] with the given [length].
*/
void setVisibleRange(int offset, int length) {
+ assert(_unlinkedParam == null);
_visibleRangeOffset = offset;
_visibleRangeLength = length;
}
@@ -4603,6 +5299,13 @@
PropertyAccessorElementImpl.forNode(Identifier name) : super.forNode(name);
/**
+ * Initialize using the given serialized information.
+ */
+ PropertyAccessorElementImpl.forSerialized(
+ UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement)
+ : super.forSerialized(serializedExecutable, enclosingElement);
+
+ /**
* Initialize a newly created synthetic property accessor element to be
* associated with the given [variable].
*/
@@ -4617,6 +5320,7 @@
* Set whether this accessor is abstract.
*/
void set abstract(bool isAbstract) {
+ assert(serializedExecutable == null);
setModifier(Modifier.ABSTRACT, isAbstract);
}
@@ -4636,10 +5340,21 @@
return variable.setter;
}
+ @override
+ String get displayName {
+ if (serializedExecutable != null && isSetter) {
+ String name = serializedExecutable.name;
+ assert(name.endsWith('='));
+ return name.substring(0, name.length - 1);
+ }
+ return super.displayName;
+ }
+
/**
* Set whether this accessor is a getter.
*/
void set getter(bool isGetter) {
+ assert(serializedExecutable == null);
setModifier(Modifier.GETTER, isGetter);
}
@@ -4654,13 +5369,29 @@
}
@override
- bool get isGetter => hasModifier(Modifier.GETTER);
+ bool get isGetter {
+ if (serializedExecutable != null) {
+ return serializedExecutable.kind == UnlinkedExecutableKind.getter;
+ }
+ return hasModifier(Modifier.GETTER);
+ }
@override
- bool get isSetter => hasModifier(Modifier.SETTER);
+ bool get isSetter {
+ if (serializedExecutable != null) {
+ return serializedExecutable.kind == UnlinkedExecutableKind.setter;
+ }
+ return hasModifier(Modifier.SETTER);
+ }
@override
- bool get isStatic => hasModifier(Modifier.STATIC);
+ bool get isStatic {
+ if (serializedExecutable != null) {
+ return serializedExecutable.isStatic ||
+ variable is TopLevelVariableElement;
+ }
+ return hasModifier(Modifier.STATIC);
+ }
@override
ElementKind get kind {
@@ -4672,6 +5403,9 @@
@override
String get name {
+ if (serializedExecutable != null) {
+ return serializedExecutable.name;
+ }
if (isSetter) {
return "${super.name}=";
}
@@ -4682,6 +5416,7 @@
* Set whether this accessor is a setter.
*/
void set setter(bool isSetter) {
+ assert(serializedExecutable == null);
setModifier(Modifier.SETTER, isSetter);
}
@@ -4689,6 +5424,7 @@
* Set whether this accessor is static.
*/
void set static(bool isStatic) {
+ assert(serializedExecutable == null);
setModifier(Modifier.STATIC, isStatic);
}
@@ -4724,8 +5460,8 @@
/**
* A concrete implementation of a [PropertyInducingElement].
*/
-abstract class PropertyInducingElementImpl extends VariableElementImpl
- implements PropertyInducingElement {
+abstract class PropertyInducingElementImpl
+ extends NonParameterVariableElementImpl implements PropertyInducingElement {
/**
* The getter associated with this element.
*/
@@ -4757,6 +5493,32 @@
}
/**
+ * The context in which elements are resynthesized.
+ */
+abstract class ResynthesizerContext {
+ /**
+ * Build [ElementAnnotationImpl] for the given [UnlinkedConst].
+ */
+ ElementAnnotationImpl buildAnnotation(UnlinkedConst uc);
+
+ /**
+ * Build [Expression] for the given [UnlinkedConst].
+ */
+ Expression buildExpression(UnlinkedConst uc);
+
+ /**
+ * Resolve an [EntityRef] into a type. If the reference is
+ * unresolved, return [DynamicTypeImpl.instance].
+ *
+ * TODO(paulberry): or should we have a class representing an
+ * unresolved type, for consistency with the full element model?
+ */
+ DartType resolveTypeRef(
+ EntityRef type, TypeParameterizedElementMixin typeParameterContext,
+ {bool defaultVoid: false, bool instantiateToBoundsAllowed: true});
+}
+
+/**
* A concrete implementation of a [ShowElementCombinator].
*/
class ShowElementCombinatorImpl implements ShowElementCombinator {
@@ -4829,39 +5591,160 @@
class TypeParameterElementImpl extends ElementImpl
implements TypeParameterElement {
/**
+ * The unlinked representation of the type parameter in the summary.
+ */
+ final UnlinkedTypeParam _unlinkedTypeParam;
+
+ /**
+ * The [TypeParameterizedElement] enclosing this one.
+ */
+ final TypeParameterizedElementMixin _enclosingTypeParameterizedElement;
+
+ /**
+ * The number of type parameters whose scope overlaps this one, and which are
+ * declared earlier in the file.
+ *
+ * TODO(scheglov) make private?
+ */
+ final int nestingLevel;
+
+ /**
* The type defined by this type parameter.
*/
- TypeParameterType type;
+ TypeParameterType _type;
/**
* The type representing the bound associated with this parameter, or `null`
* if this parameter does not have an explicit bound.
*/
- DartType bound;
+ DartType _bound;
/**
* Initialize a newly created method element to have the given [name] and
* [offset].
*/
- TypeParameterElementImpl(String name, int offset) : super(name, offset);
+ TypeParameterElementImpl(String name, int offset)
+ : _unlinkedTypeParam = null,
+ nestingLevel = null,
+ _enclosingTypeParameterizedElement = null,
+ super(name, offset);
/**
* Initialize a newly created type parameter element to have the given [name].
*/
- TypeParameterElementImpl.forNode(Identifier name) : super.forNode(name);
+ TypeParameterElementImpl.forNode(Identifier name)
+ : _unlinkedTypeParam = null,
+ nestingLevel = null,
+ _enclosingTypeParameterizedElement = null,
+ super.forNode(name);
+
+ /**
+ * Initialize using the given serialized information.
+ */
+ TypeParameterElementImpl.forSerialized(
+ this._unlinkedTypeParam,
+ ElementImpl enclosingElement,
+ this._enclosingTypeParameterizedElement,
+ this.nestingLevel)
+ : super.forSerialized(enclosingElement);
/**
* Initialize a newly created synthetic type parameter element to have the
* given [name], and with [synthetic] set to true.
*/
- TypeParameterElementImpl.synthetic(String name) : super(name, -1) {
+ TypeParameterElementImpl.synthetic(String name)
+ : _unlinkedTypeParam = null,
+ nestingLevel = null,
+ _enclosingTypeParameterizedElement = null,
+ super(name, -1) {
synthetic = true;
}
+ DartType get bound {
+ if (_unlinkedTypeParam != null) {
+ if (_unlinkedTypeParam.bound == null) {
+ return null;
+ }
+ return _bound ??= enclosingUnit.resynthesizerContext.resolveTypeRef(
+ _unlinkedTypeParam.bound, enclosingElement,
+ instantiateToBoundsAllowed: false);
+ }
+ return _bound;
+ }
+
+ void set bound(DartType bound) {
+ assert(_unlinkedTypeParam == null);
+ _bound = bound;
+ }
+
+ @override
+ int get codeLength {
+ if (_unlinkedTypeParam != null) {
+ return _unlinkedTypeParam.codeRange?.length;
+ }
+ return super.codeLength;
+ }
+
+ @override
+ int get codeOffset {
+ if (_unlinkedTypeParam != null) {
+ return _unlinkedTypeParam.codeRange?.offset;
+ }
+ return super.codeOffset;
+ }
+
+ @override
+ String get displayName => name;
+
+ @override
+ Element get enclosingElement {
+ if (_unlinkedTypeParam != null) {
+ return _enclosingTypeParameterizedElement;
+ }
+ return super.enclosingElement;
+ }
+
@override
ElementKind get kind => ElementKind.TYPE_PARAMETER;
@override
+ List<ElementAnnotation> get metadata {
+ if (_unlinkedTypeParam != null) {
+ return _metadata ??= _unlinkedTypeParam.annotations
+ .map(enclosingUnit.resynthesizerContext.buildAnnotation)
+ .toList();
+ }
+ return super.metadata;
+ }
+
+ @override
+ String get name {
+ if (_unlinkedTypeParam != null) {
+ return _unlinkedTypeParam.name;
+ }
+ return super.name;
+ }
+
+ @override
+ int get nameOffset {
+ if (_unlinkedTypeParam != null) {
+ return _unlinkedTypeParam.nameOffset;
+ }
+ return super.nameOffset;
+ }
+
+ TypeParameterType get type {
+ if (_unlinkedTypeParam != null) {
+ _type ??= new TypeParameterTypeImpl(this);
+ }
+ return _type;
+ }
+
+ void set type(TypeParameterType type) {
+ _type = type;
+ }
+
+ @override
accept(ElementVisitor visitor) => visitor.visitTypeParameterElement(this);
@override
@@ -4875,6 +5758,99 @@
}
/**
+ * Mixin representing an element which can have type parameters.
+ */
+abstract class TypeParameterizedElementMixin
+ implements TypeParameterizedElement, ElementImpl {
+ List<TypeParameterType> _typeParameterTypes;
+ List<TypeParameterElement> _typeParameterElements;
+ int _nestingLevel;
+
+ /**
+ * Get the type parameter context enclosing this one, if any.
+ */
+ TypeParameterizedElementMixin get enclosingTypeParameterContext;
+
+ /**
+ * The unit in which this element is resynthesized.
+ */
+ CompilationUnitElementImpl get enclosingUnit;
+
+ /**
+ * Find out how many type parameters are in scope in this context.
+ */
+ int get typeParameterNestingLevel =>
+ _nestingLevel ??= unlinkedTypeParams.length +
+ (enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0);
+
+ List<TypeParameterElement> get typeParameters {
+ if (_typeParameterElements == null) {
+ int enclosingNestingLevel =
+ enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0;
+ int numTypeParameters = unlinkedTypeParams.length;
+ _typeParameterElements =
+ new List<TypeParameterElement>(numTypeParameters);
+ for (int i = 0; i < numTypeParameters; i++) {
+ _typeParameterElements[i] = new TypeParameterElementImpl.forSerialized(
+ unlinkedTypeParams[i], this, this, enclosingNestingLevel + i);
+ }
+ }
+ return _typeParameterElements;
+ }
+
+ /**
+ * Get a list of [TypeParameterType] objects corresponding to the
+ * element's type parameters.
+ */
+ List<TypeParameterType> get typeParameterTypes {
+ if (_typeParameterTypes == null) {
+ _typeParameterTypes =
+ typeParameters.map((TypeParameterElement e) => e.type).toList();
+ }
+ return _typeParameterTypes;
+ }
+
+ /**
+ * Get the [UnlinkedTypeParam]s representing the type parameters declared by
+ * this element.
+ *
+ * TODO(scheglov) make private after switching linker to Impl
+ */
+ List<UnlinkedTypeParam> get unlinkedTypeParams;
+
+ /**
+ * Convert the given [index] into a type parameter type.
+ */
+ TypeParameterType getTypeParameterType(int index) {
+ List<TypeParameterType> types = typeParameterTypes;
+ if (index <= types.length) {
+ return types[types.length - index];
+ } else if (enclosingTypeParameterContext != null) {
+ return enclosingTypeParameterContext
+ .getTypeParameterType(index - types.length);
+ } else {
+ // If we get here, it means that a summary contained a type parameter index
+ // that was out of range.
+ throw new RangeError('Invalid type parameter index');
+ }
+ }
+
+ /**
+ * Find out if the given [typeParameter] is in scope in this context.
+ */
+ bool isTypeParameterInScope(TypeParameterElement typeParameter) {
+ if (typeParameter.enclosingElement == this) {
+ return true;
+ } else if (enclosingTypeParameterContext != null) {
+ return enclosingTypeParameterContext
+ .isTypeParameterInScope(typeParameter);
+ } else {
+ return false;
+ }
+ }
+}
+
+/**
* A concrete implementation of a [UriReferencedElement].
*/
abstract class UriReferencedElementImpl extends ElementImpl
@@ -4900,6 +5876,12 @@
* [offset]. The offset may be `-1` if the element is synthetic.
*/
UriReferencedElementImpl(String name, int offset) : super(name, offset);
+
+ /**
+ * Initialize using the given serialized information.
+ */
+ UriReferencedElementImpl.forSerialized(ElementImpl enclosingElement)
+ : super.forSerialized(enclosingElement);
}
/**
@@ -4930,6 +5912,12 @@
VariableElementImpl.forNode(Identifier name) : super.forNode(name);
/**
+ * Initialize using the given serialized information.
+ */
+ VariableElementImpl.forSerialized(ElementImpl enclosingElement)
+ : super.forSerialized(enclosingElement);
+
+ /**
* Set whether this variable is const.
*/
void set const3(bool isConst) {
@@ -4948,7 +5936,10 @@
Expression get constantInitializer => null;
@override
- DartObject get constantValue => null;
+ DartObject get constantValue => evaluationResult?.value;
+
+ @override
+ String get displayName => name;
/**
* Return the result of evaluating this variable's initializer as a
@@ -4975,7 +5966,9 @@
}
@override
- bool get hasImplicitType => hasModifier(Modifier.IMPLICIT_TYPE);
+ bool get hasImplicitType {
+ return hasModifier(Modifier.IMPLICIT_TYPE);
+ }
/**
* Set whether this variable element has an implicit type.
@@ -4999,10 +5992,14 @@
}
@override
- bool get isConst => hasModifier(Modifier.CONST);
+ bool get isConst {
+ return hasModifier(Modifier.CONST);
+ }
@override
- bool get isFinal => hasModifier(Modifier.FINAL);
+ bool get isFinal {
+ return hasModifier(Modifier.FINAL);
+ }
@override
bool get isPotentiallyMutatedInClosure => false;
@@ -5021,6 +6018,9 @@
}
@override
+ DartObject computeConstantValue() => null;
+
+ @override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
_initializer?.accept(visitor);
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index b922a4c..0e71499 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -98,29 +98,67 @@
List<TypeParameterElement> get typeParameters => actualElement.typeParameters;
@override
- ConstructorElement get unnamedConstructor => actualElement.unnamedConstructor;
+ ConstructorElement get unnamedConstructor {
+ ensureConstructorsReady();
+ return actualElement.unnamedConstructor;
+ }
@override
NamedCompilationUnitMember computeNode() => super.computeNode();
- @override
- FieldElement getField(String fieldName) => actualElement.getField(fieldName);
+ /**
+ * Ensure that [ClassElement.accessors] and [ClassElement.fields] are ready
+ * in [actualElement].
+ */
+ void ensureAccessorsReady() {}
+
+ /**
+ * The method is called by [ClassElementImpl.getImpl] before returning
+ * the [actualElement] as [ClassElementImpl]. At this moment we must ensure
+ * that [ClassElementImpl] is fully complete, we cannot continue filling it
+ * lazily.
+ */
+ void ensureActualElementComplete() {}
+
+ /**
+ * Ensure that [ClassElement.constructors] are ready in [actualElement].
+ */
+ void ensureConstructorsReady() {}
+
+ /**
+ * Ensure that [ClassElement.methods] are ready in [actualElement].
+ */
+ void ensureMethodsReady() {}
@override
- PropertyAccessorElement getGetter(String getterName) =>
- actualElement.getGetter(getterName);
+ FieldElement getField(String fieldName) {
+ ensureAccessorsReady();
+ return actualElement.getField(fieldName);
+ }
@override
- MethodElement getMethod(String methodName) =>
- actualElement.getMethod(methodName);
+ PropertyAccessorElement getGetter(String getterName) {
+ ensureAccessorsReady();
+ return actualElement.getGetter(getterName);
+ }
@override
- ConstructorElement getNamedConstructor(String name) =>
- actualElement.getNamedConstructor(name);
+ MethodElement getMethod(String methodName) {
+ ensureMethodsReady();
+ return actualElement.getMethod(methodName);
+ }
@override
- PropertyAccessorElement getSetter(String setterName) =>
- actualElement.getSetter(setterName);
+ ConstructorElement getNamedConstructor(String name) {
+ ensureConstructorsReady();
+ return actualElement.getNamedConstructor(name);
+ }
+
+ @override
+ PropertyAccessorElement getSetter(String setterName) {
+ ensureAccessorsReady();
+ return actualElement.getSetter(setterName);
+ }
@override
bool isSuperConstructorAccessible(ConstructorElement constructor) =>
@@ -128,8 +166,10 @@
@override
MethodElement lookUpConcreteMethod(
- String methodName, LibraryElement library) =>
- actualElement.lookUpConcreteMethod(methodName, library);
+ String methodName, LibraryElement library) {
+ ensureMethodsReady();
+ return actualElement.lookUpConcreteMethod(methodName, library);
+ }
@override
PropertyAccessorElement lookUpGetter(
@@ -138,32 +178,44 @@
@override
PropertyAccessorElement lookUpInheritedConcreteGetter(
- String methodName, LibraryElement library) =>
- actualElement.lookUpInheritedConcreteGetter(methodName, library);
+ String methodName, LibraryElement library) {
+ ensureAccessorsReady();
+ return actualElement.lookUpInheritedConcreteGetter(methodName, library);
+ }
@override
MethodElement lookUpInheritedConcreteMethod(
- String methodName, LibraryElement library) =>
- actualElement.lookUpInheritedConcreteMethod(methodName, library);
+ String methodName, LibraryElement library) {
+ ensureMethodsReady();
+ return actualElement.lookUpInheritedConcreteMethod(methodName, library);
+ }
@override
PropertyAccessorElement lookUpInheritedConcreteSetter(
- String methodName, LibraryElement library) =>
- actualElement.lookUpInheritedConcreteSetter(methodName, library);
+ String methodName, LibraryElement library) {
+ ensureAccessorsReady();
+ return actualElement.lookUpInheritedConcreteSetter(methodName, library);
+ }
@override
MethodElement lookUpInheritedMethod(
- String methodName, LibraryElement library) =>
- actualElement.lookUpInheritedMethod(methodName, library);
+ String methodName, LibraryElement library) {
+ ensureMethodsReady();
+ return actualElement.lookUpInheritedMethod(methodName, library);
+ }
@override
- MethodElement lookUpMethod(String methodName, LibraryElement library) =>
- actualElement.lookUpMethod(methodName, library);
+ MethodElement lookUpMethod(String methodName, LibraryElement library) {
+ ensureMethodsReady();
+ return actualElement.lookUpMethod(methodName, library);
+ }
@override
PropertyAccessorElement lookUpSetter(
- String setterName, LibraryElement library) =>
- actualElement.lookUpSetter(setterName, library);
+ String setterName, LibraryElement library) {
+ ensureAccessorsReady();
+ return actualElement.lookUpSetter(setterName, library);
+ }
}
/**
@@ -415,7 +467,8 @@
AstNode computeNode() => actualElement.computeNode();
@override
- Element getAncestor(Predicate<Element> predicate) =>
+ Element/*=E*/ getAncestor/*<E extends Element >*/(
+ Predicate<Element> predicate) =>
actualElement.getAncestor(predicate);
@override
@@ -1111,4 +1164,7 @@
@override
DartType get type => actualElement.type;
+
+ @override
+ DartObject computeConstantValue() => actualElement.computeConstantValue();
}
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index efb778f..025c7c5 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -515,7 +515,7 @@
AstNode computeNode() => _baseElement.computeNode();
@override
- Element getAncestor(Predicate<Element> predicate) =>
+ Element/*=E*/ getAncestor/*<E extends Element >*/(Predicate<Element> predicate) =>
baseElement.getAncestor(predicate);
@override
@@ -700,20 +700,19 @@
FormalParameter computeNode() => baseElement.computeNode();
@override
- Element getAncestor(Predicate<Element> predicate) {
+ Element/*=E*/ getAncestor/*<E extends Element>*/(Predicate<Element> predicate) {
Element element = baseElement.getAncestor(predicate);
ParameterizedType definingType = this.definingType;
if (definingType is InterfaceType) {
- InterfaceType definingInterfaceType = definingType;
if (element is ConstructorElement) {
- return ConstructorMember.from(element, definingInterfaceType);
+ return ConstructorMember.from(element, definingType) as Element/*=E*/;
} else if (element is MethodElement) {
- return MethodMember.from(element, definingInterfaceType);
+ return MethodMember.from(element, definingType) as Element/*=E*/;
} else if (element is PropertyAccessorElement) {
- return PropertyAccessorMember.from(element, definingInterfaceType);
+ return PropertyAccessorMember.from(element, definingType) as Element/*=E*/;
}
}
- return element;
+ return element as Element/*=E*/;
}
@override
@@ -1036,6 +1035,9 @@
bool get isStatic => baseElement.isStatic;
@override
+ DartObject computeConstantValue() => baseElement.computeConstantValue();
+
+ @override
void visitChildren(ElementVisitor visitor) {
// TODO(brianwilkerson) We need to finish implementing the accessors used
// below so that we can safely invoke them.
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index f2e9a15..42c8498 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1139,6 +1139,21 @@
final List<FunctionTypeAliasElement> prunedTypedefs;
/**
+ * Cached [ConstructorElement]s - members or raw elements.
+ */
+ List<ConstructorElement> _constructors;
+
+ /**
+ * Cached [PropertyAccessorElement]s - members or raw elements.
+ */
+ List<PropertyAccessorElement> _accessors;
+
+ /**
+ * Cached [MethodElement]s - members or raw elements.
+ */
+ List<MethodElement> _methods;
+
+ /**
* Initialize a newly created type to be declared by the given [element].
*/
InterfaceTypeImpl(ClassElement element, [this.prunedTypedefs])
@@ -1169,26 +1184,34 @@
InterfaceTypeImpl._(Element element, String name, this.prunedTypedefs)
: super(element, name);
+
@override
List<PropertyAccessorElement> get accessors {
- List<PropertyAccessorElement> accessors = element.accessors;
- List<PropertyAccessorElement> members =
- new List<PropertyAccessorElement>(accessors.length);
- for (int i = 0; i < accessors.length; i++) {
- members[i] = PropertyAccessorMember.from(accessors[i], this);
+ if (_accessors == null) {
+ List<PropertyAccessorElement> accessors = element.accessors;
+ List<PropertyAccessorElement> members =
+ new List<PropertyAccessorElement>(accessors.length);
+ for (int i = 0; i < accessors.length; i++) {
+ members[i] = PropertyAccessorMember.from(accessors[i], this);
+ }
+ _accessors = members;
}
- return members;
+ return _accessors;
}
+
@override
List<ConstructorElement> get constructors {
- List<ConstructorElement> constructors = element.constructors;
- List<ConstructorElement> members =
- new List<ConstructorElement>(constructors.length);
- for (int i = 0; i < constructors.length; i++) {
- members[i] = ConstructorMember.from(constructors[i], this);
+ if (_constructors == null) {
+ List<ConstructorElement> constructors = element.constructors;
+ List<ConstructorElement> members =
+ new List<ConstructorElement>(constructors.length);
+ for (int i = 0; i < constructors.length; i++) {
+ members[i] = ConstructorMember.from(constructors[i], this);
+ }
+ _constructors = members;
}
- return members;
+ return _constructors;
}
@override
@@ -1273,12 +1296,15 @@
@override
List<MethodElement> get methods {
- List<MethodElement> methods = element.methods;
- List<MethodElement> members = new List<MethodElement>(methods.length);
- for (int i = 0; i < methods.length; i++) {
- members[i] = MethodMember.from(methods[i], this);
+ if (_methods == null) {
+ List<MethodElement> methods = element.methods;
+ List<MethodElement> members = new List<MethodElement>(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ members[i] = MethodMember.from(methods[i], this);
+ }
+ _methods = members;
}
- return members;
+ return _methods;
}
@override
diff --git a/pkg/analyzer/lib/src/error/pending_error.dart b/pkg/analyzer/lib/src/error/pending_error.dart
new file mode 100644
index 0000000..6562166
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/pending_error.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2016, 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 analyzer.src.error.pending_error;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A pending error is an analysis error that could not be reported at the time
+ * it was discovered because some piece of information might be missing. After
+ * the information has been computed, the pending error can be converted into a
+ * real error.
+ */
+abstract class PendingError {
+ /**
+ * Create an analysis error based on the information in the pending error.
+ */
+ AnalysisError toAnalysisError();
+}
+
+/**
+ * A pending error used to compute either a [HintCode.MISSING_REQUIRED_PARAM] or
+ * [HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS] analysis error. These errors
+ * require that the value of the `@required` annotation be computed, which is
+ * not always true when the error is discovered.
+ */
+class PendingMissingRequiredParameterError implements PendingError {
+ /**
+ * The source against which the error will be reported.
+ */
+ final Source source;
+
+ /**
+ * The name of the parameter that is required.
+ */
+ final String parameterName;
+
+ /**
+ * The offset of the name of the method / function at the invocation site.
+ */
+ final int offset;
+
+ /**
+ * The length of the name of the method / function at the invocation site.
+ */
+ final int length;
+
+ /**
+ * The `@required` annotation whose value is used to compose the error message.
+ */
+ final ElementAnnotation annotation;
+
+ /**
+ * Initialize a newly created pending error.
+ */
+ PendingMissingRequiredParameterError(
+ this.source, this.parameterName, AstNode node, this.annotation)
+ : offset = node.offset,
+ length = node.length;
+
+ @override
+ AnalysisError toAnalysisError() {
+ HintCode errorCode;
+ List<String> arguments;
+ DartObject constantValue = annotation.constantValue;
+ String reason = constantValue?.getField('reason')?.toStringValue();
+ if (reason != null) {
+ errorCode = HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS;
+ arguments = [parameterName, reason];
+ } else {
+ errorCode = HintCode.MISSING_REQUIRED_PARAM;
+ arguments = [parameterName];
+ }
+ return new AnalysisError(source, offset, length, errorCode, arguments);
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 8db8ee0..972043a 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -729,11 +729,16 @@
static const String SUFFIX_HTML = "html";
/**
- * The file name used for analysis options files.
+ * The deprecated file name used for analysis options files.
*/
static const String ANALYSIS_OPTIONS_FILE = '.analysis_options';
/**
+ * The file name used for analysis options files.
+ */
+ static const String ANALYSIS_OPTIONS_YAML_FILE = 'analysis_options.yaml';
+
+ /**
* The unique instance of this class.
*/
static final AnalysisEngine instance = new AnalysisEngine._();
@@ -876,8 +881,9 @@
if (fileName == null) {
return false;
}
- return (context ?? pathos.posix).basename(fileName) ==
- ANALYSIS_OPTIONS_FILE;
+ String basename = (context ?? pathos.posix).basename(fileName);
+ return basename == ANALYSIS_OPTIONS_FILE ||
+ basename == ANALYSIS_OPTIONS_YAML_FILE;
}
/**
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 5d0cee2..c21e7e6 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -50,7 +50,7 @@
/**
* A [Comparator] that sorts error codes first by their severity (errors
- * first, warnings second), and then by the the error code type.
+ * first, warnings second), and then by the error code type.
*/
static Comparator<AnalysisError> ERROR_CODE_COMPARATOR =
(AnalysisError o1, AnalysisError o2) {
@@ -3595,7 +3595,8 @@
* 1: message details
*/
static const HintCode MISSING_REQUIRED_PARAM_WITH_DETAILS = const HintCode(
- 'MISSING_REQUIRED_PARAM', "The parameter '{0}' is required. {1}");
+ 'MISSING_REQUIRED_PARAM_WITH_DETAILS',
+ "The parameter '{0}' is required. {1}");
/**
* Generate a hint for an element that is annotated with `@JS(...)` whose
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 537ca31..d201e96 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -18,6 +18,7 @@
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
+import 'package:analyzer/src/error/pending_error.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -26,7 +27,9 @@
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary;
+import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/src/task/strong/info.dart' show StaticInfo;
/**
@@ -829,8 +832,6 @@
if (type is InterfaceType) {
_checkForConstOrNewWithAbstractClass(node, typeName, type);
_checkForConstOrNewWithEnum(node, typeName, type);
- _checkForMissingRequiredParam(
- node.staticElement?.type, node.argumentList, node.constructorName);
if (_isInConstInstanceCreation) {
_checkForConstWithNonConst(node);
_checkForConstWithUndefinedConstructor(
@@ -942,8 +943,6 @@
} else {
_checkForUnqualifiedReferenceToNonLocalStaticMember(methodName);
}
- _checkForMissingRequiredParam(
- node.staticInvokeType, node.argumentList, methodName);
_checkTypeArguments(
node.methodName.staticElement, node.typeArguments, target?.staticType);
return super.visitMethodInvocation(node);
@@ -4246,34 +4245,6 @@
}
}
- void _checkForMissingRequiredParam(
- DartType type, ArgumentList argumentList, AstNode node) {
- if (type is FunctionType) {
- List<ParameterElement> parameters = type.parameters;
- for (ParameterElement param in parameters) {
- if (param.parameterKind == ParameterKind.NAMED) {
- ElementAnnotationImpl annotation = _getRequiredAnnotation(param);
- if (annotation != null) {
- String paramName = param.name;
- if (!_containsNamedExpression(argumentList, paramName)) {
- DartObject constantValue = annotation.constantValue;
- String reason = constantValue.getField('reason')?.toStringValue();
- if (reason != null) {
- _errorReporter.reportErrorForNode(
- HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
- node,
- [paramName, reason]);
- } else {
- _errorReporter.reportErrorForNode(
- HintCode.MISSING_REQUIRED_PARAM, node, [paramName]);
- }
- }
- }
- }
- }
- }
- }
-
/**
* Verify that the given function [body] does not contain return statements
* that both have and do not have return values.
@@ -5040,7 +5011,7 @@
}
/**
- * Check that if the the given constructor [declaration] is generative, then
+ * Check that if the given constructor [declaration] is generative, then
* it does not have an expression function body.
*
* See [CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR].
@@ -5235,8 +5206,8 @@
NodeList<TypeName> typeNameArgList = typeName.typeArguments.arguments;
int loopThroughIndex =
math.min(typeNameArgList.length, parameterElements.length);
- bool shouldSubstitute = arguments.length != 0 &&
- arguments.length == parameterTypes.length;
+ bool shouldSubstitute =
+ arguments.length != 0 && arguments.length == parameterTypes.length;
for (int i = 0; i < loopThroughIndex; i++) {
TypeName argTypeName = typeNameArgList[i];
DartType argType = argTypeName.type;
@@ -5760,17 +5731,6 @@
return staticReturnType;
}
- bool _containsNamedExpression(ArgumentList args, String name) {
- for (Expression expression in args.arguments) {
- if (expression is NamedExpression) {
- if (expression.name.label.name == name) {
- return true;
- }
- }
- }
- return false;
- }
-
bool _expressionIsAssignableAtType(Expression expression,
DartType actualStaticType, DartType expectedStaticType) {
bool concrete =
@@ -5864,10 +5824,6 @@
return _inheritanceManager.lookupInheritance(classElement, member.name);
}
- ElementAnnotationImpl _getRequiredAnnotation(ParameterElement param) => param
- .metadata
- .firstWhere((ElementAnnotation e) => e.isRequired, orElse: () => null);
-
/**
* Return the type of the first and only parameter of the given [setter].
*/
@@ -6228,6 +6184,88 @@
}
/**
+ * A class used to compute a list of the constants whose value needs to be
+ * computed before errors can be computed by the [VerifyUnitTask].
+ */
+class RequiredConstantsComputer extends RecursiveAstVisitor {
+ /**
+ * The source with which any pending errors will be associated.
+ */
+ final Source source;
+
+ /**
+ * A list of the pending errors that were computed.
+ */
+ final List<PendingError> pendingErrors = <PendingError>[];
+
+ /**
+ * A list of the constants whose value needs to be computed before the pending
+ * errors can be used to compute an analysis error.
+ */
+ final List<ConstantEvaluationTarget> requiredConstants =
+ <ConstantEvaluationTarget>[];
+
+ /**
+ * Initialize a newly created computer to compute required constants within
+ * the given [source].
+ */
+ RequiredConstantsComputer(this.source);
+
+ @override
+ Object visitInstanceCreationExpression(InstanceCreationExpression node) {
+ DartType type = node.constructorName.type.type;
+ if (type is InterfaceType) {
+ _checkForMissingRequiredParam(
+ node.staticElement?.type, node.argumentList, node.constructorName);
+ }
+ return super.visitInstanceCreationExpression(node);
+ }
+
+ @override
+ Object visitMethodInvocation(MethodInvocation node) {
+ _checkForMissingRequiredParam(
+ node.staticInvokeType, node.argumentList, node.methodName);
+ return super.visitMethodInvocation(node);
+ }
+
+ void _checkForMissingRequiredParam(
+ DartType type, ArgumentList argumentList, AstNode node) {
+ if (type is FunctionType) {
+ for (ParameterElement parameter in type.parameters) {
+ if (parameter.parameterKind == ParameterKind.NAMED) {
+ ElementAnnotationImpl annotation = _getRequiredAnnotation(parameter);
+ if (annotation != null) {
+ String parameterName = parameter.name;
+ if (!_containsNamedExpression(argumentList, parameterName)) {
+ requiredConstants.add(annotation);
+ pendingErrors.add(new PendingMissingRequiredParameterError(
+ source, parameterName, node, annotation));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ bool _containsNamedExpression(ArgumentList args, String name) {
+ NodeList<Expression> arguments = args.arguments;
+ for (int i = arguments.length - 1; i >= 0; i--) {
+ Expression expression = arguments[i];
+ if (expression is NamedExpression) {
+ if (expression.name.label.name == name) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ ElementAnnotationImpl _getRequiredAnnotation(ParameterElement param) => param
+ .metadata
+ .firstWhere((ElementAnnotation e) => e.isRequired, orElse: () => null);
+}
+
+/**
* Recursively visits an AST, looking for method invocations.
*/
class _InvocationCollector extends RecursiveAstVisitor {
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 777d130..7f9657f 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -3577,17 +3577,17 @@
bool outerBreakValue = _enclosingBlockContainsBreak;
_enclosingBlockContainsBreak = false;
try {
+ if (_nodeExits(node.body)) {
+ return true;
+ }
Expression conditionExpression = node.condition;
if (_nodeExits(conditionExpression)) {
return true;
}
// TODO(jwren) Do we want to take all constant expressions into account?
if (conditionExpression is BooleanLiteral) {
- // If do {} while (true), and the body doesn't return or the body
- // doesn't have a break, then return true.
- bool blockReturns = _nodeExits(node.body);
- if (conditionExpression.value &&
- (blockReturns || !_enclosingBlockContainsBreak)) {
+ // If do {} while (true), and the body doesn't break, then return true.
+ if (conditionExpression.value && !_enclosingBlockContainsBreak) {
return true;
}
}
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index 9bf52bf..0d053f6b 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -284,8 +284,9 @@
if (_useSummary) {
PackageBundle sdkBundle = getSummarySdkBundle();
if (sdkBundle != null) {
- _analysisContext.resultProvider =
- new SdkSummaryResultProvider(_analysisContext, sdkBundle);
+ bool strongMode = _analysisOptions?.strongMode ?? false;
+ _analysisContext.resultProvider = new SdkSummaryResultProvider(
+ _analysisContext, sdkBundle, strongMode);
}
}
}
@@ -414,6 +415,11 @@
List<String> get uris => _libraryMap.uris;
/**
+ * Whether an SDK summary should be used.
+ */
+ bool get useSummary => _useSummary;
+
+ /**
* Specify whether SDK summary should be used.
*/
void set useSummary(bool use) {
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 3032565..4ba4c51 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -441,7 +441,7 @@
/**
* Get the contents and timestamp of this source.
*
- * Clients should consider using the the method [AnalysisContext.getContents]
+ * Clients should consider using the method [AnalysisContext.getContents]
* because contexts can have local overrides of the content of a source that the source is not
* aware of.
*
@@ -492,7 +492,7 @@
* will be returned, but if the contents of the source have been modified one
* or more times (even if the net change is zero) the stamps will be different.
*
- * Clients should consider using the the method
+ * Clients should consider using the method
* [AnalysisContext.getModificationStamp] because contexts can have local
* overrides of the content of a source that the source is not aware of.
*/
@@ -541,7 +541,7 @@
/**
* Return `true` if this source exists.
*
- * Clients should consider using the the method [AnalysisContext.exists] because
+ * Clients should consider using the method [AnalysisContext.exists] because
* contexts can have local overrides of the content of a source that the source is not aware of
* and a source with local content is considered to exist even if there is no file on disk.
*
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 5b25c2c..491e3eb 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -191,7 +191,7 @@
/**
* Get the contents and timestamp of the underlying file.
*
- * Clients should consider using the the method [AnalysisContext.getContents]
+ * Clients should consider using the method [AnalysisContext.getContents]
* because contexts can have local overrides of the content of a source that the source is not
* aware of.
*
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 877944a..19b5be5 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -752,7 +752,7 @@
* to #2.
*
* It's not immediately obvious why this is symmetric in the case that both
- * of the them are type parameters. For #1, symmetry holds since subtype
+ * of them are type parameters. For #1, symmetry holds since subtype
* is antisymmetric. For #2, it's clearly not symmetric if upper bounds of
* bottom are allowed. Ignoring this (for various reasons, not least
* of which that there's no way to write it), there's an informal
@@ -1330,18 +1330,13 @@
if (t1 is TypeParameterType) {
_TypeParameterBound bound = _bounds[t1];
if (bound != null) {
- _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
-
- DartType newUpper = t2;
- if (guardedSubtype(bound.upper, newUpper, visited)) {
- // upper bound already covers this. Nothing to do.
- } else if (guardedSubtype(newUpper, bound.upper, visited)) {
- // update to the new, more precise upper bound.
- bound.upper = newUpper;
- } else {
- // Failed to find an upper bound. Use bottom to signal no solution.
- bound.upper = BottomTypeImpl.instance;
- }
+ // Ensure T1 <: T2, where T1 is a type parameter we are inferring.
+ // T2 is an upper bound, so merge it with our existing upper bound.
+ //
+ // We already know T1 <: U, for some U.
+ // So update U to reflect the new constraint T1 <: GLB(U, T2)
+ //
+ bound.upper = getGreatestLowerBound(_typeProvider, bound.upper, t2);
// Optimistically assume we will be able to satisfy the constraint.
return true;
}
@@ -1349,6 +1344,12 @@
if (t2 is TypeParameterType) {
_TypeParameterBound bound = _bounds[t2];
if (bound != null) {
+ // Ensure T1 <: T2, where T2 is a type parameter we are inferring.
+ // T1 is a lower bound, so merge it with our existing lower bound.
+ //
+ // We already know L <: T2, for some L.
+ // So update L to reflect the new constraint LUB(L, T1) <: T2
+ //
bound.lower = getLeastUpperBound(_typeProvider, bound.lower, t1);
// Optimistically assume we will be able to satisfy the constraint.
return true;
@@ -1430,7 +1431,7 @@
void _visitFunctionType(
TypeParameterType typeParam, FunctionType type, bool paramIn) {
for (ParameterElement p in type.parameters) {
- // If a lambda L is passed in to a function F, the the parameters are
+ // If a lambda L is passed in to a function F, the parameters are
// "passed out" of F into L. Thus we invert the "passedIn" state.
_visitType(typeParam, p.type, !paramIn);
}
diff --git a/pkg/analyzer/lib/src/plugin/command_line_plugin.dart b/pkg/analyzer/lib/src/plugin/command_line_plugin.dart
index ffd43be..b2f8c58 100644
--- a/pkg/analyzer/lib/src/plugin/command_line_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/command_line_plugin.dart
@@ -33,12 +33,12 @@
* The extension point that allows plugins to register new parser
* contributors.
*/
- ExtensionPoint parserContributorExtensionPoint;
+ ExtensionPoint<ArgParserContributor> parserContributorExtensionPoint;
/**
* The extension point that allows plugins to register new result processors.
*/
- ExtensionPoint resultProcessorExtensionPoint;
+ ExtensionPoint<ArgResultsProcessor> resultProcessorExtensionPoint;
/**
* Initialize a newly created plugin.
@@ -64,39 +64,16 @@
@override
void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
- parserContributorExtensionPoint = registerExtensionPoint(
- PARSER_CONTRIBUTOR_EXTENSION_POINT,
- _validateParserContributorExtension);
- resultProcessorExtensionPoint = registerExtensionPoint(
- RESULT_PROCESSOR_EXTENSION_POINT, _validateResultProcessorExtension);
+ parserContributorExtensionPoint = new ExtensionPoint<ArgParserContributor>(
+ this, PARSER_CONTRIBUTOR_EXTENSION_POINT, null);
+ registerExtensionPoint(parserContributorExtensionPoint);
+ resultProcessorExtensionPoint = new ExtensionPoint<ArgResultsProcessor>(
+ this, RESULT_PROCESSOR_EXTENSION_POINT, null);
+ registerExtensionPoint(resultProcessorExtensionPoint);
}
@override
void registerExtensions(RegisterExtension registerExtension) {
// There are no default extensions.
}
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid parser contributor.
- */
- void _validateParserContributorExtension(Object extension) {
- if (extension is! ArgParserContributor) {
- String id = parserContributorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be an ArgParserContributor');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not a
- * valid result processor.
- */
- void _validateResultProcessorExtension(Object extension) {
- if (extension is! ArgResultsProcessor) {
- String id = resultProcessorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be an ArgResultsProcessor');
- }
- }
}
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 69b74c6..8e47707 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -66,31 +66,33 @@
* The extension point that allows plugins to register new analysis error
* results for a Dart source.
*/
- ExtensionPoint dartErrorsForSourceExtensionPoint;
+ ExtensionPoint<ListResultDescriptor<AnalysisError>>
+ dartErrorsForSourceExtensionPoint;
/**
* The extension point that allows plugins to register new analysis error
* results for a Dart library specific unit.
*/
- ExtensionPoint dartErrorsForUnitExtensionPoint;
+ ExtensionPoint<ListResultDescriptor<AnalysisError>>
+ dartErrorsForUnitExtensionPoint;
/**
* The extension point that allows plugins to register new analysis error
* results for an HTML source.
*/
- ExtensionPoint htmlErrorsExtensionPoint;
+ ExtensionPoint<ListResultDescriptor<AnalysisError>> htmlErrorsExtensionPoint;
/**
* The extension point that allows plugins to register new analysis tasks with
* the analysis engine.
*/
- ExtensionPoint taskExtensionPoint;
+ ExtensionPoint<TaskDescriptor> taskExtensionPoint;
/**
* The extension point that allows plugins to register new work manager
* factories with the analysis engine.
*/
- ExtensionPoint workManagerFactoryExtensionPoint;
+ ExtensionPoint<WorkManagerFactory> workManagerFactoryExtensionPoint;
/**
* Initialize a newly created plugin.
@@ -137,20 +139,24 @@
@override
void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
- dartErrorsForSourceExtensionPoint = registerExtensionPoint(
- DART_ERRORS_FOR_SOURCE_EXTENSION_POINT,
- _validateAnalysisErrorListResultDescriptor);
- dartErrorsForUnitExtensionPoint = registerExtensionPoint(
- DART_ERRORS_FOR_UNIT_EXTENSION_POINT,
- _validateAnalysisErrorListResultDescriptor);
- htmlErrorsExtensionPoint = registerExtensionPoint(
- HTML_ERRORS_EXTENSION_POINT,
- _validateAnalysisErrorListResultDescriptor);
+ dartErrorsForSourceExtensionPoint =
+ new ExtensionPoint<ListResultDescriptor<AnalysisError>>(
+ this, DART_ERRORS_FOR_SOURCE_EXTENSION_POINT, null);
+ registerExtensionPoint(dartErrorsForSourceExtensionPoint);
+ dartErrorsForUnitExtensionPoint =
+ new ExtensionPoint<ListResultDescriptor<AnalysisError>>(
+ this, DART_ERRORS_FOR_UNIT_EXTENSION_POINT, null);
+ registerExtensionPoint(dartErrorsForUnitExtensionPoint);
+ htmlErrorsExtensionPoint =
+ new ExtensionPoint<ListResultDescriptor<AnalysisError>>(
+ this, HTML_ERRORS_EXTENSION_POINT, null);
+ registerExtensionPoint(htmlErrorsExtensionPoint);
taskExtensionPoint =
- registerExtensionPoint(TASK_EXTENSION_POINT, _validateTaskExtension);
- workManagerFactoryExtensionPoint = registerExtensionPoint(
- WORK_MANAGER_FACTORY_EXTENSION_POINT,
- _validateWorkManagerFactoryExtension);
+ new ExtensionPoint<TaskDescriptor>(this, TASK_EXTENSION_POINT, null);
+ registerExtensionPoint(taskExtensionPoint);
+ workManagerFactoryExtensionPoint = new ExtensionPoint<WorkManagerFactory>(
+ this, WORK_MANAGER_FACTORY_EXTENSION_POINT, null);
+ registerExtensionPoint(workManagerFactoryExtensionPoint);
}
@override
@@ -198,6 +204,7 @@
registerExtension(
taskId, ComputeInferableStaticVariableDependenciesTask.DESCRIPTOR);
registerExtension(taskId, ComputeLibraryCycleTask.DESCRIPTOR);
+ registerExtension(taskId, ComputeRequiredConstantsTask.DESCRIPTOR);
registerExtension(
taskId, ComputePropagableVariableDependenciesTask.DESCRIPTOR);
registerExtension(taskId, ContainingLibrariesTask.DESCRIPTOR);
@@ -259,41 +266,6 @@
registerExtension(taskId,
(InternalAnalysisContext context) => new OptionsWorkManager(context));
}
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not
- * a [ListResultDescriptor] of [AnalysisError]s.
- */
- void _validateAnalysisErrorListResultDescriptor(Object extension) {
- if (extension is! ListResultDescriptor<AnalysisError>) {
- String id = taskExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be a ListResultDescriptor<AnalysisError>');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not
- * a [TaskDescriptor].
- */
- void _validateTaskExtension(Object extension) {
- if (extension is! TaskDescriptor) {
- String id = taskExtensionPoint.uniqueIdentifier;
- throw new ExtensionError('Extensions to $id must be a TaskDescriptor');
- }
- }
-
- /**
- * Validate the given extension by throwing an [ExtensionError] if it is not
- * a [WorkManagerFactory].
- */
- void _validateWorkManagerFactoryExtension(Object extension) {
- if (extension is! WorkManagerFactory) {
- String id = taskExtensionPoint.uniqueIdentifier;
- throw new ExtensionError(
- 'Extensions to $id must be a WorkManagerFactory');
- }
- }
}
/**
diff --git a/pkg/analyzer/lib/src/plugin/options_plugin.dart b/pkg/analyzer/lib/src/plugin/options_plugin.dart
index 9a4fc01..aceaf3b 100644
--- a/pkg/analyzer/lib/src/plugin/options_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/options_plugin.dart
@@ -26,31 +26,31 @@
/// The extension point that allows plugins to register new options
/// processors.
- ExtensionPoint optionsProcessorExtensionPoint;
+ ExtensionPoint<OptionsProcessor> optionsProcessorExtensionPoint;
/// The extension point that allows plugins to register new options
/// validators.
- ExtensionPoint optionsValidatorExtensionPoint;
+ ExtensionPoint<OptionsValidator> optionsValidatorExtensionPoint;
/// All contributed options processors.
List<OptionsProcessor> get optionsProcessors =>
- optionsProcessorExtensionPoint?.extensions as List<OptionsProcessor> ??
- const <OptionsProcessor>[];
+ optionsProcessorExtensionPoint?.extensions ?? const <OptionsProcessor>[];
/// All contributed options validators.
List<OptionsValidator> get optionsValidators =>
- optionsValidatorExtensionPoint?.extensions as List<OptionsValidator> ??
- const <OptionsValidator>[];
+ optionsValidatorExtensionPoint?.extensions ?? const <OptionsValidator>[];
@override
String get uniqueIdentifier => UNIQUE_IDENTIFIER;
@override
void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
- optionsProcessorExtensionPoint = registerExtensionPoint(
- OPTIONS_PROCESSOR_EXTENSION_POINT, _validateOptionsProcessorExtension);
- optionsValidatorExtensionPoint = registerExtensionPoint(
- OPTIONS_VALIDATOR_EXTENSION_POINT, _validateOptionsValidatorExtension);
+ optionsProcessorExtensionPoint = new ExtensionPoint<OptionsProcessor>(
+ this, OPTIONS_PROCESSOR_EXTENSION_POINT, null);
+ registerExtensionPoint(optionsProcessorExtensionPoint);
+ optionsValidatorExtensionPoint = new ExtensionPoint<OptionsValidator>(
+ this, OPTIONS_VALIDATOR_EXTENSION_POINT, null);
+ registerExtensionPoint(optionsValidatorExtensionPoint);
}
@override
@@ -62,22 +62,4 @@
registerExtension(
OPTIONS_VALIDATOR_EXTENSION_POINT_ID, new AnalyzerOptionsValidator());
}
-
- /// Validate the given extension by throwing an [ExtensionError] if it is not
- /// a valid options processor.
- void _validateOptionsProcessorExtension(Object extension) {
- if (extension is! OptionsProcessor) {
- String id = optionsProcessorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError('Extensions to $id must be an OptionsProcessor');
- }
- }
-
- /// Validate the given extension by throwing an [ExtensionError] if it is not
- /// a valid options validator.
- void _validateOptionsValidatorExtension(Object extension) {
- if (extension is! OptionsValidator) {
- String id = optionsValidatorExtensionPoint.uniqueIdentifier;
- throw new ExtensionError('Extensions to $id must be an OptionsValidator');
- }
- }
}
diff --git a/pkg/analyzer/lib/src/services/lint.dart b/pkg/analyzer/lib/src/services/lint.dart
index 3b36457..3eea1b7 100644
--- a/pkg/analyzer/lib/src/services/lint.dart
+++ b/pkg/analyzer/lib/src/services/lint.dart
@@ -25,8 +25,7 @@
/// Return lints associated with this [context], or an empty list if there are
/// none.
List<Linter> getLints(AnalysisContext context) =>
- context.getConfigurationData(CONFIGURED_LINTS_KEY) as List<Linter> ??
- _noLints;
+ context.getConfigurationData(CONFIGURED_LINTS_KEY) ?? _noLints;
/// Associate these [lints] with the given [context].
void setLints(AnalysisContext context, List<Linter> lints) {
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index bc2fc0d..6dc797a 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -160,7 +160,7 @@
EntityRefBuilder _createLinkedType(
DartType type,
CompilationUnitElementInBuildUnit compilationUnit,
- TypeParameterizedElementForLink typeParameterContext,
+ TypeParameterizedElementMixin typeParameterContext,
{int slot}) {
EntityRefBuilder result = new EntityRefBuilder(slot: slot);
if (type is InterfaceType) {
@@ -179,7 +179,7 @@
result.reference = compilationUnit.addRawReference('*bottom*');
return result;
} else if (type is TypeParameterType) {
- TypeParameterElementForLink element = type.element;
+ TypeParameterElementImpl element = type.element;
if (typeParameterContext.isTypeParameterInScope(element)) {
result.paramReference =
typeParameterContext.typeParameterNestingLevel - element.nestingLevel;
@@ -251,7 +251,7 @@
UnlinkedParamBuilder _serializeSyntheticParam(
ParameterElement parameter,
CompilationUnitElementInBuildUnit compilationUnit,
- TypeParameterizedElementForLink typeParameterContext) {
+ TypeParameterizedElementMixin typeParameterContext) {
UnlinkedParamBuilder b = new UnlinkedParamBuilder();
b.name = parameter.name;
switch (parameter.parameterKind) {
@@ -290,7 +290,7 @@
List<DartType> typeArguments,
EntityRefBuilder encodedType,
CompilationUnitElementInBuildUnit compilationUnit,
- TypeParameterizedElementForLink typeParameterContext) {
+ TypeParameterizedElementMixin typeParameterContext) {
int count = typeArguments.length;
List<EntityRefBuilder> encodedTypeArguments =
new List<EntityRefBuilder>(count);
@@ -317,8 +317,9 @@
* Element representing a class or enum resynthesized from a summary
* during linking.
*/
-abstract class ClassElementForLink
- implements ClassElementImpl, ReferenceableElementForLink {
+abstract class ClassElementForLink extends Object
+ with ReferenceableElementForLink
+ implements ClassElementImpl {
Map<String, ReferenceableElementForLink> _containedNames;
@override
@@ -338,21 +339,10 @@
ConstructorElementForLink get asConstructor => unnamedConstructor;
@override
- ConstVariableNode get asConstVariable {
- // When a class name is used as a constant variable, it doesn't depend on
- // anything, so it is not necessary to include it in the constant
- // dependency graph.
- return null;
- }
-
- @override
DartType get asStaticType =>
enclosingElement.enclosingElement._linker.typeProvider.typeType;
@override
- TypeInferenceNode get asTypeInferenceNode => null;
-
- @override
List<ConstructorElementForLink> get constructors;
@override
@@ -373,6 +363,9 @@
String get name;
@override
+ ResynthesizerContext get resynthesizerContext => enclosingElement;
+
+ @override
ConstructorElementForLink get unnamedConstructor;
@override
@@ -384,14 +377,10 @@
_containedNames[constructor.name] = constructor;
}
for (PropertyAccessorElementForLink accessor in accessors) {
- if (accessor.isStatic) {
- _containedNames[accessor.name] = accessor;
- }
+ _containedNames[accessor.name] = accessor;
}
for (MethodElementForLink method in methods) {
- if (method.isStatic) {
- _containedNames[method.name] = method;
- }
+ _containedNames[method.name] = method;
}
}
return _containedNames.putIfAbsent(
@@ -413,7 +402,7 @@
* linking.
*/
class ClassElementForLink_Class extends ClassElementForLink
- with TypeParameterizedElementForLink {
+ with TypeParameterizedElementMixin {
/**
* The unlinked representation of the class in the summary.
*/
@@ -473,9 +462,6 @@
}
@override
- CompilationUnitElementForLink get compilationUnit => enclosingElement;
-
- @override
List<ConstructorElementForLink> get constructors {
if (_constructors == null) {
_constructors = <ConstructorElementForLink>[];
@@ -499,7 +485,7 @@
String get displayName => _unlinkedClass.name;
@override
- TypeParameterizedElementForLink get enclosingTypeParameterContext => null;
+ TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
@override
List<FieldElementForLink_ClassField> get fields {
@@ -563,6 +549,10 @@
_type ??= buildType((int i) => typeParameterTypes[i], null);
@override
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
+ _unlinkedClass.typeParameters;
+
+ @override
ConstructorElementForLink get unnamedConstructor {
if (!_unnamedConstructorComputed) {
for (ConstructorElementForLink constructor in constructors) {
@@ -577,10 +567,6 @@
}
@override
- List<UnlinkedTypeParam> get _unlinkedTypeParams =>
- _unlinkedClass.typeParameters;
-
- @override
DartType buildType(
DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
int numTypeParameters = _unlinkedClass.typeParameters.length;
@@ -644,7 +630,7 @@
*/
InterfaceType _computeInterfaceType(EntityRef typeRef) {
if (typeRef != null) {
- DartType type = enclosingElement._resolveTypeRef(typeRef, this);
+ DartType type = enclosingElement.resolveTypeRef(typeRef, this);
if (type is InterfaceType) {
return type;
}
@@ -754,7 +740,7 @@
* summary during linking.
*/
abstract class CompilationUnitElementForLink
- implements CompilationUnitElementImpl {
+ implements CompilationUnitElementImpl, ResynthesizerContext {
/**
* The unlinked representation of the compilation unit in the
* summary.
@@ -886,6 +872,9 @@
LibraryElementForLink get library => enclosingElement;
@override
+ ResynthesizerContext get resynthesizerContext => this;
+
+ @override
List<TopLevelVariableElementForLink> get topLevelVariables {
if (_topLevelVariables == null) {
_topLevelVariables = <TopLevelVariableElementForLink>[];
@@ -951,12 +940,45 @@
* given slot, `dynamic` is returned.
*/
DartType getLinkedType(
- int slot, TypeParameterizedElementForLink typeParameterContext);
+ int slot, TypeParameterizedElementMixin typeParameterContext);
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
+ DartType resolveTypeRef(
+ EntityRef type, TypeParameterizedElementMixin typeParameterContext,
+ {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
+ if (type == null) {
+ if (defaultVoid) {
+ return VoidTypeImpl.instance;
+ } else {
+ return DynamicTypeImpl.instance;
+ }
+ }
+ if (type.paramReference != 0) {
+ return typeParameterContext.getTypeParameterType(type.paramReference);
+ } else if (type.syntheticReturnType != null) {
+ // TODO(paulberry): implement.
+ throw new UnimplementedError();
+ } else if (type.implicitFunctionTypeIndices.isNotEmpty) {
+ // TODO(paulberry): implement.
+ throw new UnimplementedError();
+ } else {
+ DartType getTypeArgument(int i) {
+ if (i < type.typeArguments.length) {
+ return resolveTypeRef(type.typeArguments[i], typeParameterContext);
+ } else {
+ return DynamicTypeImpl.instance;
+ }
+ }
+ ReferenceableElementForLink element = _resolveRef(type.reference);
+ return element.buildType(
+ getTypeArgument, type.implicitFunctionTypeIndices);
+ }
+ }
+
+ @override
String toString() => enclosingElement.toString();
/**
@@ -980,8 +1002,15 @@
if (containingReference != 0 &&
_linkedUnit.references[containingReference].kind !=
ReferenceKind.prefix) {
- _references[index] =
- _resolveRef(containingReference).getContainedName(name);
+ if (linkedReference.kind == ReferenceKind.function) {
+ // Local function
+ _references[index] = _resolveRef(containingReference)
+ .getLocalFunction(linkedReference.localIndex) ??
+ UndefinedElementForLink.instance;
+ } else {
+ _references[index] =
+ _resolveRef(containingReference).getContainedName(name);
+ }
} else if (linkedReference.dependency == 0) {
if (name == 'void') {
_references[index] = enclosingElement._linker.voidElement;
@@ -1000,45 +1029,6 @@
}
return _references[index];
}
-
- /**
- * Resolve an [EntityRef] into a type. If the reference is
- * unresolved, return [DynamicTypeImpl.instance].
- *
- * TODO(paulberry): or should we have a class representing an
- * unresolved type, for consistency with the full element model?
- */
- DartType _resolveTypeRef(
- EntityRef type, TypeParameterizedElementForLink typeParameterContext,
- {bool defaultVoid: false}) {
- if (type == null) {
- if (defaultVoid) {
- return VoidTypeImpl.instance;
- } else {
- return DynamicTypeImpl.instance;
- }
- }
- if (type.paramReference != 0) {
- return typeParameterContext.getTypeParameterType(type.paramReference);
- } else if (type.syntheticReturnType != null) {
- // TODO(paulberry): implement.
- throw new UnimplementedError();
- } else if (type.implicitFunctionTypeIndices.isNotEmpty) {
- // TODO(paulberry): implement.
- throw new UnimplementedError();
- } else {
- DartType getTypeArgument(int i) {
- if (i < type.typeArguments.length) {
- return _resolveTypeRef(type.typeArguments[i], typeParameterContext);
- } else {
- return DynamicTypeImpl.instance;
- }
- }
- ReferenceableElementForLink element = _resolveRef(type.reference);
- return element.buildType(
- getTypeArgument, type.implicitFunctionTypeIndices);
- }
- }
}
/**
@@ -1136,7 +1126,20 @@
numTypeParameters: element.typeParameters.length,
unitNum: element.enclosingElement.unitNum,
kind: ReferenceKind.typedef);
- } else if (element is ExecutableElementForLink) {
+ } else if (element is FunctionElementForLink_Initializer) {
+ return addRawReference('',
+ containingReference: addReference(element.enclosingElement),
+ kind: ReferenceKind.function,
+ localIndex: 0);
+ } else if (element is FunctionElementForLink_Local_NonSynthetic) {
+ ExecutableElementForLink parent = element.enclosingElement;
+ int localIndex = parent.functions.indexOf(element);
+ assert(localIndex != -1);
+ return addRawReference(element.name,
+ containingReference: addReference(parent),
+ kind: ReferenceKind.function,
+ localIndex: localIndex);
+ } else if (element is ExecutableElementForLink_NonLocal) {
ClassElementForLink_Class enclosingClass = element.enclosingClass;
ReferenceKind kind;
switch (element._unlinkedExecutable.kind) {
@@ -1156,21 +1159,17 @@
numTypeParameters: element.typeParameters.length,
containingReference:
enclosingClass != null ? addReference(enclosingClass) : null,
+ dependency: enclosingClass != null
+ ? null
+ : library.addDependency(element.library),
kind: kind);
- } else if (element is FunctionElementForLink_Local) {
- FunctionElementImpl parent = element.enclosingElement;
- int localIndex = parent.functions.indexOf(element);
- assert(localIndex != -1);
- return addRawReference(element.name,
- containingReference: addReference(parent),
- kind: ReferenceKind.function,
- localIndex: localIndex);
} else if (element is FunctionElementForLink_Initializer) {
return addRawReference('',
containingReference: addReference(element.enclosingElement),
kind: ReferenceKind.function);
} else if (element is TopLevelVariableElementForLink) {
return addRawReference(element.name,
+ dependency: library.addDependency(element.library),
kind: ReferenceKind.topLevelPropertyAccessor);
} else if (element is FieldElementForLink_ClassField) {
ClassElementForLink_Class enclosingClass = element.enclosingElement;
@@ -1186,7 +1185,7 @@
@override
DartType getLinkedType(
- int slot, TypeParameterizedElementForLink typeParameterContext) {
+ int slot, TypeParameterizedElementMixin typeParameterContext) {
// This method should only be called on compilation units that come from
// dependencies, never on compilation units that are part of the current
// build unit.
@@ -1235,7 +1234,7 @@
* unit's linked type list.
*/
void _storeLinkedType(int slot, DartType linkedType,
- TypeParameterizedElementForLink typeParameterContext) {
+ TypeParameterizedElementMixin typeParameterContext) {
if (slot != 0) {
if (linkedType != null && !linkedType.isDynamic) {
_linkedUnit.types.add(_createLinkedType(
@@ -1292,9 +1291,9 @@
@override
DartType getLinkedType(
- int slot, TypeParameterizedElementForLink typeParameterContext) {
+ int slot, TypeParameterizedElementMixin typeParameterContext) {
if (slot < _linkedTypeRefs.length) {
- return _resolveTypeRef(_linkedTypeRefs[slot], typeParameterContext);
+ return resolveTypeRef(_linkedTypeRefs[slot], typeParameterContext);
} else {
return DynamicTypeImpl.instance;
}
@@ -1522,8 +1521,9 @@
* Element representing a constructor resynthesized from a summary
* during linking.
*/
-class ConstructorElementForLink extends ExecutableElementForLink
- implements ConstructorElementImpl, ReferenceableElementForLink {
+class ConstructorElementForLink extends ExecutableElementForLink_NonLocal
+ with ReferenceableElementForLink
+ implements ConstructorElementImpl {
/**
* If this is a `const` constructor and the enclosing library is
* part of the build unit being linked, the constructor's node in
@@ -1546,19 +1546,6 @@
ConstructorElementForLink get asConstructor => this;
@override
- ConstVariableNode get asConstVariable => null;
-
- @override
- DartType get asStaticType {
- // Referring to a constructor directly is an error, so just use
- // `dynamic`.
- return DynamicTypeImpl.instance;
- }
-
- @override
- TypeInferenceNode get asTypeInferenceNode => null;
-
- @override
bool get isCycleFree {
if (!_constNode.isEvaluated) {
new ConstDependencyWalker().walk(_constNode);
@@ -1566,15 +1553,6 @@
return _constNode.isCycleFree;
}
- @override
- DartType buildType(DartType getTypeArgument(int i),
- List<int> implicitFunctionTypeIndices) =>
- DynamicTypeImpl.instance;
-
- @override
- ReferenceableElementForLink getContainedName(String name) =>
- UndefinedElementForLink.instance;
-
/**
* Perform const cycle detection on this constructor.
*/
@@ -1775,7 +1753,7 @@
* linking.
*/
abstract class ExecutableElementForLink extends Object
- with TypeParameterizedElementForLink, ParameterParentElementForLink
+ with TypeParameterizedElementMixin, ParameterParentElementForLink
implements ExecutableElementImpl {
/**
* The unlinked representation of the method in the summary.
@@ -1788,17 +1766,10 @@
String _name;
String _displayName;
- /**
- * Return the class in which this executable appears, maybe `null` for a
- * top-level function.
- */
- final ClassElementForLink_Class enclosingClass;
-
@override
final CompilationUnitElementForLink compilationUnit;
- ExecutableElementForLink(
- this.compilationUnit, this.enclosingClass, this._unlinkedExecutable);
+ ExecutableElementForLink(this.compilationUnit, this._unlinkedExecutable);
/**
* If the executable element had an explicitly declared return type, return
@@ -1809,7 +1780,7 @@
return null;
} else {
return _declaredReturnType ??=
- compilationUnit._resolveTypeRef(_unlinkedExecutable.returnType, this);
+ compilationUnit.resolveTypeRef(_unlinkedExecutable.returnType, this);
}
}
@@ -1825,11 +1796,7 @@
}
@override
- Element get enclosingElement => enclosingClass ?? compilationUnit;
-
- @override
- TypeParameterizedElementForLink get enclosingTypeParameterContext =>
- enclosingClass;
+ CompilationUnitElementImpl get enclosingUnit => compilationUnit;
@override
bool get hasImplicitReturnType => _unlinkedExecutable.returnType == null;
@@ -1899,13 +1866,13 @@
FunctionTypeImpl get type => _type ??= new FunctionTypeImpl(this);
@override
- TypeParameterizedElementForLink get typeParameterContext => this;
+ TypeParameterizedElementMixin get typeParameterContext => this;
@override
List<UnlinkedParam> get unlinkedParameters => _unlinkedExecutable.parameters;
@override
- List<UnlinkedTypeParam> get _unlinkedTypeParams =>
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
_unlinkedExecutable.typeParameters;
@override
@@ -1913,19 +1880,6 @@
!Identifier.isPrivateName(name) || identical(this.library, library);
/**
- * Store the results of type inference for this method in [compilationUnit].
- */
- void link(CompilationUnitElementInBuildUnit compilationUnit) {
- if (_unlinkedExecutable.returnType == null) {
- compilationUnit._storeLinkedType(
- _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
- }
- for (ParameterElementForLink parameterElement in parameters) {
- parameterElement.link(compilationUnit);
- }
- }
-
- /**
* Compute the default return type for this type of executable element (if no
* return type is declared and strong mode type inference cannot infer a
* better return type).
@@ -1942,6 +1896,45 @@
}
}
+/**
+ * Base class for executable elements that are resynthesized from a summary
+ * during linking and are not local functions.
+ */
+abstract class ExecutableElementForLink_NonLocal
+ extends ExecutableElementForLink {
+ /**
+ * Return the class in which this executable appears, maybe `null` for a
+ * top-level function.
+ */
+ final ClassElementForLink_Class enclosingClass;
+
+ ExecutableElementForLink_NonLocal(
+ CompilationUnitElementForLink compilationUnit,
+ this.enclosingClass,
+ UnlinkedExecutable unlinkedExecutable)
+ : super(compilationUnit, unlinkedExecutable);
+
+ @override
+ Element get enclosingElement => enclosingClass ?? compilationUnit;
+
+ @override
+ TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+ enclosingClass;
+
+ /**
+ * Store the results of type inference for this method in [compilationUnit].
+ */
+ void link(CompilationUnitElementInBuildUnit compilationUnit) {
+ if (_unlinkedExecutable.returnType == null) {
+ compilationUnit._storeLinkedType(
+ _unlinkedExecutable.inferredReturnTypeSlot, inferredReturnType, this);
+ }
+ for (ParameterElementForLink parameterElement in parameters) {
+ parameterElement.link(compilationUnit);
+ }
+ }
+}
+
class ExprTypeComputer {
VariableElementForLink variable;
FunctionElementForLink_Initializer initializer;
@@ -2282,7 +2275,7 @@
stack.add(enclosingClass.buildType((int i) {
// Type argument explicitly specified.
if (i < ref.typeArguments.length) {
- return unit._resolveTypeRef(
+ return unit.resolveTypeRef(
ref.typeArguments[i], variable._typeParameterContext);
}
// In strong mode, type argument defaults to bound (if any).
@@ -2422,7 +2415,7 @@
DartType _getNextTypeRef() {
EntityRef ref = _getNextRef();
- return unit._resolveTypeRef(ref, variable._typeParameterContext);
+ return unit.resolveTypeRef(ref, variable._typeParameterContext);
}
/**
@@ -2609,7 +2602,7 @@
}
@override
- TypeParameterizedElementForLink get _typeParameterContext => enclosingElement;
+ TypeParameterizedElementMixin get _typeParameterContext => enclosingElement;
/**
* Store the results of type inference for this field in
@@ -2683,7 +2676,7 @@
final ParameterElementForLink enclosingElement;
@override
- final TypeParameterizedElementForLink typeParameterContext;
+ final TypeParameterizedElementMixin typeParameterContext;
@override
final List<UnlinkedParam> unlinkedParameters;
@@ -2711,7 +2704,7 @@
if (enclosingElement._unlinkedParam.type == null) {
_returnType = DynamicTypeImpl.instance;
} else {
- _returnType = enclosingElement.compilationUnit._resolveTypeRef(
+ _returnType = enclosingElement.compilationUnit.resolveTypeRef(
enclosingElement._unlinkedParam.type, typeParameterContext);
}
}
@@ -2728,25 +2721,33 @@
/**
* Element representing the initializer expression of a variable.
*/
-class FunctionElementForLink_Initializer implements FunctionElementImpl {
+class FunctionElementForLink_Initializer extends Object
+ with ReferenceableElementForLink
+ implements FunctionElementForLink_Local {
/**
* The variable for which this element is the initializer.
*/
final VariableElementForLink _variable;
- List<FunctionElementForLink_Local> _functions;
+ List<FunctionElementForLink_Local_NonSynthetic> _functions;
FunctionElementForLink_Initializer(this._variable);
@override
VariableElementForLink get enclosingElement => _variable;
+ TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+ _variable.enclosingElement is ClassElementForLink
+ ? _variable.enclosingElement
+ : null;
+
@override
- List<FunctionElementForLink_Local> get functions => _functions ??= _variable
- .unlinkedVariable.initializer.localFunctions
- .map(
- (UnlinkedExecutable ex) => new FunctionElementForLink_Local(this, ex))
- .toList();
+ List<FunctionElementForLink_Local_NonSynthetic> get functions =>
+ _functions ??= _variable.unlinkedVariable.initializer.localFunctions
+ .map((UnlinkedExecutable ex) =>
+ new FunctionElementForLink_Local_NonSynthetic(
+ _variable.compilationUnit, this, ex))
+ .toList();
@override
DartType get returnType {
@@ -2770,31 +2771,62 @@
}
@override
+ int get typeParameterNestingLevel =>
+ enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0;
+
+ List<TypeParameterElement> get typeParameters => const [];
+
+ @override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ List<FunctionElementForLink_Local_NonSynthetic> functions = this.functions;
+ return index < functions.length ? functions[index] : null;
+ }
+
+ @override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
/**
+ * Element representing a local function (possibly a closure).
+ */
+abstract class FunctionElementForLink_Local
+ implements
+ ExecutableElementForLink,
+ FunctionElementImpl,
+ ReferenceableElementForLink {}
+
+/**
* Element representing a local function (possibly a closure) inside another
* executable.
*/
-class FunctionElementForLink_Local implements FunctionElementImpl {
- /**
- * The unlinked representation of the local function in the summary.
- */
- final UnlinkedExecutable _executable;
+class FunctionElementForLink_Local_NonSynthetic extends ExecutableElementForLink
+ with ReferenceableElementForLink
+ implements FunctionElementForLink_Local {
+ @override
+ final ExecutableElementForLink enclosingElement;
+
+ FunctionElementForLink_Local_NonSynthetic(
+ CompilationUnitElementForLink compilationUnit,
+ this.enclosingElement,
+ UnlinkedExecutable unlinkedExecutable)
+ : super(compilationUnit, unlinkedExecutable);
@override
- final FunctionElementImpl enclosingElement;
-
- DartType _type;
-
- FunctionElementForLink_Local(this.enclosingElement, this._executable);
+ TypeParameterizedElementMixin get enclosingTypeParameterContext =>
+ enclosingElement;
@override
- String get name => _executable.name;
+ DartType buildType(
+ DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
+ assert(implicitFunctionTypeIndices.isEmpty);
+ return type;
+ }
@override
- DartType get type => _type ??= new FunctionTypeImpl(this);
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement.
+ throw new UnimplementedError();
+ }
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@@ -2804,11 +2836,11 @@
* Element representing a typedef resynthesized from a summary during linking.
*/
class FunctionTypeAliasElementForLink extends Object
- with TypeParameterizedElementForLink, ParameterParentElementForLink
- implements
- FunctionTypeAliasElement,
- ReferenceableElementForLink,
- ElementImpl {
+ with
+ TypeParameterizedElementMixin,
+ ParameterParentElementForLink,
+ ReferenceableElementForLink
+ implements FunctionTypeAliasElement, ElementImpl {
@override
final CompilationUnitElementForLink enclosingElement;
@@ -2823,29 +2855,15 @@
FunctionTypeAliasElementForLink(this.enclosingElement, this._unlinkedTypedef);
@override
- ConstructorElementForLink get asConstructor => null;
-
- @override
- ConstVariableNode get asConstVariable {
- // When a typedef name is used as a constant variable, it doesn't depend on
- // anything, so it is not necessary to include it in the constant
- // dependency graph.
- return null;
- }
-
- @override
DartType get asStaticType {
return enclosingElement.enclosingElement._linker.typeProvider.typeType;
}
@override
- TypeInferenceNode get asTypeInferenceNode => null;
+ TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
@override
- CompilationUnitElementForLink get compilationUnit => enclosingElement;
-
- @override
- TypeParameterizedElementForLink get enclosingTypeParameterContext => null;
+ CompilationUnitElementInBuildUnit get enclosingUnit => enclosingElement;
@override
String get identifier => _unlinkedTypedef.name;
@@ -2864,16 +2882,16 @@
@override
DartType get returnType => _returnType ??=
- enclosingElement._resolveTypeRef(_unlinkedTypedef.returnType, this);
+ enclosingElement.resolveTypeRef(_unlinkedTypedef.returnType, this);
@override
- TypeParameterizedElementForLink get typeParameterContext => this;
+ TypeParameterizedElementMixin get typeParameterContext => this;
@override
List<UnlinkedParam> get unlinkedParameters => _unlinkedTypedef.parameters;
@override
- List<UnlinkedTypeParam> get _unlinkedTypeParams =>
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
_unlinkedTypedef.typeParameters;
@override
@@ -2893,12 +2911,6 @@
}
@override
- ReferenceableElementForLink getContainedName(String name) {
- // TODO(paulberry): implement.
- throw new UnimplementedError();
- }
-
- @override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
@@ -3447,40 +3459,27 @@
/**
* Element representing a method resynthesized from a summary during linking.
*/
-class MethodElementForLink extends ExecutableElementForLink
- implements MethodElementImpl, ReferenceableElementForLink {
+class MethodElementForLink extends ExecutableElementForLink_NonLocal
+ with ReferenceableElementForLink
+ implements MethodElementImpl {
MethodElementForLink(ClassElementForLink_Class enclosingClass,
UnlinkedExecutable unlinkedExecutable)
: super(enclosingClass.enclosingElement, enclosingClass,
unlinkedExecutable);
@override
- ConstructorElementForLink get asConstructor => null;
-
- @override
- ConstVariableNode get asConstVariable => null;
-
- @override
DartType get asStaticType => type;
@override
- TypeInferenceNode get asTypeInferenceNode => null;
-
- @override
String get identifier => name;
@override
ElementKind get kind => ElementKind.METHOD;
@override
- DartType buildType(DartType getTypeArgument(int i),
- List<int> implicitFunctionTypeIndices) =>
- DynamicTypeImpl.instance;
-
- @override
- ReferenceableElementForLink getContainedName(String name) {
- // TODO(paulberry): handle references to `call`.
- return UndefinedElementForLink.instance;
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement.
+ return null;
}
@override
@@ -3538,7 +3537,8 @@
* creating a [NonstaticMemberElementForLink] that points to another
* [NonstaticMemberElementForLink], to whatever nesting level is necessary.
*/
-class NonstaticMemberElementForLink implements ReferenceableElementForLink {
+class NonstaticMemberElementForLink extends Object
+ with ReferenceableElementForLink {
/**
* The [ReferenceableElementForLink] which is the target of the non-static
* reference.
@@ -3559,9 +3559,6 @@
NonstaticMemberElementForLink(this._library, this._target, this._name);
@override
- ConstructorElementForLink get asConstructor => null;
-
- @override
ConstVariableNode get asConstVariable => _target.asConstVariable;
@override
@@ -3590,11 +3587,6 @@
TypeInferenceNode get asTypeInferenceNode => _target.asTypeInferenceNode;
@override
- DartType buildType(DartType getTypeArgument(int i),
- List<int> implicitFunctionTypeIndices) =>
- DynamicTypeImpl.instance;
-
- @override
ReferenceableElementForLink getContainedName(String name) {
return new NonstaticMemberElementForLink(_library, this, name);
}
@@ -3613,7 +3605,7 @@
/**
* The innermost enclosing element that can declare type parameters.
*/
- final TypeParameterizedElementForLink _typeParameterContext;
+ final TypeParameterizedElementMixin _typeParameterContext;
/**
* If this parameter has a default value and the enclosing library
@@ -3685,7 +3677,7 @@
_declaredType = DynamicTypeImpl.instance;
}
} else {
- _declaredType = compilationUnit._resolveTypeRef(
+ _declaredType = compilationUnit.resolveTypeRef(
_unlinkedParam.type, _typeParameterContext);
}
}
@@ -3762,8 +3754,13 @@
_parameters = new List<ParameterElementForLink>(numParameters);
for (int i = 0; i < numParameters; i++) {
UnlinkedParam unlinkedParam = unlinkedParameters[i];
- _parameters[i] = new ParameterElementForLink(this, unlinkedParam,
- typeParameterContext, typeParameterContext.compilationUnit, i);
+ _parameters[i] = new ParameterElementForLink(
+ this,
+ unlinkedParam,
+ typeParameterContext,
+ typeParameterContext.enclosingUnit.resynthesizerContext
+ as CompilationUnitElementForLink,
+ i);
}
}
return _parameters;
@@ -3774,7 +3771,7 @@
* may be [this], or may be a parent when there are function-typed
* parameters).
*/
- TypeParameterizedElementForLink get typeParameterContext;
+ TypeParameterizedElementMixin get typeParameterContext;
/**
* Get the list of unlinked parameters of this element.
@@ -3795,7 +3792,8 @@
* Specialization of [PropertyAccessorElementForLink] for synthetic accessors
* implied by the synthetic fields of an enum declaration.
*/
-class PropertyAccessorElementForLink_EnumField
+class PropertyAccessorElementForLink_EnumField extends Object
+ with ReferenceableElementForLink
implements PropertyAccessorElementForLink {
@override
final FieldElementForLink_EnumField variable;
@@ -3805,18 +3803,9 @@
PropertyAccessorElementForLink_EnumField(this.variable);
@override
- ConstructorElementForLink get asConstructor => null;
-
- @override
- ConstVariableNode get asConstVariable => null;
-
- @override
DartType get asStaticType => returnType;
@override
- TypeInferenceNode get asTypeInferenceNode => null;
-
- @override
Element get enclosingElement => variable.enclosingElement;
@override
@@ -3854,16 +3843,18 @@
List<TypeParameterElement> get typeParameters => const [];
@override
- DartType buildType(DartType getTypeArgument(int i),
- List<int> implicitFunctionTypeIndices) =>
- DynamicTypeImpl.instance;
-
- @override
ReferenceableElementForLink getContainedName(String name) {
return new NonstaticMemberElementForLink(library, this, name);
}
@override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement (should return the synthetic function element
+ // for the enum field's initializer).
+ return null;
+ }
+
+ @override
bool isAccessibleIn(LibraryElement library) =>
!Identifier.isPrivateName(name) || identical(this.library, library);
@@ -3881,7 +3872,9 @@
* Specialization of [PropertyAccessorElementForLink] for non-synthetic
* accessors explicitly declared in the source code.
*/
-class PropertyAccessorElementForLink_Executable extends ExecutableElementForLink
+class PropertyAccessorElementForLink_Executable
+ extends ExecutableElementForLink_NonLocal
+ with ReferenceableElementForLink
implements PropertyAccessorElementForLink {
@override
SyntheticVariableElementForLink variable;
@@ -3894,18 +3887,9 @@
: super(enclosingUnit, enclosingClass, unlinkedExecutable);
@override
- ConstructorElementForLink get asConstructor => null;
-
- @override
- ConstVariableNode get asConstVariable => null;
-
- @override
DartType get asStaticType => returnType;
@override
- TypeInferenceNode get asTypeInferenceNode => null;
-
- @override
PropertyAccessorElementForLink_Executable get correspondingGetter =>
variable.getter;
@@ -3918,20 +3902,24 @@
_unlinkedExecutable.kind == UnlinkedExecutableKind.setter;
@override
+ bool get isStatic => enclosingClass == null || super.isStatic;
+
+ @override
ElementKind get kind => _unlinkedExecutable.kind ==
UnlinkedExecutableKind.getter ? ElementKind.GETTER : ElementKind.SETTER;
@override
- DartType buildType(DartType getTypeArgument(int i),
- List<int> implicitFunctionTypeIndices) =>
- DynamicTypeImpl.instance;
-
- @override
ReferenceableElementForLink getContainedName(String name) {
return new NonstaticMemberElementForLink(library, this, name);
}
@override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement
+ return null;
+ }
+
+ @override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
@@ -3942,7 +3930,8 @@
* Specialization of [PropertyAccessorElementForLink] for synthetic accessors
* implied by a field or variable declaration.
*/
-class PropertyAccessorElementForLink_Variable
+class PropertyAccessorElementForLink_Variable extends Object
+ with ReferenceableElementForLink
implements PropertyAccessorElementForLink {
@override
final bool isSetter;
@@ -3954,9 +3943,6 @@
PropertyAccessorElementForLink_Variable(this.variable, this.isSetter);
@override
- ConstructorElementForLink get asConstructor => null;
-
- @override
ConstVariableNode get asConstVariable => variable._constNode;
@override
@@ -4016,11 +4002,6 @@
return const [];
}
- @override
- DartType buildType(DartType getTypeArgument(int i),
- List<int> implicitFunctionTypeIndices) =>
- DynamicTypeImpl.instance;
-
/**
* Compute the type of the corresponding variable, which may depend on the
* progress of type inference.
@@ -4045,6 +4026,15 @@
}
@override
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ if (index == 0) {
+ return variable.initializer;
+ } else {
+ return null;
+ }
+ }
+
+ @override
bool isAccessibleIn(LibraryElement library) =>
!Identifier.isPrivateName(name) || identical(this.library, library);
@@ -4059,44 +4049,46 @@
}
/**
- * Abstract base class representing an element which can be the target
- * of a reference.
+ * Base class representing an element which can be the target of a reference.
+ * When used as a mixin, implements the default behavior shared by most
+ * elements.
*/
-abstract class ReferenceableElementForLink {
+class ReferenceableElementForLink {
/**
* If this element can be used in a constructor invocation context,
* return the associated constructor (which may be `this` or some
* other element). Otherwise return `null`.
*/
- ConstructorElementForLink get asConstructor;
+ ConstructorElementForLink get asConstructor => null;
/**
* If this element can be used in a getter context to refer to a
* constant variable, return the [ConstVariableNode] for the
* constant value. Otherwise return `null`.
*/
- ConstVariableNode get asConstVariable;
+ ConstVariableNode get asConstVariable => null;
/**
* Return the static type (possibly inferred) of the entity referred to by
* this element.
*/
- DartType get asStaticType;
+ DartType get asStaticType => DynamicTypeImpl.instance;
/**
* If this element can be used in a getter context as a type inference
* dependency, return the [TypeInferenceNode] for the inferred type.
* Otherwise return `null`.
*/
- TypeInferenceNode get asTypeInferenceNode;
+ TypeInferenceNode get asTypeInferenceNode => null;
/**
* Return the type indicated by this element when it is used in a
* type instantiation context. If this element can't legally be
* instantiated as a type, return the dynamic type.
*/
- DartType buildType(
- DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices);
+ DartType buildType(DartType getTypeArgument(int i),
+ List<int> implicitFunctionTypeIndices) =>
+ DynamicTypeImpl.instance;
/**
* If this element contains other named elements, return the
@@ -4105,40 +4097,37 @@
* with the given name, return the singleton of
* [UndefinedElementForLink].
*/
- ReferenceableElementForLink getContainedName(String name);
+ ReferenceableElementForLink getContainedName(String name) {
+ // TODO(paulberry): handle references to `call` for function types.
+ return UndefinedElementForLink.instance;
+ }
+
+ /**
+ * If this element contains local functions, return the contained local
+ * function having the given [index]. If this element doesn't contain local
+ * functions, or the index is out of range, return `null`.
+ */
+ FunctionElementForLink_Local getLocalFunction(int index) => null;
}
/**
* Element used for references to special types such as `void`.
*/
-class SpecialTypeElementForLink extends ReferenceableElementForLink {
+class SpecialTypeElementForLink extends Object
+ with ReferenceableElementForLink {
final Linker linker;
final DartType type;
SpecialTypeElementForLink(this.linker, this.type);
@override
- ConstructorElementForLink get asConstructor => null;
-
- @override
- ConstVariableNode get asConstVariable => null;
-
- @override
DartType get asStaticType => linker.typeProvider.typeType;
@override
- TypeInferenceNode get asTypeInferenceNode => null;
-
- @override
DartType buildType(
DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
return type;
}
-
- @override
- ReferenceableElementForLink getContainedName(String name) {
- return UndefinedElementForLink.instance;
- }
}
/**
@@ -4168,8 +4157,9 @@
/**
* Element representing a top-level function.
*/
-class TopLevelFunctionElementForLink extends ExecutableElementForLink
- implements FunctionElementImpl, ReferenceableElementForLink {
+class TopLevelFunctionElementForLink extends ExecutableElementForLink_NonLocal
+ with ReferenceableElementForLink
+ implements FunctionElementImpl {
DartType _returnType;
TopLevelFunctionElementForLink(
@@ -4177,29 +4167,21 @@
: super(enclosingUnit, null, _buf);
@override
- ConstructorElementForLink get asConstructor => null;
-
- @override
- ConstVariableNode get asConstVariable => null;
-
- @override
DartType get asStaticType => type;
@override
- TypeInferenceNode get asTypeInferenceNode => null;
+ String get identifier => _unlinkedExecutable.name;
+
+ @override
+ bool get isStatic => true;
@override
ElementKind get kind => ElementKind.FUNCTION;
@override
- DartType buildType(DartType getTypeArgument(int i),
- List<int> implicitFunctionTypeIndices) =>
- DynamicTypeImpl.instance;
-
- @override
- ReferenceableElementForLink getContainedName(String name) {
- // TODO(paulberry): handle references to `call`.
- return UndefinedElementForLink.instance;
+ FunctionElementForLink_Local getLocalFunction(int index) {
+ // TODO(paulberry): implement.
+ return null;
}
@override
@@ -4226,7 +4208,7 @@
LibraryElementForLink get library => compilationUnit.library;
@override
- TypeParameterizedElementForLink get _typeParameterContext => null;
+ TypeParameterizedElementMixin get _typeParameterContext => null;
/**
* Store the results of type inference for this variable in
@@ -4355,154 +4337,6 @@
String toString() => 'TypeInferenceNode($variableElement)';
}
-/**
- * Element representing a type parameter resynthesized from a summary during
- * linking.
- */
-class TypeParameterElementForLink implements TypeParameterElementImpl {
- /**
- * The unlinked representation of the type parameter in the summary.
- */
- final UnlinkedTypeParam _unlinkedTypeParam;
-
- /**
- * The number of type parameters whose scope overlaps this one, and which are
- * declared earlier in the file.
- */
- final int nestingLevel;
-
- @override
- final TypeParameterizedElementForLink enclosingElement;
-
- TypeParameterTypeImpl _type;
- ElementLocation _location;
-
- DartType _bound;
-
- TypeParameterElementForLink(
- this.enclosingElement, this._unlinkedTypeParam, this.nestingLevel);
-
- @override
- DartType get bound {
- if (_unlinkedTypeParam.bound == null) {
- return null;
- }
- return _bound ??= enclosingElement.compilationUnit
- ._resolveTypeRef(_unlinkedTypeParam.bound, enclosingElement);
- }
-
- @override
- String get identifier => name;
-
- @override
- ElementKind get kind => ElementKind.TYPE_PARAMETER;
-
- @override
- ElementLocation get location =>
- _location ??= new ElementLocationImpl.con1(this);
-
- @override
- String get name => _unlinkedTypeParam.name;
-
- @override
- TypeParameterTypeImpl get type => _type ??= new TypeParameterTypeImpl(this);
-
- @override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-/**
- * Mixin representing an element which can have type parameters.
- */
-abstract class TypeParameterizedElementForLink
- implements TypeParameterizedElement {
- List<TypeParameterType> _typeParameterTypes;
- List<TypeParameterElementForLink> _typeParameters;
- int _nestingLevel;
-
- /**
- * Get the compilation unit in which this element is declared.
- */
- CompilationUnitElementForLink get compilationUnit;
-
- /**
- * Get the type parameter context enclosing this one, if any.
- */
- TypeParameterizedElementForLink get enclosingTypeParameterContext;
-
- /**
- * Find out how many type parameters are in scope in this context.
- */
- int get typeParameterNestingLevel =>
- _nestingLevel ??= _unlinkedTypeParams.length +
- (enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0);
-
- List<TypeParameterElementForLink> get typeParameters {
- if (_typeParameters == null) {
- int enclosingNestingLevel =
- enclosingTypeParameterContext?.typeParameterNestingLevel ?? 0;
- int numTypeParameters = _unlinkedTypeParams.length;
- _typeParameters =
- new List<TypeParameterElementForLink>(numTypeParameters);
- for (int i = 0; i < numTypeParameters; i++) {
- _typeParameters[i] = new TypeParameterElementForLink(
- this, _unlinkedTypeParams[i], enclosingNestingLevel + i);
- }
- }
- return _typeParameters;
- }
-
- /**
- * Get a list of [TypeParameterType] objects corresponding to the
- * element's type parameters.
- */
- List<TypeParameterType> get typeParameterTypes {
- if (_typeParameterTypes == null) {
- _typeParameterTypes = typeParameters
- .map((TypeParameterElementForLink e) => e.type)
- .toList();
- }
- return _typeParameterTypes;
- }
-
- /**
- * Get the [UnlinkedTypeParam]s representing the type parameters declared by
- * this element.
- */
- List<UnlinkedTypeParam> get _unlinkedTypeParams;
-
- /**
- * Convert the given [index] into a type parameter type.
- */
- TypeParameterType getTypeParameterType(int index) {
- List<TypeParameterType> types = typeParameterTypes;
- if (index <= types.length) {
- return types[types.length - index];
- } else if (enclosingTypeParameterContext != null) {
- return enclosingTypeParameterContext
- .getTypeParameterType(index - types.length);
- } else {
- // If we get here, it means that a summary contained a type parameter index
- // that was out of range.
- throw new RangeError('Invalid type parameter index');
- }
- }
-
- /**
- * Find out if the given [typeParameter] is in scope in this context.
- */
- bool isTypeParameterInScope(TypeParameterElementForLink typeParameter) {
- if (typeParameter.enclosingElement == this) {
- return true;
- } else if (enclosingTypeParameterContext != null) {
- return enclosingTypeParameterContext
- .isTypeParameterInScope(typeParameter);
- } else {
- return false;
- }
- }
-}
-
class TypeProviderForLink implements TypeProvider {
final Linker _linker;
@@ -4652,31 +4486,11 @@
/**
* Singleton element used for unresolved references.
*/
-class UndefinedElementForLink implements ReferenceableElementForLink {
- static const UndefinedElementForLink instance =
- const UndefinedElementForLink._();
+class UndefinedElementForLink extends Object with ReferenceableElementForLink {
+ static final UndefinedElementForLink instance =
+ new UndefinedElementForLink._();
- const UndefinedElementForLink._();
-
- @override
- ConstructorElementForLink get asConstructor => null;
-
- @override
- ConstVariableNode get asConstVariable => null;
-
- @override
- DartType get asStaticType => DynamicTypeImpl.instance;
-
- @override
- TypeInferenceNode get asTypeInferenceNode => null;
-
- @override
- DartType buildType(DartType getTypeArgument(int i),
- List<int> implicitFunctionTypeIndices) =>
- DynamicTypeImpl.instance;
-
- @override
- ReferenceableElementForLink getContainedName(String name) => this;
+ UndefinedElementForLink._();
}
/**
@@ -4684,7 +4498,7 @@
* summary during linking.
*/
abstract class VariableElementForLink
- implements VariableElementImpl, PropertyInducingElement {
+ implements NonParameterVariableElementImpl, PropertyInducingElement {
/**
* The unlinked representation of the variable in the summary.
*/
@@ -4732,7 +4546,7 @@
if (unlinkedVariable.type == null) {
return null;
} else {
- return _declaredType ??= compilationUnit._resolveTypeRef(
+ return _declaredType ??= compilationUnit.resolveTypeRef(
unlinkedVariable.type, _typeParameterContext);
}
}
@@ -4774,7 +4588,7 @@
@override
FunctionElementForLink_Initializer get initializer {
- if (unlinkedVariable.constExpr == null) {
+ if (unlinkedVariable.initializer == null) {
return null;
} else {
return _initializer ??= new FunctionElementForLink_Initializer(this);
@@ -4824,7 +4638,7 @@
* The context in which type parameters should be interpreted, or `null` if
* there are no type parameters in scope.
*/
- TypeParameterizedElementForLink get _typeParameterContext;
+ TypeParameterizedElementMixin get _typeParameterContext;
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
index eb6020f..7c6ee32 100644
--- a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
@@ -134,6 +134,8 @@
/**
* The [UriResolver] that knows about sources that are served from their
* summaries.
+ *
+ * TODO(scheglov) rename to `InSummaryUriResolver` - it's not `package:` specific.
*/
class InSummaryPackageUriResolver extends UriResolver {
final SummaryDataStore _dataStore;
@@ -143,9 +145,10 @@
@override
Source resolveAbsolute(Uri uri, [Uri actualUri]) {
actualUri ??= uri;
- UnlinkedUnit unit = _dataStore.unlinkedMap[uri.toString()];
+ String uriString = uri.toString();
+ UnlinkedUnit unit = _dataStore.unlinkedMap[uriString];
if (unit != null) {
- String summaryPath = _dataStore.uriToSummaryPath[uri.toString()];
+ String summaryPath = _dataStore.uriToSummaryPath[uriString];
if (unit.fallbackModePath.isNotEmpty) {
return new _InSummaryFallbackSource(
new JavaFile(unit.fallbackModePath), actualUri, summaryPath);
@@ -185,7 +188,7 @@
int get hashCode => uri.hashCode;
@override
- bool get isInSystemLibrary => false;
+ bool get isInSystemLibrary => uri.scheme == DartUriResolver.DART_SCHEME;
@override
int get modificationStamp => 0;
@@ -214,6 +217,11 @@
*/
class SummaryDataStore {
/**
+ * List of all [PackageBundle]s.
+ */
+ final List<PackageBundle> bundles = <PackageBundle>[];
+
+ /**
* Map from the URI of a compilation unit to the unlinked summary of that
* compilation unit.
*/
@@ -237,6 +245,7 @@
* Add the given [bundle] loaded from the file with the given [path].
*/
void addBundle(String path, PackageBundle bundle) {
+ bundles.add(bundle);
for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
String uri = bundle.unlinkedUnitUris[i];
uriToSummaryPath[uri] = path;
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index acc6ff3..dfcaa98 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -548,7 +548,8 @@
*/
TypeName _newTypeName() {
EntityRef typeRef = uc.references[refPtr++];
- DartType type = resynthesizer.buildType(typeRef);
+ DartType type = resynthesizer.buildType(
+ typeRef, resynthesizer._currentTypeParameterizedElement);
return _buildTypeAst(type);
}
@@ -577,7 +578,7 @@
void _pushInstanceCreation() {
EntityRef ref = uc.references[refPtr++];
- _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
+ _ReferenceInfo info = resynthesizer.getReferenceInfo(ref.reference);
// prepare ConstructorElement
TypeName typeNode;
String constructorName;
@@ -645,7 +646,7 @@
void _pushInvokeMethodRef() {
List<Expression> arguments = _buildArguments();
EntityRef ref = uc.references[refPtr++];
- _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
+ _ReferenceInfo info = resynthesizer.getReferenceInfo(ref.reference);
Expression node = _buildIdentifierSequence(info);
if (node is SimpleIdentifier) {
_push(new MethodInvocation(
@@ -686,7 +687,7 @@
void _pushReference() {
EntityRef ref = uc.references[refPtr++];
- _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
+ _ReferenceInfo info = resynthesizer.getReferenceInfo(ref.reference);
Expression node = _buildIdentifierSequence(info);
_push(node);
}
@@ -701,6 +702,25 @@
}
/**
+ * Temporary [TypeParameterizedElementMixin] implementation.
+ *
+ * TODO(scheglov) remove after moving resynthesize logic to Impl.
+ */
+class _CurrentTypeParameterizedElement
+ implements TypeParameterizedElementMixin {
+ final _UnitResynthesizer unitResynthesizer;
+
+ _CurrentTypeParameterizedElement(this.unitResynthesizer);
+
+ @override
+ TypeParameterType getTypeParameterType(int index) {
+ return unitResynthesizer.getTypeParameterFromScope(index);
+ }
+
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+/**
* A class element that has been resynthesized from a summary. The actual
* element won't be constructed until it is requested. But properties
* [context], [displayName], [enclosingElement] and [name] can be used without
@@ -714,6 +734,12 @@
ClassElementImpl _actualElement;
+ /**
+ * We don't resynthesize executables of classes until they are requested.
+ * TODO(scheglov) Check whether we need separate flags for separate kinds.
+ */
+ bool _executablesResynthesized = false;
+
@override
final String name;
@@ -733,15 +759,27 @@
: super(null, location);
@override
+ List<PropertyAccessorElement> get accessors {
+ _ensureExecutables();
+ return actualElement.accessors;
+ }
+
+ @override
ClassElementImpl get actualElement {
if (_actualElement == null) {
- _actualElement = unitResynthesizer.buildClassImpl(serializedClass);
+ _actualElement = unitResynthesizer.buildClassImpl(serializedClass, this);
_actualElement.enclosingElement = unitElement;
}
return _actualElement;
}
@override
+ List<ConstructorElement> get constructors {
+ _ensureExecutables();
+ return actualElement.constructors;
+ }
+
+ @override
AnalysisContext get context => unitElement.context;
@override
@@ -751,6 +789,48 @@
CompilationUnitElement get enclosingElement {
return unitElement;
}
+
+ @override
+ List<FieldElement> get fields {
+ _ensureExecutables();
+ return actualElement.fields;
+ }
+
+ @override
+ List<MethodElement> get methods {
+ _ensureExecutables();
+ return actualElement.methods;
+ }
+
+ @override
+ void ensureAccessorsReady() {
+ _ensureExecutables();
+ }
+
+ @override
+ void ensureActualElementComplete() {
+ _ensureExecutables();
+ }
+
+ @override
+ void ensureConstructorsReady() {
+ _ensureExecutables();
+ }
+
+ @override
+ void ensureMethodsReady() {
+ _ensureExecutables();
+ }
+
+ /**
+ * Ensure that we have [actualElement], and it has all executables.
+ */
+ void _ensureExecutables() {
+ if (!_executablesResynthesized) {
+ _executablesResynthesized = true;
+ unitResynthesizer.buildClassExecutables(actualElement, serializedClass);
+ }
+ }
}
/**
@@ -921,11 +1001,21 @@
final Source librarySource;
/**
+ * The URI of [librarySource].
+ */
+ String libraryUri;
+
+ /**
* Indicates whether [librarySource] is the `dart:core` library.
*/
bool isCoreLibrary;
/**
+ * The resynthesized library.
+ */
+ LibraryElementImpl library;
+
+ /**
* Classes which should have their supertype set to "object" once
* resynthesis is complete. Only used if [isCoreLibrary] is `true`.
*/
@@ -955,7 +1045,8 @@
_LibraryResynthesizer(this.summaryResynthesizer, this.linkedLibrary,
this.unlinkedUnits, this.librarySource) {
- isCoreLibrary = librarySource.uri.toString() == 'dart:core';
+ libraryUri = librarySource.uri.toString();
+ isCoreLibrary = libraryUri == 'dart:core';
}
/**
@@ -1109,17 +1200,17 @@
* Main entry point. Resynthesize the [LibraryElement] and return it.
*/
LibraryElement buildLibrary() {
- CompilationUnitElementImpl definingUnit =
- new CompilationUnitElementImpl(librarySource.shortName);
- _UnitResynthesizer definingUnitResynthesizer =
- createUnitResynthesizer(definingUnit, 0);
// Create LibraryElementImpl.
bool hasName = unlinkedUnits[0].libraryName.isNotEmpty;
- LibraryElementImpl library = new LibraryElementImpl(
+ library = new LibraryElementImpl(
summaryResynthesizer.context,
unlinkedUnits[0].libraryName,
hasName ? unlinkedUnits[0].libraryNameOffset : -1,
unlinkedUnits[0].libraryNameLength);
+ // Create the defining unit.
+ _UnitResynthesizer definingUnitResynthesizer =
+ createUnitResynthesizer(0, librarySource, null);
+ CompilationUnitElementImpl definingUnit = definingUnitResynthesizer.unit;
definingUnitResynthesizer.buildDocumentation(
library, unlinkedUnits[0].libraryDocumentationComment);
definingUnitResynthesizer.buildAnnotations(
@@ -1128,19 +1219,19 @@
definingUnit.source = librarySource;
definingUnit.librarySource = librarySource;
// Create parts.
- List<CompilationUnitElement> partUnits = <CompilationUnitElement>[];
+ List<_UnitResynthesizer> partResynthesizers = <_UnitResynthesizer>[];
UnlinkedUnit unlinkedDefiningUnit = unlinkedUnits[0];
assert(unlinkedDefiningUnit.publicNamespace.parts.length + 1 ==
linkedLibrary.units.length);
for (int i = 1; i < linkedLibrary.units.length; i++) {
- CompilationUnitElementImpl part = buildPart(
+ _UnitResynthesizer partResynthesizer = buildPart(
definingUnitResynthesizer,
unlinkedDefiningUnit.publicNamespace.parts[i - 1],
unlinkedDefiningUnit.parts[i - 1],
i);
- partUnits.add(part);
+ partResynthesizers.add(partResynthesizer);
}
- library.parts = partUnits;
+ library.parts = partResynthesizers.map((r) => r.unit).toList();
// Create imports.
List<ImportElement> imports = <ImportElement>[];
for (int i = 0; i < unlinkedDefiningUnit.imports.length; i++) {
@@ -1164,9 +1255,7 @@
library.exports = exports;
// Populate units.
populateUnit(definingUnitResynthesizer);
- for (int i = 0; i < partUnits.length; i++) {
- _UnitResynthesizer partResynthesizer =
- createUnitResynthesizer(partUnits[i], i + 1);
+ for (_UnitResynthesizer partResynthesizer in partResynthesizers) {
populateUnit(partResynthesizer);
}
BuildLibraryElementUtils.patchTopLevelAccessors(library);
@@ -1206,32 +1295,30 @@
* Create, but do not populate, the [CompilationUnitElement] for a part other
* than the defining compilation unit.
*/
- CompilationUnitElementImpl buildPart(
- _UnitResynthesizer definingUnitResynthesizer,
- String uri,
- UnlinkedPart partDecl,
- int unitNum) {
+ _UnitResynthesizer buildPart(_UnitResynthesizer definingUnitResynthesizer,
+ String uri, UnlinkedPart partDecl, int unitNum) {
Source unitSource =
summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
- CompilationUnitElementImpl partUnit =
- new CompilationUnitElementImpl(unitSource.shortName);
+ _UnitResynthesizer partResynthesizer =
+ createUnitResynthesizer(unitNum, unitSource, partDecl);
+ CompilationUnitElementImpl partUnit = partResynthesizer.unit;
partUnit.uriOffset = partDecl.uriOffset;
partUnit.uriEnd = partDecl.uriEnd;
partUnit.source = unitSource;
partUnit.librarySource = librarySource;
partUnit.uri = uri;
- definingUnitResynthesizer.buildAnnotations(partUnit, partDecl.annotations);
- return partUnit;
+ return partResynthesizer;
}
/**
* Set up data structures for deserializing a compilation unit.
*/
_UnitResynthesizer createUnitResynthesizer(
- CompilationUnitElementImpl unit, int unitNum) {
+ int unitNum, Source unitSource, UnlinkedPart unlinkedPart) {
LinkedUnit linkedUnit = linkedLibrary.units[unitNum];
UnlinkedUnit unlinkedUnit = unlinkedUnits[unitNum];
- return new _UnitResynthesizer(this, unlinkedUnit, linkedUnit, unit);
+ return new _UnitResynthesizer(
+ this, unlinkedUnit, linkedUnit, unitSource, unlinkedPart);
}
/**
@@ -1242,7 +1329,7 @@
List<String> getReferencedLocationComponents(
int dependencyIndex, int unit, String name) {
if (dependencyIndex == 0) {
- String referencedLibraryUri = librarySource.uri.toString();
+ String referencedLibraryUri = libraryUri;
String partUri;
if (unit != 0) {
String uri = unlinkedUnits[0].publicNamespace.parts[unit - 1];
@@ -1465,6 +1552,31 @@
}
}
+class _ResynthesizerContext implements ResynthesizerContext {
+ final _UnitResynthesizer _unitResynthesizer;
+
+ _ResynthesizerContext(this._unitResynthesizer);
+
+ @override
+ ElementAnnotationImpl buildAnnotation(UnlinkedConst uc) {
+ return _unitResynthesizer.buildAnnotation(uc);
+ }
+
+ @override
+ Expression buildExpression(UnlinkedConst uc) {
+ return _unitResynthesizer._buildConstExpression(uc);
+ }
+
+ @override
+ DartType resolveTypeRef(
+ EntityRef type, TypeParameterizedElementMixin typeParameterContext,
+ {bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
+ return _unitResynthesizer.buildType(type, typeParameterContext,
+ defaultVoid: defaultVoid,
+ instantiateToBoundsAllowed: instantiateToBoundsAllowed);
+ }
+}
+
/**
* An instance of [_UnitResynthesizer] is responsible for resynthesizing the
* elements in a single unit from that unit's summary.
@@ -1489,7 +1601,7 @@
* The [CompilationUnitElementImpl] for the compilation unit currently being
* resynthesized.
*/
- final CompilationUnitElementImpl unit;
+ CompilationUnitElementImpl unit;
/**
* [ElementHolder] into which resynthesized elements should be placed. This
@@ -1549,19 +1661,44 @@
*/
Map<String, ConstructorElementImpl> constructors;
+ int numLinkedReferences;
+ int numUnlinkedReferences;
+
/**
* List of [_ReferenceInfo] objects describing the references in the current
- * compilation unit.
+ * compilation unit. This list is works as a lazily filled cache, use
+ * [getReferenceInfo] to get the [_ReferenceInfo] for an index.
*/
List<_ReferenceInfo> referenceInfos;
+ /**
+ * The [ResynthesizerContext] for this resynthesize session.
+ */
+ ResynthesizerContext _resynthesizerContext;
+
+ /**
+ * TODO(scheglov) clean up after moving resynthesize logic to Impl.
+ */
+ TypeParameterizedElementMixin _currentTypeParameterizedElement;
+
_UnitResynthesizer(this.libraryResynthesizer, this.unlinkedUnit,
- this.linkedUnit, this.unit) {
+ this.linkedUnit, Source unitSource, UnlinkedPart unlinkedPart) {
+ _resynthesizerContext = new _ResynthesizerContext(this);
+ unit = new CompilationUnitElementImpl.forSerialized(
+ libraryResynthesizer.library,
+ _resynthesizerContext,
+ unlinkedUnit,
+ unlinkedPart,
+ unitSource.shortName);
for (EntityRef t in linkedUnit.types) {
linkedTypeMap[t.slot] = t;
}
constCycles = linkedUnit.constCycles.toSet();
- populateReferenceInfos();
+ numLinkedReferences = linkedUnit.references.length;
+ numUnlinkedReferences = unlinkedUnit.references.length;
+ referenceInfos = new List<_ReferenceInfo>(numLinkedReferences);
+ _currentTypeParameterizedElement =
+ new _CurrentTypeParameterizedElement(this);
}
SummaryResynthesizer get summaryResynthesizer =>
@@ -1570,36 +1707,40 @@
TypeProvider get typeProvider => summaryResynthesizer.typeProvider;
/**
+ * Build [ElementAnnotationImpl] for the given [UnlinkedConst].
+ */
+ ElementAnnotationImpl buildAnnotation(UnlinkedConst uc) {
+ ElementAnnotationImpl elementAnnotation = new ElementAnnotationImpl(unit);
+ Expression constExpr = _buildConstExpression(uc);
+ if (constExpr is Identifier) {
+ elementAnnotation.element = constExpr.staticElement;
+ elementAnnotation.annotationAst = AstFactory.annotation(constExpr);
+ } else if (constExpr is InstanceCreationExpression) {
+ elementAnnotation.element = constExpr.staticElement;
+ Identifier typeName = constExpr.constructorName.type.name;
+ SimpleIdentifier constructorName = constExpr.constructorName.name;
+ if (typeName is SimpleIdentifier && constructorName != null) {
+ // E.g. `@cls.ctor()`. Since `cls.ctor` would have been parsed as
+ // a PrefixedIdentifier, we need to resynthesize it as one.
+ typeName = AstFactory.identifier(typeName, constructorName);
+ constructorName = null;
+ }
+ elementAnnotation.annotationAst = AstFactory.annotation2(
+ typeName, constructorName, constExpr.argumentList);
+ } else {
+ throw new StateError(
+ 'Unexpected annotation type: ${constExpr.runtimeType}');
+ }
+ return elementAnnotation;
+ }
+
+ /**
* Build the annotations for the given [element].
*/
void buildAnnotations(
ElementImpl element, List<UnlinkedConst> serializedAnnotations) {
if (serializedAnnotations.isNotEmpty) {
- element.metadata = serializedAnnotations.map((UnlinkedConst a) {
- ElementAnnotationImpl elementAnnotation =
- new ElementAnnotationImpl(this.unit);
- Expression constExpr = _buildConstExpression(a);
- if (constExpr is Identifier) {
- elementAnnotation.element = constExpr.staticElement;
- elementAnnotation.annotationAst = AstFactory.annotation(constExpr);
- } else if (constExpr is InstanceCreationExpression) {
- elementAnnotation.element = constExpr.staticElement;
- Identifier typeName = constExpr.constructorName.type.name;
- SimpleIdentifier constructorName = constExpr.constructorName.name;
- if (typeName is SimpleIdentifier && constructorName != null) {
- // E.g. `@cls.ctor()`. Since `cls.ctor` would have been parsed as
- // a PrefixedIdentifier, we need to resynthesize it as one.
- typeName = AstFactory.identifier(typeName, constructorName);
- constructorName = null;
- }
- elementAnnotation.annotationAst = AstFactory.annotation2(
- typeName, constructorName, constExpr.argumentList);
- } else {
- throw new StateError(
- 'Unexpected annotation type: ${constExpr.runtimeType}');
- }
- return elementAnnotation;
- }).toList();
+ element.metadata = serializedAnnotations.map(buildAnnotation).toList();
}
}
@@ -1610,7 +1751,7 @@
ClassElement classElement;
if (libraryResynthesizer.isCoreLibrary &&
serializedClass.supertype == null) {
- classElement = buildClassImpl(serializedClass);
+ classElement = buildClassImpl(serializedClass, null);
if (!serializedClass.hasNoSupertype) {
libraryResynthesizer.delayedObjectSubclasses.add(classElement);
}
@@ -1621,25 +1762,11 @@
}
/**
- * Resynthesize a [ClassElementImpl].
+ * Fill the given [ClassElementImpl] with executable elements and fields.
*/
- ClassElementImpl buildClassImpl(UnlinkedClass serializedClass) {
- ClassElementImpl classElement =
- new ClassElementImpl(serializedClass.name, serializedClass.nameOffset);
- classElement.hasBeenInferred = summaryResynthesizer.strongMode;
- classElement.typeParameters =
- buildTypeParameters(serializedClass.typeParameters);
- classElement.abstract = serializedClass.isAbstract;
- classElement.mixinApplication = serializedClass.isMixinApplication;
- InterfaceTypeImpl correspondingType = new InterfaceTypeImpl(classElement);
- if (serializedClass.supertype != null) {
- classElement.supertype = buildType(serializedClass.supertype);
- } else if (!libraryResynthesizer.isCoreLibrary) {
- classElement.supertype = typeProvider.objectType;
- }
- classElement.interfaces =
- serializedClass.interfaces.map(buildType).toList();
- classElement.mixins = serializedClass.mixins.map(buildType).toList();
+ void buildClassExecutables(
+ ClassElementImpl classElement, UnlinkedClass serializedClass) {
+ currentTypeParameters.add(classElement.typeParameters);
ElementHolder memberHolder = new ElementHolder();
fields = <String, FieldElementImpl>{};
for (UnlinkedVariable serializedVariable in serializedClass.fields) {
@@ -1652,8 +1779,7 @@
switch (serializedExecutable.kind) {
case UnlinkedExecutableKind.constructor:
constructorFound = true;
- buildConstructor(
- serializedExecutable, memberHolder, correspondingType);
+ buildConstructor(serializedExecutable, classElement, memberHolder);
break;
case UnlinkedExecutableKind.functionOrMethod:
case UnlinkedExecutableKind.getter:
@@ -1661,7 +1787,7 @@
if (serializedExecutable.isStatic) {
currentTypeParameters.removeLast();
}
- buildExecutable(serializedExecutable, memberHolder);
+ buildExecutable(serializedExecutable, classElement, memberHolder);
if (serializedExecutable.isStatic) {
currentTypeParameters.add(classElement.typeParameters);
}
@@ -1673,7 +1799,7 @@
// Synthesize implicit constructors.
ConstructorElementImpl constructor = new ConstructorElementImpl('', -1);
constructor.synthetic = true;
- constructor.returnType = correspondingType;
+ constructor.returnType = classElement.type;
constructor.type = new FunctionTypeImpl.elementWithNameAndArgs(
constructor, null, getCurrentTypeArguments(), false);
memberHolder.addConstructor(constructor);
@@ -1683,14 +1809,44 @@
classElement.accessors = memberHolder.accessors;
classElement.fields = memberHolder.fields;
classElement.methods = memberHolder.methods;
- correspondingType.typeArguments = getCurrentTypeArguments();
- classElement.type = correspondingType;
- buildDocumentation(classElement, serializedClass.documentationComment);
- buildAnnotations(classElement, serializedClass.annotations);
- buildCodeRange(classElement, serializedClass.codeRange);
resolveConstructorInitializers(classElement);
currentTypeParameters.removeLast();
assert(currentTypeParameters.isEmpty);
+ }
+
+ /**
+ * Resynthesize a [ClassElementImpl]. If [handle] is not `null`, then
+ * executables are not resynthesized, and [InterfaceTypeImpl] is created
+ * around the [handle], so that executables are resynthesized lazily.
+ */
+ ClassElementImpl buildClassImpl(
+ UnlinkedClass serializedClass, ClassElementHandle handle) {
+ ClassElementImpl classElement =
+ new ClassElementImpl.forSerialized(serializedClass, unit);
+ classElement.hasBeenInferred = summaryResynthesizer.strongMode;
+ InterfaceTypeImpl correspondingType =
+ new InterfaceTypeImpl(handle ?? classElement);
+ if (serializedClass.supertype != null) {
+ classElement.supertype =
+ buildType(serializedClass.supertype, classElement);
+ } else if (!libraryResynthesizer.isCoreLibrary) {
+ classElement.supertype = typeProvider.objectType;
+ }
+ classElement.interfaces = serializedClass.interfaces
+ .map((EntityRef t) => buildType(t, classElement))
+ .toList();
+ classElement.mixins = serializedClass.mixins
+ .map((EntityRef t) => buildType(t, classElement))
+ .toList();
+ // TODO(scheglov) move to ClassElementImpl
+ correspondingType.typeArguments = classElement.typeParameterTypes;
+ classElement.type = correspondingType;
+ assert(currentTypeParameters.isEmpty);
+ // TODO(scheglov) Somehow Observatory shows too much time spent here
+ // during DDC run on the large codebase. I would expect only Object here.
+ if (handle == null) {
+ buildClassExecutables(classElement, serializedClass);
+ }
fields = null;
constructors = null;
return classElement;
@@ -1729,24 +1885,22 @@
* constructor.
*/
void buildConstructor(UnlinkedExecutable serializedExecutable,
- ElementHolder holder, InterfaceType classType) {
+ ClassElementImpl classElement, ElementHolder holder) {
assert(serializedExecutable.kind == UnlinkedExecutableKind.constructor);
- currentConstructor = new ConstructorElementImpl(
- serializedExecutable.name, serializedExecutable.nameOffset);
+ currentConstructor = new ConstructorElementImpl.forSerialized(
+ serializedExecutable, classElement);
currentConstructor.isCycleFree = serializedExecutable.isConst &&
!constCycles.contains(serializedExecutable.constCycleSlot);
if (serializedExecutable.name.isEmpty) {
currentConstructor.nameEnd =
- serializedExecutable.nameOffset + classType.name.length;
+ serializedExecutable.nameOffset + classElement.name.length;
} else {
currentConstructor.nameEnd = serializedExecutable.nameEnd;
currentConstructor.periodOffset = serializedExecutable.periodOffset;
}
constructors[serializedExecutable.name] = currentConstructor;
- currentConstructor.returnType = classType;
+ currentConstructor.returnType = classElement.type;
buildExecutableCommonParts(currentConstructor, serializedExecutable);
- currentConstructor.factory = serializedExecutable.isFactory;
- currentConstructor.const2 = serializedExecutable.isConst;
currentConstructor.constantInitializers = serializedExecutable
.constantInitializers
.map(buildConstructorInitializer)
@@ -1755,17 +1909,17 @@
if (serializedExecutable.isFactory) {
EntityRef redirectedConstructor =
serializedExecutable.redirectedConstructor;
- _ReferenceInfo info = referenceInfos[redirectedConstructor.reference];
+ _ReferenceInfo info = getReferenceInfo(redirectedConstructor.reference);
List<EntityRef> typeArguments = redirectedConstructor.typeArguments;
currentConstructor.redirectedConstructor = _createConstructorElement(
_createConstructorDefiningType(info, typeArguments), info);
} else {
List<String> locationComponents = unit.location.components.toList();
- locationComponents.add(classType.name);
+ locationComponents.add(classElement.name);
locationComponents.add(serializedExecutable.redirectedConstructorName);
currentConstructor.redirectedConstructor =
new _DeferredConstructorElement._(
- classType,
+ classElement.type,
serializedExecutable.redirectedConstructorName,
new ElementLocationImpl.con3(locationComponents));
}
@@ -1889,7 +2043,8 @@
/**
* Resynthesize an [ExecutableElement] and place it in the given [holder].
*/
- void buildExecutable(UnlinkedExecutable serializedExecutable,
+ void buildExecutable(
+ UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement,
[ElementHolder holder]) {
bool isTopLevel = holder == null;
if (holder == null) {
@@ -1905,36 +2060,28 @@
case UnlinkedExecutableKind.functionOrMethod:
if (isTopLevel) {
FunctionElementImpl executableElement =
- new FunctionElementImpl(name, serializedExecutable.nameOffset);
+ new FunctionElementImpl.forSerialized(
+ serializedExecutable, enclosingElement);
buildExecutableCommonParts(executableElement, serializedExecutable);
holder.addFunction(executableElement);
} else {
MethodElementImpl executableElement =
- new MethodElementImpl(name, serializedExecutable.nameOffset);
- executableElement.abstract = serializedExecutable.isAbstract;
+ new MethodElementImpl.forSerialized(
+ serializedExecutable, enclosingElement);
buildExecutableCommonParts(executableElement, serializedExecutable);
- executableElement.static = serializedExecutable.isStatic;
holder.addMethod(executableElement);
}
break;
case UnlinkedExecutableKind.getter:
case UnlinkedExecutableKind.setter:
PropertyAccessorElementImpl executableElement =
- new PropertyAccessorElementImpl(
- name, serializedExecutable.nameOffset);
- if (isTopLevel) {
- executableElement.static = true;
- } else {
- executableElement.static = serializedExecutable.isStatic;
- executableElement.abstract = serializedExecutable.isAbstract;
- }
+ new PropertyAccessorElementImpl.forSerialized(
+ serializedExecutable, enclosingElement);
buildExecutableCommonParts(executableElement, serializedExecutable);
DartType type;
if (kind == UnlinkedExecutableKind.getter) {
- executableElement.getter = true;
type = executableElement.returnType;
} else {
- executableElement.setter = true;
type = executableElement.parameters[0].type;
}
holder.addAccessor(executableElement);
@@ -1969,36 +2116,32 @@
UnlinkedExecutable serializedExecutable) {
executableElement.typeParameters =
buildTypeParameters(serializedExecutable.typeParameters);
- executableElement.parameters =
- serializedExecutable.parameters.map(buildParameter).toList();
+ executableElement.parameters = serializedExecutable.parameters
+ .map((p) => buildParameter(p, executableElement))
+ .toList();
if (serializedExecutable.kind == UnlinkedExecutableKind.constructor) {
// Caller handles setting the return type.
assert(serializedExecutable.returnType == null);
} else {
bool isSetter =
serializedExecutable.kind == UnlinkedExecutableKind.setter;
- executableElement.returnType =
- buildLinkedType(serializedExecutable.inferredReturnTypeSlot) ??
- buildType(serializedExecutable.returnType,
- defaultVoid: isSetter && summaryResynthesizer.strongMode);
- executableElement.hasImplicitReturnType =
- serializedExecutable.returnType == null;
+ executableElement.returnType = buildLinkedType(
+ serializedExecutable.inferredReturnTypeSlot,
+ _currentTypeParameterizedElement) ??
+ buildType(
+ serializedExecutable.returnType, _currentTypeParameterizedElement,
+ defaultVoid: isSetter && summaryResynthesizer.strongMode);
}
executableElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
executableElement, null, getCurrentTypeArguments(skipLevels: 1), false);
- executableElement.asynchronous = serializedExecutable.isAsynchronous;
- executableElement.external = serializedExecutable.isExternal;
- executableElement.generator = serializedExecutable.isGenerator;
- buildDocumentation(
- executableElement, serializedExecutable.documentationComment);
- buildAnnotations(executableElement, serializedExecutable.annotations);
- buildCodeRange(executableElement, serializedExecutable.codeRange);
- executableElement.functions =
- serializedExecutable.localFunctions.map(buildLocalFunction).toList();
+ executableElement.functions = serializedExecutable.localFunctions
+ .map((f) => buildLocalFunction(f, executableElement))
+ .toList();
executableElement.labels =
serializedExecutable.localLabels.map(buildLocalLabel).toList();
- executableElement.localVariables =
- serializedExecutable.localVariables.map(buildLocalVariable).toList();
+ executableElement.localVariables = serializedExecutable.localVariables
+ .map((v) => buildLocalVariable(v, executableElement))
+ .toList();
currentTypeParameters.removeLast();
}
@@ -2086,7 +2229,8 @@
* Build the appropriate [DartType] object corresponding to a slot id in the
* [LinkedUnit.types] table.
*/
- DartType buildLinkedType(int slot) {
+ DartType buildLinkedType(
+ int slot, TypeParameterizedElementMixin typeParameterContext) {
if (slot == 0) {
// A slot id of 0 means there is no [DartType] object to build.
return null;
@@ -2097,16 +2241,16 @@
// stored in this slot.
return null;
}
- return buildType(type);
+ return buildType(type, typeParameterContext);
}
/**
* Resynthesize a local [FunctionElement].
*/
FunctionElementImpl buildLocalFunction(
- UnlinkedExecutable serializedExecutable) {
- FunctionElementImpl element = new FunctionElementImpl(
- serializedExecutable.name, serializedExecutable.nameOffset);
+ UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement) {
+ FunctionElementImpl element = new FunctionElementImpl.forSerialized(
+ serializedExecutable, enclosingElement);
if (serializedExecutable.visibleOffset != 0) {
element.setVisibleRange(serializedExecutable.visibleOffset,
serializedExecutable.visibleLength);
@@ -2129,33 +2273,37 @@
/**
* Resynthesize a [LocalVariableElement].
*/
- LocalVariableElement buildLocalVariable(UnlinkedVariable serializedVariable) {
+ LocalVariableElement buildLocalVariable(UnlinkedVariable serializedVariable,
+ ExecutableElementImpl enclosingExecutable) {
LocalVariableElementImpl element;
if (serializedVariable.constExpr != null && serializedVariable.isConst) {
ConstLocalVariableElementImpl constElement =
- new ConstLocalVariableElementImpl(
- serializedVariable.name, serializedVariable.nameOffset);
+ new ConstLocalVariableElementImpl.forSerialized(
+ serializedVariable, enclosingExecutable);
element = constElement;
constElement.constantInitializer =
_buildConstExpression(serializedVariable.constExpr);
} else {
- element = new LocalVariableElementImpl(
- serializedVariable.name, serializedVariable.nameOffset);
+ element = new LocalVariableElementImpl.forSerialized(
+ serializedVariable, enclosingExecutable);
}
if (serializedVariable.visibleOffset != 0) {
element.setVisibleRange(
serializedVariable.visibleOffset, serializedVariable.visibleLength);
}
- buildVariableCommonParts(element, serializedVariable);
+ buildVariableCommonParts(element, serializedVariable,
+ isLazilyResynthesized: true);
return element;
}
/**
* Resynthesize a [ParameterElement].
*/
- ParameterElement buildParameter(UnlinkedParam serializedParameter,
+ ParameterElement buildParameter(
+ UnlinkedParam serializedParameter, ElementImpl enclosingElement,
{bool synthetic: false}) {
ParameterElementImpl parameterElement;
+ bool isLazilyResynthesized = false;
int nameOffset = synthetic ? -1 : serializedParameter.nameOffset;
if (serializedParameter.isInitializingFormal) {
FieldFormalParameterElementImpl initializingParameter;
@@ -2178,30 +2326,29 @@
initializingParameter.field = fields[serializedParameter.name];
} else {
if (serializedParameter.kind == UnlinkedParamKind.required) {
- parameterElement =
- new ParameterElementImpl(serializedParameter.name, nameOffset);
+ parameterElement = new ParameterElementImpl.forSerialized(
+ serializedParameter, enclosingElement);
+ isLazilyResynthesized = true;
} else {
DefaultParameterElementImpl defaultParameter =
- new DefaultParameterElementImpl(
- serializedParameter.name, nameOffset);
+ new DefaultParameterElementImpl.forSerialized(
+ serializedParameter, enclosingElement);
+ isLazilyResynthesized = true;
parameterElement = defaultParameter;
- if (serializedParameter.defaultValue != null) {
- defaultParameter.constantInitializer =
- _buildConstExpression(serializedParameter.defaultValue);
- defaultParameter.defaultValueCode =
- serializedParameter.defaultValueCode;
- }
}
}
parameterElement.synthetic = synthetic;
- buildAnnotations(parameterElement, serializedParameter.annotations);
- buildCodeRange(parameterElement, serializedParameter.codeRange);
+ if (!isLazilyResynthesized) {
+ buildAnnotations(parameterElement, serializedParameter.annotations);
+ buildCodeRange(parameterElement, serializedParameter.codeRange);
+ }
if (serializedParameter.isFunctionTyped) {
FunctionElementImpl parameterTypeElement =
new FunctionElementImpl('', -1);
parameterTypeElement.synthetic = true;
List<ParameterElement> subParameters = serializedParameter.parameters
- .map((UnlinkedParam p) => buildParameter(p, synthetic: synthetic))
+ .map((UnlinkedParam p) =>
+ buildParameter(p, parameterTypeElement, synthetic: synthetic))
.toList();
if (synthetic) {
parameterTypeElement.parameters = subParameters;
@@ -2210,7 +2357,8 @@
parameterTypeElement.shareParameters(subParameters);
parameterTypeElement.enclosingElement = parameterElement;
}
- parameterTypeElement.returnType = buildType(serializedParameter.type);
+ parameterTypeElement.returnType =
+ buildType(serializedParameter.type, _currentTypeParameterizedElement);
parameterElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
parameterTypeElement, null, getCurrentTypeArguments(), false);
parameterTypeElement.type = parameterElement.type;
@@ -2221,11 +2369,15 @@
parameterElement.type =
fields[serializedParameter.name]?.type ?? DynamicTypeImpl.instance;
} else {
- parameterElement.type =
- buildLinkedType(serializedParameter.inferredTypeSlot) ??
- buildType(serializedParameter.type);
+ parameterElement.type = buildLinkedType(
+ serializedParameter.inferredTypeSlot,
+ _currentTypeParameterizedElement) ??
+ buildType(
+ serializedParameter.type, _currentTypeParameterizedElement);
}
- parameterElement.hasImplicitType = serializedParameter.type == null;
+ if (!isLazilyResynthesized) {
+ parameterElement.hasImplicitType = serializedParameter.type == null;
+ }
}
buildVariableInitializer(parameterElement, serializedParameter.initializer);
switch (serializedParameter.kind) {
@@ -2239,9 +2391,11 @@
parameterElement.parameterKind = ParameterKind.REQUIRED;
break;
}
- if (serializedParameter.visibleOffset != 0) {
- parameterElement.setVisibleRange(
- serializedParameter.visibleOffset, serializedParameter.visibleLength);
+ if (!isLazilyResynthesized) {
+ if (serializedParameter.visibleOffset != 0) {
+ parameterElement.setVisibleRange(serializedParameter.visibleOffset,
+ serializedParameter.visibleLength);
+ }
}
return parameterElement;
}
@@ -2253,8 +2407,9 @@
PropertyInducingElementImpl element,
UnlinkedVariable serializedVariable) {
buildVariableCommonParts(element, serializedVariable);
- element.propagatedType =
- buildLinkedType(serializedVariable.propagatedTypeSlot);
+ element.propagatedType = buildLinkedType(
+ serializedVariable.propagatedTypeSlot,
+ _currentTypeParameterizedElement);
}
/**
@@ -2263,7 +2418,8 @@
* deserialized, so handles are used to avoid having to deserialize other
* libraries in the process.
*/
- DartType buildType(EntityRef type,
+ DartType buildType(
+ EntityRef type, TypeParameterizedElementMixin typeParameterContext,
{bool defaultVoid: false, bool instantiateToBoundsAllowed: true}) {
if (type == null) {
if (defaultVoid) {
@@ -2273,14 +2429,16 @@
}
}
if (type.paramReference != 0) {
- return getTypeParameterFromScope(type.paramReference);
+ return typeParameterContext.getTypeParameterType(type.paramReference);
} else if (type.syntheticReturnType != null) {
FunctionElementImpl element = new FunctionElementImpl('', -1);
element.synthetic = true;
element.parameters = type.syntheticParams
- .map((UnlinkedParam param) => buildParameter(param, synthetic: true))
+ .map((UnlinkedParam param) =>
+ buildParameter(param, element, synthetic: true))
.toList();
- element.returnType = buildType(type.syntheticReturnType);
+ element.returnType =
+ buildType(type.syntheticReturnType, typeParameterContext);
FunctionTypeImpl result = new FunctionTypeImpl.elementWithNameAndArgs(
element, null, null, false);
element.type = result;
@@ -2288,12 +2446,12 @@
} else {
DartType getTypeArgument(int i) {
if (i < type.typeArguments.length) {
- return buildType(type.typeArguments[i]);
+ return buildType(type.typeArguments[i], typeParameterContext);
} else {
return DynamicTypeImpl.instance;
}
}
- _ReferenceInfo referenceInfo = referenceInfos[type.reference];
+ _ReferenceInfo referenceInfo = getReferenceInfo(type.reference);
return referenceInfo.buildType(
instantiateToBoundsAllowed,
type.typeArguments.length,
@@ -2308,21 +2466,18 @@
*/
void buildTypedef(UnlinkedTypedef serializedTypedef) {
FunctionTypeAliasElementImpl functionTypeAliasElement =
- new FunctionTypeAliasElementImpl(
- serializedTypedef.name, serializedTypedef.nameOffset);
- functionTypeAliasElement.typeParameters =
- buildTypeParameters(serializedTypedef.typeParameters);
- functionTypeAliasElement.parameters =
- serializedTypedef.parameters.map(buildParameter).toList();
+ new FunctionTypeAliasElementImpl.forSerialized(serializedTypedef, unit);
+ // TODO(scheglov) remove this after delaying parameters and their types
+ currentTypeParameters.add(functionTypeAliasElement.typeParameters);
+ functionTypeAliasElement.parameters = serializedTypedef.parameters
+ .map((p) => buildParameter(p, functionTypeAliasElement))
+ .toList();
functionTypeAliasElement.returnType =
- buildType(serializedTypedef.returnType);
+ buildType(serializedTypedef.returnType, functionTypeAliasElement);
functionTypeAliasElement.type =
new FunctionTypeImpl.forTypedef(functionTypeAliasElement);
- buildDocumentation(
- functionTypeAliasElement, serializedTypedef.documentationComment);
- buildAnnotations(functionTypeAliasElement, serializedTypedef.annotations);
- buildCodeRange(functionTypeAliasElement, serializedTypedef.codeRange);
unitHolder.addTypeAlias(functionTypeAliasElement);
+ // TODO(scheglov) remove this after delaying parameters and their types
currentTypeParameters.removeLast();
assert(currentTypeParameters.isEmpty);
}
@@ -2409,16 +2564,20 @@
* Handle the parts that are common to variables.
*/
void buildVariableCommonParts(
- VariableElementImpl element, UnlinkedVariable serializedVariable) {
- element.type = buildLinkedType(serializedVariable.inferredTypeSlot) ??
- buildType(serializedVariable.type);
- element.const3 = serializedVariable.isConst;
- element.final2 = serializedVariable.isFinal;
- element.hasImplicitType = serializedVariable.type == null;
+ VariableElementImpl element, UnlinkedVariable serializedVariable,
+ {bool isLazilyResynthesized: false}) {
+ element.type = buildLinkedType(serializedVariable.inferredTypeSlot,
+ _currentTypeParameterizedElement) ??
+ buildType(serializedVariable.type, _currentTypeParameterizedElement);
+ if (!isLazilyResynthesized) {
+ element.const3 = serializedVariable.isConst;
+ element.final2 = serializedVariable.isFinal;
+ element.hasImplicitType = serializedVariable.type == null;
+ buildDocumentation(element, serializedVariable.documentationComment);
+ buildAnnotations(element, serializedVariable.annotations);
+ buildCodeRange(element, serializedVariable.codeRange);
+ }
buildVariableInitializer(element, serializedVariable.initializer);
- buildDocumentation(element, serializedVariable.documentationComment);
- buildAnnotations(element, serializedVariable.annotations);
- buildCodeRange(element, serializedVariable.codeRange);
}
/**
@@ -2431,9 +2590,8 @@
return null;
}
FunctionElementImpl initializerElement =
- buildLocalFunction(serializedInitializer);
+ buildLocalFunction(serializedInitializer, variable);
initializerElement.synthetic = true;
- initializerElement.setCodeRange(null, null);
variable.initializer = initializerElement;
}
@@ -2443,7 +2601,8 @@
void finishTypeParameter(UnlinkedTypeParam serializedTypeParameter,
TypeParameterElementImpl typeParameterElement) {
if (serializedTypeParameter.bound != null) {
- typeParameterElement.bound = buildType(serializedTypeParameter.bound,
+ typeParameterElement.bound = buildType(
+ serializedTypeParameter.bound, _currentTypeParameterizedElement,
instantiateToBoundsAllowed: false);
}
}
@@ -2468,44 +2627,24 @@
}
/**
- * Get the type parameter from the surrounding scope whose De Bruijn index is
- * [index].
+ * Return [_ReferenceInfo] with the given [index], lazily resolving it.
*/
- DartType getTypeParameterFromScope(int index) {
- for (int i = currentTypeParameters.length - 1; i >= 0; i--) {
- List<TypeParameterElement> paramsAtThisNestingLevel =
- currentTypeParameters[i];
- int numParamsAtThisNestingLevel = paramsAtThisNestingLevel.length;
- if (index <= numParamsAtThisNestingLevel) {
- return paramsAtThisNestingLevel[numParamsAtThisNestingLevel - index]
- .type;
- }
- index -= numParamsAtThisNestingLevel;
- }
- throw new StateError('Type parameter not found');
- }
-
- /**
- * Populate [referenceInfos] with the correct information for the current
- * compilation unit.
- */
- void populateReferenceInfos() {
- int numLinkedReferences = linkedUnit.references.length;
- int numUnlinkedReferences = unlinkedUnit.references.length;
- referenceInfos = new List<_ReferenceInfo>(numLinkedReferences);
- for (int i = 0; i < numLinkedReferences; i++) {
- LinkedReference linkedReference = linkedUnit.references[i];
+ _ReferenceInfo getReferenceInfo(int index) {
+ _ReferenceInfo result = referenceInfos[index];
+ if (result == null) {
+ LinkedReference linkedReference = linkedUnit.references[index];
String name;
int containingReference;
- if (i < numUnlinkedReferences) {
- name = unlinkedUnit.references[i].name;
- containingReference = unlinkedUnit.references[i].prefixReference;
+ if (index < numUnlinkedReferences) {
+ name = unlinkedUnit.references[index].name;
+ containingReference = unlinkedUnit.references[index].prefixReference;
} else {
- name = linkedUnit.references[i].name;
- containingReference = linkedUnit.references[i].containingReference;
+ name = linkedUnit.references[index].name;
+ containingReference = linkedUnit.references[index].containingReference;
}
- _ReferenceInfo enclosingInfo =
- containingReference != 0 ? referenceInfos[containingReference] : null;
+ _ReferenceInfo enclosingInfo = containingReference != 0
+ ? getReferenceInfo(containingReference)
+ : null;
Element element;
DartType type;
int numTypeParameters = linkedReference.numTypeParameters;
@@ -2596,9 +2735,29 @@
break;
}
}
- referenceInfos[i] = new _ReferenceInfo(libraryResynthesizer,
- enclosingInfo, name, element, type, numTypeParameters);
+ result = new _ReferenceInfo(libraryResynthesizer, enclosingInfo, name,
+ element, type, numTypeParameters);
+ referenceInfos[index] = result;
}
+ return result;
+ }
+
+ /**
+ * Get the type parameter from the surrounding scope whose De Bruijn index is
+ * [index].
+ */
+ DartType getTypeParameterFromScope(int index) {
+ for (int i = currentTypeParameters.length - 1; i >= 0; i--) {
+ List<TypeParameterElement> paramsAtThisNestingLevel =
+ currentTypeParameters[i];
+ int numParamsAtThisNestingLevel = paramsAtThisNestingLevel.length;
+ if (index <= numParamsAtThisNestingLevel) {
+ return paramsAtThisNestingLevel[numParamsAtThisNestingLevel - index]
+ .type;
+ }
+ index -= numParamsAtThisNestingLevel;
+ }
+ throw new StateError('Type parameter not found');
}
/**
@@ -2608,7 +2767,7 @@
void populateUnit() {
unlinkedUnit.classes.forEach(buildClass);
unlinkedUnit.enums.forEach(buildEnum);
- unlinkedUnit.executables.forEach(buildExecutable);
+ unlinkedUnit.executables.forEach((e) => buildExecutable(e, unit));
unlinkedUnit.typedefs.forEach(buildTypedef);
unlinkedUnit.variables.forEach(buildVariable);
unit.accessors = unitHolder.accessors;
@@ -2638,7 +2797,6 @@
for (PropertyAccessorElementImpl accessor in unit.accessors) {
elementMap[accessor.identifier] = accessor;
}
- buildCodeRange(unit, unlinkedUnit.codeRange);
assert(currentTypeParameters.isEmpty);
}
@@ -2682,7 +2840,9 @@
_ReferenceInfo info, List<EntityRef> typeArgumentRefs) {
bool isClass = info.element is ClassElement;
_ReferenceInfo classInfo = isClass ? info : info.enclosing;
- List<DartType> typeArguments = typeArgumentRefs.map(buildType).toList();
+ List<DartType> typeArguments = typeArgumentRefs
+ .map((t) => buildType(t, _currentTypeParameterizedElement))
+ .toList();
return classInfo.buildType(true, typeArguments.length, (i) {
if (i < typeArguments.length) {
return typeArguments[i];
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index 8349428..f5dd314 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -388,7 +388,9 @@
return const <UnlinkedConstBuilder>[];
}
return annotations.map((Annotation a) {
- Map<int, int> localClosureIndexMap = null; // TODO(paulberry): fix.
+ // Closures can't appear inside annotations, so we don't need a
+ // localClosureIndexMap.
+ Map<int, int> localClosureIndexMap = null;
_ConstExprSerializer serializer =
new _ConstExprSerializer(this, localClosureIndexMap, null);
serializer.serializeAnnotation(a);
@@ -641,7 +643,7 @@
}
b.visibleOffset = enclosingBlock?.offset;
b.visibleLength = enclosingBlock?.length;
- serializeFunctionBody(b, body);
+ serializeFunctionBody(b, null, body);
scopes.removeLast();
assert(scopes.length == oldScopesLength);
return b;
@@ -651,8 +653,12 @@
* Record local functions and variables into the given executable. The given
* [body] is usually an actual [FunctionBody], but may be an [Expression]
* when we process a synthetic variable initializer function.
+ *
+ * If [initializers] is non-`null`, closures occurring inside the initializers
+ * are serialized first.
*/
- void serializeFunctionBody(UnlinkedExecutableBuilder b, AstNode body) {
+ void serializeFunctionBody(UnlinkedExecutableBuilder b,
+ List<ConstructorInitializer> initializers, AstNode body) {
if (body is BlockFunctionBody || body is ExpressionFunctionBody) {
for (UnlinkedParamBuilder parameter in b.parameters) {
parameter.visibleOffset = body.offset;
@@ -665,6 +671,11 @@
executables = <UnlinkedExecutableBuilder>[];
labels = <UnlinkedLabelBuilder>[];
variables = <UnlinkedVariableBuilder>[];
+ if (initializers != null) {
+ for (ConstructorInitializer initializer in initializers) {
+ initializer.accept(this);
+ }
+ }
body.accept(this);
b.localFunctions = executables;
b.localLabels = labels;
@@ -700,7 +711,7 @@
}
UnlinkedExecutableBuilder initializer =
new UnlinkedExecutableBuilder(nameOffset: expression.offset);
- serializeFunctionBody(initializer, expression);
+ serializeFunctionBody(initializer, null, expression);
initializer.inferredReturnTypeSlot = assignSlot();
return initializer;
}
@@ -987,7 +998,9 @@
if (node.redirectedConstructor != null) {
b.isRedirectedConstructor = true;
TypeName typeName = node.redirectedConstructor.type;
- Map<int, int> localClosureIndexMap = null; // TODO(paulberry): fix.
+ // Closures can't appear inside factory constructor redirections, so we
+ // don't need a localClosureIndexMap.
+ Map<int, int> localClosureIndexMap = null;
b.redirectedConstructor =
new _ConstExprSerializer(this, localClosureIndexMap, null)
.serializeConstructorRef(null, typeName.name,
@@ -1009,10 +1022,12 @@
b.documentationComment = serializeDocumentation(node.documentationComment);
b.annotations = serializeAnnotations(node.metadata);
b.codeRange = serializeCodeRange(node);
+ Map<int, int> localClosureIndexMap = _withLocalClosureIndexMap(() {
+ serializeFunctionBody(b, node.initializers, node.body);
+ });
if (node.constKeyword != null) {
Set<String> constructorParameterNames =
node.parameters.parameters.map((p) => p.identifier.name).toSet();
- Map<int, int> localClosureIndexMap = null; // TODO(paulberry): fix.
b.constantInitializers = node.initializers
.map((ConstructorInitializer initializer) =>
serializeConstructorInitializer(initializer, (Expression expr) {
@@ -1021,7 +1036,6 @@
}))
.toList();
}
- serializeFunctionBody(b, node.body);
executables.add(b);
}
@@ -1030,7 +1044,9 @@
DefaultFormalParameter node) {
UnlinkedParamBuilder b = node.parameter.accept(this);
if (node.defaultValue != null) {
- Map<int, int> localClosureIndexMap = null; // TODO(paulberry): fix.
+ // Closures can't appear inside default values, so we don't need a
+ // localClosureIndexMap.
+ Map<int, int> localClosureIndexMap = null;
b.defaultValue =
serializeConstExpr(localClosureIndexMap, node.defaultValue);
b.defaultValueCode = node.defaultValue.toSource();
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 2dfa154..ec9c988 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -13,9 +13,11 @@
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart'
- show Source, SourceFactory, SourceKind;
+ show DartUriResolver, Source, SourceFactory, SourceKind;
import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/task/dart.dart';
@@ -30,9 +32,9 @@
@override
SummaryResynthesizer resynthesizer;
- SdkSummaryResultProvider(this.context, this.bundle) {
+ SdkSummaryResultProvider(this.context, this.bundle, bool strongMode) {
resynthesizer = new SdkSummaryResynthesizer(
- context, typeProvider, context.sourceFactory, bundle);
+ context, typeProvider, context.sourceFactory, bundle, strongMode);
_buildCoreLibrary();
_buildAsyncLibrary();
resynthesizer.finalizeCoreAsyncLibraries();
@@ -119,6 +121,11 @@
return true;
}
}
+ } else if (target is VariableElement) {
+ if (result == PROPAGATED_VARIABLE || result == INFERRED_STATIC_VARIABLE) {
+ entry.setValue(result, target, TargetedResult.EMPTY_LIST);
+ return true;
+ }
}
return false;
}
@@ -156,10 +163,8 @@
final Map<String, LinkedLibrary> linkedSummaries = <String, LinkedLibrary>{};
SdkSummaryResynthesizer(AnalysisContext context, TypeProvider typeProvider,
- SourceFactory sourceFactory, this.bundle)
- : super(null, context, typeProvider, sourceFactory, false) {
- // TODO(paulberry): we always resynthesize the summary in weak mode. Is
- // this ok?
+ SourceFactory sourceFactory, this.bundle, bool strongMode)
+ : super(null, context, typeProvider, sourceFactory, strongMode) {
for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
unlinkedSummaries[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
}
@@ -185,6 +190,82 @@
}
/**
+ * An implementation of [DartSdk] which provides analysis results for `dart:`
+ * libraries from the given summary file. This implementation is limited and
+ * suitable only for command-line tools, but not for IDEs - it does not
+ * implement [sdkLibraries], [sdkVersion], [uris] and [fromFileUri].
+ */
+class SummaryBasedDartSdk implements DartSdk {
+ final bool strongMode;
+ SummaryDataStore _dataStore;
+ InSummaryPackageUriResolver _uriResolver;
+ PackageBundle _bundle;
+
+ /**
+ * The [AnalysisContext] which is used for all of the sources in this sdk.
+ */
+ InternalAnalysisContext _analysisContext;
+
+ SummaryBasedDartSdk(String summaryPath, this.strongMode) {
+ _dataStore = new SummaryDataStore(<String>[summaryPath]);
+ _uriResolver = new InSummaryPackageUriResolver(_dataStore);
+ _bundle = _dataStore.bundles.single;
+ }
+
+ /**
+ * Return the [PackageBundle] for this SDK, not `null`.
+ */
+ PackageBundle get bundle => _bundle;
+
+ @override
+ AnalysisContext get context {
+ if (_analysisContext == null) {
+ AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl()
+ ..strongMode = strongMode;
+ _analysisContext = new SdkAnalysisContext(analysisOptions);
+ SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
+ _analysisContext.sourceFactory = factory;
+ _analysisContext.resultProvider =
+ new SdkSummaryResultProvider(_analysisContext, _bundle, strongMode);
+ }
+ return _analysisContext;
+ }
+
+ @override
+ List<SdkLibrary> get sdkLibraries {
+ throw new UnimplementedError();
+ }
+
+ @override
+ String get sdkVersion {
+ throw new UnimplementedError();
+ }
+
+ @override
+ List<String> get uris {
+ throw new UnimplementedError();
+ }
+
+ @override
+ Source fromFileUri(Uri uri) {
+ return null;
+ }
+
+ @override
+ SdkLibrary getSdkLibrary(String uri) {
+ // This is not quite correct, but currently it's used only in
+ // to report errors on importing or exporting of internal libraries.
+ return null;
+ }
+
+ @override
+ Source mapDartUri(String uriStr) {
+ Uri uri = Uri.parse(uriStr);
+ return _uriResolver.resolveAbsolute(uri);
+ }
+}
+
+/**
* Provider for analysis results.
*/
abstract class SummaryResultProvider extends ResultProvider {
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index b1b6d95..3d9d552 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -19,6 +19,7 @@
import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/error/pending_error.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -563,6 +564,15 @@
'PARSE_ERRORS', AnalysisError.NO_ERRORS);
/**
+ * The list of [PendingError]s for a compilation unit.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<PendingError> PENDING_ERRORS =
+ new ListResultDescriptor<PendingError>(
+ 'PENDING_ERRORS', const <PendingError>[]);
+
+/**
* A list of the [VariableElement]s whose type should be known to propagate
* the type of another variable (the target).
*
@@ -648,6 +658,15 @@
new ListResultDescriptor<Source>('REFERENCED_SOURCES', Source.EMPTY_LIST);
/**
+ * The list of [ConstantEvaluationTarget]s on which error verification depends.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<ConstantEvaluationTarget> REQUIRED_CONSTANTS =
+ new ListResultDescriptor<ConstantEvaluationTarget>(
+ 'REQUIRED_CONSTANTS', const <ConstantEvaluationTarget>[]);
+
+/**
* The errors produced while resolving bounds of type parameters of classes,
* class and function aliases.
*
@@ -2247,6 +2266,73 @@
}
/**
+ * A task that builds [REQUIRED_CONSTANTS] for a unit.
+ */
+class ComputeRequiredConstantsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ComputeRequiredConstantsTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[PENDING_ERRORS, REQUIRED_CONSTANTS]);
+
+ ComputeRequiredConstantsTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ Source source = getRequiredSource();
+ //
+ // Prepare inputs.
+ //
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ //
+ // Use the ErrorVerifier to compute errors.
+ //
+ RequiredConstantsComputer computer = new RequiredConstantsComputer(source);
+ unit.accept(computer);
+ List<PendingError> pendingErrors = computer.pendingErrors;
+ List<ConstantEvaluationTarget> requiredConstants =
+ computer.requiredConstants;
+ //
+ // Record outputs.
+ //
+ outputs[PENDING_ERRORS] = pendingErrors;
+ outputs[REQUIRED_CONSTANTS] = requiredConstants;
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(unit)};
+ }
+
+ /**
+ * Create a [ComputeRequiredConstantsTask] based on the given [target] in
+ * the given [context].
+ */
+ static ComputeRequiredConstantsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ComputeRequiredConstantsTask(context, target);
+ }
+}
+
+/**
* A base class for analysis tasks whose target is expected to be a
* [ConstantEvaluationTarget].
*/
@@ -5547,9 +5633,9 @@
*/
class VerifyUnitTask extends SourceBasedAnalysisTask {
/**
- * The name of the [RESOLVED_UNIT] input.
+ * The name of the [PENDING_ERRORS] input.
*/
- static const String UNIT_INPUT = 'UNIT_INPUT';
+ static const String PENDING_ERRORS_INPUT = 'PENDING_ERRORS_INPUT';
/**
* The name of the input of a mapping from [REFERENCED_SOURCES] to their
@@ -5564,6 +5650,11 @@
static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
/**
+ * The name of the [RESOLVED_UNIT] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
* The task descriptor describing this kind of task.
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('VerifyUnitTask',
@@ -5594,10 +5685,7 @@
//
// Prepare inputs.
//
- TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
- sourceTimeMap =
- getRequiredInput(REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT);
CompilationUnitElement unitElement = unit.element;
LibraryElement libraryElement = unitElement.library;
if (libraryElement == null) {
@@ -5605,6 +5693,10 @@
'VerifyUnitTask verifying a unit with no library: '
'${unitElement.source.fullName}');
}
+ List<PendingError> pendingErrors = getRequiredInput(PENDING_ERRORS_INPUT);
+ sourceTimeMap =
+ getRequiredInput(REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT);
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
//
// Validate the directives.
//
@@ -5626,7 +5718,12 @@
context.analysisOptions.enableSuperMixins,
context.analysisOptions.enableAssertMessage);
unit.accept(errorVerifier);
-
+ //
+ // Convert the pending errors into actual errors.
+ //
+ for (PendingError pendingError in pendingErrors) {
+ errorListener.onError(pendingError.toAnalysisError());
+ }
//
// Record outputs.
//
@@ -5682,6 +5779,8 @@
UNIT_INPUT: RESOLVED_UNIT.of(unit),
REFERENCED_SOURCE_MODIFICATION_TIME_MAP_INPUT:
REFERENCED_SOURCES.of(unit.library).toMapOf(MODIFICATION_TIME),
+ PENDING_ERRORS_INPUT: PENDING_ERRORS.of(unit),
+ 'requiredConstants': REQUIRED_CONSTANTS.of(unit).toListOf(CONSTANT_VALUE),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
};
}
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 47acf37..fd1c224 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -21,7 +21,7 @@
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';
-/// The errors produced while parsing `.analysis_options` files.
+/// The errors produced while parsing an analysis options file.
///
/// The list will be empty if there were no errors, but will not be `null`.
final ListResultDescriptor<AnalysisError> ANALYSIS_OPTIONS_ERRORS =
@@ -204,7 +204,7 @@
}
}
-/// A task that generates errors for an `.analysis_options` file.
+/// A task that generates errors for an analysis options file.
class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
/// The name of the input whose value is the content of the file.
static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
@@ -276,7 +276,8 @@
*/
static TaskSuitability suitabilityFor(AnalysisTarget target) {
if (target is Source &&
- target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_FILE) {
+ (target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_FILE ||
+ target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE)) {
return TaskSuitability.HIGHEST;
}
return TaskSuitability.NONE;
@@ -324,7 +325,7 @@
LinterOptionsValidator() : super('linter', const ['rules']);
}
-/// Validates options defined in an `.analysis_options` file.
+/// Validates options defined in an analysis options file.
class OptionsFileValidator {
// TODO(pq): move to an extension point.
final List<OptionsValidator> _validators = [
diff --git a/pkg/analyzer/lib/src/task/options_work_manager.dart b/pkg/analyzer/lib/src/task/options_work_manager.dart
index 2074eb0..7956a8a 100644
--- a/pkg/analyzer/lib/src/task/options_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/options_work_manager.dart
@@ -14,7 +14,7 @@
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/task/model.dart';
-/// The manager for `.analysis_options` specific analysis.
+/// The manager for analysis options specific analysis.
class OptionsWorkManager implements WorkManager {
/// The context for which work is being managed.
final InternalAnalysisContext context;
@@ -162,7 +162,7 @@
return state != CacheState.VALID && state != CacheState.ERROR;
}
- /// Return `true` if the given target is an `.analysis_options` source.
+ /// Return `true` if the given target is an analysis options source.
static bool _isOptionsSource(AnalysisTarget target) =>
target is Source &&
AnalysisEngine.isAnalysisOptionsFileName(target.fullName);
diff --git a/pkg/analyzer/lib/src/task/strong/info.dart b/pkg/analyzer/lib/src/task/strong/info.dart
index 39885cd..408c05d 100644
--- a/pkg/analyzer/lib/src/task/strong/info.dart
+++ b/pkg/analyzer/lib/src/task/strong/info.dart
@@ -469,7 +469,7 @@
abstract class StaticInfo {
/// Strong-mode error code names.
///
- /// Used for error code configuration validation in `.analysis_options`.
+ /// Used for error code configuration validation in an analysis options file.
static const List<String> names = const [
//
// Manually populated.
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 9e15c290..541d5fc 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.27.4-alpha.2
+version: 0.27.4-alpha.6
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -12,7 +12,7 @@
html: ^0.12.0
package_config: ^0.1.1
path: '>=0.9.0 <2.0.0'
- plugin: ^0.1.0
+ plugin: ^0.2.0
watcher: '>=0.9.6 <0.10.0'
yaml: ^2.1.2
dev_dependencies:
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index f032daf..04481ef 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -3483,6 +3483,10 @@
_assertTrue("{ do {} while (throw ''); }");
}
+ void test_doStatement_return() {
+ _assertTrue("{ do { return null; } while (1 == 2); }");
+ }
+
void test_doStatement_true_break() {
_assertFalse("{ do { break; } while (true); }");
}
diff --git a/pkg/analyzer/test/generated/hint_code_test.dart b/pkg/analyzer/test/generated/hint_code_test.dart
index 7a05a39..3975270 100644
--- a/pkg/analyzer/test/generated/hint_code_test.dart
+++ b/pkg/analyzer/test/generated/hint_code_test.dart
@@ -1738,6 +1738,29 @@
verify([source]);
}
+ void test_required_method_param_in_other_lib() {
+ addNamedSource(
+ '/a_lib.dart',
+ r'''
+library a_lib;
+import 'package:meta/meta.dart';
+class A {
+ void m({@Required('must specify an `a`') int a}) {}
+}
+''');
+
+ Source source = addSource(r'''
+import "a_lib.dart";
+f() {
+ new A().m();
+}
+''');
+
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS]);
+ verify([source]);
+ }
+
void test_typeCheck_type_is_Null() {
Source source = addSource(r'''
m(i) {
@@ -1765,8 +1788,7 @@
addNamedSource("/lib1.dart", "library lib1;");
computeLibrarySourceErrors(source);
assertErrors(
- source,
- [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_HIDDEN_NAME]);
+ source, [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_HIDDEN_NAME]);
verify([source]);
}
@@ -1777,8 +1799,7 @@
addNamedSource("/lib1.dart", "library lib1;");
computeLibrarySourceErrors(source);
assertErrors(
- source,
- [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_SHOWN_NAME]);
+ source, [HintCode.UNUSED_IMPORT, HintCode.UNDEFINED_SHOWN_NAME]);
verify([source]);
}
diff --git a/pkg/analyzer/test/source/analysis_options_provider_test.dart b/pkg/analyzer/test/source/analysis_options_provider_test.dart
index ee9f0e0..07a7ff6 100644
--- a/pkg/analyzer/test/source/analysis_options_provider_test.dart
+++ b/pkg/analyzer/test/source/analysis_options_provider_test.dart
@@ -9,6 +9,7 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:unittest/unittest.dart';
import 'package:yaml/yaml.dart';
@@ -18,7 +19,8 @@
main() {
initializeTestEnvironment();
- runReflectiveTests(AnalysisOptionsProviderTest);
+ runReflectiveTests(AnalysisOptionsProviderOldTest);
+ runReflectiveTests(AnalysisOptionsProviderNewTest);
group('AnalysisOptionsProvider', () {
void expectMergesTo(String defaults, String overrides, String expected) {
var optionsProvider = new AnalysisOptionsProvider();
@@ -100,12 +102,23 @@
}
@reflectiveTest
-class AnalysisOptionsProviderTest {
+class AnalysisOptionsProviderNewTest extends AnalysisOptionsProviderTest {
+ String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
+}
+
+@reflectiveTest
+class AnalysisOptionsProviderOldTest extends AnalysisOptionsProviderTest {
+ String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+}
+
+abstract class AnalysisOptionsProviderTest {
TestPathTranslator pathTranslator;
ResourceProvider resourceProvider;
AnalysisOptionsProvider provider = new AnalysisOptionsProvider();
+ String get optionsFileName;
+
void setUp() {
var rawProvider = new MemoryResourceProvider(isWindows: isWindows);
resourceProvider = new TestResourceProvider(rawProvider);
@@ -115,14 +128,14 @@
void test_getOptions_crawlUp_hasInFolder() {
pathTranslator.newFolder('/foo/bar');
pathTranslator.newFile(
- '/foo/.analysis_options',
+ '/foo/$optionsFileName',
r'''
analyzer:
ignore:
- foo
''');
pathTranslator.newFile(
- '/foo/bar/.analysis_options',
+ '/foo/bar/$optionsFileName',
r'''
analyzer:
ignore:
@@ -140,14 +153,14 @@
void test_getOptions_crawlUp_hasInParent() {
pathTranslator.newFolder('/foo/bar/baz');
pathTranslator.newFile(
- '/foo/.analysis_options',
+ '/foo/$optionsFileName',
r'''
analyzer:
ignore:
- foo
''');
pathTranslator.newFile(
- '/foo/bar/.analysis_options',
+ '/foo/bar/$optionsFileName',
r'''
analyzer:
ignore:
@@ -169,14 +182,14 @@
}
void test_getOptions_empty() {
- pathTranslator.newFile('/.analysis_options', r'''#empty''');
+ pathTranslator.newFile('/$optionsFileName', r'''#empty''');
Map<String, YamlNode> options = _getOptions('/');
expect(options, isNotNull);
expect(options, isEmpty);
}
void test_getOptions_invalid() {
- pathTranslator.newFile('/.analysis_options', r''':''');
+ pathTranslator.newFile('/$optionsFileName', r''':''');
expect(() {
_getOptions('/');
}, throws);
@@ -184,7 +197,7 @@
void test_getOptions_simple() {
pathTranslator.newFile(
- '/.analysis_options',
+ '/$optionsFileName',
r'''
analyzer:
ignore:
diff --git a/pkg/analyzer/test/src/dart/ast/utilities_test.dart b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
index ce4b499..6653c20 100644
--- a/pkg/analyzer/test/src/dart/ast/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
@@ -664,6 +664,11 @@
fromNode.staticElement = staticElement;
FunctionExpressionInvocation toNode =
AstFactory.functionExpressionInvocation(AstFactory.identifier3("f"));
+ ClassElement elementT = ElementFactory.classElement2('T');
+ fromNode.typeArguments =
+ AstFactory.typeArgumentList(<TypeName>[AstFactory.typeName(elementT)]);
+ toNode.typeArguments =
+ AstFactory.typeArgumentList(<TypeName>[AstFactory.typeName4('T')]);
_copyAndVerifyInvocation(fromNode, toNode);
@@ -791,6 +796,11 @@
void test_visitMethodInvocation() {
MethodInvocation fromNode = AstFactory.methodInvocation2("m");
MethodInvocation toNode = AstFactory.methodInvocation2("m");
+ ClassElement elementT = ElementFactory.classElement2('T');
+ fromNode.typeArguments =
+ AstFactory.typeArgumentList(<TypeName>[AstFactory.typeName(elementT)]);
+ toNode.typeArguments =
+ AstFactory.typeArgumentList(<TypeName>[AstFactory.typeName4('T')]);
_copyAndVerifyInvocation(fromNode, toNode);
}
@@ -1086,6 +1096,15 @@
expect(toNode.staticType, same(staticType));
expect(toNode.propagatedInvokeType, same(propagatedInvokeType));
expect(toNode.staticInvokeType, same(staticInvokeType));
+ List<TypeName> fromTypeArguments = toNode.typeArguments.arguments;
+ List<TypeName> toTypeArguments = fromNode.typeArguments.arguments;
+ if (fromTypeArguments != null) {
+ for (int i = 0; i < fromTypeArguments.length; i++) {
+ TypeName toArgument = fromTypeArguments[i];
+ TypeName fromArgument = toTypeArguments[i];
+ expect(toArgument.type, same(fromArgument.type));
+ }
+ }
}
}
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index 4b5ee12..ff2f9568 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -5,6 +5,7 @@
library analyzer.test.src.dart.element.element_test;
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
@@ -21,12 +22,14 @@
import '../../../generated/analysis_context_factory.dart'
show AnalysisContextHelper;
+import '../../../generated/resolver_test_case.dart';
import '../../../generated/test_support.dart';
import '../../../reflective_tests.dart';
import '../../../utils.dart';
main() {
initializeTestEnvironment();
+ runReflectiveTests(ElementAnnotationImplTest);
runReflectiveTests(FieldElementImplTest);
runReflectiveTests(FunctionTypeImplTest);
runReflectiveTests(InterfaceTypeImplTest);
@@ -41,6 +44,7 @@
runReflectiveTests(MethodElementImplTest);
runReflectiveTests(MultiplyDefinedElementImplTest);
runReflectiveTests(ParameterElementImplTest);
+ runReflectiveTests(TopLevelVariableElementImplTest);
}
@reflectiveTest
@@ -1091,6 +1095,41 @@
}
@reflectiveTest
+class ElementAnnotationImplTest extends ResolverTestCase {
+ void test_computeConstantValue() {
+ addNamedSource(
+ '/a.dart',
+ r'''
+class A {
+ final String f;
+ const A(this.f);
+}
+void f(@A('x') int p) {}
+''');
+ Source source = addSource(r'''
+import 'a.dart';
+main() {
+ f(3);
+}
+''');
+ LibraryElement library = resolve2(source);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration main = unit.declarations[0];
+ BlockFunctionBody body = main.functionExpression.body;
+ ExpressionStatement statement = body.block.statements[0];
+ MethodInvocation invocation = statement.expression;
+ ParameterElement parameter =
+ invocation.argumentList.arguments[0].bestParameterElement;
+ ElementAnnotation annotation = parameter.metadata[0];
+ expect(annotation.constantValue, isNull);
+ DartObject value = annotation.computeConstantValue();
+ expect(value, isNotNull);
+ expect(value.getField('f').toStringValue(), 'x');
+ expect(annotation.constantValue, value);
+ }
+}
+
+@reflectiveTest
class ElementImplTest extends EngineTestCase {
void test_equals() {
LibraryElementImpl library =
@@ -4158,6 +4197,37 @@
}
@reflectiveTest
+class TopLevelVariableElementImplTest extends ResolverTestCase {
+ void test_computeConstantValue() {
+ addNamedSource(
+ '/a.dart',
+ r'''
+const int C = 42;
+''');
+ Source source = addSource(r'''
+import 'a.dart';
+main() {
+ print(C);
+}
+''');
+ LibraryElement library = resolve2(source);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration main = unit.declarations[0];
+ BlockFunctionBody body = main.functionExpression.body;
+ ExpressionStatement statement = body.block.statements[0];
+ MethodInvocation invocation = statement.expression;
+ SimpleIdentifier argument = invocation.argumentList.arguments[0];
+ PropertyAccessorElementImpl getter = argument.bestElement;
+ TopLevelVariableElement constant = getter.variable;
+ expect(constant.constantValue, isNull);
+ DartObject value = constant.computeConstantValue();
+ expect(value, isNotNull);
+ expect(value.toIntValue(), 42);
+ expect(constant.constantValue, value);
+ }
+}
+
+@reflectiveTest
class TypeParameterTypeImplTest extends EngineTestCase {
void test_creation() {
expect(
diff --git a/pkg/analyzer/test/src/summary/linker_test.dart b/pkg/analyzer/test/src/summary/linker_test.dart
index 3883876..c067a9e 100644
--- a/pkg/analyzer/test/src/summary/linker_test.dart
+++ b/pkg/analyzer/test/src/summary/linker_test.dart
@@ -3,7 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/link.dart';
import 'package:unittest/unittest.dart';
@@ -24,6 +26,8 @@
@override
bool get allowMissingFiles => false;
+ Matcher get isUndefined => new isInstanceOf<UndefinedElementForLink>();
+
LibraryElementInBuildUnit get testLibrary => _testLibrary ??=
linker.getLibrary(linkerInputs.testDartUri) as LibraryElementInBuildUnit;
@@ -150,6 +154,56 @@
expect(classC.unnamedConstructor.isCycleFree, false);
}
+ void test_getContainedName_nonStaticField() {
+ createLinker('class C { var f; }');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ ClassElementForLink_Class c = library.getContainedName('C');
+ expect(c.getContainedName('f'), isNot(isUndefined));
+ }
+
+ void test_getContainedName_nonStaticGetter() {
+ createLinker('class C { get g => null; }');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ ClassElementForLink_Class c = library.getContainedName('C');
+ expect(c.getContainedName('g'), isNot(isUndefined));
+ }
+
+ void test_getContainedName_nonStaticMethod() {
+ createLinker('class C { m() {} }');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ ClassElementForLink_Class c = library.getContainedName('C');
+ expect(c.getContainedName('m'), isNot(isUndefined));
+ }
+
+ void test_getContainedName_nonStaticSetter() {
+ createLinker('class C { void set s(value) {} }');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ ClassElementForLink_Class c = library.getContainedName('C');
+ expect(c.getContainedName('s='), isNot(isUndefined));
+ }
+
+ void test_inferredType_closure_fromBundle() {
+ var bundle = createPackageBundle(
+ '''
+var x = () {};
+''',
+ path: '/a.dart');
+ addBundle(bundle);
+ createLinker('''
+import 'a.dart';
+var y = x;
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ expect(
+ library
+ .getContainedName('y')
+ .asTypeInferenceNode
+ .variableElement
+ .inferredType
+ .toString(),
+ '() → dynamic');
+ }
+
void test_inferredType_instanceField_dynamic() {
createLinker('''
var x;
@@ -552,6 +606,34 @@
expect(libraryCycle.libraries, [testLibrary]);
}
+ void test_malformed_function_reference() {
+ // Create a corrupted package bundle in which the inferred type of `x`
+ // refers to a non-existent local function.
+ var bundle = createPackageBundle('var x = () {}', path: '/a.dart');
+ expect(bundle.linkedLibraries, hasLength(1));
+ expect(bundle.linkedLibraries[0].units, hasLength(1));
+ for (LinkedReferenceBuilder ref
+ in bundle.linkedLibraries[0].units[0].references) {
+ if (ref.kind == ReferenceKind.function) {
+ ref.localIndex = 1234;
+ }
+ }
+ addBundle(bundle);
+ createLinker('''
+import 'a.dart';
+var y = x;
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ expect(
+ library
+ .getContainedName('y')
+ .asTypeInferenceNode
+ .variableElement
+ .inferredType
+ .toString(),
+ 'dynamic');
+ }
+
void test_multiplyInheritedExecutable_differentSignatures() {
createLinker('''
class B {
@@ -598,11 +680,41 @@
expect(hTypeElement.typeParameterContext, same(f));
}
+ void test_topLevelFunction_isStatic() {
+ createLinker('f() {}');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ TopLevelFunctionElementForLink f = library.getContainedName('f');
+ expect(f.isStatic, true);
+ }
+
+ void test_topLevelGetter_isStatic() {
+ createLinker('get x => null;');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ PropertyAccessorElementForLink_Executable x = library.getContainedName('x');
+ expect(x.isStatic, true);
+ }
+
+ void test_topLevelSetter_isStatic() {
+ createLinker('void set x(value) {}');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ PropertyAccessorElementForLink_Executable x =
+ library.getContainedName('x=');
+ expect(x.isStatic, true);
+ }
+
+ void test_topLevelVariable_isStatic() {
+ createLinker('var x;');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ PropertyAccessorElementForLink_Variable x = library.getContainedName('x');
+ expect(x.isStatic, true);
+ expect(x.variable.isStatic, true);
+ }
+
void test_typeParameter_isTypeParameterInScope_direct() {
createLinker('class C<T, U> {}');
ClassElementForLink_Class c = testLibrary.getContainedName('C');
- TypeParameterElementForLink t = c.typeParameters[0];
- TypeParameterElementForLink u = c.typeParameters[1];
+ TypeParameterElementImpl t = c.typeParameters[0];
+ TypeParameterElementImpl u = c.typeParameters[1];
expect(c.isTypeParameterInScope(t), true);
expect(c.isTypeParameterInScope(u), true);
}
@@ -611,8 +723,8 @@
createLinker('class C<T, U> { f<V, W>() {} }');
ClassElementForLink_Class c = testLibrary.getContainedName('C');
MethodElementForLink f = c.methods[0];
- TypeParameterElementForLink t = c.typeParameters[0];
- TypeParameterElementForLink u = c.typeParameters[1];
+ TypeParameterElementImpl t = c.typeParameters[0];
+ TypeParameterElementImpl u = c.typeParameters[1];
expect(f.isTypeParameterInScope(t), true);
expect(f.isTypeParameterInScope(u), true);
}
@@ -621,8 +733,8 @@
createLinker('class C<T, U> { f<V, W>() {} }');
ClassElementForLink_Class c = testLibrary.getContainedName('C');
MethodElementForLink f = c.methods[0];
- TypeParameterElementForLink v = f.typeParameters[0];
- TypeParameterElementForLink w = f.typeParameters[1];
+ TypeParameterElementImpl v = f.typeParameters[0];
+ TypeParameterElementImpl w = f.typeParameters[1];
expect(c.isTypeParameterInScope(v), false);
expect(c.isTypeParameterInScope(w), false);
}
@@ -631,13 +743,34 @@
createLinker('class C<T, U> {} class D<V, W> {}');
ClassElementForLink_Class c = testLibrary.getContainedName('C');
ClassElementForLink_Class d = testLibrary.getContainedName('D');
- TypeParameterElementForLink t = c.typeParameters[0];
- TypeParameterElementForLink u = c.typeParameters[1];
- TypeParameterElementForLink v = d.typeParameters[0];
- TypeParameterElementForLink w = d.typeParameters[1];
+ TypeParameterElementImpl t = c.typeParameters[0];
+ TypeParameterElementImpl u = c.typeParameters[1];
+ TypeParameterElementImpl v = d.typeParameters[0];
+ TypeParameterElementImpl w = d.typeParameters[1];
expect(c.isTypeParameterInScope(v), false);
expect(c.isTypeParameterInScope(w), false);
expect(d.isTypeParameterInScope(t), false);
expect(d.isTypeParameterInScope(u), false);
}
+
+ void test_variable_initializer_presence() {
+ // Any variable declaration with an initializer should have a non-null value
+ // for `initializer`, regardless of whether it is constant and regardless of
+ // whether it has an explicit type.
+ createLinker('''
+const int c = 0;
+int i = 0;
+int j;
+var v = 0;
+''');
+ LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
+ PropertyAccessorElementForLink_Variable c = library.getContainedName('c');
+ expect(c.variable.initializer, isNotNull);
+ PropertyAccessorElementForLink_Variable i = library.getContainedName('i');
+ expect(i.variable.initializer, isNotNull);
+ PropertyAccessorElementForLink_Variable j = library.getContainedName('j');
+ expect(j.variable.initializer, isNull);
+ PropertyAccessorElementForLink_Variable v = library.getContainedName('v');
+ expect(v.variable.initializer, isNotNull);
+ }
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 47faf81..cf9d727 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -564,12 +564,6 @@
TestSummaryResynthesizer encodeDecodeLibrarySource(Source source) {
return _encodeLibrary(source);
}
-
- @override
- @failingTest
- void test_inferred_function_type_in_generic_class_constructor() {
- super.test_inferred_function_type_in_generic_class_constructor();
- }
}
/**
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index 30221bb..e4f296e 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -211,8 +211,8 @@
void compareClassElements(
ClassElement resynthesized, ClassElement original, String desc) {
- ClassElementImpl r = getActualElement(resynthesized, desc);
- ClassElementImpl o = getActualElement(original, desc);
+ ClassElementImpl r = ClassElementImpl.getImpl(resynthesized);
+ ClassElementImpl o = ClassElementImpl.getImpl(original);
compareElements(r, o, desc);
expect(r.fields.length, o.fields.length, reason: '$desc fields.length');
for (int i = 0; i < r.fields.length; i++) {
@@ -675,11 +675,11 @@
reason: desc);
expect(resynthesized.docRange, original.docRange, reason: desc);
compareMetadata(resynthesized.metadata, original.metadata, desc);
- // Modifiers are a pain to test via handles. So just test them via the
- // actual element.
+
+ // Validate modifiers.
for (Modifier modifier in Modifier.persistedValues) {
- bool got = rImpl.hasModifier(modifier);
- bool want = oImpl.hasModifier(modifier);
+ bool got = _hasModifier(resynthesized, modifier);
+ bool want = _hasModifier(original, modifier);
expect(got, want,
reason: 'Mismatch in $desc.$modifier: got $got, want $want');
}
@@ -1221,6 +1221,97 @@
SimpleIdentifier identifier = initializer;
expect(identifier.staticElement, isNull, reason: desc);
}
+
+ bool _hasModifier(Element element, Modifier modifier) {
+ if (modifier == Modifier.ABSTRACT) {
+ if (element is ClassElement) {
+ return element.isAbstract;
+ }
+ if (element is ExecutableElement) {
+ return element.isAbstract;
+ }
+ return false;
+ } else if (modifier == Modifier.ASYNCHRONOUS) {
+ if (element is ExecutableElement) {
+ return element.isAsynchronous;
+ }
+ return false;
+ } else if (modifier == Modifier.CONST) {
+ if (element is VariableElement) {
+ return element.isConst;
+ }
+ return false;
+ } else if (modifier == Modifier.DEFERRED) {
+ if (element is ImportElement) {
+ return element.isDeferred;
+ }
+ return false;
+ } else if (modifier == Modifier.ENUM) {
+ if (element is ClassElement) {
+ return element.isEnum;
+ }
+ return false;
+ } else if (modifier == Modifier.EXTERNAL) {
+ if (element is ExecutableElement) {
+ return element.isExternal;
+ }
+ return false;
+ } else if (modifier == Modifier.FACTORY) {
+ if (element is ConstructorElement) {
+ return element.isFactory;
+ }
+ return false;
+ } else if (modifier == Modifier.FINAL) {
+ if (element is VariableElement) {
+ return element.isFinal;
+ }
+ return false;
+ } else if (modifier == Modifier.GENERATOR) {
+ if (element is ExecutableElement) {
+ return element.isGenerator;
+ }
+ return false;
+ } else if (modifier == Modifier.GETTER) {
+ if (element is PropertyAccessorElement) {
+ return element.isGetter;
+ }
+ return false;
+ } else if (modifier == Modifier.HAS_EXT_URI) {
+ if (element is LibraryElement) {
+ return element.hasExtUri;
+ }
+ return false;
+ } else if (modifier == Modifier.IMPLICIT_TYPE) {
+ if (element is ExecutableElement) {
+ return element.hasImplicitReturnType;
+ }
+ return false;
+ } else if (modifier == Modifier.MIXIN_APPLICATION) {
+ if (element is ClassElement) {
+ return element.isMixinApplication;
+ }
+ return false;
+ } else if (modifier == Modifier.REFERENCES_SUPER) {
+ if (element is ClassElement) {
+ return element.hasReferenceToSuper;
+ }
+ return false;
+ } else if (modifier == Modifier.SETTER) {
+ if (element is PropertyAccessorElement) {
+ return element.isSetter;
+ }
+ return false;
+ } else if (modifier == Modifier.STATIC) {
+ if (element is ExecutableElement) {
+ return element.isStatic;
+ }
+ return false;
+ } else if (modifier == Modifier.SYNTHETIC) {
+ return element.isSynthetic;
+ }
+ throw new UnimplementedError(
+ 'Modifier $modifier for ${element?.runtimeType}');
+ }
}
@reflectiveTest
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 0abc4de..9c50c86 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -1823,6 +1823,27 @@
]);
}
+ test_constExpr_functionExpression_inConstructorInitializers() {
+ // Even though function expressions are not allowed in constant
+ // declarations, they might occur due to erroneous code, so make sure they
+ // function correctly.
+ UnlinkedExecutable executable = serializeClassText('''
+class C {
+ final x, y;
+ const C() : x = (() => 42), y = (() => 43);
+}
+''').executables[0];
+ expect(executable.localFunctions, hasLength(2));
+ _assertUnlinkedConst(executable.constantInitializers[0].expression,
+ isValidConst: false,
+ operators: [UnlinkedConstOperation.pushLocalFunctionReference],
+ ints: [0, 0]);
+ _assertUnlinkedConst(executable.constantInitializers[1].expression,
+ isValidConst: false,
+ operators: [UnlinkedConstOperation.pushLocalFunctionReference],
+ ints: [0, 1]);
+ }
+
test_constExpr_invokeConstructor_generic_named() {
UnlinkedVariable variable = serializeVariableText('''
class C<K, V> {
@@ -3471,6 +3492,33 @@
operators: [UnlinkedConstOperation.pushInt], ints: [42]);
}
+ test_constructor_initializers_superInvocation_namedExpression() {
+ UnlinkedExecutable executable =
+ findExecutable('', executables: serializeClassText(r'''
+class A {
+ const A(a, {int b, int c});
+}
+class C extends A {
+ const C() : super(1, b: 2, c: 3);
+}
+''').executables);
+ expect(executable.constantInitializers, hasLength(1));
+ UnlinkedConstructorInitializer initializer =
+ executable.constantInitializers[0];
+ expect(
+ initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
+ expect(initializer.name, '');
+ expect(initializer.expression, isNull);
+ expect(initializer.arguments, hasLength(3));
+ _assertUnlinkedConst(initializer.arguments[0],
+ operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+ _assertUnlinkedConst(initializer.arguments[1],
+ operators: [UnlinkedConstOperation.pushInt], ints: [2]);
+ _assertUnlinkedConst(initializer.arguments[2],
+ operators: [UnlinkedConstOperation.pushInt], ints: [3]);
+ expect(initializer.argumentNames, ['b', 'c']);
+ }
+
test_constructor_initializers_superInvocation_unnamed() {
UnlinkedExecutable executable =
findExecutable('ccc', executables: serializeClassText(r'''
@@ -3538,33 +3586,6 @@
expect(initializer.argumentNames, ['b', 'c']);
}
- test_constructor_initializers_superInvocation_namedExpression() {
- UnlinkedExecutable executable =
- findExecutable('', executables: serializeClassText(r'''
-class A {
- const A(a, {int b, int c});
-}
-class C extends A {
- const C() : super(1, b: 2, c: 3);
-}
-''').executables);
- expect(executable.constantInitializers, hasLength(1));
- UnlinkedConstructorInitializer initializer =
- executable.constantInitializers[0];
- expect(
- initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
- expect(initializer.name, '');
- expect(initializer.expression, isNull);
- expect(initializer.arguments, hasLength(3));
- _assertUnlinkedConst(initializer.arguments[0],
- operators: [UnlinkedConstOperation.pushInt], ints: [1]);
- _assertUnlinkedConst(initializer.arguments[1],
- operators: [UnlinkedConstOperation.pushInt], ints: [2]);
- _assertUnlinkedConst(initializer.arguments[2],
- operators: [UnlinkedConstOperation.pushInt], ints: [3]);
- expect(initializer.argumentNames, ['b', 'c']);
- }
-
test_constructor_initializers_thisInvocation_unnamed() {
UnlinkedExecutable executable =
findExecutable('named', executables: serializeClassText(r'''
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 880479d..f65c3fb 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -23,7 +23,8 @@
main() {
initializeTestEnvironment();
runReflectiveTests(ContextConfigurationTest);
- runReflectiveTests(GenerateOptionsErrorsTaskTest);
+ runReflectiveTests(GenerateNewOptionsErrorsTaskTest);
+ runReflectiveTests(GenerateOldOptionsErrorsTaskTest);
runReflectiveTests(OptionsFileValidatorTest);
}
@@ -104,8 +105,7 @@
''');
List<ErrorProcessor> processors =
- context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS)
- as List<ErrorProcessor>;
+ context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
expect(processors, hasLength(2));
var unused_local = new AnalysisError(
@@ -146,10 +146,19 @@
}
@reflectiveTest
-class GenerateOptionsErrorsTaskTest extends AbstractContextTest {
- final optionsFilePath = '/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}';
+class GenerateNewOptionsErrorsTaskTest extends GenerateOptionsErrorsTaskTest {
+ String get optionsFilePath => '/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}';
+}
+@reflectiveTest
+class GenerateOldOptionsErrorsTaskTest extends GenerateOptionsErrorsTaskTest {
+ String get optionsFilePath => '/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}';
+}
+
+abstract class GenerateOptionsErrorsTaskTest extends AbstractContextTest {
Source source;
+
+ String get optionsFilePath;
LineInfo lineInfo(String source) =>
GenerateOptionsErrorsTask.computeLineInfo(source);
diff --git a/pkg/analyzer/test/src/task/options_work_manager_test.dart b/pkg/analyzer/test/src/task/options_work_manager_test.dart
index cf6cac0..64baa5c 100644
--- a/pkg/analyzer/test/src/task/options_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/options_work_manager_test.dart
@@ -31,27 +31,37 @@
main() {
initializeTestEnvironment();
- runReflectiveTests(OptionsWorkManagerTest);
+ runReflectiveTests(OptionsWorkManagerNewFileTest);
+ runReflectiveTests(OptionsWorkManagerOldFileTest);
}
@reflectiveTest
-class OptionsWorkManagerTest {
- static final optionsFile = AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+class OptionsWorkManagerNewFileTest extends OptionsWorkManagerTest {
+ String get optionsFile => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
+}
+
+@reflectiveTest
+class OptionsWorkManagerOldFileTest extends OptionsWorkManagerTest {
+ String get optionsFile => AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+}
+
+abstract class OptionsWorkManagerTest {
InternalAnalysisContext context = new _InternalAnalysisContextMock();
AnalysisCache cache;
-
OptionsWorkManager manager;
CaughtException caughtException = new CaughtException(null, null);
- Source source1 = new TestSource('test1/$optionsFile');
- Source source2 = new TestSource('test2/$optionsFile');
- Source source3 = new TestSource('test3/$optionsFile');
- Source source4 = new TestSource('test4/$optionsFile');
+ Source source1;
+
+ Source source2;
+ Source source3;
+ Source source4;
CacheEntry entry1;
CacheEntry entry2;
CacheEntry entry3;
CacheEntry entry4;
+ String get optionsFile;
void expect_sourceQueue(List<Source> sources) {
expect(manager.sourceQueue, unorderedEquals(sources));
@@ -60,6 +70,10 @@
void setUp() {
cache = context.analysisCache;
manager = new OptionsWorkManager(context);
+ source1 = new TestSource('test1/$optionsFile');
+ source2 = new TestSource('test2/$optionsFile');
+ source3 = new TestSource('test3/$optionsFile');
+ source4 = new TestSource('test4/$optionsFile');
entry1 = context.getCacheEntry(source1);
entry2 = context.getCacheEntry(source2);
entry3 = context.getCacheEntry(source3);
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 83d6485..a4bc6b7 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1571,6 +1571,19 @@
''');
}
+ void test_genericMethods_usesGreatestLowerBound() {
+ var mainUnit = checkFile(r'''
+typedef Iterable<num> F(int x);
+typedef List<int> G(double x);
+
+/*=T*/ generic/*<T>*/(a(/*=T*/ _), b(/*=T*/ _)) => null;
+
+var v = generic((F f) => null, (G g) => null);
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.type.toString(), '(num) → List<int>');
+ }
+
void test_infer_assignToIndex() {
checkFile(r'''
List<double> a = <double>[];
@@ -2305,6 +2318,14 @@
expect(f.type.toString(), '() → dynamic');
}
+ void test_inferredType_fromTopLevelExecutableTearoff() {
+ var mainUnit = checkFile('''
+var v = print;
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.type.toString(), '(Object) → void');
+ }
+
void test_inferredType_isEnum() {
var mainUnit = checkFile('''
enum E { v1 }
diff --git a/pkg/analyzer/tool/summary/build_sdk_summaries.dart b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
index 8a9adb8..9d1c34b 100644
--- a/pkg/analyzer/tool/summary/build_sdk_summaries.dart
+++ b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
@@ -19,7 +19,10 @@
return;
}
String command = args[0];
- if (command == 'multiple-outputs' && args.length >= 2 && args.length <= 3) {
+ if ((command == 'multiple-outputs' || command == 'strong-outputs') &&
+ args.length >= 2 &&
+ args.length <= 3) {
+ bool includeSpec = command != 'strong-outputs';
//
// Prepare the output path.
//
@@ -34,7 +37,7 @@
// Prepare results.
//
String sdkPath = args.length > 2 ? args[2] : null;
- _Output output = _buildMultipleOutputs(sdkPath);
+ _Output output = _buildMultipleOutputs(sdkPath, includeSpec);
if (output == null) {
exitCode = 1;
return;
@@ -42,7 +45,9 @@
//
// Write results.
//
- output.spec.writeMultiple(outputDirectoryPath, 'spec');
+ if (includeSpec) {
+ output.spec.writeMultiple(outputDirectoryPath, 'spec');
+ }
output.strong.writeMultiple(outputDirectoryPath, 'strong');
} else if (command == 'single-output' &&
args.length >= 2 &&
@@ -52,7 +57,7 @@
//
// Prepare results.
//
- _Output output = _buildMultipleOutputs(sdkPath);
+ _Output output = _buildMultipleOutputs(sdkPath, true);
if (output == null) {
exitCode = 1;
return;
@@ -106,7 +111,7 @@
const int _FIELD_STRONG_INDEX = 3;
const int _FIELD_STRONG_SUM = 2;
-_Output _buildMultipleOutputs(String sdkPath) {
+_Output _buildMultipleOutputs(String sdkPath, bool includeSpec) {
//
// Validate the SDK path.
//
@@ -122,7 +127,8 @@
//
// Build spec and strong outputs.
//
- _BuilderOutput spec = new _Builder(sdkPath, false).build();
+ _BuilderOutput spec =
+ includeSpec ? new _Builder(sdkPath, false).build() : null;
_BuilderOutput strong = new _Builder(sdkPath, true).build();
return new _Output(spec, strong);
}
@@ -148,6 +154,8 @@
print('Where command can be one of the following:');
print(' multiple-outputs output_directory_path [sdk_path]');
print(' Generate separate summary and index files.');
+ print(' strong-outputs output_directory_path [sdk_path]');
+ print(' Generate separate summary and index files (strong mode only).');
print(' single-output output_file_path [sdk_path]');
print(' Generate a single file with summary and index.');
print(' extract-spec-sum input_file output_file');
diff --git a/pkg/analyzer/tool/summary/dump_inferred_types.dart b/pkg/analyzer/tool/summary/dump_inferred_types.dart
index a964675..135783e 100644
--- a/pkg/analyzer/tool/summary/dump_inferred_types.dart
+++ b/pkg/analyzer/tool/summary/dump_inferred_types.dart
@@ -8,20 +8,16 @@
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/base.dart';
import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
/**
* Collect the inferred types from all the summary files listed in [args] and
* print them in alphabetical order.
*/
main(List<String> args) {
+ SummaryDataStore summaryDataStore = new SummaryDataStore(args);
InferredTypeCollector collector = new InferredTypeCollector();
- for (String arg in args) {
- PackageBundle bundle =
- new PackageBundle.fromBuffer(new File(arg).readAsBytesSync());
- collector.visitPackageBundle(bundle, arg);
- }
- collector.dumpLibraryIndex();
- collector.dumpPartIndex();
+ collector.visitSummaryDataStore(summaryDataStore);
collector.dumpCollectedTypes();
}
@@ -34,8 +30,6 @@
LinkedUnit linkedUnit;
final Map<String, String> inferredTypes = <String, String>{};
List<String> typeParamsInScope = <String>[];
- final Map<String, Set<String>> libraryIndex = <String, Set<String>>{};
- final Map<String, Set<String>> partIndex = <String, Set<String>>{};
/**
* If an inferred type exists matching the given [slot], record that it is the
@@ -94,38 +88,6 @@
}
/**
- * Print out an index mapping library names to the summary files containing
- * them.
- */
- void dumpLibraryIndex() {
- print('Library index:');
- List<String> libraryNames = libraryIndex.keys.toList();
- libraryNames.sort();
- for (String libraryName in libraryNames) {
- List<String> summaryFiles = libraryIndex[libraryName].toList();
- summaryFiles.sort();
- print('$libraryName -> ${summaryFiles.join(', ')}');
- }
- print('');
- }
-
- /**
- * Print out an index mapping part file names to the summary files containing
- * them.
- */
- void dumpPartIndex() {
- print('Part index:');
- List<String> partNames = partIndex.keys.toList();
- partNames.sort();
- for (String partName in partNames) {
- List<String> summaryFiles = partIndex[partName].toList();
- summaryFiles.sort();
- print('$partName -> ${summaryFiles.join(', ')}');
- }
- print('');
- }
-
- /**
* Interpret the given [param] as a parameter in a synthetic typedef, and
* format it as a string.
*/
@@ -278,25 +240,14 @@
}
/**
- * Collect all the inferred types contained in [bundle].
+ * Collect all the inferred types contained in [summaryDataStore].
*/
- void visitPackageBundle(PackageBundle bundle, String summaryPath) {
- Map<String, LinkedLibrary> linkedLibraries = <String, LinkedLibrary>{};
- Map<String, UnlinkedUnit> unlinkedUnits = <String, UnlinkedUnit>{};
- for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
- linkedLibraries[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
- }
- for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
- String unitUriString = bundle.unlinkedUnitUris[i];
- partIndex
- .putIfAbsent(unitUriString, () => new Set<String>())
- .add(summaryPath);
- unlinkedUnits[unitUriString] = bundle.unlinkedUnits[i];
- }
+ void visitSummaryDataStore(SummaryDataStore summaryDataStore) {
// Figure out which unlinked units are a part of another library so we won't
// visit them redundantly.
Set<String> partOfUris = new Set<String>();
- unlinkedUnits.forEach((String unitUriString, UnlinkedUnit unlinkedUnit) {
+ summaryDataStore.unlinkedMap
+ .forEach((String unitUriString, UnlinkedUnit unlinkedUnit) {
Uri unitUri = Uri.parse(unitUriString);
for (String relativePartUriString in unlinkedUnit.publicNamespace.parts) {
partOfUris.add(
@@ -304,16 +255,14 @@
.toString());
}
});
- linkedLibraries
+ summaryDataStore.linkedMap
.forEach((String libraryUriString, LinkedLibrary linkedLibrary) {
if (partOfUris.contains(libraryUriString)) {
return;
}
- libraryIndex
- .putIfAbsent(libraryUriString, () => new Set<String>())
- .add(summaryPath);
Uri libraryUri = Uri.parse(libraryUriString);
- UnlinkedUnit definingUnlinkedUnit = unlinkedUnits[libraryUriString];
+ UnlinkedUnit definingUnlinkedUnit =
+ summaryDataStore.unlinkedMap[libraryUriString];
if (definingUnlinkedUnit != null) {
visitUnit(
definingUnlinkedUnit, linkedLibrary.units[0], libraryUriString);
@@ -324,7 +273,8 @@
Uri.parse(definingUnlinkedUnit.publicNamespace.parts[i]);
String unitUriString =
resolveRelativeUri(libraryUri, relativePartUri).toString();
- UnlinkedUnit unlinkedUnit = unlinkedUnits[unitUriString];
+ UnlinkedUnit unlinkedUnit =
+ summaryDataStore.unlinkedMap[unitUriString];
if (unlinkedUnit != null) {
visitUnit(
unlinkedUnit, linkedLibrary.units[i + 1], libraryUriString);
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index 212dc2b..402efa5 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -39,6 +39,7 @@
CONSTANT_EXPRESSION_RESOLVED [shape=box]
CONSTANT_VALUE -> ComputeConstantValueTask
CONSTANT_VALUE -> EvaluateUnitConstantsTask
+ CONSTANT_VALUE -> VerifyUnitTask
CONSTANT_VALUE [shape=box]
CONTAINING_LIBRARIES -> DartErrorsTask
CONTAINING_LIBRARIES [shape=box]
@@ -73,6 +74,8 @@
ComputeLibraryCycleTask -> LIBRARY_CYCLE_DEPENDENCIES
ComputeLibraryCycleTask -> LIBRARY_CYCLE_UNITS
ComputePropagableVariableDependenciesTask -> PROPAGABLE_VARIABLE_DEPENDENCIES
+ ComputeRequiredConstantsTask -> PENDING_ERRORS
+ ComputeRequiredConstantsTask -> REQUIRED_CONSTANTS
ContainingLibrariesTask -> CONTAINING_LIBRARIES
DART_ERRORS -> LibraryErrorsReadyTask
DART_ERRORS [shape=box]
@@ -190,6 +193,8 @@
PARSED_UNIT [shape=box]
PARSE_ERRORS -> dartErrorsForSource
PARSE_ERRORS [shape=box]
+ PENDING_ERRORS -> VerifyUnitTask
+ PENDING_ERRORS [shape=box]
PROPAGABLE_VARIABLES_IN_UNIT -> PropagateVariableTypesInUnitTask
PROPAGABLE_VARIABLES_IN_UNIT [shape=box]
PROPAGABLE_VARIABLE_DEPENDENCIES -> PropagateVariableTypeTask
@@ -232,6 +237,9 @@
REFERENCED_SOURCES -> BuildDirectiveElementsTask
REFERENCED_SOURCES -> VerifyUnitTask
REFERENCED_SOURCES [shape=box]
+ REQUIRED_CONSTANTS -> VerifyUnitTask
+ REQUIRED_CONSTANTS [shape=box]
+ RESOLVED_UNIT -> ComputeRequiredConstantsTask
RESOLVED_UNIT -> GenerateHintsTask
RESOLVED_UNIT -> GenerateLintsTask
RESOLVED_UNIT -> ReadyResolvedUnitTask
diff --git a/pkg/analyzer_cli/lib/src/boot_loader.dart b/pkg/analyzer_cli/lib/src/boot_loader.dart
index 6df71ae..5b03f40 100644
--- a/pkg/analyzer_cli/lib/src/boot_loader.dart
+++ b/pkg/analyzer_cli/lib/src/boot_loader.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'dart:isolate';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/source/analysis_options_provider.dart';
import 'package:analyzer/src/context/context.dart';
@@ -108,7 +109,7 @@
errorSink.writeln('Plugin configuration skipped: $details');
};
- /// Reads plugin config info from `.analysis_options`.
+ /// Reads plugin config info from the analysis options file.
PluginConfigOptionsProcessor _pluginOptionsProcessor =
new PluginConfigOptionsProcessor(_pluginConfigErrorHandler);
@@ -126,12 +127,26 @@
args: args, packageRootPath: options.packageRootPath);
}
- void _processAnalysisOptions(CommandLineOptions options) {
+ File _getOptionsFile(
+ CommandLineOptions options, ResourceProvider resourceProvider) {
+ String analysisOptionsFile = options.analysisOptionsFile;
+ if (analysisOptionsFile != null) {
+ return resourceProvider.getFile(analysisOptionsFile);
+ }
+ File file =
+ resourceProvider.getFile(engine.AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+ if (!file.exists) {
+ file = resourceProvider
+ .getFile(engine.AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
+ }
+ return file;
+ }
+
+ void _processAnalysisOptions(CommandLineOptions commandLineOptions) {
// Determine options file path.
- var filePath = options.analysisOptionsFile ??
- engine.AnalysisEngine.ANALYSIS_OPTIONS_FILE;
try {
- var file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+ File file = _getOptionsFile(
+ commandLineOptions, PhysicalResourceProvider.INSTANCE);
AnalysisOptionsProvider analysisOptionsProvider =
new AnalysisOptionsProvider();
Map<String, YamlNode> options =
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index d49a519..f6b3ddd 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -14,6 +14,7 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
@@ -23,6 +24,7 @@
import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/summary/summarize_ast.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
+import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
import 'package:analyzer/task/dart.dart';
import 'package:analyzer_cli/src/analyzer_impl.dart';
import 'package:analyzer_cli/src/driver.dart';
@@ -60,6 +62,7 @@
/**
* Perform a single loop step.
*/
+ @override
WorkResponse performRequest(WorkRequest request) {
errorBuffer.clear();
outBuffer.clear();
@@ -237,18 +240,29 @@
}
void _createContext() {
- DirectoryBasedDartSdk sdk =
- new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
- sdk.analysisOptions =
- Driver.createAnalysisOptionsForCommandLineOptions(options);
- sdk.useSummary = !options.buildSummaryOnlyAst;
-
// Read the summaries.
summaryDataStore = new SummaryDataStore(options.buildSummaryInputs);
+ DartSdk sdk;
+ PackageBundle sdkBundle;
+ if (options.dartSdkSummaryPath != null) {
+ SummaryBasedDartSdk summarySdk = new SummaryBasedDartSdk(
+ options.dartSdkSummaryPath, options.strongMode);
+ sdk = summarySdk;
+ sdkBundle = summarySdk.bundle;
+ } else {
+ DirectoryBasedDartSdk directorySdk =
+ new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
+ directorySdk.analysisOptions =
+ Driver.createAnalysisOptionsForCommandLineOptions(options);
+ directorySdk.useSummary = !options.buildSummaryOnlyAst;
+ sdk = directorySdk;
+ sdkBundle = directorySdk.getSummarySdkBundle();
+ }
+
// In AST mode include SDK bundle to avoid parsing SDK sources.
if (options.buildSummaryOnlyAst) {
- summaryDataStore.addBundle(null, sdk.getSummarySdkBundle());
+ summaryDataStore.addBundle(null, sdkBundle);
}
// Create the context.
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index aaff20d..4d80c61 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -8,7 +8,7 @@
import 'dart:convert';
import 'dart:io';
-import 'package:analyzer/file_system/file_system.dart' as fileSystem;
+import 'package:analyzer/file_system/file_system.dart' as file_system;
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/plugin/embedded_resolver_provider.dart';
import 'package:analyzer/plugin/options.dart';
@@ -25,12 +25,14 @@
import 'package:analyzer/src/generated/interner.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/utilities_general.dart'
show PerformanceTag;
import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer_cli/src/analyzer_impl.dart';
import 'package:analyzer_cli/src/build_mode.dart';
@@ -39,7 +41,7 @@
import 'package:analyzer_cli/src/perf_report.dart';
import 'package:analyzer_cli/starter.dart';
import 'package:linter/src/plugin/linter_plugin.dart';
-import 'package:package_config/discovery.dart' as pkgDiscovery;
+import 'package:package_config/discovery.dart' as pkg_discovery;
import 'package:package_config/packages.dart' show Packages;
import 'package:package_config/packages_file.dart' as pkgfile show parse;
import 'package:package_config/src/packages_impl.dart' show MapPackages;
@@ -91,7 +93,7 @@
ResolverProvider packageResolverProvider;
/// SDK instance.
- DirectoryBasedDartSdk sdk;
+ DartSdk sdk;
/// Collected analysis statistics.
final AnalysisStats stats = new AnalysisStats();
@@ -328,15 +330,11 @@
/// Decide on the appropriate method for resolving URIs based on the given
/// [options] and [customUrlMappings] settings, and return a
/// [SourceFactory] that has been configured accordingly.
- SourceFactory _chooseUriResolutionPolicy(
- CommandLineOptions options, EmbedderYamlLocator yamlLocator) {
- Packages packages;
- Map<String, List<fileSystem.Folder>> packageMap;
- UriResolver packageUriResolver;
-
+ SourceFactory _chooseUriResolutionPolicy(CommandLineOptions options,
+ Map<file_system.Folder, YamlMap> embedderMap, _PackageInfo packageInfo) {
// Create a custom package resolver if one has been specified.
if (packageResolverProvider != null) {
- fileSystem.Folder folder =
+ file_system.Folder folder =
PhysicalResourceProvider.INSTANCE.getResource('.');
UriResolver resolver = packageResolverProvider(folder);
if (resolver != null) {
@@ -354,7 +352,7 @@
// Default to a Dart URI resolver if no embedder is found.
sdkResolver ??= new DartUriResolver(sdk);
- // TODO(brianwilkerson) This doesn't sdk extensions.
+ // TODO(brianwilkerson) This doesn't handle sdk extensions.
List<UriResolver> resolvers = <UriResolver>[
sdkResolver,
resolver,
@@ -363,43 +361,24 @@
return new SourceFactory(resolvers);
}
}
- // Process options, caching package resolution details.
- if (options.packageConfigPath != null) {
- String packageConfigPath = options.packageConfigPath;
- Uri fileUri = new Uri.file(packageConfigPath);
- try {
- File configFile = new File.fromUri(fileUri).absolute;
- List<int> bytes = configFile.readAsBytesSync();
- Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);
- packages = new MapPackages(map);
- packageMap = _getPackageMap(packages);
- } catch (e) {
- printAndFail(
- 'Unable to read package config data from $packageConfigPath: $e');
- }
- } else if (options.packageRootPath != null) {
- packageMap = _PackageRootPackageMapBuilder
- .buildPackageMap(options.packageRootPath);
+ UriResolver packageUriResolver;
+
+ if (options.packageRootPath != null) {
JavaFile packageDirectory = new JavaFile(options.packageRootPath);
packageUriResolver = new PackageUriResolver([packageDirectory]);
- } else {
- fileSystem.Resource cwd =
- PhysicalResourceProvider.INSTANCE.getResource('.');
-
- // Look for .packages.
- packages = _discoverPackagespec(new Uri.directory(cwd.path));
-
- if (packages != null) {
- packageMap = _getPackageMap(packages);
- } else {
+ } else if (options.packageConfigPath == null) {
+ // TODO(pq): remove?
+ if (packageInfo.packageMap == null) {
// Fall back to pub list-package-dirs.
-
PubPackageMapProvider pubPackageMapProvider =
new PubPackageMapProvider(PhysicalResourceProvider.INSTANCE, sdk);
+ file_system.Resource cwd =
+ PhysicalResourceProvider.INSTANCE.getResource('.');
PackageMapInfo packageMapInfo =
pubPackageMapProvider.computePackageMap(cwd);
- packageMap = packageMapInfo.packageMap;
+ Map<String, List<file_system.Folder>> packageMap =
+ packageMapInfo.packageMap;
// Only create a packageUriResolver if pub list-package-dirs succeeded.
// If it failed, that's not a problem; it simply means we have no way
@@ -417,10 +396,8 @@
// 'dart:' URIs come first.
// Setup embedding.
- yamlLocator.refresh(packageMap);
-
EmbedderUriResolver embedderUriResolver =
- new EmbedderUriResolver(yamlLocator.embedderYamls);
+ new EmbedderUriResolver(embedderMap);
if (embedderUriResolver.length == 0) {
// The embedder uri resolver has no mappings. Use the default Dart SDK
// uri resolver.
@@ -432,8 +409,8 @@
}
// Next SdkExts.
- if (packageMap != null) {
- resolvers.add(new SdkExtUriResolver(packageMap));
+ if (packageInfo.packageMap != null) {
+ resolvers.add(new SdkExtUriResolver(packageInfo.packageMap));
}
// Then package URIs.
@@ -444,7 +421,7 @@
// Finally files.
resolvers.add(new FileUriResolver());
- return new SourceFactory(resolvers, packages);
+ return new SourceFactory(resolvers, packageInfo.packages);
}
/// Collect all analyzable files at [filePath], recursively if it's a
@@ -511,13 +488,26 @@
contextOptions.analyzeFunctionBodiesPredicate = dietParsingPolicy;
});
- // Once options are processed, setup the SDK.
- _setupSdk(options);
+ // Find package info.
+ _PackageInfo packageInfo = _findPackages(options);
+
+ // Process embedders.
+ Map<file_system.Folder, YamlMap> embedderMap =
+ _findEmbedders(packageInfo.packageMap);
+
+ // Scan for SDK extenders.
+ bool hasSdkExt = _hasSdkExt(packageInfo.packageMap?.values);
+
+ // No summaries in the presence of embedders or extenders.
+ bool useSummaries = embedderMap.isEmpty && !hasSdkExt;
+
+ // Once options and embedders are processed, setup the SDK.
+ _setupSdk(options, useSummaries);
// Choose a package resolution policy and a diet parsing policy based on
// the command-line options.
- SourceFactory sourceFactory = _chooseUriResolutionPolicy(
- options, (_context as InternalAnalysisContext).embedderYamlLocator);
+ SourceFactory sourceFactory =
+ _chooseUriResolutionPolicy(options, embedderMap, packageInfo);
_context.sourceFactory = sourceFactory;
}
@@ -525,7 +515,7 @@
/// Return discovered packagespec, or `null` if none is found.
Packages _discoverPackagespec(Uri root) {
try {
- Packages packages = pkgDiscovery.findPackagesFromFile(root);
+ Packages packages = pkg_discovery.findPackagesFromFile(root);
if (packages != Packages.noPackages) {
return packages;
}
@@ -536,13 +526,57 @@
return null;
}
- Map<String, List<fileSystem.Folder>> _getPackageMap(Packages packages) {
+ Map<file_system.Folder, YamlMap> _findEmbedders(
+ Map<String, List<file_system.Folder>> packageMap) {
+ EmbedderYamlLocator locator =
+ (_context as InternalAnalysisContext).embedderYamlLocator;
+ locator.refresh(packageMap);
+ return locator.embedderYamls;
+ }
+
+ _PackageInfo _findPackages(CommandLineOptions options) {
+ if (packageResolverProvider != null) {
+ // The resolver provider will do all the work later.
+ return null;
+ }
+
+ Packages packages;
+ Map<String, List<file_system.Folder>> packageMap;
+
+ if (options.packageConfigPath != null) {
+ String packageConfigPath = options.packageConfigPath;
+ Uri fileUri = new Uri.file(packageConfigPath);
+ try {
+ File configFile = new File.fromUri(fileUri).absolute;
+ List<int> bytes = configFile.readAsBytesSync();
+ Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);
+ packages = new MapPackages(map);
+ packageMap = _getPackageMap(packages);
+ } catch (e) {
+ printAndFail(
+ 'Unable to read package config data from $packageConfigPath: $e');
+ }
+ } else if (options.packageRootPath != null) {
+ packageMap = _PackageRootPackageMapBuilder
+ .buildPackageMap(options.packageRootPath);
+ } else {
+ file_system.Resource cwd =
+ PhysicalResourceProvider.INSTANCE.getResource('.');
+ // Look for .packages.
+ packages = _discoverPackagespec(new Uri.directory(cwd.path));
+ packageMap = _getPackageMap(packages);
+ }
+
+ return new _PackageInfo(packages, packageMap);
+ }
+
+ Map<String, List<file_system.Folder>> _getPackageMap(Packages packages) {
if (packages == null) {
return null;
}
- Map<String, List<fileSystem.Folder>> folderMap =
- new Map<String, List<fileSystem.Folder>>();
+ Map<String, List<file_system.Folder>> folderMap =
+ new Map<String, List<file_system.Folder>>();
packages.asMap().forEach((String packagePath, Uri uri) {
folderMap[packagePath] = [
PhysicalResourceProvider.INSTANCE.getFolder(path.fromUri(uri))
@@ -551,6 +585,19 @@
return folderMap;
}
+ bool _hasSdkExt(Iterable<List<file_system.Folder>> folders) {
+ if (folders != null) {
+ //TODO: ideally share this traversal with SdkExtUriResolver
+ for (Iterable<file_system.Folder> libDirs in folders) {
+ if (libDirs.any((file_system.Folder libDir) =>
+ libDir.getChild(SdkExtUriResolver.SDK_EXT_NAME).exists)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/// Returns `true` if this relative path is a hidden directory.
bool _isInHiddenDir(String relative) =>
path.split(relative).any((part) => part.startsWith("."));
@@ -582,16 +629,25 @@
return errorSeverity;
}
- void _setupSdk(CommandLineOptions options) {
+ void _setupSdk(CommandLineOptions options, bool useSummaries) {
if (sdk == null) {
- String dartSdkPath = options.dartSdkPath;
- sdk = new DirectoryBasedDartSdk(new JavaFile(dartSdkPath));
- sdk.useSummary = options.sourceFiles.every((String sourcePath) {
- sourcePath = path.absolute(sourcePath);
- sourcePath = path.normalize(sourcePath);
- return !path.isWithin(dartSdkPath, sourcePath);
- });
- sdk.analysisOptions = context.analysisOptions;
+ if (options.dartSdkSummaryPath != null) {
+ sdk = new SummaryBasedDartSdk(
+ options.dartSdkSummaryPath, options.strongMode);
+ } else {
+ String dartSdkPath = options.dartSdkPath;
+ DirectoryBasedDartSdk directorySdk = new DirectoryBasedDartSdk(
+ new JavaFile(dartSdkPath), options.strongMode);
+ directorySdk.useSummary = useSummaries &&
+ options.sourceFiles.every((String sourcePath) {
+ sourcePath = path.absolute(sourcePath);
+ sourcePath = path.normalize(sourcePath);
+ return !path.isWithin(dartSdkPath, sourcePath);
+ });
+
+ directorySdk.analysisOptions = context.analysisOptions;
+ sdk = directorySdk;
+ }
}
}
@@ -613,7 +669,7 @@
CommandLineOptions options,
void configureContextOptions(AnalysisOptionsImpl contextOptions)) {
Map<String, String> definedVariables = options.definedVariables;
- if (!definedVariables.isEmpty) {
+ if (definedVariables.isNotEmpty) {
DeclaredVariables declaredVariables = context.declaredVariables;
definedVariables.forEach((String variableName, String value) {
declaredVariables.define(variableName, value);
@@ -649,8 +705,8 @@
return true;
}
- static fileSystem.File _getOptionsFile(CommandLineOptions options) {
- fileSystem.File file;
+ static file_system.File _getOptionsFile(CommandLineOptions options) {
+ file_system.File file;
String filePath = options.analysisOptionsFile;
if (filePath != null) {
file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
@@ -661,6 +717,10 @@
} else {
filePath = AnalysisEngine.ANALYSIS_OPTIONS_FILE;
file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+ if (!file.exists) {
+ filePath = AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
+ file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+ }
}
return file;
}
@@ -671,7 +731,7 @@
static void _processAnalysisOptions(
AnalysisContext context, CommandLineOptions options) {
- fileSystem.File file = _getOptionsFile(options);
+ file_system.File file = _getOptionsFile(options);
List<OptionsProcessor> optionsProcessors =
AnalysisEngine.instance.optionsPlugin.optionsProcessors;
try {
@@ -761,13 +821,19 @@
_DriverError(this.msg);
}
+class _PackageInfo {
+ Packages packages;
+ Map<String, List<file_system.Folder>> packageMap;
+ _PackageInfo(this.packages, this.packageMap);
+}
+
/// [SdkExtUriResolver] needs a Map from package name to folder. In the case
/// that the analyzer is invoked with a --package-root option, we need to
/// manually create this mapping. Given [packageRootPath],
/// [_PackageRootPackageMapBuilder] creates a simple mapping from package name
/// to full path on disk (resolving any symbolic links).
class _PackageRootPackageMapBuilder {
- static Map<String, List<fileSystem.Folder>> buildPackageMap(
+ static Map<String, List<file_system.Folder>> buildPackageMap(
String packageRootPath) {
var packageRoot = new Directory(packageRootPath);
if (!packageRoot.existsSync()) {
@@ -775,7 +841,7 @@
'Package root directory ($packageRootPath) does not exist.');
}
var packages = packageRoot.listSync(followLinks: false);
- var result = new Map<String, List<fileSystem.Folder>>();
+ var result = new Map<String, List<file_system.Folder>>();
for (var package in packages) {
var packageName = path.basename(package.path);
var realPath = package.resolveSymbolicLinksSync();
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index ae8466c..5a2e939 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -68,9 +68,12 @@
/// Whether to suppress a nonzero exit code in build mode.
final bool buildSuppressExitCode;
- /// The path to the dart SDK
+ /// The path to the dart SDK.
String dartSdkPath;
+ /// The path to the dart SDK summary file.
+ String dartSdkSummaryPath;
+
/// A table mapping the names of defined variables to their values.
final Map<String, String> definedVariables;
@@ -159,6 +162,7 @@
buildSummaryOutput = args['build-summary-output'],
buildSuppressExitCode = args['build-suppress-exit-code'],
dartSdkPath = args['dart-sdk'],
+ dartSdkSummaryPath = args['dart-sdk-summary'],
definedVariables = definedVariables,
analysisOptionsFile = args['options'],
disableHints = args['no-hints'],
@@ -193,7 +197,7 @@
[printAndFail(String msg) = printAndFail]) {
CommandLineOptions options = _parse(args);
// Check SDK.
- {
+ if (!options.buildModePersistentWorker) {
// Infer if unspecified.
if (options.dartSdkPath == null) {
Directory sdkDir = getSdkDir(args);
@@ -273,6 +277,8 @@
defaultsTo: false,
negatable: false)
..addOption('dart-sdk', help: 'The path to the Dart SDK.')
+ ..addOption('dart-sdk-summary',
+ help: 'The path to the Dart SDK summary file.', hide: true)
..addOption('packages',
help:
'Path to the package resolution configuration file, which supplies '
diff --git a/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart b/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
index 13a8202..7c819fd 100644
--- a/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
+++ b/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
@@ -11,9 +11,9 @@
const _manifestFileName = 'plugins.yaml';
-/// Given a local configuration (as defined in `.analysis_options`)
-/// and information from a plugin manifest, return plugin info
-/// appropriate for configuring this plugin.
+/// Given a local configuration (as defined in an analysis options file) and
+/// information from a plugin manifest, return plugin info appropriate for
+/// configuring this plugin.
PluginInfo combine(PluginInfo localConfig, PluginInfo manifestInfo) {
return new PluginInfo(
name: localConfig.name,
diff --git a/pkg/analyzer_cli/pubspec.yaml b/pkg/analyzer_cli/pubspec.yaml
index dbccd97..a0ded9b 100644
--- a/pkg/analyzer_cli/pubspec.yaml
+++ b/pkg/analyzer_cli/pubspec.yaml
@@ -10,9 +10,9 @@
args: ^0.13.0
bazel_worker: ^0.1.0
cli_util: ^0.0.1
- linter: ^0.1.10
+ linter: ^0.1.16
package_config: ^0.1.1
- plugin: ^0.1.0
+ plugin: '>=0.1.0 <0.3.0'
protobuf: ^0.5.0
yaml: ^2.1.2
dev_dependencies:
diff --git a/pkg/analyzer_cli/test/all.dart b/pkg/analyzer_cli/test/all.dart
index 13f72d1..5764922 100644
--- a/pkg/analyzer_cli/test/all.dart
+++ b/pkg/analyzer_cli/test/all.dart
@@ -5,23 +5,25 @@
import 'boot_loader_test.dart' as boot_loader;
import 'build_mode_test.dart' as build_mode_test;
import 'driver_test.dart' as driver;
+import 'embedder_test.dart' as embedder;
import 'error_test.dart' as error;
import 'options_test.dart' as options;
import 'package_prefix_test.dart' as package_prefix;
import 'perf_report_test.dart' as perf;
import 'plugin_manager_test.dart' as plugin_manager;
import 'reporter_test.dart' as reporter;
+import 'sdk_ext_test.dart' as sdk_ext;
import 'super_mixin_test.dart' as super_mixin;
-//import 'sdk_ext_test.dart' as sdk_ext;
//import 'strong_mode_test.dart' as strong_mode;
main() {
boot_loader.main();
build_mode_test.main();
driver.main();
+ embedder.main();
+ sdk_ext.main();
// TODO(pq): fix tests to run safely on the bots
// https://github.com/dart-lang/sdk/issues/25001
- //sdk_ext.main();
//strong_mode.main();
error.main();
options.main();
diff --git a/pkg/analyzer_cli/test/data/linter_project/analysis_options.yaml b/pkg/analyzer_cli/test/data/linter_project/analysis_options.yaml
new file mode 100644
index 0000000..6af57a5
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/linter_project/analysis_options.yaml
@@ -0,0 +1,3 @@
+linter:
+ rules:
+ - camel_case_types
diff --git a/pkg/analyzer_cli/test/data/no_lints_project/analysis_options.yaml b/pkg/analyzer_cli/test/data/no_lints_project/analysis_options.yaml
new file mode 100644
index 0000000..1bb8bf6
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/no_lints_project/analysis_options.yaml
@@ -0,0 +1 @@
+# empty
diff --git a/pkg/analyzer_cli/test/data/options_tests_project/analysis_options.yaml b/pkg/analyzer_cli/test/data/options_tests_project/analysis_options.yaml
new file mode 100644
index 0000000..c0f4f1c
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/options_tests_project/analysis_options.yaml
@@ -0,0 +1,8 @@
+analyzer:
+ strong-mode: true
+ errors:
+ unused_local_variable: ignore
+ missing_return: error
+ undefined_function: warning
+ language:
+ enableSuperMixins: true
diff --git a/pkg/analyzer_cli/test/data/packages_file/_packages b/pkg/analyzer_cli/test/data/packages_file/_packages
new file mode 100644
index 0000000..c863897
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/packages_file/_packages
@@ -0,0 +1 @@
+package_with_sdk_extension:../package_with_sdk_extension/lib/
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 6c85880..e549603 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -134,74 +134,78 @@
});
group('linter', () {
- group('lints in options', () {
- // Shared lint command.
- var runLinter = () => drive('data/linter_project/test_file.dart',
- options: 'data/linter_project/.analysis_options',
- args: ['--lints']);
+ void createTests(String designator, String optionsFileName) {
+ group('lints in options - $designator', () {
+ // Shared lint command.
+ void runLinter() => drive('data/linter_project/test_file.dart',
+ options: 'data/linter_project/$optionsFileName',
+ args: ['--lints']);
- test('gets analysis options', () {
- runLinter();
+ test('gets analysis options', () {
+ runLinter();
- /// Lints should be enabled.
- expect(driver.context.analysisOptions.lint, isTrue);
+ /// Lints should be enabled.
+ expect(driver.context.analysisOptions.lint, isTrue);
- /// The .analysis_options file only specifies 'camel_case_types'.
- var lintNames = getLints(driver.context).map((r) => r.name);
- expect(lintNames, orderedEquals(['camel_case_types']));
+ /// The analysis options file only specifies 'camel_case_types'.
+ var lintNames = getLints(driver.context).map((r) => r.name);
+ expect(lintNames, orderedEquals(['camel_case_types']));
+ });
+
+ test('generates lints', () {
+ runLinter();
+ expect(outSink.toString(),
+ contains('[lint] Name types using UpperCamelCase.'));
+ });
});
- test('generates lints', () {
- runLinter();
- expect(outSink.toString(),
- contains('[lint] Name types using UpperCamelCase.'));
- });
- });
+ group('default lints - $designator', () {
+ // Shared lint command.
+ void runLinter() => drive('data/linter_project/test_file.dart',
+ options: 'data/linter_project/$optionsFileName',
+ args: ['--lints']);
- group('default lints', () {
- // Shared lint command.
- var runLinter = () => drive('data/linter_project/test_file.dart',
- options: 'data/linter_project/.analysis_options',
- args: ['--lints']);
+ test('gets default lints', () {
+ runLinter();
- test('gets default lints', () {
- runLinter();
+ /// Lints should be enabled.
+ expect(driver.context.analysisOptions.lint, isTrue);
- /// Lints should be enabled.
- expect(driver.context.analysisOptions.lint, isTrue);
+ /// Default list should include camel_case_types.
+ var lintNames = getLints(driver.context).map((r) => r.name);
+ expect(lintNames, contains('camel_case_types'));
+ });
- /// Default list should include camel_case_types.
- var lintNames = getLints(driver.context).map((r) => r.name);
- expect(lintNames, contains('camel_case_types'));
+ test('generates lints', () {
+ runLinter();
+ expect(outSink.toString(),
+ contains('[lint] Name types using UpperCamelCase.'));
+ });
});
- test('generates lints', () {
- runLinter();
- expect(outSink.toString(),
- contains('[lint] Name types using UpperCamelCase.'));
- });
- });
+ group('no `--lints` flag (none in options) - $designator', () {
+ // Shared lint command.
+ void runLinter() => drive('data/no_lints_project/test_file.dart',
+ options: 'data/no_lints_project/$optionsFileName');
- group('no `--lints` flag (none in options)', () {
- // Shared lint command.
- var runLinter = () => drive('data/no_lints_project/test_file.dart',
- options: 'data/no_lints_project/.analysis_options');
+ test('lints disabled', () {
+ runLinter();
+ expect(driver.context.analysisOptions.lint, isFalse);
+ });
- test('lints disabled', () {
- runLinter();
- expect(driver.context.analysisOptions.lint, isFalse);
- });
+ test('no registered lints', () {
+ runLinter();
+ expect(getLints(driver.context), isEmpty);
+ });
- test('no registered lints', () {
- runLinter();
- expect(getLints(driver.context), isEmpty);
+ test('no generated warnings', () {
+ runLinter();
+ expect(outSink.toString(), contains('No issues found'));
+ });
});
-
- test('no generated warnings', () {
- runLinter();
- expect(outSink.toString(), contains('No issues found'));
- });
- });
+ }
+ createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+ createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
});
test('containsLintRuleEntry', () {
@@ -230,116 +234,126 @@
});
group('options processing', () {
- group('basic config', () {
- // Shared driver command.
- var doDrive = () => drive('data/options_tests_project/test_file.dart',
- options: 'data/options_tests_project/.analysis_options');
+ void createTests(String designator, String optionsFileName) {
+ group('basic config - $designator', () {
+ // Shared driver command.
+ void doDrive() => drive('data/options_tests_project/test_file.dart',
+ options: 'data/options_tests_project/$optionsFileName');
- test('filters', () {
- doDrive();
- expect(processors, hasLength(3));
+ test('filters', () {
+ doDrive();
+ expect(processors, hasLength(3));
- // unused_local_variable: ignore
- var unused_local_variable = new AnalysisError(
- new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
- ['x']
- ]);
- expect(processorFor(unused_local_variable).severity, isNull);
+ // unused_local_variable: ignore
+ var unused_local_variable = new AnalysisError(
+ new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
+ ['x']
+ ]);
+ expect(processorFor(unused_local_variable).severity, isNull);
- // missing_return: error
- var missing_return = new AnalysisError(
- new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
- ['x']
- ]);
- expect(processorFor(missing_return).severity, ErrorSeverity.ERROR);
- expect(
- outSink.toString(),
- contains(
- "[error] This function declares a return type of 'int'"));
- expect(outSink.toString(), contains("1 error and 1 warning found."));
+ // missing_return: error
+ var missing_return = new AnalysisError(
+ new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
+ ['x']
+ ]);
+ expect(processorFor(missing_return).severity, ErrorSeverity.ERROR);
+ expect(
+ outSink.toString(),
+ contains(
+ "[error] This function declares a return type of 'int'"));
+ expect(
+ outSink.toString(), contains("1 error and 1 warning found."));
+ });
+
+ test('language', () {
+ doDrive();
+ expect(driver.context.analysisOptions.enableSuperMixins, isTrue);
+ });
+
+ test('strongMode', () {
+ doDrive();
+ expect(driver.context.analysisOptions.strongMode, isTrue);
+ //https://github.com/dart-lang/sdk/issues/26129
+ AnalysisContext sdkContext =
+ driver.context.sourceFactory.dartSdk.context;
+ expect(sdkContext.analysisOptions.strongMode, isTrue);
+ });
});
- test('language', () {
- doDrive();
- expect(driver.context.analysisOptions.enableSuperMixins, isTrue);
+ group('with flags - $designator', () {
+ // Shared driver command.
+ void doDrive() => drive('data/options_tests_project/test_file.dart',
+ args: ['--fatal-warnings'],
+ options: 'data/options_tests_project/$optionsFileName');
+
+ test('override fatal warning', () {
+ doDrive();
+ // missing_return: error
+ var undefined_function = new AnalysisError(new TestSource(), 0, 1,
+ StaticTypeWarningCode.UNDEFINED_FUNCTION, [
+ ['x']
+ ]);
+ expect(processorFor(undefined_function).severity,
+ ErrorSeverity.WARNING);
+ // Should not be made fatal by `--fatal-warnings`.
+ expect(outSink.toString(),
+ contains("[warning] The function 'baz' is not defined"));
+ expect(
+ outSink.toString(), contains("1 error and 1 warning found."));
+ });
});
-
- test('strongMode', () {
- doDrive();
- expect(driver.context.analysisOptions.strongMode, isTrue);
- //https://github.com/dart-lang/sdk/issues/26129
- AnalysisContext sdkContext =
- driver.context.sourceFactory.dartSdk.context;
- expect(sdkContext.analysisOptions.strongMode, isTrue);
- });
- });
-
- group('with flags', () {
- // Shared driver command.
- var doDrive = () => drive('data/options_tests_project/test_file.dart',
- args: ['--fatal-warnings'],
- options: 'data/options_tests_project/.analysis_options');
-
- test('override fatal warning', () {
- doDrive();
- // missing_return: error
- var undefined_function = new AnalysisError(new TestSource(), 0, 1,
- StaticTypeWarningCode.UNDEFINED_FUNCTION, [
- ['x']
- ]);
- expect(
- processorFor(undefined_function).severity, ErrorSeverity.WARNING);
- // Should not be made fatal by `--fatal-warnings`.
- expect(outSink.toString(),
- contains("[warning] The function 'baz' is not defined"));
- expect(outSink.toString(), contains("1 error and 1 warning found."));
- });
- });
- });
-
- group('build-mode', () {
- // Shared driver command.
- void doDrive(String filePath, {List<String> additionalArgs: const []}) {
- drive('file:///test_file.dart|$filePath',
- args: [
- '--dart-sdk',
- findSdkDirForSummaries(),
- '--build-mode',
- '--machine'
- ]..addAll(additionalArgs),
- options: 'data/options_tests_project/.analysis_options');
}
-
- test('no stats', () {
- doDrive('data/test_file.dart');
- // Should not print stat summary.
- expect(outSink.toString(), isEmpty);
- expect(errorSink.toString(), isEmpty);
- expect(exitCode, 0);
- });
-
- test(
- 'Fails if file not found, even when --build-suppress-exit-code is given',
- () {
- doDrive('data/non_existent_file.dart',
- additionalArgs: ['--build-suppress-exit-code']);
- expect(exitCode, isNot(0));
- });
-
- test('Fails if there are errors', () {
- doDrive('data/file_with_error.dart');
- expect(exitCode, isNot(0));
- });
-
- test(
- 'Succeeds if there are errors, when --build-suppress-exit-code is given',
- () {
- doDrive('data/file_with_error.dart',
- additionalArgs: ['--build-suppress-exit-code']);
- expect(exitCode, 0);
- });
+ createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+ createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
});
+ void createTests(String designator, String optionsFileName) {
+ group('build-mode - $designator', () {
+ // Shared driver command.
+ void doDrive(String filePath, {List<String> additionalArgs: const []}) {
+ drive('file:///test_file.dart|$filePath',
+ args: [
+ '--dart-sdk',
+ findSdkDirForSummaries(),
+ '--build-mode',
+ '--machine'
+ ]..addAll(additionalArgs),
+ options: 'data/options_tests_project/$optionsFileName');
+ }
+
+ test('no stats', () {
+ doDrive('data/test_file.dart');
+ // Should not print stat summary.
+ expect(outSink.toString(), isEmpty);
+ expect(errorSink.toString(), isEmpty);
+ expect(exitCode, 0);
+ });
+
+ test(
+ 'Fails if file not found, even when --build-suppress-exit-code is given',
+ () {
+ doDrive('data/non_existent_file.dart',
+ additionalArgs: ['--build-suppress-exit-code']);
+ expect(exitCode, isNot(0));
+ });
+
+ test('Fails if there are errors', () {
+ doDrive('data/file_with_error.dart');
+ expect(exitCode, isNot(0));
+ });
+
+ test(
+ 'Succeeds if there are errors, when --build-suppress-exit-code is given',
+ () {
+ doDrive('data/file_with_error.dart',
+ additionalArgs: ['--build-suppress-exit-code']);
+ expect(exitCode, 0);
+ });
+ });
+ }
+ createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE);
+ createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
+
//TODO(pq): fix to be bot-friendly (sdk#25258).
// group('in temp directory', () {
// Directory savedCurrentDirectory;
diff --git a/pkg/analyzer_cli/test/embedder_test.dart b/pkg/analyzer_cli/test/embedder_test.dart
index ded83fd..5a57c2d 100644
--- a/pkg/analyzer_cli/test/embedder_test.dart
+++ b/pkg/analyzer_cli/test/embedder_test.dart
@@ -4,6 +4,7 @@
import 'dart:io';
+import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
@@ -41,6 +42,19 @@
expect(exitCode, 0);
expect(outSink.toString(), contains('No issues found'));
}));
+
+ test('sdk setup', wrap(() {
+ var testDir = path.join(testDirectory, 'data', 'embedder_client');
+ Driver driver = new Driver();
+ driver.start([
+ '--packages',
+ path.join(testDir, '_packages'),
+ path.join(testDir, 'embedder_yaml_user.dart')
+ ]);
+
+ DirectoryBasedDartSdk sdk = driver.sdk;
+ expect(sdk.useSummary, false);
+ }));
});
}
diff --git a/pkg/analyzer_cli/test/sdk_ext_test.dart b/pkg/analyzer_cli/test/sdk_ext_test.dart
index e7aa5ce..1376d46 100644
--- a/pkg/analyzer_cli/test/sdk_ext_test.dart
+++ b/pkg/analyzer_cli/test/sdk_ext_test.dart
@@ -7,48 +7,47 @@
import 'dart:io';
+import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:analyzer_cli/src/options.dart';
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
import 'utils.dart';
-// TODO(pq): fix tests to run safely on the bots
-// https://github.com/dart-lang/sdk/issues/25001
-main() {}
-not_main() {
+main() {
group('Sdk extensions', () {
StringSink savedOutSink, savedErrorSink;
int savedExitCode;
- Directory savedCurrentDirectory;
+ ExitHandler savedExitHandler;
+
setUp(() {
savedOutSink = outSink;
savedErrorSink = errorSink;
+ savedExitHandler = exitHandler;
savedExitCode = exitCode;
+ exitHandler = (code) => exitCode = code;
outSink = new StringBuffer();
errorSink = new StringBuffer();
- savedCurrentDirectory = Directory.current;
});
tearDown(() {
outSink = savedOutSink;
errorSink = savedErrorSink;
exitCode = savedExitCode;
- Directory.current = savedCurrentDirectory;
+ exitHandler = savedExitHandler;
});
- test('--packages option supplied', () async {
- var testDir = path.join(testDirectory, 'data', 'no_packages_file');
- Directory.current = new Directory(testDir);
- var packagesPath = path.join('..', 'packages_file', '.packages');
- new Driver().start(['--packages', packagesPath, 'sdk_ext_user.dart']);
+ test('.packages file specified', () async {
+ String testDir = path.join(testDirectory, 'data', 'packages_file');
+ Driver driver = new Driver()
+ ..start([
+ '--packages',
+ path.join(testDir, '_packages'),
+ path.join(testDir, 'sdk_ext_user.dart')
+ ]);
- expect(exitCode, 0);
- });
-
- test('.packages file present', () async {
- var testDir = path.join(testDirectory, 'data', 'packages_file');
- Directory.current = new Directory(testDir);
- new Driver().start(['sdk_ext_user.dart']);
+ DirectoryBasedDartSdk sdk = driver.sdk;
+ expect(sdk.useSummary, isFalse);
expect(exitCode, 0);
});
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index e802bd4..631d29b 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -26,6 +26,7 @@
import 'platform_configuration.dart' as platform_configuration;
import 'resolved_uri_translator.dart';
import 'script.dart';
+import 'serialization/system.dart';
/// Implements the [Compiler] using a [api.CompilerInput] for supplying the
/// sources.
@@ -112,17 +113,8 @@
// TODO(johnniwinther): Wrap the result from [provider] in a specialized
// [Future] to ensure that we never execute an asynchronous action without
// setting up the current element of the compiler.
- return new Future.sync(() => callUserProvider(resourceUri)).then((data) {
- SourceFile sourceFile;
- if (data is List<int>) {
- sourceFile = new Utf8BytesSourceFile(resourceUri, data);
- } else if (data is String) {
- sourceFile = new StringSourceFile.fromUri(resourceUri, data);
- } else {
- String message = "Expected a 'String' or a 'List<int>' from the input "
- "provider, but got: ${Error.safeToString(data)}.";
- reportReadError(message);
- }
+ return new Future.sync(() => callUserProvider(resourceUri))
+ .then((SourceFile sourceFile) {
// We use [readableUri] as the URI for the script since need to preserve
// the scheme in the script because [Script.uri] is used for resolving
// relative URIs mentioned in the script. See the comment on
@@ -182,10 +174,9 @@
// and we can't depend on 'dart:io' classes.
packages = new NonFilePackagesDirectoryPackages(options.packageRoot);
} else if (options.packageConfig != null) {
- return callUserProvider(options.packageConfig).then((configContents) {
- if (configContents is String) {
- configContents = UTF8.encode(configContents);
- }
+ return callUserProvider(options.packageConfig)
+ .then((SourceFile sourceFile) {
+ List<int> configContents = sourceFile.slowUtf8ZeroTerminatedBytes();
// The input provider may put a trailing 0 byte when it reads a source
// file, which confuses the package config parser.
if (configContents.length > 0 && configContents.last == 0) {
@@ -213,18 +204,27 @@
}
Future<Null> setupSdk() {
- if (resolvedUriTranslator.isNotSet) {
- return platform_configuration
- .load(options.platformConfigUri, provider)
- .then((Map<String, Uri> mapping) {
- resolvedUriTranslator.resolvedUriTranslator =
- new ResolvedUriTranslator(mapping, reporter);
+ Future future = new Future.value(null);
+ if (options.resolutionInput != null) {
+ reporter.log('Reading serialized data from ${options.resolutionInput}');
+ future = callUserProvider(options.resolutionInput)
+ .then((SourceFile sourceFile) {
+ serialization.deserializeFromText(sourceFile.slowText());
});
- } else {
- // The incremental compiler sets up the sdk before run.
- // Therefore this will be called a second time.
- return new Future.value(null);
}
+ if (resolvedUriTranslator.isNotSet) {
+ future = future.then((_) {
+ return platform_configuration
+ .load(options.platformConfigUri, provider)
+ .then((Map<String, Uri> mapping) {
+ resolvedUriTranslator.resolvedUriTranslator =
+ new ResolvedUriTranslator(mapping, reporter);
+ });
+ });
+ }
+ // The incremental compiler sets up the sdk before run.
+ // Therefore this will be called a second time.
+ return future;
}
Future<bool> run(Uri uri) {
@@ -316,9 +316,22 @@
}
}
- Future callUserProvider(Uri uri) {
+ Future<SourceFile> callUserProvider(Uri uri) {
try {
- return userProviderTask.measureIo(() => provider.readFromUri(uri));
+ return userProviderTask
+ .measureIo(() => provider.readFromUri(uri))
+ .then((data) {
+ SourceFile sourceFile;
+ if (data is List<int>) {
+ sourceFile = new Utf8BytesSourceFile(uri, data);
+ } else if (data is String) {
+ sourceFile = new StringSourceFile.fromUri(uri, data);
+ } else {
+ throw "Expected a 'String' or a 'List<int>' from the input "
+ "provider, but got: ${Error.safeToString(data)}.";
+ }
+ return sourceFile;
+ });
} catch (ex, s) {
reportCrashInUserCode('Uncaught exception in input provider', ex, s);
rethrow;
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 0e9f37f..4e0c2ef 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -36,37 +36,42 @@
if (resolvedAst.kind != ResolvedAstKind.PARSED) {
return new ClosureClassMap(null, null, null, new ThisLocal(element));
}
- Node node = resolvedAst.node;
- TreeElements elements = resolvedAst.elements;
+ return reporter.withCurrentElement(element.implementation, () {
+ Node node = resolvedAst.node;
+ TreeElements elements = resolvedAst.elements;
- ClosureClassMap cached = closureMappingCache[node];
- if (cached != null) return cached;
+ ClosureClassMap cached = closureMappingCache[node];
+ if (cached != null) return cached;
- ClosureTranslator translator =
- new ClosureTranslator(compiler, elements, closureMappingCache);
+ ClosureTranslator translator =
+ new ClosureTranslator(compiler, elements, closureMappingCache);
- // The translator will store the computed closure-mappings inside the
- // cache. One for given node and one for each nested closure.
- if (node is FunctionExpression) {
- translator.translateFunction(element, node);
- } else if (element.isSynthesized) {
- reporter.internalError(
- element, "Unexpected synthesized element: $element");
- return new ClosureClassMap(null, null, null, new ThisLocal(element));
- } else {
- assert(element.isField);
- Node initializer = resolvedAst.body;
- if (initializer != null) {
- // The lazy initializer of a static.
- translator.translateLazyInitializer(element, node, initializer);
+ // The translator will store the computed closure-mappings inside the
+ // cache. One for given node and one for each nested closure.
+ if (node is FunctionExpression) {
+ translator.translateFunction(element, node);
+ } else if (element.isSynthesized) {
+ reporter.internalError(
+ element, "Unexpected synthesized element: $element");
+ return new ClosureClassMap(null, null, null, new ThisLocal(element));
} else {
- assert(element.isInstanceMember);
- closureMappingCache[node] =
- new ClosureClassMap(null, null, null, new ThisLocal(element));
+ assert(invariant(element, element.isField,
+ message: "Expected $element to be a field."));
+ Node initializer = resolvedAst.body;
+ if (initializer != null) {
+ // The lazy initializer of a static.
+ translator.translateLazyInitializer(element, node, initializer);
+ } else {
+ assert(invariant(element, element.isInstanceMember,
+ message: "Expected $element (${element
+ .runtimeType}) to be an instance field."));
+ closureMappingCache[node] =
+ new ClosureClassMap(null, null, null, new ThisLocal(element));
+ }
}
- }
- assert(closureMappingCache[node] != null);
- return closureMappingCache[node];
+ assert(closureMappingCache[node] != null);
+ return closureMappingCache[node];
+ });
});
}
@@ -96,6 +101,7 @@
/// Common interface for [BoxFieldElement] and [ClosureFieldElement] as
/// non-elements.
+// TODO(johnniwinther): Remove `implements Element`.
abstract class CapturedVariable implements Element {}
// TODO(ahe): These classes continuously cause problems. We need to
@@ -243,6 +249,8 @@
final ExecutableElement executableContext;
BoxLocal(this.name, this.executableContext);
+
+ String toString() => 'BoxLocal($name)';
}
// TODO(ngeoffray, ahe): These classes continuously cause problems. We need to
@@ -348,6 +356,8 @@
Element get analyzableElement => closureClass.methodElement.analyzableElement;
+ bool get hasResolvedAst => true;
+
ResolvedAst get resolvedAst {
return new ParsedResolvedAst(this, node, node.body, treeElements,
expression.compilationUnit.script.resourceUri);
@@ -433,7 +443,7 @@
///
/// Also parameters to a `sync*` generator must be boxed, because of the way
/// we rewrite sync* functions. See also comments in [useLocal].
- /// TODO(johnniwinter): Add variables to this only if the variable is mutated.
+ // TODO(johnniwinther): Add variables to this only if the variable is mutated.
final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>();
ClosureClassMap(this.closureElement, this.closureClassElement,
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 9c0c244..fba8401 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -53,9 +53,13 @@
// Experimental flags.
static const String genericMethodSyntax = '--generic-method-syntax';
+ static const String resolveOnly = '--resolve-only';
}
class Option {
static const String showPackageWarnings =
'${Flags.showPackageWarnings}|${Flags.showPackageWarnings}=.*';
+
+ // Experimental options.
+ static const String resolutionInput = '--resolution-input=.+';
}
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 8ad503c..9860b08 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -234,9 +234,9 @@
// missing call of form registry.registerXXX. Alternatively, the code
// generation could spuriously be adding dependencies on things we know we
// don't need.
- assert(invariant(element, compiler.backend.frontend.hasResolvedAst(element),
+ assert(invariant(element, element.hasResolvedAst,
message: "$element has no resolved ast."));
- ResolvedAst resolvedAst = compiler.backend.frontend.getResolvedAst(element);
+ ResolvedAst resolvedAst = element.resolvedAst;
return new CodegenWorkItem.internal(resolvedAst, compilationContext);
}
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 250a038..53f6190 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -191,12 +191,6 @@
/// Interface for the accessing the front-end analysis.
// TODO(johnniwinther): Find a better name for this.
abstract class Frontend {
- /// Returns `true` if [element] has a [ResolvedAst].
- bool hasResolvedAst(ExecutableElement element);
-
- /// Returns the `ResolvedAst` for the [element].
- ResolvedAst getResolvedAst(ExecutableElement element);
-
/// Returns the [ResolutionImpact] for [element].
ResolutionImpact getResolutionImpact(Element element);
}
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index 724e6f6..82cc6de 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -1187,7 +1187,8 @@
* the [fieldValues] map.
*/
void evaluateConstructorInitializers() {
- if (constructor.isSynthesized) {
+ ResolvedAst resolvedAst = constructor.resolvedAst;
+ if (resolvedAst.kind != ResolvedAstKind.PARSED) {
List<AstConstant> compiledArguments = <AstConstant>[];
Function compileArgument = (element) => definitions[element];
@@ -1198,7 +1199,7 @@
evaluateSuperOrRedirectSend(compiledArguments, target);
return;
}
- FunctionExpression functionNode = constructor.node;
+ FunctionExpression functionNode = resolvedAst.node;
NodeList initializerList = functionNode.initializers;
bool foundSuperOrRedirect = false;
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 7dbee2a..de80e0b 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -364,6 +364,9 @@
reuseLibraryTask = new GenericTask('Reuse library', this),
selfTask = new GenericTask('self', this),
];
+ if (options.resolveOnly) {
+ serialization.supportSerialization = true;
+ }
_parsingContext =
new ParsingContext(reporter, options, parser, patchParser, backend);
@@ -858,6 +861,12 @@
}
}
+ if (options.resolveOnly) {
+ reporter.log('Serializing to ${options.resolutionOutput}');
+ serialization.serializeToSink(
+ userOutputProvider.createEventSink('', 'data'),
+ libraryLoader.libraries);
+ }
if (options.analyzeOnly) {
if (!analyzeAll && !compilationFailed) {
// No point in reporting unused code when [analyzeAll] is true: all
@@ -1934,9 +1943,6 @@
message: "Element $element must be the declaration."));
assert(invariant(element, hasResolvedAst(element),
message: "ResolvedAst not available for $element."));
- if (compiler.serialization.isDeserialized(element)) {
- return compiler.serialization.getResolvedAst(element);
- }
return element.resolvedAst;
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
index 992ae55..4e22d0e 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -270,7 +270,7 @@
///
/// Returns a primitive containing the function's return value.
///
- /// The new hole is the the point after [target] has returned. The fragment
+ /// The new hole is the point after [target] has returned. The fragment
/// remains open, even if [target] never returns.
///
/// The [target] function is destroyed and should not be reused.
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index c382e4e..29b516d 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -291,6 +291,7 @@
assert(constructor.isGenerativeConstructor);
assert(constructor.isImplementation);
if (constructor.isSynthesized) return null;
+ ResolvedAst resolvedAst = constructor.resolvedAst;
ast.FunctionExpression node = constructor.node;
// If we know the body doesn't have any code, we don't generate it.
if (!node.hasBody) return null;
@@ -306,14 +307,14 @@
}
});
if (bodyElement == null) {
- bodyElement = new ConstructorBodyElementX(constructor);
+ bodyElement = new ConstructorBodyElementX(resolvedAst, constructor);
classElement.addBackendMember(bodyElement);
if (constructor.isPatch) {
// Create origin body element for patched constructors.
ConstructorBodyElementX patch = bodyElement;
ConstructorBodyElementX origin =
- new ConstructorBodyElementX(constructor.origin);
+ new ConstructorBodyElementX(resolvedAst, constructor.origin);
origin.applyPatch(patch);
classElement.origin.addBackendMember(bodyElement.origin);
}
@@ -502,7 +503,7 @@
/// Every visitor can only be applied to nodes in one context, because
/// the [elements] field is specific to that context.
IrBuilderVisitor makeVisitorForContext(AstElement context) {
- ResolvedAst resolvedAst = backend.frontend.getResolvedAst(context);
+ ResolvedAst resolvedAst = context.resolvedAst;
return new IrBuilderVisitor(resolvedAst, compiler,
sourceInformationBuilder.forContext(resolvedAst), typeMaskSystem);
}
diff --git a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
index 35d9b76..60129af 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
@@ -134,7 +134,7 @@
return _markInnerLoop(target, catchLoop);
}
- /// Returns the the innermost loop that effectively encloses both
+ /// Returns the innermost loop that effectively encloses both
/// c1 and c2 (or `null` if there is no such loop).
Continuation lowestCommonAncestor(Continuation c1, Continuation c2) {
int d1 = getDepth(c1), d2 = getDepth(c2);
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 336dfc6..5dffdf7de 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -4,16 +4,20 @@
library dart2js.cmdline;
-import 'dart:async' show Future;
+import 'dart:async' show EventSink, Future;
import 'dart:convert' show UTF8, LineSplitter;
import 'dart:io' show exit, File, FileMode, Platform, stdin, stderr;
import 'package:package_config/discovery.dart' show findPackages;
-import '../compiler.dart' as api;
+import '../compiler_new.dart' as api;
+import 'apiimpl.dart';
+import 'common/names.dart' show Uris;
import 'commandline_options.dart';
import 'filenames.dart';
import 'io/source_file.dart';
+import 'null_compiler_output.dart';
+import 'options.dart' show CompilerOptions;
import 'source_file_provider.dart';
import 'util/command_line.dart';
import 'util/uri_extras.dart';
@@ -104,16 +108,19 @@
Uri libraryRoot = currentDirectory;
Uri out = currentDirectory.resolve('out.js');
Uri sourceMapOut = currentDirectory.resolve('out.js.map');
+ Uri resolutionInput;
Uri packageConfig = null;
Uri packageRoot = null;
List<String> options = new List<String>();
- bool explicitOut = false;
+ List<String> explicitOutputArguments = <String>[];
bool wantHelp = false;
bool wantVersion = false;
String outputLanguage = 'JavaScript';
bool stripArgumentSet = false;
bool analyzeOnly = false;
bool analyzeAll = false;
+ bool resolveOnly = false;
+ Uri resolutionOutput = currentDirectory.resolve('out.data');
bool dumpInfo = false;
bool allowNativeExtensions = false;
bool trustTypeAnnotations = false;
@@ -127,47 +134,47 @@
diagnosticHandler = new FormattingDiagnosticHandler(inputProvider);
Map<String, dynamic> environment = new Map<String, dynamic>();
- passThrough(String argument) => options.add(argument);
+ void passThrough(String argument) => options.add(argument);
if (BUILD_ID != null) {
passThrough("--build-id=$BUILD_ID");
}
- setLibraryRoot(String argument) {
+ void setLibraryRoot(String argument) {
libraryRoot = currentDirectory.resolve(extractPath(argument));
}
- setPackageRoot(String argument) {
+ void setPackageRoot(String argument) {
packageRoot = currentDirectory.resolve(extractPath(argument));
}
- setPackageConfig(String argument) {
+ void setPackageConfig(String argument) {
packageConfig =
currentDirectory.resolve(extractPath(argument, isDirectory: false));
}
- setOutput(Iterator<String> arguments) {
- optionsImplyCompilation.add(arguments.current);
+ void setOutput(Iterator<String> arguments) {
+ explicitOutputArguments.add(arguments.current);
String path;
if (arguments.current == '-o') {
if (!arguments.moveNext()) {
helpAndFail('Error: Missing file after -o option.');
}
+ explicitOutputArguments.add(arguments.current);
path = arguments.current;
} else {
path = extractParameter(arguments.current);
}
- explicitOut = true;
- out = currentDirectory.resolve(nativeToUriPath(path));
+ resolutionOutput = out = currentDirectory.resolve(nativeToUriPath(path));
sourceMapOut = Uri.parse('$out.map');
}
- setOutputType(String argument) {
+ void setOutputType(String argument) {
optionsImplyCompilation.add(argument);
if (argument == '--output-type=dart' ||
argument == '--output-type=dart-multi') {
outputLanguage = OUTPUT_LANGUAGE_DART;
- if (!explicitOut) {
+ if (explicitOutputArguments.isNotEmpty) {
out = currentDirectory.resolve('out.dart');
sourceMapOut = currentDirectory.resolve('out.dart.map');
}
@@ -182,75 +189,84 @@
passThrough(argument);
}
+ void setResolutionInput(String argument) {
+ resolutionInput =
+ currentDirectory.resolve(extractPath(argument, isDirectory: false));
+ }
+
+ void setResolveOnly(String argument) {
+ resolveOnly = true;
+ passThrough(argument);
+ }
+
String getDepsOutput(Map<Uri, SourceFile> sourceFiles) {
var filenames = sourceFiles.keys.map((uri) => '$uri').toList();
filenames.sort();
return filenames.join("\n");
}
- setStrip(String argument) {
+ void implyCompilation(String argument) {
optionsImplyCompilation.add(argument);
- stripArgumentSet = true;
passThrough(argument);
}
- setAnalyzeOnly(String argument) {
+ void setStrip(String argument) {
+ stripArgumentSet = true;
+ implyCompilation(argument);
+ }
+
+ void setAnalyzeOnly(String argument) {
analyzeOnly = true;
passThrough(argument);
}
- setAnalyzeAll(String argument) {
+ void setAnalyzeAll(String argument) {
analyzeAll = true;
passThrough(argument);
}
- setAllowNativeExtensions(String argument) {
+ void setAllowNativeExtensions(String argument) {
allowNativeExtensions = true;
passThrough(argument);
}
- setVerbose(_) {
+ void setVerbose(_) {
diagnosticHandler.verbose = true;
passThrough('--verbose');
}
- implyCompilation(String argument) {
- optionsImplyCompilation.add(argument);
- passThrough(argument);
- }
-
- setDumpInfo(String argument) {
+ void setDumpInfo(String argument) {
implyCompilation(argument);
dumpInfo = true;
}
- setTrustTypeAnnotations(String argument) {
+ void setTrustTypeAnnotations(String argument) {
trustTypeAnnotations = true;
implyCompilation(argument);
}
- setTrustJSInteropTypeAnnotations(String argument) {
+ void setTrustJSInteropTypeAnnotations(String argument) {
trustJSInteropTypeAnnotations = true;
implyCompilation(argument);
}
- setTrustPrimitives(String argument) {
+ void setTrustPrimitives(String argument) {
implyCompilation(argument);
}
- setCheckedMode(String argument) {
+ void setCheckedMode(String argument) {
checkedMode = true;
passThrough(argument);
}
- addInEnvironment(String argument) {
+ void addInEnvironment(String argument) {
int eqIndex = argument.indexOf('=');
String name = argument.substring(2, eqIndex);
String value = argument.substring(eqIndex + 1);
environment[name] = value;
}
- setCategories(String argument) {
+ void setCategories(String argument) {
List<String> categories = extractParameter(argument).split(',');
if (categories.contains('all')) {
categories = ["Client", "Server"];
@@ -273,7 +289,7 @@
}
}
- handleShortOptions(String argument) {
+ void handleShortOptions(String argument) {
var shortOptions = argument.substring(1).split("");
for (var shortOption in shortOptions) {
switch (shortOption) {
@@ -342,6 +358,8 @@
new OptionHandler(Flags.analyzeAll, setAnalyzeAll),
new OptionHandler(Flags.analyzeOnly, setAnalyzeOnly),
new OptionHandler(Flags.noSourceMaps, passThrough),
+ new OptionHandler(Option.resolutionInput, setResolutionInput),
+ new OptionHandler(Flags.resolveOnly, setResolveOnly),
new OptionHandler(Flags.analyzeSignaturesOnly, setAnalyzeOnly),
new OptionHandler(Flags.disableNativeLiveTypeAnalysis, passThrough),
new OptionHandler('--categories=.*', setCategories),
@@ -355,6 +373,7 @@
new OptionHandler(Flags.useContentSecurityPolicy, passThrough),
new OptionHandler(Flags.enableExperimentalMirrors, passThrough),
new OptionHandler(Flags.enableAssertMessage, passThrough),
+
// TODO(floitsch): remove conditional directives flag.
// We don't provide the info-message yet, since we haven't publicly
// launched the feature yet.
@@ -427,18 +446,31 @@
helpAndFail("Cannot specify both '--package-root' and '--packages.");
}
- if ((analyzeOnly || analyzeAll) && !optionsImplyCompilation.isEmpty) {
- if (!analyzeOnly) {
+ List<String> optionsImplyOutput = <String>[]
+ ..addAll(optionsImplyCompilation)
+ ..addAll(explicitOutputArguments);
+ if (resolveOnly && !optionsImplyCompilation.isEmpty) {
+ diagnosticHandler.info(
+ "Options $optionsImplyCompilation indicate that compilation is "
+ "expected, but compilation is turned off by the option "
+ "'${Flags.resolveOnly}'.",
+ api.Diagnostic.INFO);
+ } else if ((analyzeOnly || analyzeAll) && !optionsImplyOutput.isEmpty) {
+ if (analyzeAll && !analyzeOnly) {
diagnosticHandler.info(
"Option '${Flags.analyzeAll}' implies '${Flags.analyzeOnly}'.",
api.Diagnostic.INFO);
}
diagnosticHandler.info(
- "Options $optionsImplyCompilation indicate that output is expected, "
+ "Options $optionsImplyOutput indicate that output is expected, "
"but compilation is turned off by the option '${Flags.analyzeOnly}'.",
api.Diagnostic.INFO);
}
- if (analyzeAll) analyzeOnly = true;
+ if (resolveOnly) {
+ analyzeOnly = analyzeAll = true;
+ } else if (analyzeAll) {
+ analyzeOnly = true;
+ }
if (!analyzeOnly) {
if (allowNativeExtensions) {
helpAndFail("Option '${Flags.allowNativeExtensions}' is only supported "
@@ -455,7 +487,9 @@
RandomAccessFileOutputProvider outputProvider =
new RandomAccessFileOutputProvider(out, sourceMapOut,
- onInfo: diagnosticHandler.info, onFailure: fail);
+ onInfo: diagnosticHandler.info,
+ onFailure: fail,
+ resolutionOutput: resolveOnly ? resolutionOutput : null);
api.CompilationResult compilationDone(api.CompilationResult result) {
if (analyzeOnly) return result;
@@ -476,7 +510,7 @@
for (String filename in outputProvider.allOutputFiles) {
print(" $filename");
}
- } else if (!explicitOut) {
+ } else if (explicitOutputArguments.isNotEmpty) {
String input = uriPathToNative(arguments[0]);
String output = relativize(currentDirectory, out, Platform.isWindows);
print('Dart file ($input) compiled to $outputLanguage: $output');
@@ -484,18 +518,19 @@
return result;
}
- Uri uri = currentDirectory.resolve(arguments[0]);
+ Uri script = currentDirectory.resolve(arguments[0]);
+ CompilerOptions compilerOptions = new CompilerOptions.parse(
+ entryPoint: script,
+ libraryRoot: libraryRoot,
+ packageRoot: packageRoot,
+ packageConfig: packageConfig,
+ packagesDiscoveryProvider: findPackages,
+ resolutionInput: resolutionInput,
+ resolutionOutput: resolutionOutput,
+ options: options,
+ environment: environment);
return compileFunc(
- uri,
- libraryRoot,
- packageRoot,
- inputProvider,
- diagnosticHandler,
- options,
- outputProvider,
- environment,
- packageConfig,
- findPackages)
+ compilerOptions, inputProvider, diagnosticHandler, outputProvider)
.then(compilationDone);
}
@@ -706,8 +741,15 @@
internalMain(arguments);
}
-var exitFunc = exit;
-var compileFunc = api.compile;
+typedef void ExitFunc(int exitCode);
+typedef Future<api.CompilationResult> CompileFunc(
+ CompilerOptions compilerOptions,
+ api.CompilerInput compilerInput,
+ api.CompilerDiagnostics compilerDiagnostics,
+ api.CompilerOutput compilerOutput);
+
+ExitFunc exitFunc = exit;
+CompileFunc compileFunc = api.compile;
Future<api.CompilationResult> internalMain(List<String> arguments) {
Future onError(exception, trace) {
@@ -754,6 +796,10 @@
throw _EXIT_SIGNAL;
};
+ if (USE_SERIALIZED_DART_CORE) {
+ _useSerializedDataForDartCore(compileFunc);
+ }
+
var stream = stdin.transform(UTF8.decoder).transform(new LineSplitter());
var subscription;
subscription = stream.listen((line) {
@@ -784,3 +830,84 @@
});
});
}
+
+final bool USE_SERIALIZED_DART_CORE =
+ Platform.environment['USE_SERIALIZED_DART_CORE'] == 'true';
+
+void _useSerializedDataForDartCore(CompileFunc oldCompileFunc) {
+ String serializedData;
+
+ Future<api.CompilationResult> compileWithSerializedData(
+ CompilerOptions compilerOptions,
+ api.CompilerInput compilerInput,
+ api.CompilerDiagnostics compilerDiagnostics,
+ api.CompilerOutput compilerOutput) async {
+ CompilerImpl compiler = new CompilerImpl(
+ compilerInput, compilerOutput, compilerDiagnostics, compilerOptions);
+ compiler.serialization.deserializeFromText(serializedData);
+ return compiler.run(compilerOptions.entryPoint).then((bool success) {
+ return new api.CompilationResult(compiler, isSuccess: success);
+ });
+ }
+
+ Future<api.CompilationResult> generateSerializedDataForDartCore(
+ CompilerOptions compilerOptions,
+ api.CompilerInput compilerInput,
+ api.CompilerDiagnostics compilerDiagnostics,
+ api.CompilerOutput compilerOutput) async {
+ _CompilerOutput output = new _CompilerOutput();
+ api.CompilationResult result = await oldCompileFunc(
+ new CompilerOptions.parse(
+ entryPoint: Uris.dart_core,
+ libraryRoot: compilerOptions.libraryRoot,
+ packageRoot: compilerOptions.packageRoot,
+ packageConfig: compilerOptions.packageConfig,
+ packagesDiscoveryProvider:
+ compilerOptions.packagesDiscoveryProvider,
+ environment: compilerOptions.environment,
+ resolutionOutput: Uri.parse('file:fake.data'),
+ options: [Flags.resolveOnly]),
+ compilerInput,
+ compilerDiagnostics,
+ output);
+ serializedData = output.serializedData;
+ compileFunc = compileWithSerializedData;
+ return compileWithSerializedData(
+ compilerOptions, compilerInput, compilerDiagnostics, compilerOutput);
+ }
+
+ compileFunc = generateSerializedDataForDartCore;
+}
+
+class _CompilerOutput extends NullCompilerOutput {
+ _BufferedEventSink sink;
+
+ @override
+ EventSink<String> createEventSink(String name, String extension) {
+ if (name == '' && extension == 'data') {
+ return sink = new _BufferedEventSink();
+ }
+ return super.createEventSink(name, extension);
+ }
+
+ String get serializedData => sink.sb.toString();
+}
+
+class _BufferedEventSink implements EventSink<String> {
+ StringBuffer sb = new StringBuffer();
+
+ @override
+ void add(String event) {
+ sb.write(event);
+ }
+
+ @override
+ void close() {
+ // Do nothing.
+ }
+
+ @override
+ void addError(errorEvent, [StackTrace stackTrace]) {
+ // Ignore
+ }
+}
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index bbd91ae..c34c06e 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -351,13 +351,13 @@
backend.constants.getConstantValue(expression);
assert(invariant(node, value != null,
message: "Constant expression without value: "
- "${expression.toStructuredText()}."));
+ "${expression.toStructuredText()}."));
constants.add(value);
} else {
- assert(invariant(node,
- expression.isImplicit || expression.isPotential,
- message: "Unexpected unevaluated constant expression: "
- "${expression.toStructuredText()}."));
+ assert(
+ invariant(node, expression.isImplicit || expression.isPotential,
+ message: "Unexpected unevaluated constant expression: "
+ "${expression.toStructuredText()}."));
}
});
}
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 74ac6ad..3e14846 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -778,7 +778,7 @@
Map<Element, List<ImportElement>> importers =
new Map<Element, List<ImportElement>>();
- /// Returns the the list of [ImportElement]s through which [element] was
+ /// Returns the list of [ImportElement]s through which [element] was
/// imported.
List<ImportElement> getImports(Element element) {
List<ImportElement> imports = importers[element];
@@ -2284,18 +2284,32 @@
class ConstructorBodyElementX extends BaseFunctionElementX
implements ConstructorBodyElement {
- ConstructorElementX constructor;
+ final ResolvedAst _resolvedAst;
+ final ConstructorElement constructor;
- ConstructorBodyElementX(ConstructorElementX constructor)
- : this.constructor = constructor,
+ ConstructorBodyElementX(
+ ResolvedAst resolvedAst, ConstructorElement constructor)
+ : this._resolvedAst = resolvedAst,
+ this.constructor = constructor,
super(constructor.name, ElementKind.GENERATIVE_CONSTRUCTOR_BODY,
Modifiers.EMPTY, constructor.enclosingElement) {
functionSignature = constructor.functionSignature;
}
- bool get hasNode => constructor.hasNode;
+ bool get hasNode => _resolvedAst.kind == ResolvedAstKind.PARSED;
- FunctionExpression get node => constructor.node;
+ FunctionExpression get node => _resolvedAst.node;
+
+ bool get hasResolvedAst => true;
+
+ ResolvedAst get resolvedAst {
+ if (_resolvedAst.kind == ResolvedAstKind.PARSED) {
+ return new ParsedResolvedAst(declaration, _resolvedAst.node,
+ _resolvedAst.body, _resolvedAst.elements, _resolvedAst.sourceUri);
+ } else {
+ return new SynthesizedResolvedAst(declaration, _resolvedAst.kind);
+ }
+ }
List<MetadataAnnotation> get metadata => constructor.metadata;
@@ -2307,6 +2321,8 @@
return null;
}
+ int get sourceOffset => constructor.sourceOffset;
+
Token get position => constructor.position;
Element get outermostEnclosingMemberOrTopLevel => constructor;
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index e800c0f..a65d3e3 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -47,10 +47,6 @@
CoreTypes get coreTypes => compiler.coreTypes;
- ResolvedAst getResolvedAst(Element element) {
- return compiler.backend.frontend.getResolvedAst(element.declaration);
- }
-
/**
* Records the default type of parameter [parameter].
*/
@@ -268,7 +264,7 @@
throw "updateSelector for IR node $node";
}
ast.Node astNode = node;
- TreeElements elements = getResolvedAst(owner).elements;
+ TreeElements elements = owner.resolvedAst.elements;
if (astNode.asSendSet() != null) {
if (selector.isSetter || selector.isIndexSet) {
elements.setTypeMask(node, mask);
@@ -359,12 +355,9 @@
compiler,
handler);
- ResolvedAst getResolvedAst(Element element) {
- return compiler.backend.frontend.getResolvedAst(element.declaration);
- }
-
- void analyzeSuperConstructorCall(Element target, ArgumentsTypes arguments) {
- ResolvedAst resolvedAst = getResolvedAst(target);
+ void analyzeSuperConstructorCall(
+ AstElement target, ArgumentsTypes arguments) {
+ ResolvedAst resolvedAst = target.resolvedAst;
inferrer.analyze(resolvedAst, arguments);
isThisExposed = isThisExposed || inferrer.checkIfExposesThis(target);
}
@@ -487,7 +480,7 @@
cls.forEachInstanceField((_, FieldElement field) {
if (field.isFinal) return;
T type = locals.fieldScope.readField(field);
- ResolvedAst resolvedAst = getResolvedAst(field);
+ ResolvedAst resolvedAst = field.resolvedAst;
if (type == null && resolvedAst.body == null) {
inferrer.recordTypeOfNonFinalField(
spannable, field, types.nullType);
@@ -565,7 +558,7 @@
LocalsHandler closureLocals =
new LocalsHandler<T>.from(locals, node, useOtherTryBlock: false);
SimpleTypeInferrerVisitor visitor = new SimpleTypeInferrerVisitor<T>(
- element, getResolvedAst(element), compiler, inferrer, closureLocals);
+ element, element.resolvedAst, compiler, inferrer, closureLocals);
visitor.run();
inferrer.recordReturnType(element, visitor.returnType);
@@ -667,16 +660,17 @@
if (isThisExposed) return;
inferrer.forEachElementMatching(selector, mask, (element) {
if (element.isField) {
+ ResolvedAst elementResolvedAst = element.resolvedAst;
if (!selector.isSetter &&
isInClassOrSubclass(element) &&
- !element.modifiers.isFinal &&
+ !element.isFinal &&
locals.fieldScope.readField(element) == null &&
- element.initializer == null) {
+ elementResolvedAst.body == null) {
// If the field is being used before this constructor
// actually had a chance to initialize it, say it can be
// null.
inferrer.recordTypeOfNonFinalField(
- analyzedElement.node, element, types.nullType);
+ resolvedAst.node, element, types.nullType);
}
// Accessing a field does not expose [:this:].
return true;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 1cac7aa..f81a6ca 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -858,7 +858,7 @@
compiler.backend.constants.getConstantValue(constant);
assert(invariant(fieldElement, value != null,
message: "Constant expression without value: "
- "${constant.toStructuredText()}."));
+ "${constant.toStructuredText()}."));
if (value.isFunction) {
FunctionConstantValue functionConstant = value;
type = types.allocateClosure(node, functionConstant.element);
@@ -1242,7 +1242,7 @@
// TODO(ngeoffray): Not sure why the resolver would put a null
// mapping.
if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
- ResolvedAst resolvedAst = getResolvedAst(element);
+ ResolvedAst resolvedAst = element.resolvedAst;
element = element.implementation;
if (element.impliesType) return;
assert(invariant(
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 15b8de4..5f334e3 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -2508,41 +2508,6 @@
ResolutionImpact getResolutionImpact(Element element) {
return resolution.getResolutionImpact(element);
}
-
- @override
- bool hasResolvedAst(ExecutableElement element) {
- if (element is SynthesizedCallMethodElementX) {
- return true;
- } else if (element is ConstructorBodyElementX) {
- return true;
- } else if (element is FieldElementX) {
- return true;
- } else if (element is DeferredLoaderGetterElementX) {
- return true;
- } else {
- return resolution.hasResolvedAst(element);
- }
- }
-
- @override
- ResolvedAst getResolvedAst(ExecutableElement element) {
- if (element is SynthesizedCallMethodElementX) {
- return element.resolvedAst;
- } else if (element is ConstructorBodyElementX) {
- return element.resolvedAst;
- } else if (element is DeferredLoaderGetterElementX) {
- return element.resolvedAst;
- } else if (element is FieldElementX) {
- // TODO(johnniwinther): Find a good invariant for resolution of fields.
- // Currently some but not all are resolved (maybe it has to do with
- // initializers?)
- return element.resolvedAst;
- } else {
- assert(invariant(element, resolution.hasResolvedAst(element.declaration),
- message: 'No ResolvedAst for $element'));
- return resolution.getResolvedAst(element.declaration);
- }
- }
}
/// Handling of special annotations for tests.
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 4e8fe30..c0f21c5 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -478,6 +478,10 @@
return asName('${callPrefix}\$2');
case JsGetName.CALL_PREFIX3:
return asName('${callPrefix}\$3');
+ case JsGetName.CALL_PREFIX4:
+ return asName('${callPrefix}\$4');
+ case JsGetName.CALL_PREFIX5:
+ return asName('${callPrefix}\$5');
case JsGetName.CALL_CATCH_ALL:
return asName(callCatchAllName);
case JsGetName.REFLECTABLE:
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
index 3eb4c8c..7df112d 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
@@ -403,7 +403,7 @@
// that we have a string.
if (!superclass || typeof superclass != "string") {
// Inlined special case of InheritFrom here for performance reasons.
- // Fix up the the Dart Object class' prototype.
+ // Fix up the Dart Object class' prototype.
var constructor = allClasses[cls];
var prototype = constructor.prototype;
prototype.constructor = constructor;
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index da33e20..b779ef7 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -428,11 +428,11 @@
// Check whether the arity matches this member.
var argumentCount = selector.argumentCount;
// JS interop does not support named arguments.
- if (selector.namedArgumentCount > 0) break;
- if (argumentCount < minArgs) break;
- if (argumentCount > maxArgs) break;
+ if (selector.namedArgumentCount > 0) continue;
+ if (argumentCount < minArgs) continue;
+ if (argumentCount > maxArgs) continue;
var stubName = namer.invocationName(selector);
- if (!stubNames.add(stubName.key)) break;
+ if (!stubNames.add(stubName.key)) continue;
var parameters =
new List<String>.generate(argumentCount, (i) => 'p$i');
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 84c8a80..93af700 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -187,6 +187,15 @@
/// Whether to emit URIs in the reflection metadata.
final bool preserveUris;
+ /// The location of serialized data used for resolution.
+ final Uri resolutionInput;
+
+ /// The location of the serialized data from resolution.
+ final Uri resolutionOutput;
+
+ // If `true`, sources are resolved and serialized.
+ final bool resolveOnly;
+
/// URI where the compiler should generate the output source map file.
final Uri sourceMapUri;
@@ -247,6 +256,8 @@
Uri libraryRoot,
Uri packageRoot,
Uri packageConfig,
+ Uri resolutionInput,
+ Uri resolutionOutput,
PackagesDiscoveryProvider packagesDiscoveryProvider,
Map<String, dynamic> environment: const <String, dynamic>{},
List<String> options}) {
@@ -298,6 +309,9 @@
_resolvePlatformConfigFromOptions(libraryRoot, options),
preserveComments: _hasOption(options, Flags.preserveComments),
preserveUris: _hasOption(options, Flags.preserveUris),
+ resolutionInput: resolutionInput,
+ resolutionOutput: resolutionOutput,
+ resolveOnly: _hasOption(options, Flags.resolveOnly),
sourceMapUri: _extractUriOption(options, '--source-map='),
strips: _extractCsvOption(options, '--force-strip='),
testMode: _hasOption(options, Flags.testMode),
@@ -359,6 +373,9 @@
Uri platformConfigUri: null,
bool preserveComments: false,
bool preserveUris: false,
+ Uri resolutionInput: null,
+ Uri resolutionOutput: null,
+ bool resolveOnly: false,
Uri sourceMapUri: null,
List<String> strips: const [],
bool testMode: false,
@@ -398,9 +415,10 @@
packageConfig, packagesDiscoveryProvider, environment,
allowMockCompilation: allowMockCompilation,
allowNativeExtensions: allowNativeExtensions,
- analyzeAll: analyzeAll,
+ analyzeAll: analyzeAll || resolveOnly,
analyzeMain: analyzeMain,
- analyzeOnly: analyzeOnly || analyzeSignaturesOnly || analyzeAll,
+ analyzeOnly:
+ analyzeOnly || analyzeSignaturesOnly || analyzeAll || resolveOnly,
analyzeSignaturesOnly: analyzeSignaturesOnly,
buildId: buildId,
dart2dartMultiFile: dart2dartMultiFile,
@@ -430,6 +448,9 @@
libraryRoot, null, !emitJavaScript, const []),
preserveComments: preserveComments,
preserveUris: preserveUris,
+ resolutionInput: resolutionInput,
+ resolutionOutput: resolutionOutput,
+ resolveOnly: resolveOnly,
sourceMapUri: sourceMapUri,
strips: strips,
testMode: testMode,
@@ -478,6 +499,9 @@
this.platformConfigUri: null,
this.preserveComments: false,
this.preserveUris: false,
+ this.resolutionInput: null,
+ this.resolutionOutput: null,
+ this.resolveOnly: false,
this.sourceMapUri: null,
this.strips: const [],
this.testMode: false,
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 4079c78..1150c96 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -248,7 +248,7 @@
return enumType;
}
- /// Resolves the mixed type for [mixinNode] and checks that the the mixin type
+ /// Resolves the mixed type for [mixinNode] and checks that the mixin type
/// is a valid, non-blacklisted interface type. The mixin type is returned.
DartType checkMixinType(TypeAnnotation mixinNode) {
DartType mixinType = resolveType(mixinNode);
@@ -444,7 +444,6 @@
previous = current;
current = currentMixinApplication.mixin;
}
- registry.registerMixinUse(mixinApplication, mixin);
return mixinType;
}
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index 0f9f099..17bd6e0 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -249,7 +249,7 @@
/// reported and an [ErroneousConstructorElement] is returned.
ConstructorElement verifyThatConstructorMatchesCall(
Node node,
- ConstructorElementX lookedupConstructor,
+ ConstructorElement lookedupConstructor,
CallStructure callStructure,
String className,
{String constructorName: '',
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index 7de89c2..6d56c8e 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -22,7 +22,6 @@
import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
import '../universe/world_impact.dart' show WorldImpact, WorldImpactBuilder;
import '../util/enumset.dart' show EnumSet;
-import '../world.dart' show World;
import 'send_structure.dart';
@@ -170,10 +169,6 @@
bool get isForResolution => true;
- ResolutionEnqueuer get world => compiler.enqueuer.resolution;
-
- World get universe => compiler.world;
-
Backend get backend => compiler.backend;
String toString() => 'ResolutionRegistry for ${mapping.analyzedElement}';
@@ -399,11 +394,6 @@
return backend.defaultSuperclass(element);
}
- void registerMixinUse(
- MixinApplicationElement mixinApplication, ClassElement mixin) {
- universe.registerMixinUse(mixinApplication, mixin);
- }
-
void registerInstantiation(InterfaceType type) {
worldImpact.registerTypeUse(new TypeUse.instantiation(type));
}
diff --git a/pkg/compiler/lib/src/serialization/equivalence.dart b/pkg/compiler/lib/src/serialization/equivalence.dart
index be8ff7f..ab8f78e 100644
--- a/pkg/compiler/lib/src/serialization/equivalence.dart
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart
@@ -6,6 +6,7 @@
library dart2js.serialization.equivalence;
+import '../closure.dart';
import '../common.dart';
import '../common/resolution.dart';
import '../constants/expressions.dart';
@@ -405,6 +406,14 @@
}
@override
+ bool visitBoxFieldElement(
+ BoxFieldElement element1, BoxFieldElement element2) {
+ return element1.box.name == element2.box.name &&
+ visit(element1.box.executableContext, element2.box.executableContext) &&
+ visit(element1.variableElement, element2.variableElement);
+ }
+
+ @override
bool visitConstructorElement(
ConstructorElement element1, ConstructorElement element2) {
return checkMembers(element1, element2);
@@ -822,7 +831,11 @@
TreeElementsEquivalenceVisitor visitor = new TreeElementsEquivalenceVisitor(
indices1, indices2, elements1, elements2, strategy);
resolvedAst1.node.accept(visitor);
- return visitor.success;
+ if (visitor.success) {
+ return strategy.test(elements1, elements2, 'containsTryStatement',
+ elements1.containsTryStatement, elements2.containsTryStatement);
+ }
+ return false;
}
/// Visitor that checks the equivalence of [TreeElements] data.
diff --git a/pkg/compiler/lib/src/serialization/keys.dart b/pkg/compiler/lib/src/serialization/keys.dart
index de805fe..179b727 100644
--- a/pkg/compiler/lib/src/serialization/keys.dart
+++ b/pkg/compiler/lib/src/serialization/keys.dart
@@ -22,6 +22,7 @@
static const Key CONSTANT = const Key('constant');
static const Key CONSTANTS = const Key('constants');
static const Key CONSTRUCTOR = const Key('constructor');
+ static const Key CONTAINS_TRY = const Key('containsTryStatement');
static const Key DATA = const Key('data');
static const Key DEFAULT = const Key('default');
static const Key DEFAULTS = const Key('defaults');
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index 7772956..3c10292 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -82,13 +82,13 @@
bool get isClosure => false;
@override
- bool get isConst => _unsupported('isConst');
+ bool get isConst => false;
@override
bool get isDeferredLoaderGetter => false;
@override
- bool get isFinal => _unsupported('isFinal');
+ bool get isFinal => false;
@override
bool get isInstanceMember => false;
@@ -249,20 +249,32 @@
TreeElements get treeElements => _unsupported('treeElements');
}
-abstract class AstElementMixin implements AstElement, ElementZ {
+abstract class AstElementMixinZ implements AstElement, ElementZ {
+ ResolvedAst _resolvedAst;
+
// TODO(johnniwinther): This is needed for the token invariant assertion. Find
// another way to bypass the test for modelz.
@override
bool get hasNode => false;
@override
- bool get hasResolvedAst => _unsupported('hasResolvedAst');
+ bool get hasResolvedAst => _resolvedAst != null;
@override
get node => _unsupported('node');
@override
- ResolvedAst get resolvedAst => _unsupported('resolvedAst');
+ ResolvedAst get resolvedAst {
+ assert(invariant(this, _resolvedAst != null,
+ message: "ResolvedAst has not been set for $this."));
+ return _resolvedAst;
+ }
+
+ void set resolvedAst(ResolvedAst value) {
+ assert(invariant(this, _resolvedAst == null,
+ message: "ResolvedAst has already been set for $this."));
+ _resolvedAst = value;
+ }
}
abstract class ContainerMixin
@@ -801,7 +813,7 @@
class ClassElementZ extends DeserializedElementZ
with
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
ClassElementCommon,
class_members.ClassMemberMixin,
ContainerMixin,
@@ -922,7 +934,7 @@
class_members.ClassMemberMixin,
TypeDeclarationMixin<InterfaceType>,
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
MixinApplicationElementCommon,
MixinApplicationElementMixin {
final String name;
@@ -943,6 +955,9 @@
CompilationUnitElement get compilationUnit => _subclass.compilationUnit;
@override
+ bool get isTopLevel => true;
+
+ @override
bool get isUnnamedMixinApplication => true;
Link<ConstructorElement> get constructors {
@@ -1040,7 +1055,7 @@
abstract class ConstructorElementZ extends DeserializedElementZ
with
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
ClassMemberMixin,
FunctionTypedElementMixin,
ParametersMixin,
@@ -1221,7 +1236,7 @@
}
class ForwardingConstructorElementZ extends ElementZ
- with AnalyzableElementMixin, AstElementMixin
+ with AnalyzableElementMixin, AstElementMixinZ
implements ConstructorElement {
final MixinApplicationElement enclosingClass;
final ConstructorElement definingConstructor;
@@ -1261,7 +1276,9 @@
@override
FunctionSignature get functionSignature {
- return _unsupported('functionSignature');
+ // TODO(johnniwinther): Ensure that the function signature (and with it the
+ // function type) substitutes type variables correctly.
+ return definingConstructor.functionSignature;
}
@override
@@ -1354,7 +1371,7 @@
abstract class FieldElementZ extends DeserializedElementZ
with
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
TypedElementMixin,
MemberElementMixin
implements FieldElement {
@@ -1421,7 +1438,7 @@
abstract class FunctionElementZ extends DeserializedElementZ
with
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
ParametersMixin,
FunctionTypedElementMixin,
TypedElementMixin,
@@ -1500,7 +1517,7 @@
class LocalFunctionElementZ extends DeserializedElementZ
with
LocalExecutableMixin,
- AstElementMixin,
+ AstElementMixinZ,
ParametersMixin,
FunctionTypedElementMixin,
TypedElementMixin
@@ -1524,7 +1541,7 @@
abstract class GetterElementZ extends DeserializedElementZ
with
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
FunctionTypedElementMixin,
ParametersMixin,
TypedElementMixin,
@@ -1564,7 +1581,7 @@
abstract class SetterElementZ extends DeserializedElementZ
with
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
FunctionTypedElementMixin,
ParametersMixin,
TypedElementMixin,
@@ -1656,7 +1673,7 @@
class TypedefElementZ extends DeserializedElementZ
with
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
LibraryMemberMixin,
ParametersMixin,
TypeDeclarationMixin<TypedefType>
@@ -1698,7 +1715,7 @@
}
class TypeVariableElementZ extends DeserializedElementZ
- with AnalyzableElementMixin, AstElementMixin, TypedElementMixin
+ with AnalyzableElementMixin, AstElementMixinZ, TypedElementMixin
implements TypeVariableElement {
TypeDeclarationElement _typeDeclaration;
TypeVariableType _type;
@@ -1756,7 +1773,7 @@
}
class SyntheticTypeVariableElementZ extends ElementZ
- with AnalyzableElementMixin, AstElementMixin
+ with AnalyzableElementMixin, AstElementMixinZ
implements TypeVariableElement {
final TypeDeclarationElement typeDeclaration;
final int index;
@@ -1820,7 +1837,7 @@
}
abstract class ParameterElementZ extends DeserializedElementZ
- with AnalyzableElementMixin, AstElementMixin, TypedElementMixin
+ with AnalyzableElementMixin, AstElementMixinZ, TypedElementMixin
implements ParameterElement {
FunctionElement _functionDeclaration;
ConstantExpression _constant;
@@ -1901,6 +1918,9 @@
}
@override
+ bool get isLocal => true;
+
+ @override
ElementKind get kind => ElementKind.PARAMETER;
}
@@ -1930,7 +1950,7 @@
class LocalVariableElementZ extends DeserializedElementZ
with
AnalyzableElementMixin,
- AstElementMixin,
+ AstElementMixinZ,
LocalExecutableMixin,
TypedElementMixin
implements LocalVariableElement {
diff --git a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
index 633b65e..9b4e0d3 100644
--- a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
@@ -25,6 +25,7 @@
import 'modelz.dart';
import 'serialization.dart';
import 'serialization_util.dart';
+import 'modelz.dart';
/// Visitor that computes a node-index mapping.
class AstIndexComputer extends Visitor {
@@ -146,11 +147,12 @@
}
objectEncoder.setEnum(Key.SUB_KIND, kind);
root.accept(indexComputer);
+ objectEncoder.setBool(Key.CONTAINS_TRY, elements.containsTryStatement);
if (resolvedAst.body != null) {
int index = nodeIndices[resolvedAst.body];
assert(invariant(element, index != null,
- message:
- "No index for body of $element: ${resolvedAst.body} ($nodeIndices)."));
+ message: "No index for body of $element: "
+ "${resolvedAst.body} ($nodeIndices)."));
objectEncoder.setInt(Key.BODY, index);
}
root.accept(this);
@@ -343,18 +345,18 @@
ObjectDecoder objectDecoder,
ParsingContext parsing,
Token getBeginToken(Uri uri, int charOffset),
- DeserializerPlugin nativeDataDeserializer,
- Map<Element, ResolvedAst> resolvedAstMap) {
+ DeserializerPlugin nativeDataDeserializer) {
ResolvedAstKind kind =
objectDecoder.getEnum(Key.KIND, ResolvedAstKind.values);
switch (kind) {
case ResolvedAstKind.PARSED:
deserializeParsed(element, objectDecoder, parsing, getBeginToken,
- nativeDataDeserializer, resolvedAstMap);
+ nativeDataDeserializer);
break;
case ResolvedAstKind.DEFAULT_CONSTRUCTOR:
case ResolvedAstKind.FORWARDING_CONSTRUCTOR:
- resolvedAstMap[element] = new SynthesizedResolvedAst(element, kind);
+ (element as AstElementMixinZ).resolvedAst =
+ new SynthesizedResolvedAst(element, kind);
break;
}
}
@@ -363,12 +365,11 @@
/// method, or field) and its nested closures. The [ResolvedAst]s are added
/// to [resolvedAstMap].
static void deserializeParsed(
- Element element,
+ AstElementMixinZ element,
ObjectDecoder objectDecoder,
ParsingContext parsing,
Token getBeginToken(Uri uri, int charOffset),
- DeserializerPlugin nativeDataDeserializer,
- Map<Element, ResolvedAst> resolvedAstMap) {
+ DeserializerPlugin nativeDataDeserializer) {
CompilationUnitElement compilationUnit = element.compilationUnit;
DiagnosticReporter reporter = parsing.reporter;
Uri uri = objectDecoder.getUri(Key.URI);
@@ -479,7 +480,7 @@
builder.emptyStatement());
return constructorNode;
case AstKind.ENUM_CONSTANT:
- EnumConstantElement enumConstant = element;
+ EnumConstantElementZ enumConstant = element;
EnumClassElement enumClass = element.enclosingClass;
int index = enumConstant.index;
AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
@@ -528,6 +529,8 @@
Map<Node, int> nodeIndices = indexComputer.nodeIndices;
List<Node> nodeList = indexComputer.nodeList;
root.accept(indexComputer);
+ elements.containsTryStatement = objectDecoder.getBool(Key.CONTAINS_TRY);
+
Node body;
int bodyNodeIndex = objectDecoder.getInt(Key.BODY, isOptional: true);
if (bodyNodeIndex != null) {
@@ -657,13 +660,11 @@
elements.registerNativeData(node, nativeData);
}
}
- FunctionElement function =
+ LocalFunctionElementZ function =
objectDecoder.getElement(Key.FUNCTION, isOptional: true);
if (function != null) {
FunctionExpression functionExpression = node;
- assert(invariant(function, !resolvedAstMap.containsKey(function),
- message: "ResolvedAst has already been computed for $function."));
- resolvedAstMap[function] = new ParsedResolvedAst(function,
+ function.resolvedAst = new ParsedResolvedAst(function,
functionExpression, functionExpression.body, elements, uri);
}
// TODO(johnniwinther): Remove these when inference doesn't need `.node`
@@ -680,9 +681,7 @@
}
}
}
- assert(invariant(element, !resolvedAstMap.containsKey(element),
- message: "ResolvedAst has already been computed for $element."));
- resolvedAstMap[element] =
+ element.resolvedAst =
new ParsedResolvedAst(element, root, body, elements, uri);
}
}
diff --git a/pkg/compiler/lib/src/serialization/system.dart b/pkg/compiler/lib/src/serialization/system.dart
new file mode 100644
index 0000000..8db5c4b
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/system.dart
@@ -0,0 +1,255 @@
+// Copyright (c) 2016, 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 dart2js.serialization_system;
+
+import 'dart:async';
+import '../commandline_options.dart';
+import '../common.dart';
+import '../common/backend_api.dart';
+import '../common/names.dart';
+import '../common/resolution.dart';
+import '../compiler.dart';
+import '../elements/elements.dart';
+import '../io/source_file.dart';
+import '../scanner/scanner.dart';
+import '../script.dart';
+import '../serialization/impact_serialization.dart';
+import '../tokens/token.dart';
+import '../universe/call_structure.dart';
+import '../universe/world_impact.dart';
+import '../universe/use.dart';
+import 'json_serializer.dart';
+import 'modelz.dart';
+import 'resolved_ast_serialization.dart';
+import 'serialization.dart';
+import 'task.dart';
+
+class DeserializerSystemImpl extends DeserializerSystem {
+ final Compiler _compiler;
+ final Deserializer _deserializer;
+ final List<LibraryElement> deserializedLibraries = <LibraryElement>[];
+ final ResolutionImpactDeserializer _resolutionImpactDeserializer;
+ final ResolvedAstDeserializerPlugin _resolvedAstDeserializer;
+ final ImpactTransformer _impactTransformer;
+
+ factory DeserializerSystemImpl(Compiler compiler, Deserializer deserializer,
+ ImpactTransformer impactTransformer) {
+ List<DeserializerPlugin> plugins = <DeserializerPlugin>[];
+ DeserializerPlugin backendDeserializer =
+ compiler.backend.serialization.deserializer;
+ deserializer.plugins.add(backendDeserializer);
+ ResolutionImpactDeserializer resolutionImpactDeserializer =
+ new ResolutionImpactDeserializer(backendDeserializer);
+ deserializer.plugins.add(resolutionImpactDeserializer);
+ ResolvedAstDeserializerPlugin resolvedAstDeserializer =
+ new ResolvedAstDeserializerPlugin(
+ compiler.parsingContext, backendDeserializer);
+ deserializer.plugins.add(resolvedAstDeserializer);
+ return new DeserializerSystemImpl._(
+ compiler,
+ deserializer,
+ impactTransformer,
+ resolutionImpactDeserializer,
+ resolvedAstDeserializer);
+ }
+
+ DeserializerSystemImpl._(
+ this._compiler,
+ this._deserializer,
+ this._impactTransformer,
+ this._resolutionImpactDeserializer,
+ this._resolvedAstDeserializer);
+
+ @override
+ Future<LibraryElement> readLibrary(Uri resolvedUri) {
+ LibraryElement library = _deserializer.lookupLibrary(resolvedUri);
+ if (library != null) {
+ deserializedLibraries.add(library);
+ return Future.forEach(library.compilationUnits,
+ (CompilationUnitElement compilationUnit) {
+ ScriptZ script = compilationUnit.script;
+ return _compiler
+ .readScript(script.readableUri)
+ .then((Script newScript) {
+ script.file = newScript.file;
+ _resolvedAstDeserializer.sourceFiles[script.resourceUri] =
+ newScript.file;
+ });
+ }).then((_) => library);
+ }
+ return new Future<LibraryElement>.value(library);
+ }
+
+ // TODO(johnniwinther): Remove the need for this method.
+ @override
+ bool hasResolvedAst(ExecutableElement element) {
+ return getResolvedAst(element) != null;
+ }
+
+ @override
+ ResolvedAst getResolvedAst(ExecutableElement element) {
+ return _resolvedAstDeserializer.getResolvedAst(element);
+ }
+
+ @override
+ bool hasResolutionImpact(Element element) {
+ if (element.isConstructor &&
+ element.enclosingClass.isUnnamedMixinApplication) {
+ return true;
+ }
+ return _resolutionImpactDeserializer.impactMap.containsKey(element);
+ }
+
+ @override
+ ResolutionImpact getResolutionImpact(Element element) {
+ if (element.isConstructor &&
+ element.enclosingClass.isUnnamedMixinApplication) {
+ ClassElement superclass = element.enclosingClass.superclass;
+ ConstructorElement superclassConstructor =
+ superclass.lookupConstructor(element.name);
+ assert(invariant(element, superclassConstructor != null,
+ message: "Superclass constructor '${element.name}' called from "
+ "${element} not found in ${superclass}."));
+ // TODO(johnniwinther): Compute callStructure. Currently not used.
+ CallStructure callStructure;
+ return _resolutionImpactDeserializer.impactMap.putIfAbsent(element, () {
+ return new DeserializedResolutionImpact(staticUses: <StaticUse>[
+ new StaticUse.superConstructorInvoke(
+ superclassConstructor, callStructure)
+ ]);
+ });
+ }
+ return _resolutionImpactDeserializer.impactMap[element];
+ }
+
+ @override
+ WorldImpact computeWorldImpact(Element element) {
+ ResolutionImpact resolutionImpact = getResolutionImpact(element);
+ assert(invariant(element, resolutionImpact != null,
+ message: 'No impact found for $element (${element.library})'));
+ if (element is ExecutableElement) {
+ getResolvedAst(element);
+ }
+ return _impactTransformer.transformResolutionImpact(resolutionImpact);
+ }
+
+ @override
+ bool isDeserialized(Element element) {
+ return deserializedLibraries.contains(element.library);
+ }
+}
+
+const String WORLD_IMPACT_TAG = 'worldImpact';
+
+class ResolutionImpactSerializer extends SerializerPlugin {
+ final Resolution resolution;
+ final SerializerPlugin nativeDataSerializer;
+
+ ResolutionImpactSerializer(this.resolution, this.nativeDataSerializer);
+
+ @override
+ void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
+ if (resolution.hasBeenResolved(element)) {
+ ResolutionImpact impact = resolution.getResolutionImpact(element);
+ ObjectEncoder encoder = createEncoder(WORLD_IMPACT_TAG);
+ new ImpactSerializer(element, encoder, nativeDataSerializer)
+ .serialize(impact);
+ }
+ }
+}
+
+class ResolutionImpactDeserializer extends DeserializerPlugin {
+ Map<Element, ResolutionImpact> impactMap = <Element, ResolutionImpact>{};
+ final DeserializerPlugin nativeDataDeserializer;
+
+ ResolutionImpactDeserializer(this.nativeDataDeserializer);
+
+ @override
+ void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
+ ObjectDecoder decoder = getDecoder(WORLD_IMPACT_TAG);
+ if (decoder != null) {
+ impactMap[element] = ImpactDeserializer.deserializeImpact(
+ element, decoder, nativeDataDeserializer);
+ }
+ }
+}
+
+const String RESOLVED_AST_TAG = 'resolvedAst';
+
+class ResolvedAstSerializerPlugin extends SerializerPlugin {
+ final Resolution resolution;
+ final SerializerPlugin nativeDataSerializer;
+
+ ResolvedAstSerializerPlugin(this.resolution, this.nativeDataSerializer);
+
+ @override
+ void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
+ assert(invariant(element, element.isDeclaration,
+ message: "Element $element must be the declaration"));
+ if (element is MemberElement) {
+ assert(invariant(element, resolution.hasResolvedAst(element),
+ message: "Element $element must have a resolved ast"));
+ ResolvedAst resolvedAst = resolution.getResolvedAst(element);
+ ObjectEncoder objectEncoder = createEncoder(RESOLVED_AST_TAG);
+ new ResolvedAstSerializer(
+ objectEncoder, resolvedAst, nativeDataSerializer)
+ .serialize();
+ }
+ }
+}
+
+class ResolvedAstDeserializerPlugin extends DeserializerPlugin {
+ final ParsingContext parsingContext;
+ final DeserializerPlugin nativeDataDeserializer;
+ final Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{};
+
+ Map<MemberElement, ObjectDecoder> _decoderMap =
+ <MemberElement, ObjectDecoder>{};
+ Map<Uri, Token> beginTokenMap = <Uri, Token>{};
+
+ ResolvedAstDeserializerPlugin(
+ this.parsingContext, this.nativeDataDeserializer);
+
+ bool hasResolvedAst(ExecutableElement element) {
+ return getResolvedAst(element) != null;
+ }
+
+ ResolvedAst getResolvedAst(ExecutableElement element) {
+ if (element.hasResolvedAst) {
+ return element.resolvedAst;
+ }
+
+ ObjectDecoder decoder = _decoderMap[element.memberContext];
+ if (decoder != null) {
+ ResolvedAstDeserializer.deserialize(element.memberContext, decoder,
+ parsingContext, findToken, nativeDataDeserializer);
+ _decoderMap.remove(element);
+ assert(invariant(element, element.hasResolvedAst,
+ message: "ResolvedAst not computed for $element."));
+ return element.resolvedAst;
+ }
+ return null;
+ }
+
+ Token findToken(Uri uri, int offset) {
+ Token beginToken = beginTokenMap.putIfAbsent(uri, () {
+ SourceFile sourceFile = sourceFiles[uri];
+ if (sourceFile == null) {
+ throw 'No source file found for $uri in:\n '
+ '${sourceFiles.keys.join('\n ')}';
+ }
+ return new Scanner(sourceFile).tokenize();
+ });
+ return ResolvedAstDeserializer.findTokenInStream(beginToken, offset);
+ }
+
+ @override
+ void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
+ ObjectDecoder decoder = getDecoder(RESOLVED_AST_TAG);
+ if (decoder != null) {
+ _decoderMap[element] = decoder;
+ }
+ }
+}
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 6ca4636..f0cd00e 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -4,7 +4,7 @@
library dart2js.serialization.task;
-import 'dart:async' show Future;
+import 'dart:async' show EventSink, Future;
import '../common/resolution.dart' show ResolutionImpact, ResolutionWorkItem;
import '../common/tasks.dart' show CompilerTask;
import '../common/work.dart' show ItemCompilationContext;
@@ -12,6 +12,9 @@
import '../elements/elements.dart';
import '../enqueue.dart' show ResolutionEnqueuer;
import '../universe/world_impact.dart' show WorldImpact;
+import 'json_serializer.dart';
+import 'serialization.dart';
+import 'system.dart';
/// A deserializer that can load a library element by reading it's information
/// from a serialized form.
@@ -75,6 +78,48 @@
ResolvedAst getResolvedAst(ExecutableElement element) {
return deserializer != null ? deserializer.getResolvedAst(element) : null;
}
+
+ Serializer createSerializer(Iterable<LibraryElement> libraries) {
+ return measure(() {
+ assert(supportSerialization);
+
+ Serializer serializer = new Serializer();
+ SerializerPlugin backendSerializer =
+ compiler.backend.serialization.serializer;
+ serializer.plugins.add(backendSerializer);
+ serializer.plugins.add(new ResolutionImpactSerializer(
+ compiler.resolution, backendSerializer));
+ serializer.plugins.add(new ResolvedAstSerializerPlugin(
+ compiler.resolution, backendSerializer));
+
+ for (LibraryElement library in libraries) {
+ serializer.serialize(library);
+ }
+ return serializer;
+ });
+ }
+
+ void serializeToSink(
+ EventSink<String> sink, Iterable<LibraryElement> libraries) {
+ measure(() {
+ sink
+ ..add(createSerializer(libraries)
+ .toText(const JsonSerializationEncoder()))
+ ..close();
+ });
+ }
+
+ void deserializeFromText(String serializedData) {
+ measure(() {
+ Deserializer dataDeserializer = new Deserializer.fromText(
+ new DeserializationContext(),
+ serializedData,
+ const JsonSerializationDecoder());
+ dataDeserializer.plugins.add(compiler.backend.serialization.deserializer);
+ deserializer = new DeserializerSystemImpl(
+ compiler, dataDeserializer, compiler.backend.impactTransformer);
+ });
+ }
}
/// A [ResolutionWorkItem] for a deserialized element.
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index da15419..57bc9d3 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -238,9 +238,10 @@
typedef void MessageCallback(String message);
-class RandomAccessFileOutputProvider {
+class RandomAccessFileOutputProvider implements CompilerOutput {
final Uri out;
final Uri sourceMapOut;
+ final Uri resolutionOutput;
final MessageCallback onInfo;
final MessageCallback onFailure;
@@ -248,7 +249,7 @@
List<String> allOutputFiles = new List<String>();
RandomAccessFileOutputProvider(this.out, this.sourceMapOut,
- {this.onInfo, this.onFailure});
+ {this.onInfo, this.onFailure, this.resolutionOutput});
static Uri computePrecompiledUri(Uri out) {
String extension = 'precompiled.js';
@@ -262,6 +263,10 @@
}
EventSink<String> call(String name, String extension) {
+ return createEventSink(name, extension);
+ }
+
+ EventSink<String> createEventSink(String name, String extension) {
Uri uri;
bool isPrimaryOutput = false;
// TODO (johnniwinther, sigurdm): Make a better interface for
@@ -278,9 +283,14 @@
" \"Content-Security-Policy: script-src 'self'\"");
} else if (extension == 'js.map' || extension == 'dart.map') {
uri = sourceMapOut;
- } else if (extension == "info.json") {
+ } else if (extension == 'info.json') {
String outName = out.path.substring(out.path.lastIndexOf('/') + 1);
uri = out.resolve('$outName.$extension');
+ } else if (extension == 'data') {
+ if (resolutionOutput == null) {
+ onFailure('Serialization target unspecified.');
+ }
+ uri = resolutionOutput;
} else {
onFailure('Unknown extension: $extension');
}
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 50db1bf..f8c3ad0 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -327,8 +327,8 @@
void startFunction(AstElement element, ast.Node node) {
assert(invariant(element, element.isImplementation));
Compiler compiler = builder.compiler;
- closureData = compiler.closureToClassMapper.computeClosureToClassMapping(
- compiler.backend.frontend.getResolvedAst(element.declaration));
+ closureData = compiler.closureToClassMapper
+ .computeClosureToClassMapping(element.resolvedAst);
if (element is FunctionElement) {
FunctionElement functionElement = element;
@@ -512,7 +512,12 @@
// it could then have another name than the real parameter. And
// the other one would not know it is just a copy of the real
// parameter.
- if (local is ParameterElement) return builder.parameters[local];
+ if (local is ParameterElement) {
+ assert(invariant(local, builder.parameters.containsKey(local),
+ message: "No local value for parameter $local in "
+ "${builder.parameters}."));
+ return builder.parameters[local];
+ }
return builder.activationVariables.putIfAbsent(local, () {
JavaScriptBackend backend = builder.backend;
@@ -1378,7 +1383,7 @@
if (compiler.elementHasCompileTimeError(element)) return false;
FunctionElement function = element;
- ResolvedAst functionResolvedAst = backend.frontend.getResolvedAst(function);
+ ResolvedAst functionResolvedAst = function.resolvedAst;
bool insideLoop = loopNesting > 0 || graph.calledInLoop;
// Bail out early if the inlining decision is in the cache and we can't
@@ -1801,14 +1806,15 @@
}
});
if (bodyElement == null) {
- bodyElement = new ConstructorBodyElementX(constructor);
+ bodyElement =
+ new ConstructorBodyElementX(constructorResolvedAst, constructor);
classElement.addBackendMember(bodyElement);
if (constructor.isPatch) {
// Create origin body element for patched constructors.
ConstructorBodyElementX patch = bodyElement;
- ConstructorBodyElementX origin =
- new ConstructorBodyElementX(constructor.origin);
+ ConstructorBodyElementX origin = new ConstructorBodyElementX(
+ constructorResolvedAst, constructor.origin);
origin.applyPatch(patch);
classElement.origin.addBackendMember(bodyElement.origin);
}
@@ -1841,8 +1847,7 @@
void setupStateForInlining(
FunctionElement function, List<HInstruction> compiledArguments,
{InterfaceType instanceType}) {
- ResolvedAst resolvedAst =
- compiler.backend.frontend.getResolvedAst(function.declaration);
+ ResolvedAst resolvedAst = function.resolvedAst;
assert(resolvedAst != null);
localsHandler = new LocalsHandler(this, function, instanceType);
localsHandler.closureData =
@@ -2018,7 +2023,7 @@
// Build the initializers in the context of the new constructor.
ResolvedAst oldResolvedAst = resolvedAst;
- resolvedAst = backend.frontend.getResolvedAst(callee);
+ resolvedAst = callee.resolvedAst;
ClosureClassMap oldClosureData = localsHandler.closureData;
ClosureClassMap newClosureData = compiler.closureToClassMapper
.computeClosureToClassMapping(resolvedAst);
@@ -2059,7 +2064,7 @@
return localsHandler.readLocal(parameter);
}
- Element target = constructor.definingConstructor.implementation;
+ ConstructorElement target = constructor.definingConstructor.implementation;
bool match = !target.isMalformed &&
CallStructure.addForwardingElementArgumentsToList(
constructor,
@@ -2078,7 +2083,7 @@
reporter.internalError(
constructor, 'forwarding constructor call does not match');
}
- inlineSuperOrRedirect(backend.frontend.getResolvedAst(target), arguments,
+ inlineSuperOrRedirect(target.resolvedAst, arguments,
constructorResolvedAsts, fieldValues, constructor);
}
@@ -2125,12 +2130,8 @@
compiledArguments =
makeStaticArgumentList(callStructure, arguments, target);
});
- inlineSuperOrRedirect(
- backend.frontend.getResolvedAst(target.declaration),
- compiledArguments,
- constructorResolvedAsts,
- fieldValues,
- constructor);
+ inlineSuperOrRedirect(target.resolvedAst, compiledArguments,
+ constructorResolvedAsts, fieldValues, constructor);
} else {
// A field initializer.
ast.SendSet init = link.head;
@@ -2163,12 +2164,8 @@
target.implementation,
null,
handleConstantForOptionalParameter);
- inlineSuperOrRedirect(
- backend.frontend.getResolvedAst(target.declaration),
- arguments,
- constructorResolvedAsts,
- fieldValues,
- constructor);
+ inlineSuperOrRedirect(target.resolvedAst, arguments,
+ constructorResolvedAsts, fieldValues, constructor);
}
}
}
@@ -2186,7 +2183,7 @@
(ClassElement enclosingClass, FieldElement member) {
if (compiler.elementHasCompileTimeError(member)) return;
reporter.withCurrentElement(member, () {
- ResolvedAst fieldResolvedAst = backend.frontend.getResolvedAst(member);
+ ResolvedAst fieldResolvedAst = member.resolvedAst;
ast.Node node = fieldResolvedAst.node;
ast.Expression initializer = fieldResolvedAst.body;
if (initializer == null) {
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 8b9ab16..74cd875 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2205,7 +2205,7 @@
Element element = work.element;
if (element is FunctionElement && element.asyncMarker.isYielding) {
// `return <expr>;` is illegal in a sync* or async* function.
- // To have the the async-translator working, we avoid introducing
+ // To have the async-translator working, we avoid introducing
// `return` nodes.
pushStatement(new js.ExpressionStatement(value)
.withSourceInformation(sourceInformation));
diff --git a/pkg/compiler/lib/src/string_validator.dart b/pkg/compiler/lib/src/string_validator.dart
index 70a90b9..1965695 100644
--- a/pkg/compiler/lib/src/string_validator.dart
+++ b/pkg/compiler/lib/src/string_validator.dart
@@ -52,7 +52,7 @@
// Check if a multiline string starts with optional whitespace followed by
// a newline (CR, LF or CR+LF).
- // We also accept if the these characters are escaped by a backslash.
+ // We also accept if these characters are escaped by a backslash.
int newLineLength = 1;
while (true) {
// Due to string-interpolations we are not guaranteed to see the
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index bb025f0..a1fe55e 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -396,7 +396,7 @@
/// An && or || expression. The operator is internally represented as a boolean
/// [isAnd] to simplify rewriting of logical operators.
-/// Note the the result of && and || is one of the arguments, which might not be
+/// Note the result of && and || is one of the arguments, which might not be
/// boolean. 'ShortCircuitOperator' might have been a better name.
class LogicalOperator extends Expression {
Expression left;
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index f217263..bfa2100 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -460,7 +460,7 @@
if (isInstantiated(mixinApplication)) {
uses.add(mixinApplication);
} else if (mixinApplication.isNamedMixinApplication) {
- List<MixinApplicationElement> next = _mixinUses[mixinApplication];
+ Set<MixinApplicationElement> next = _mixinUses[mixinApplication];
if (next != null) {
next.forEach(addLiveUse);
}
@@ -511,8 +511,8 @@
final Set<TypedefElement> allTypedefs = new Set<TypedefElement>();
- final Map<ClassElement, List<MixinApplicationElement>> _mixinUses =
- new Map<ClassElement, List<MixinApplicationElement>>();
+ final Map<ClassElement, Set<MixinApplicationElement>> _mixinUses =
+ new Map<ClassElement, Set<MixinApplicationElement>>();
Map<ClassElement, List<MixinApplicationElement>> _liveMixinUses;
final Map<ClassElement, Set<ClassElement>> _typesImplementedBySubclasses =
@@ -605,6 +605,15 @@
ClassSet subtypeSet = _ensureClassSet(type.element);
subtypeSet.addSubtype(node);
}
+ if (cls.isMixinApplication) {
+ // TODO(johnniwinther): Store this in the [ClassSet].
+ MixinApplicationElement mixinApplication = cls;
+ if (mixinApplication.mixin != null) {
+ // If [mixinApplication] is malformed [mixin] is `null`.
+ registerMixinUse(mixinApplication, mixinApplication.mixin);
+ }
+ }
+
return classSet;
});
}
@@ -687,8 +696,8 @@
// TODO(johnniwinther): Add map restricted to live classes.
// We don't support patch classes as mixin.
assert(mixin.isDeclaration);
- List<MixinApplicationElement> users = _mixinUses.putIfAbsent(
- mixin, () => new List<MixinApplicationElement>());
+ Set<MixinApplicationElement> users =
+ _mixinUses.putIfAbsent(mixin, () => new Set<MixinApplicationElement>());
users.add(mixinApplication);
}
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index ad030b8..e6794ec 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -104,6 +104,11 @@
if (dart_target_arch != "") {
if (dart_target_arch == "arm") {
defines += [ "TARGET_ARCH_ARM" ]
+ if (target_os == "mac" || target_os == "ios") {
+ defines += [ "TARGET_ABI_IOS" ]
+ } else {
+ defines += [ "TARGET_ABI_EABI" ]
+ }
} else if (dart_target_arch == "arm64") {
defines += [ "TARGET_ARCH_ARM64" ]
} else if (dart_target_arch == "mips") {
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index bb3173f..a9b2331 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -115,28 +115,20 @@
}
-void FUNCTION_NAME(Directory_List)(Dart_NativeArguments args) {
- Dart_Handle path = Dart_GetNativeArgument(args, 0);
- Dart_Handle recursive = Dart_GetNativeArgument(args, 1);
- // Create the list to hold the directory listing here, and pass it to the
+void FUNCTION_NAME(Directory_FillWithDirectoryListing)(
+ Dart_NativeArguments args) {
+ // The list that we should fill.
+ Dart_Handle results = Dart_GetNativeArgument(args, 0);
+ Dart_Handle path = Dart_GetNativeArgument(args, 1);
+ Dart_Handle recursive = Dart_GetNativeArgument(args, 2);
+ Dart_Handle follow_links = Dart_GetNativeArgument(args, 3);
+ // Pass the list that should hold the directory listing to the
// SyncDirectoryListing object, which adds elements to it.
- Dart_Handle follow_links = Dart_GetNativeArgument(args, 2);
- // Create the list to hold the directory listing here, and pass it to the
- // SyncDirectoryListing object, which adds elements to it.
- Dart_Handle results =
- Dart_New(DartUtils::GetDartType(DartUtils::kCoreLibURL, "List"),
- Dart_Null(),
- 0,
- NULL);
- if (Dart_IsError(results)) {
- Dart_PropagateError(results);
- }
SyncDirectoryListing sync_listing(results,
DartUtils::GetStringValue(path),
DartUtils::GetBooleanValue(recursive),
DartUtils::GetBooleanValue(follow_links));
Directory::List(&sync_listing);
- Dart_SetReturnValue(args, results);
}
@@ -407,7 +399,10 @@
Dart_Handle dir_name_dart = DartUtils::NewString(dir_name);
Dart_Handle dir =
Dart_New(directory_type_, Dart_Null(), 1, &dir_name_dart);
- Dart_Invoke(results_, add_string_, 1, &dir);
+ Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &dir);
+ if (Dart_IsError(result)) {
+ Dart_PropagateError(result);
+ }
return true;
}
@@ -416,7 +411,10 @@
Dart_Handle link_name_dart = DartUtils::NewString(link_name);
Dart_Handle link =
Dart_New(link_type_, Dart_Null(), 1, &link_name_dart);
- Dart_Invoke(results_, add_string_, 1, &link);
+ Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &link);
+ if (Dart_IsError(result)) {
+ Dart_PropagateError(result);
+ }
return true;
}
@@ -425,7 +423,10 @@
Dart_Handle file_name_dart = DartUtils::NewString(file_name);
Dart_Handle file =
Dart_New(file_type_, Dart_Null(), 1, &file_name_dart);
- Dart_Invoke(results_, add_string_, 1, &file);
+ Dart_Handle result = Dart_Invoke(results_, add_string_, 1, &file);
+ if (Dart_IsError(result)) {
+ Dart_PropagateError(result);
+ }
return true;
}
diff --git a/runtime/bin/directory_patch.dart b/runtime/bin/directory_patch.dart
index f98a52e..9f4a265 100644
--- a/runtime/bin/directory_patch.dart
+++ b/runtime/bin/directory_patch.dart
@@ -13,8 +13,10 @@
native "Directory_Delete";
/* patch */ static _rename(String path, String newPath)
native "Directory_Rename";
- /* patch */ static List _list(String path, bool recursive, bool followLinks)
- native "Directory_List";
+ /* patch */ static void _fillWithDirectoryListing(
+ List<FileSystemEntity> list, String path, bool recursive,
+ bool followLinks)
+ native "Directory_FillWithDirectoryListing";
}
patch class _AsyncDirectoryListerOps {
diff --git a/runtime/bin/directory_unsupported.cc b/runtime/bin/directory_unsupported.cc
index 1b1abd2..c4398bb 100644
--- a/runtime/bin/directory_unsupported.cc
+++ b/runtime/bin/directory_unsupported.cc
@@ -59,7 +59,8 @@
}
-void FUNCTION_NAME(Directory_List)(Dart_NativeArguments args) {
+void FUNCTION_NAME(Directory_FillWithDirectoryListing)(
+ Dart_NativeArguments args) {
Dart_ThrowException(DartUtils::NewInternalError(
"Directory is not supported on this platform"));
}
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index dfd4985..f125bb8 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -126,6 +126,7 @@
last_error_(NOERROR),
flags_(0),
read_thread_id_(Thread::kInvalidThreadId),
+ read_thread_handle_(NULL),
read_thread_starting_(false),
read_thread_finished_(false),
monitor_(new Monitor()) {
@@ -188,8 +189,7 @@
void Handle::WaitForReadThreadFinished() {
- // Join the Reader thread if there is one.
- ThreadId to_join = Thread::kInvalidThreadId;
+ HANDLE to_join = NULL;
{
MonitorLocker ml(monitor_);
if (read_thread_id_ != Thread::kInvalidThreadId) {
@@ -197,12 +197,16 @@
ml.Wait();
}
read_thread_finished_ = false;
- to_join = read_thread_id_;
read_thread_id_ = Thread::kInvalidThreadId;
+ to_join = read_thread_handle_;
+ read_thread_handle_ = NULL;
}
}
- if (to_join != Thread::kInvalidThreadId) {
- Thread::Join(to_join);
+ if (to_join != NULL) {
+ // Join the read thread.
+ DWORD res = WaitForSingleObject(to_join, INFINITE);
+ CloseHandle(to_join);
+ ASSERT(res == WAIT_OBJECT_0);
}
}
@@ -250,10 +254,12 @@
ASSERT(read_thread_starting_);
ASSERT(read_thread_id_ == Thread::kInvalidThreadId);
read_thread_id_ = Thread::GetCurrentThreadId();
+ read_thread_handle_ = OpenThread(SYNCHRONIZE, false, read_thread_id_);
read_thread_starting_ = false;
ml.Notify();
}
+
void Handle::NotifyReadThreadFinished() {
MonitorLocker ml(monitor_);
ASSERT(!read_thread_finished_);
@@ -750,6 +756,7 @@
MonitorLocker ml(monitor_);
write_thread_running_ = true;
thread_id_ = Thread::GetCurrentThreadId();
+ thread_handle_ = OpenThread(SYNCHRONIZE, false, thread_id_);
// Notify we have started.
ml.Notify();
@@ -839,7 +846,10 @@
while (write_thread_exists_) {
ml.Wait(Monitor::kNoTimeout);
}
- Thread::Join(thread_id_);
+ // Join the thread.
+ DWORD res = WaitForSingleObject(thread_handle_, INFINITE);
+ CloseHandle(thread_handle_);
+ ASSERT(res == WAIT_OBJECT_0);
}
Handle::DoClose();
}
@@ -1366,6 +1376,7 @@
EventHandlerImplementation::EventHandlerImplementation() {
startup_monitor_ = new Monitor();
handler_thread_id_ = Thread::kInvalidThreadId;
+ handler_thread_handle_ = NULL;
completion_port_ =
CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1);
if (completion_port_ == NULL) {
@@ -1376,7 +1387,10 @@
EventHandlerImplementation::~EventHandlerImplementation() {
- Thread::Join(handler_thread_id_);
+ // Join the handler thread.
+ DWORD res = WaitForSingleObject(handler_thread_handle_, INFINITE);
+ CloseHandle(handler_thread_handle_);
+ ASSERT(res == WAIT_OBJECT_0);
delete startup_monitor_;
CloseHandle(completion_port_);
}
@@ -1415,6 +1429,8 @@
{
MonitorLocker ml(handler_impl->startup_monitor_);
handler_impl->handler_thread_id_ = Thread::GetCurrentThreadId();
+ handler_impl->handler_thread_handle_ =
+ OpenThread(SYNCHRONIZE, false, handler_impl->handler_thread_id_);
ml.Notify();
}
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index edb5c48..9daff93 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -263,6 +263,7 @@
DWORD last_error_;
ThreadId read_thread_id_;
+ HANDLE read_thread_handle_;
bool read_thread_starting_;
bool read_thread_finished_;
@@ -298,6 +299,7 @@
explicit StdHandle(HANDLE handle)
: FileHandle(handle),
thread_id_(Thread::kInvalidThreadId),
+ thread_handle_(NULL),
thread_wrote_(0),
write_thread_exists_(false),
write_thread_running_(false) {
@@ -312,6 +314,7 @@
private:
ThreadId thread_id_;
+ HANDLE thread_handle_;
intptr_t thread_wrote_;
bool write_thread_exists_;
bool write_thread_running_;
@@ -538,6 +541,7 @@
Monitor* startup_monitor_;
ThreadId handler_thread_id_;
+ HANDLE handler_thread_handle_;
TimeoutQueue timeout_queue_; // Time for next timeout.
bool shutdown_;
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 7783422..3e18248 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -154,7 +154,6 @@
memmove(name_chars, utf8_array, utf8_len);
name_chars[utf8_len] = '\0';
const char* value = NULL;
- printf("Looking for %s\n", name_chars);
if (environment != NULL) {
HashMap::Entry* entry = environment->Lookup(
GetHashmapKeyFromString(name_chars),
diff --git a/runtime/bin/hashmap_test.cc b/runtime/bin/hashmap_test.cc
index b51d1cf..3a74138 100644
--- a/runtime/bin/hashmap_test.cc
+++ b/runtime/bin/hashmap_test.cc
@@ -146,7 +146,7 @@
EXPECT(!set.Present(x));
x = x * factor + offset;
- // Verify the the expected values are still there.
+ // Verify the expected values are still there.
int y = start;
for (uint32_t j = 0; j < n; j++) {
if (j <= i) {
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 4c55b6f..609bbef 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -28,7 +28,7 @@
V(Directory_CreateTemp, 1) \
V(Directory_Delete, 2) \
V(Directory_Rename, 2) \
- V(Directory_List, 3) \
+ V(Directory_FillWithDirectoryListing, 4) \
V(Directory_GetAsyncDirectoryListerPointer, 1) \
V(Directory_SetAsyncDirectoryListerPointer, 2) \
V(EventHandler_SendData, 3) \
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index ab45b95..5ab2826 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -384,7 +384,7 @@
DEFAULT_VM_SERVICE_SERVER_PORT,
DEFAULT_VM_SERVICE_SERVER_IP)) {
Log::PrintErr("unrecognized --enable-vm-service option syntax. "
- "Use --enable-vm-service[:<port number>[/<IPv4 address>]]\n");
+ "Use --enable-vm-service[=<port number>[/<IPv4 address>]]\n");
return false;
}
@@ -402,10 +402,11 @@
DEFAULT_VM_SERVICE_SERVER_PORT,
DEFAULT_VM_SERVICE_SERVER_IP)) {
Log::PrintErr("unrecognized --observe option syntax. "
- "Use --observe[:<port number>[/<IPv4 address>]]\n");
+ "Use --observe[=<port number>[/<IPv4 address>]]\n");
return false;
}
+ // These options should also be documented in the help message.
vm_options->AddArgument("--pause-isolates-on-exit");
vm_options->AddArgument("--pause-isolates-on-unhandled-exceptions");
vm_options->AddArgument("--warn-on-pause-with-no-debugger");
@@ -855,11 +856,15 @@
"--packages=<path>\n"
" Where to find a package spec file.\n"
"--observe[=<port>[/<bind-address>]]\n"
-" The observe flag is used to run a program with a default set of options\n"
-" for debugging under Observatory. With the default options, Observatory\n"
-" will be available at http://127.0.0.1:8181/ (default port is 8181,\n"
-" default bind address is 127.0.0.1). Isolates will pause at exit and\n"
-" when they throw unhandled exceptions.\n"
+" The observe flag is a convenience flag used to run a program with a\n"
+" set of options which are often useful for debugging under Observatory.\n"
+" These options are currently:\n"
+" --enable-vm-service[=<port>[/<bind-address>]]\n"
+" --pause-isolates-on-exit\n"
+" --pause-isolates-on-unhandled-exceptions\n"
+" --warn-on-pause-with-no-debugger\n"
+" This set is subject to change.\n"
+" Please see these options (--help --verbose) for further documentation.\n"
"--version\n"
" Print the VM version.\n");
} else {
@@ -875,11 +880,15 @@
"--packages=<path>\n"
" Where to find a package spec file.\n"
"--observe[=<port>[/<bind-address>]]\n"
-" The observe flag is used to run a program with a default set of options\n"
-" for debugging under Observatory. With the default options, Observatory\n"
-" will be available at http://127.0.0.1:8181/ (default port is 8181,\n"
-" default bind address is 127.0.0.1). Isolates will pause at exit and\n"
-" when they throw unhandled exceptions.\n"
+" The observe flag is a convenience flag used to run a program with a\n"
+" set of options which are often useful for debugging under Observatory.\n"
+" These options are currently:\n"
+" --enable-vm-service[=<port>[/<bind-address>]]\n"
+" --pause-isolates-on-exit\n"
+" --pause-isolates-on-unhandled-exceptions\n"
+" --warn-on-pause-with-no-debugger\n"
+" This set is subject to change.\n"
+" Please see these options for further documentation.\n"
"--version\n"
" Print the VM version.\n"
"\n"
@@ -889,7 +898,7 @@
"--trace-loading\n"
" enables tracing of library and script loading\n"
"\n"
-"--enable-vm-service[:<port>[/<bind-address>]]\n"
+"--enable-vm-service[=<port>[/<bind-address>]]\n"
" enables the VM service and listens on specified port for connections\n"
" (default port number is 8181, default bind address is 127.0.0.1).\n"
"\n"
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 8025ab4..2d3ba73 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -46,6 +46,11 @@
String host, {InternetAddressType type: InternetAddressType.ANY}) {
return _NativeSocket.lookup(host, type: type);
}
+
+ /* patch */ static InternetAddress _cloneWithNewHost(
+ InternetAddress address, String host) {
+ return (address as _InternetAddress)._cloneWithNewHost(host);
+ }
}
patch class NetworkInterface {
@@ -1250,7 +1255,7 @@
if (fd != null) _getStdioHandle(native, fd);
var result = new _RawSocket(native);
if (fd != null) {
- var socketType = _StdIOUtils._socketType(result._socket);
+ var socketType = _StdIOUtils._nativeSocketType(result._socket);
result._isMacOSTerminalInput =
Platform.isMacOS && socketType == _STDIO_HANDLE_TYPE_TERMINAL;
}
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index 7e66009..cf02819 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -29,10 +29,16 @@
}
}
- static int _socketType(nativeSocket) {
+ static int _socketType(Socket socket) {
+ if (socket is _Socket) return _nativeSocketType(socket._nativeSocket);
+ return null;
+ }
+
+ static int _nativeSocketType(_NativeSocket nativeSocket) {
var result = _getSocketType(nativeSocket);
if (result is OSError) {
- throw new FileSystemException("Error retrieving socket type", "", result);
+ throw new FileSystemException(
+ "Error retrieving socket type", "", result);
}
return result;
}
diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h
index d95675d..979c77f 100644
--- a/runtime/bin/thread.h
+++ b/runtime/bin/thread.h
@@ -51,7 +51,6 @@
static void SetThreadLocal(ThreadLocalKey key, uword value);
static intptr_t GetMaxStackSize();
static ThreadId GetCurrentThreadId();
- static bool Join(ThreadId id);
static intptr_t ThreadIdToIntPtr(ThreadId id);
static bool Compare(ThreadId a, ThreadId b);
static void GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage);
diff --git a/runtime/bin/thread_android.cc b/runtime/bin/thread_android.cc
index 4f5c547..ce27ea3 100644
--- a/runtime/bin/thread_android.cc
+++ b/runtime/bin/thread_android.cc
@@ -155,11 +155,6 @@
}
-bool Thread::Join(ThreadId id) {
- return false;
-}
-
-
intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
ASSERT(sizeof(id) == sizeof(intptr_t));
return static_cast<intptr_t>(id);
diff --git a/runtime/bin/thread_linux.cc b/runtime/bin/thread_linux.cc
index 7a2a92a..6ea923e 100644
--- a/runtime/bin/thread_linux.cc
+++ b/runtime/bin/thread_linux.cc
@@ -156,11 +156,6 @@
}
-bool Thread::Join(ThreadId id) {
- return false;
-}
-
-
intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
ASSERT(sizeof(id) == sizeof(intptr_t));
return static_cast<intptr_t>(id);
diff --git a/runtime/bin/thread_macos.cc b/runtime/bin/thread_macos.cc
index 8286835..9477e8ab 100644
--- a/runtime/bin/thread_macos.cc
+++ b/runtime/bin/thread_macos.cc
@@ -148,11 +148,6 @@
}
-bool Thread::Join(ThreadId id) {
- return false;
-}
-
-
intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
ASSERT(sizeof(id) == sizeof(intptr_t));
return reinterpret_cast<intptr_t>(id);
diff --git a/runtime/bin/thread_win.cc b/runtime/bin/thread_win.cc
index db41196..92a9801 100644
--- a/runtime/bin/thread_win.cc
+++ b/runtime/bin/thread_win.cc
@@ -103,27 +103,6 @@
}
-bool Thread::Join(ThreadId id) {
- HANDLE handle = OpenThread(SYNCHRONIZE, false, id);
-
- // TODO(zra): OSThread::Start() closes the handle to the thread. Thus, by the
- // time we try to join the thread, its resources may have already been
- // reclaimed, and joining will fail. This can be avoided in a couple of ways.
- // First, GetCurrentThreadJoinId could call OpenThread and return a handle.
- // This is bad, because each of those handles would have to be closed.
- // Second OSThread could be refactored to no longer be AllStatic. Then the
- // handle could be cached in the object by the Start method.
- if (handle == NULL) {
- return false;
- }
-
- DWORD res = WaitForSingleObject(handle, INFINITE);
- CloseHandle(handle);
- ASSERT(res == WAIT_OBJECT_0);
- return true;
-}
-
-
intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
ASSERT(sizeof(id) <= sizeof(intptr_t));
return static_cast<intptr_t>(id);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index c7390e7..bc8c474 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2658,7 +2658,8 @@
typedef enum {
Dart_kImportTag = 0,
Dart_kSourceTag,
- Dart_kCanonicalizeUrl
+ Dart_kCanonicalizeUrl,
+ Dart_kScriptTag,
} Dart_LibraryTag;
/* TODO(turnidge): Document. */
diff --git a/runtime/lib/convert_patch.dart b/runtime/lib/convert_patch.dart
index 3c50f2a..d4acc18a 100644
--- a/runtime/lib/convert_patch.dart
+++ b/runtime/lib/convert_patch.dart
@@ -23,12 +23,14 @@
patch class Utf8Decoder {
/* patch */
- Converter<List<int>, dynamic> fuse(Converter<String, dynamic> next) {
+ Converter<List<int>, dynamic/*=T*/> fuse/*<T>*/(
+ Converter<String, dynamic/*=T*/> next) {
if (next is JsonDecoder) {
- return new _JsonUtf8Decoder(next._reviver, this._allowMalformed);
+ return new _JsonUtf8Decoder(next._reviver, this._allowMalformed)
+ as dynamic/*=Converter<List<int>, T>*/;
}
// TODO(lrn): Recognize a fused decoder where the next step is JsonDecoder.
- return super.fuse(next);
+ return super.fuse/*<T>*/(next);
}
// Allow intercepting of UTF-8 decoding when built-in lists are passed.
@@ -39,8 +41,7 @@
}
}
-class _JsonUtf8Decoder extends
- ChunkedConverter<List<int>, Object, List<int>, Object> {
+class _JsonUtf8Decoder extends Converter<List<int>, Object> {
final _Reviver _reviver;
final bool _allowMalformed;
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index e47e8ef..a2811ee 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -13,11 +13,11 @@
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/service.h"
+#include "vm/service_isolate.h"
namespace dart {
// Native implementations for the dart:developer library.
-
DEFINE_NATIVE_ENTRY(Developer_debugger, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Bool, when, arguments->NativeArgAt(0));
GET_NATIVE_ARGUMENT(String, msg, arguments->NativeArgAt(1));
@@ -26,7 +26,7 @@
return when.raw();
}
if (when.value()) {
- debugger->BreakHere(msg);
+ debugger->PauseDeveloper(msg);
}
return when.raw();
}
@@ -92,7 +92,13 @@
}
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Instance, handler, arguments->NativeArgAt(1));
- isolate->RegisterServiceExtensionHandler(name, handler);
+ // We don't allow service extensions to be registered for the
+ // service isolate. This can happen, for example, because the
+ // service isolate uses dart:io. If we decide that we want to start
+ // supporting this in the future, it will take some work.
+ if (!ServiceIsolate::IsServiceIsolateDescendant(isolate)) {
+ isolate->RegisterServiceExtensionHandler(name, handler);
+ }
return Object::null();
}
diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart
index 06cd324..cbf955d 100644
--- a/runtime/lib/double.dart
+++ b/runtime/lib/double.dart
@@ -63,28 +63,28 @@
}
bool _greaterThan(double other) native "Double_greaterThan";
bool operator >=(num other) {
- return (this == other) || (this > other);
+ return (this == other) || (this > other);
}
bool operator <=(num other) {
- return (this == other) || (this < other);
+ return (this == other) || (this < other);
}
double _addFromInteger(int other) {
- return new _Double.fromInteger(other) + this;
+ return new _Double.fromInteger(other)._add(this);
}
double _subFromInteger(int other) {
- return new _Double.fromInteger(other) - this;
+ return new _Double.fromInteger(other)._sub(this);
}
double _mulFromInteger(int other) {
- return new _Double.fromInteger(other) * this;
+ return new _Double.fromInteger(other)._mul(this);
}
int _truncDivFromInteger(int other) {
- return new _Double.fromInteger(other) ~/ this;
+ return new _Double.fromInteger(other)._trunc_div(this);
}
double _moduloFromInteger(int other) {
- return new _Double.fromInteger(other) % this;
+ return new _Double.fromInteger(other)._modulo(this);
}
double _remainderFromInteger(int other) {
- return new _Double.fromInteger(other).remainder(this);
+ return new _Double.fromInteger(other)._remainder(this);
}
bool _greaterThanFromInteger(int other)
native "Double_greaterThanFromInteger";
@@ -117,8 +117,12 @@
double truncateToDouble() native "Double_truncate";
num clamp(num lowerLimit, num upperLimit) {
- if (lowerLimit is! num) throw new ArgumentError(lowerLimit);
- if (upperLimit is! num) throw new ArgumentError(upperLimit);
+ if (lowerLimit is! num) {
+ throw new ArgumentError.value(lowerLimit, "lowerLimit", "not a number");
+ }
+ if (upperLimit is! num) {
+ throw new ArgumentError.value(upperLimit, "upperLimit", "not a number");
+ }
if (lowerLimit.compareTo(upperLimit) > 0) {
throw new ArgumentError(lowerLimit);
@@ -166,11 +170,12 @@
// See ECMAScript-262, 15.7.4.5 for details.
if (fractionDigits is! int) {
- throw new ArgumentError(fractionDigits);
+ throw new ArgumentError.value(
+ fractionDigits, "fractionDigits", "not an integer");
}
// Step 2.
if (fractionDigits < 0 || fractionDigits > 20) {
- throw new RangeError(fractionDigits);
+ throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
}
// Step 3.
@@ -200,10 +205,11 @@
// Step 7.
if (fractionDigits != null) {
if (fractionDigits is! int) {
- throw new ArgumentError(fractionDigits);
+ throw new ArgumentError.value(
+ fractionDigits, "fractionDigits", "not an integer");
}
if (fractionDigits < 0 || fractionDigits > 20) {
- throw new RangeError(fractionDigits);
+ throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
}
}
@@ -227,11 +233,12 @@
// at the fractionDigits. In Dart we are consistent with toStringAsFixed and
// look at the fractionDigits first.
- if (precision is! int) throw new ArgumentError(precision);
-
+ if (precision is! int) {
+ throw new ArgumentError.value(precision, "precision", "not an integer");
+ }
// Step 8.
if (precision < 1 || precision > 21) {
- throw new RangeError(precision);
+ throw new RangeError.range(precision, 1, 21, "precision");
}
if (isNaN) return "NaN";
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index a1aa3bd..351cbbf 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -206,14 +206,9 @@
}
}
- Scanner scanner(value, Symbols::Empty());
- const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
const String* int_string;
bool is_positive;
- if (Scanner::IsValidLiteral(tokens,
- Token::kINTEGER,
- &is_positive,
- &int_string)) {
+ if (Scanner::IsValidInteger(value, &is_positive, &int_string)) {
if (is_positive) {
return Integer::New(*int_string);
}
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index a103f23..a7722b0 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -174,22 +174,21 @@
num clamp(num lowerLimit, num upperLimit) {
if (lowerLimit is! num) {
- throw new ArgumentError.value(lowerLimit, "lowerLimit");
+ throw new ArgumentError.value(lowerLimit, "lowerLimit", "not a number");
}
if (upperLimit is! num) {
- throw new ArgumentError.value(upperLimit, "upperLimit");
+ throw new ArgumentError.value(upperLimit, "upperLimit", "not a number");
}
// Special case for integers.
- if (lowerLimit is int && upperLimit is int &&
- lowerLimit <= upperLimit) {
+ if (lowerLimit is int && upperLimit is int && lowerLimit <= upperLimit) {
if (this < lowerLimit) return lowerLimit;
if (this > upperLimit) return upperLimit;
return this;
}
// Generic case involving doubles, and invalid integer ranges.
if (lowerLimit.compareTo(upperLimit) > 0) {
- throw new RangeError.range(upperLimit, lowerLimit, null, "upperLimit");
+ throw new ArgumentError(lowerLimit);
}
if (lowerLimit.isNaN) return lowerLimit;
// Note that we don't need to care for -0.0 for the lower limit.
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
index d8bef45..b5b397d 100644
--- a/runtime/lib/timeline.cc
+++ b/runtime/lib/timeline.cc
@@ -15,6 +15,17 @@
// Native implementations for the dart:developer library.
+DEFINE_NATIVE_ENTRY(Timeline_isDartStreamEnabled, 0) {
+ if (!FLAG_support_timeline) {
+ return Bool::False().raw();
+ }
+ if (Timeline::GetDartStream()->enabled()) {
+ return Bool::True().raw();
+ }
+ return Bool::False().raw();
+}
+
+
DEFINE_NATIVE_ENTRY(Timeline_getIsolateNum, 0) {
return Integer::New(static_cast<int64_t>(isolate->main_port()), Heap::kOld);
}
diff --git a/runtime/lib/timeline.dart b/runtime/lib/timeline.dart
index b4ecd44..df43dec 100644
--- a/runtime/lib/timeline.dart
+++ b/runtime/lib/timeline.dart
@@ -4,6 +4,8 @@
import 'dart:_internal';
+patch bool _isDartStreamEnabled() native "Timeline_isDartStreamEnabled";
+
patch int _getTraceClock() native "Timeline_getTraceClock";
patch int _getThreadCpuClock() native "Timeline_getThreadCpuClock";
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index e2d5126..0ffe385 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -101,6 +101,10 @@
// Ignore for now.
break;
+ case ServiceEvent.kIsolateReload:
+ notifications.add(new Notification.fromEvent(event));
+ break;
+
case ServiceEvent.kIsolateExit:
case ServiceEvent.kResume:
removePauseEvents(event.isolate);
@@ -230,7 +234,7 @@
void handleException(e, st) {
if (e is ServerRpcException) {
if (e.code == ServerRpcException.kFeatureDisabled) return;
- if (e.code == ServerRpcException.kVMMustBePaused) return;
+ if (e.code == ServerRpcException.kIsolateMustBePaused) return;
if (e.code == ServerRpcException.kCannotAddBreakpoint) return;
Logger.root.fine('Dropping exception: ${e}\n${st}');
}
diff --git a/runtime/observatory/lib/src/app/view_model.dart b/runtime/observatory/lib/src/app/view_model.dart
index 6562e1f..76033eb 100644
--- a/runtime/observatory/lib/src/app/view_model.dart
+++ b/runtime/observatory/lib/src/app/view_model.dart
@@ -6,7 +6,7 @@
abstract class VirtualTreeRow {
// Number of ems each subtree is indented.
- static const subtreeIndent = 1.05;
+ static const subtreeIndent = 2.0;
static const redColor = '#F44336';
static const blueColor = '#3F51B5';
@@ -46,7 +46,7 @@
}
}
- Element makeColorBar() {
+ Element makeColorBar(int depth) {
var element = new SpanElement();
element.style.paddingLeft = '2px';
element.style.paddingRight = '2px';
@@ -78,7 +78,7 @@
return element;
}
- Element makeIndenter({colored: true}) {
+ Element makeIndenter(int depth, {colored: true}) {
SpanElement element = new SpanElement();
element.style.paddingLeft = '${subtreeIndent * depth}em';
element.style.flexBasis = '${subtreeIndent * depth}em';
@@ -93,7 +93,9 @@
return element;
}
- Element makeText(String text, {String toolTip, String flexBasis: '7em'}) {
+ Element makeText(String text, {String toolTip,
+ String flexBasis: '4.5em',
+ String cssClass}) {
SpanElement element = new SpanElement();
element.text = text;
if (toolTip != null) {
@@ -102,6 +104,9 @@
if (flexBasis != null) {
element.style.flexBasis = flexBasis;
}
+ if (cssClass != null) {
+ element.classes.add(cssClass);
+ }
return element;
}
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index c13cbb3..b1ac3fc 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -20,7 +20,7 @@
@observable ObservableList mostRetained;
SampleBufferControlElement sampleBufferControlElement;
StackTraceTreeConfigElement stackTraceTreeConfigElement;
- CpuProfileTreeElement cpuProfileTreeElement;
+ CpuProfileVirtualTreeElement cpuProfileTreeElement;
ClassViewElement.created() : super.created();
@@ -70,6 +70,7 @@
assert(stackTraceTreeConfigElement != null);
stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
stackTraceTreeConfigElement.show = false;
+ stackTraceTreeConfigElement.showFilter = false;
cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree');
assert(cpuProfileTreeElement != null);
cpuProfileTreeElement.profile = sampleBufferControlElement.profile;
@@ -94,7 +95,9 @@
cpuProfileTreeElement.render();
}
- onTreeConfigChange(String modeSelector, String directionSelector) {
+ onTreeConfigChange(String modeSelector,
+ String directionSelector,
+ String filter) {
ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
if (directionSelector != 'Up') {
direction = ProfileTreeDirection.Inclusive;
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index a40ef165d..086b96b 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -270,7 +270,7 @@
<br>
<div class="flex-row centered">
<div class="flex-item-90-percent outlined" style="margin: 16px; margin-left: 8px; margin-right: 8px">
- <cpu-profile-tree id="cpuProfileTree"></cpu-profile-tree>
+ <cpu-profile-virtual-tree id="cpuProfileTree"></cpu-profile-virtual-tree>
</div>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index e9d9805..305706a 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -448,6 +448,11 @@
onSampleBufferUpdate(profile);
return profile;
}
+ profileVM = isolate.vm.profileVM;
+ if (tagSelector == null) {
+ // Set default value.
+ tagSelector = profileVM ? 'UserVM' : 'None';
+ }
await _changeState(kFetchingState);
try {
var response;
@@ -516,7 +521,7 @@
Function onSampleBufferUpdate;
@observable bool showTagSelector = true;
-
+ @observable bool profileVM = false;
@observable String sampleCount = '';
@observable String refreshTime = '';
@observable String sampleRate = '';
@@ -524,7 +529,7 @@
@observable String timeSpan = '';
@observable String fetchTime = '';
@observable String loadTime = '';
- @observable String tagSelector = 'UserVM';
+ @observable String tagSelector;
@observable String state = kFetchingState;
@observable var exception;
@observable var stackTrace;
@@ -608,31 +613,66 @@
class FunctionCallTreeNodeRow extends VirtualTreeRow {
final CpuProfile profile;
final FunctionCallTreeNode node;
- final String selfPercent;
- final String totalPercent;
- final String percent;
+ String selfPercent;
+ String totalPercent;
+ String percent;
+
+ static const kHotThreshold = 0.05; // 5%.
+ static const kMediumThreshold = 0.02; // 2%.
+
+ double _percent(bool self) {
+ if (self) {
+ return node.profileFunction.normalizedExclusiveTicks;
+ } else {
+ return node.profileFunction.normalizedInclusiveTicks;
+ }
+ }
+
+ bool isHot(bool self) => _percent(self) > kHotThreshold;
+ bool isMedium(bool self) => _percent(self) > kMediumThreshold;
+
+ String rowClass(bool self) {
+ if (isHot(self)) {
+ return 'hotProfile';
+ } else if (isMedium(self)) {
+ return 'mediumProfile';
+ } else {
+ return 'coldProfile';
+ }
+ }
FunctionCallTreeNodeRow(VirtualTree tree,
int depth,
this.profile,
FunctionCallTreeNode node)
: node = node,
- selfPercent = Utils.formatPercentNormalized(node.profileFunction.normalizedExclusiveTicks),
- totalPercent = Utils.formatPercentNormalized(node.profileFunction.normalizedInclusiveTicks),
- percent = Utils.formatPercentNormalized(node.percentage),
super(tree, depth) {
+ if ((node.profileFunction.function.kind == FunctionKind.kTag) &&
+ (node.profileFunction.normalizedExclusiveTicks == 0) &&
+ (node.profileFunction.normalizedInclusiveTicks == 0)) {
+ selfPercent = '';
+ totalPercent = '';
+ } else {
+ selfPercent = Utils.formatPercentNormalized(
+ node.profileFunction.normalizedExclusiveTicks);
+ totalPercent = Utils.formatPercentNormalized(
+ node.profileFunction.normalizedInclusiveTicks);
+ }
+ percent = Utils.formatPercentNormalized(node.percentage);
}
void onRender(DivElement rowDiv) {
rowDiv.children.add(makeGap(ems:0.1));
rowDiv.children.add(
- makeText(totalPercent, toolTip: 'global % on stack'));
+ makeText(totalPercent,
+ toolTip: 'global % on stack'));
rowDiv.children.add(makeGap());
rowDiv.children.add(
- makeText(selfPercent, toolTip: 'global % executing'));
+ makeText(selfPercent,
+ toolTip: 'global % executing'));
rowDiv.children.add(makeGap());
- rowDiv.children.add(makeIndenter(colored: false));
- rowDiv.children.add(makeColorBar());
+ rowDiv.children.add(makeIndenter(depth, colored: false));
+ rowDiv.children.add(makeColorBar(depth));
rowDiv.children.add(makeGap(ems: 1.0));
rowDiv.children.add(makeExpander());
rowDiv.children.add(
@@ -661,31 +701,66 @@
class CodeCallTreeNodeRow extends VirtualTreeRow {
final CpuProfile profile;
final CodeCallTreeNode node;
- final String selfPercent;
- final String totalPercent;
- final String percent;
+ String selfPercent;
+ String totalPercent;
+ String percent;
+
+ static const kHotThreshold = 0.05; // 5%.
+ static const kMediumThreshold = 0.02; // 2%.
+
+ double _percent(bool self) {
+ if (self) {
+ return node.profileCode.normalizedExclusiveTicks;
+ } else {
+ return node.profileCode.normalizedInclusiveTicks;
+ }
+ }
+
+ bool isHot(bool self) => _percent(self) > kHotThreshold;
+ bool isMedium(bool self) => _percent(self) > kMediumThreshold;
+
+ String rowClass(bool self) {
+ if (isHot(self)) {
+ return 'hotProfile';
+ } else if (isMedium(self)) {
+ return 'mediumProfile';
+ } else {
+ return 'coldProfile';
+ }
+ }
CodeCallTreeNodeRow(VirtualTree tree,
int depth,
this.profile,
CodeCallTreeNode node)
: node = node,
- selfPercent = Utils.formatPercentNormalized(node.profileCode.normalizedExclusiveTicks),
- totalPercent = Utils.formatPercentNormalized(node.profileCode.normalizedInclusiveTicks),
- percent = Utils.formatPercentNormalized(node.percentage),
super(tree, depth) {
+ if ((node.profileCode.code.kind == CodeKind.Tag) &&
+ (node.profileCode.normalizedExclusiveTicks == 0) &&
+ (node.profileCode.normalizedInclusiveTicks == 0)) {
+ selfPercent = '';
+ totalPercent = '';
+ } else {
+ selfPercent = Utils.formatPercentNormalized(
+ node.profileCode.normalizedExclusiveTicks);
+ totalPercent = Utils.formatPercentNormalized(
+ node.profileCode.normalizedInclusiveTicks);
+ }
+ percent = Utils.formatPercentNormalized(node.percentage);
}
void onRender(DivElement rowDiv) {
rowDiv.children.add(makeGap(ems:0.1));
rowDiv.children.add(
- makeText(totalPercent, toolTip: 'global % on stack'));
+ makeText(totalPercent,
+ toolTip: 'global % on stack'));
rowDiv.children.add(makeGap());
rowDiv.children.add(
- makeText(selfPercent, toolTip: 'global % executing'));
+ makeText(selfPercent,
+ toolTip: 'global % executing'));
rowDiv.children.add(makeGap());
- rowDiv.children.add(makeIndenter(colored: false));
- rowDiv.children.add(makeColorBar());
+ rowDiv.children.add(makeIndenter(depth, colored: false));
+ rowDiv.children.add(makeColorBar(depth));
rowDiv.children.add(makeGap(ems: 1.0));
rowDiv.children.add(makeExpander());
rowDiv.children.add(
@@ -1283,7 +1358,7 @@
///
TableTree functionTree;
_updateFunctionTreeView() {
- cpuProfileTreeElement.functionFilter = (FunctionCallTreeNode node) {
+ cpuProfileTreeElement.filter = (FunctionCallTreeNode node) {
return node.profileFunction.function == focusedFunction;
};
cpuProfileTreeElement.render();
@@ -1304,7 +1379,7 @@
CpuProfile get profile => sampleBufferControlElement.profile;
SampleBufferControlElement sampleBufferControlElement;
StackTraceTreeConfigElement stackTraceTreeConfigElement;
- CpuProfileTreeElement cpuProfileTreeElement;
+ CpuProfileVirtualTreeElement cpuProfileTreeElement;
}
enum ProfileTreeDirection {
@@ -1344,9 +1419,11 @@
}
showChanged(oldValue) {
- var treeTable = shadowRoot.querySelector('#treeTable');
- assert(treeTable != null);
- treeTable.style.display = show ? 'table' : 'none';
+ if (show) {
+ virtualTree?.root?.style?.display = 'block';
+ } else {
+ virtualTree?.root?.style?.display = 'none';
+ }
}
void _updateView() {
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.html b/runtime/observatory/lib/src/elements/cpu_profile.html
index b5f2432..50db2db 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -91,13 +91,21 @@
<div class="memberItem">
<div class="memberName">Tag Order</div>
<div class="memberValue">
- <select value="{{tagSelector}}">
- <option value="UserVM">User > VM</option>
- <option value="UserOnly">User</option>
- <option value="VMUser">VM > User</option>
- <option value="VMOnly">VM</option>
- <option value="None">None</option>
- </select>
+ <template if="{{ profileVM }}">
+ <select value="{{tagSelector}}">
+ <option value="UserVM">User > VM</option>
+ <option value="UserOnly">User</option>
+ <option value="VMUser">VM > User</option>
+ <option value="VMOnly">VM</option>
+ <option value="None">None</option>
+ </select>
+ </template>
+ <template if="{{ !profileVM }}">
+ <select value="{{tagSelector}}">
+ <option value="UserOnly">User</option>
+ <option value="None">None</option>
+ </select>
+ </template>
</div>
</div>
</template>
@@ -254,6 +262,15 @@
height: 50%;
width: 100%;
}
+ .coldProfile {
+ background-color: #aea;
+ }
+ .mediumProfile {
+ background-color: #fe9;
+ }
+ .hotProfile {
+ background-color: #faa;
+ }
</style>
<div id="tree" class="full"></div>
</template>
@@ -468,7 +485,7 @@
<br>
<div class="flex-row centered">
<div class="flex-item-90-percent outlined" style="margin: 16px; margin-left: 8px; margin-right: 8px">
- <cpu-profile-tree id="cpuProfileTree"></cpu-profile-tree>
+ <cpu-profile-virtual-tree id="cpuProfileTree"></cpu-profile-virtual-tree>
</div>
</div>
</template>
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 81541ef..61a8989 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -902,6 +902,7 @@
IsolateCommand(Debugger debugger) : super(debugger, 'isolate', [
new IsolateListCommand(debugger),
new IsolateNameCommand(debugger),
+ new IsolateReloadCommand(debugger),
]) {
alias = 'i';
}
@@ -962,10 +963,10 @@
}
return new Future.value(result);
}
- String helpShort = 'Switch the current isolate';
+ String helpShort = 'Switch, list, rename, or reload isolates';
String helpLong =
- 'Switch, list, or rename isolates.\n'
+ 'Switch the current isolate.\n'
'\n'
'Syntax: isolate <number>\n'
' isolate <name>\n';
@@ -1042,14 +1043,36 @@
return debugger.isolate.setName(args[0]);
}
- String helpShort = 'Rename an isolate';
+ String helpShort = 'Rename the current isolate';
String helpLong =
- 'Rename an isolate.\n'
+ 'Rename the current isolate.\n'
'\n'
'Syntax: isolate name <name>\n';
}
+class IsolateReloadCommand extends DebuggerCommand {
+ IsolateReloadCommand(Debugger debugger) : super(debugger, 'reload', []);
+
+ Future run(List<String> args) async {
+ if (debugger.isolate == null) {
+ debugger.console.print('There is no current vm');
+ return;
+ }
+
+ await debugger.isolate.reloadSources();
+
+ debugger.console.print('Isolate reloading....');
+ }
+
+ String helpShort = 'Reload the sources for the current isolate.';
+
+ String helpLong =
+ 'Reload the sources for the current isolate.\n'
+ '\n'
+ 'Syntax: reload\n';
+}
+
class InfoCommand extends DebuggerCommand {
InfoCommand(Debugger debugger) : super(debugger, 'info', [
new InfoBreakpointsCommand(debugger),
@@ -1650,6 +1673,15 @@
console.print("Isolate ${iso.number} renamed to '${iso.name}'");
break;
+ case ServiceEvent.kIsolateReload:
+ var reloadError = event.reloadError;
+ if (reloadError != null) {
+ console.print('Isolate reload failed: ${event.reloadError}');
+ } else {
+ console.print('Isolate reloaded.');
+ }
+ break;
+
case ServiceEvent.kPauseStart:
case ServiceEvent.kPauseExit:
case ServiceEvent.kPauseBreakpoint:
diff --git a/runtime/observatory/lib/src/elements/instance_ref.dart b/runtime/observatory/lib/src/elements/instance_ref.dart
index 86727ae..cbf5eae 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.dart
+++ b/runtime/observatory/lib/src/elements/instance_ref.dart
@@ -4,6 +4,7 @@
library instance_ref_element;
+import 'dart:async';
import 'package:polymer/polymer.dart';
import 'package:observatory/service.dart';
import 'service_ref.dart';
@@ -58,4 +59,15 @@
String makeExpandKey(String key) {
return '${expandKey}/${key}';
}
+
+ Future showMore() async {
+ Instance instance = ref;
+ if (instance.isList) {
+ await instance.reload(count: instance.elements.length * 2);
+ } else if (instance.isMap) {
+ await instance.reload(count: instance.associations.length * 2);
+ } else if (instance.isTypedData) {
+ await instance.reload(count: instance.typedElements.length * 2);
+ }
+ }
}
diff --git a/runtime/observatory/lib/src/elements/instance_ref.html b/runtime/observatory/lib/src/elements/instance_ref.html
index 385727b..311732b 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.html
+++ b/runtime/observatory/lib/src/elements/instance_ref.html
@@ -88,7 +88,11 @@
</any-service-ref><br>
</template>
<template if="{{ ref.length != ref.elements.length }}">
- <div><em>{{ ref.length - ref.elements.length }} omitted elements</em></div>
+ <div>
+ <action-link callback="{{ showMore }}"
+ label="show next {{ref.elements.length}}">
+ </action-link>
+ </div>
</template>
</div>
</curly-block>
@@ -107,7 +111,9 @@
</any-service-ref><br>
</template>
<template if="{{ ref.length != ref.associations.length }}">
- <div><em>{{ ref.length - ref.associations.length }} omitted associations</em></div>
+ <action-link callback="{{ showMore }}"
+ label="show next {{ref.associations.length}}">
+ </action-link>
</template>
</div>
</curly-block>
@@ -122,7 +128,9 @@
{{ ref.typedElements[index].toString() }}<br>
</template>
<template if="{{ ref.length != ref.typedElements.length }}">
- <div><em>{{ ref.length - ref.typedElements.length }} omitted elements</em></div>
+ <action-link callback="{{ showMore }}"
+ label="show next {{ref.typedElements.length}}">
+ </action-link>
</template>
</div>
</curly-block>
diff --git a/runtime/observatory/lib/src/elements/isolate_view.dart b/runtime/observatory/lib/src/elements/isolate_view.dart
index 40738a1..c45acfa 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.dart
+++ b/runtime/observatory/lib/src/elements/isolate_view.dart
@@ -33,4 +33,8 @@
await isolate.topFrame.function.load();
}
}
+
+ Future reloadSources() {
+ return isolate.reloadSources();
+ }
}
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index a2fe66d..69c30ed 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -94,7 +94,16 @@
<div class="memberName">service protocol extensions</div>
<div class="memberValue">{{ isolate.extensionRPCs }}</div>
</div>
+
+ <div class="memberItem">
+ <div class="memberName">
+ <action-link callback="{{ reloadSources }}"
+ label="reload sources">
+ </action-link>
+ </div>
+ </div>
</div>
+
</div>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/nav_bar.html b/runtime/observatory/lib/src/elements/nav_bar.html
index 983f8af..c97b1d1 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.html
+++ b/runtime/observatory/lib/src/elements/nav_bar.html
@@ -298,6 +298,10 @@
animation: fadein 1s;
}
+ .wide-item {
+ width: 50vw;
+ }
+
@keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
@@ -328,6 +332,9 @@
a.boxclose:hover {
background: rgba(255,255,255,0.5);
}
+ .error {
+ white-space: pre;
+ }
</style>
<template if="{{ event != null }}">
<template if="{{ notifyOnPause && event.isPauseEvent }}">
@@ -372,6 +379,21 @@
<a class="boxclose" on-click="{{ closeItem }}">×</a>
</div>
</template>
+ <template if="{{ event.kind == 'IsolateReload' }}">
+ <div class="wide-item item">
+ Isolate reload
+ <template if="{{ event.reloadError != null }}">
+ failed:
+ <br>
+ <br>
+ <div class="indent error">{{ event.reloadError.message.toString() }}</div><br>
+ </template>
+ <template if="{{ event.reloadError == null }}">
+ succeeded
+ </template>
+ <a class="boxclose" on-click="{{ closeItem }}">×</a>
+ </div>
+ </template>
</template>
</template>
</polymer-element>
diff --git a/runtime/observatory/lib/src/elements/script_view.html b/runtime/observatory/lib/src/elements/script_view.html
index c65fa49..e5aec18 100644
--- a/runtime/observatory/lib/src/elements/script_view.html
+++ b/runtime/observatory/lib/src/elements/script_view.html
@@ -21,6 +21,13 @@
<object-common object="{{ script }}"></object-common>
<br>
+ <div class="memberList">
+ <div class="memberItem">
+ <div class="memberName">loaded at</div>
+ <div class="memberValue">{{ script.loadTime.toString() }}</div>
+ </div>
+ </div>
+
<hr>
<script-inset id="scriptInset" script="{{ script }}"
currentPos="{{ app.locationManager.internalArguments['pos'] | parseInt }}">
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index cc66f9a..28f3046 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -15,15 +15,14 @@
@CustomTag('timeline-page')
class TimelinePageElement extends ObservatoryElement {
- TimelinePageElement.created() : super.created();
+ TimelinePageElement.created() : super.created() {
+ }
attached() {
super.attached();
_resizeSubscription = window.onResize.listen((_) => _updateSize());
_updateSize();
- // Click refresh button.
- NavRefreshElement refreshButton = $['refresh'];
- refreshButton.buttonClick(null, null, null);
+ _setupInitialState();
}
detached() {
@@ -50,6 +49,131 @@
return null;
}
+ void _processFlags(ServiceMap response) {
+ // Grab the recorder name.
+ recorderName = response['recorderName'];
+ // Update the set of available streams.
+ _availableStreams.clear();
+ response['availableStreams'].forEach(
+ (String streamName) => _availableStreams.add(streamName));
+ // Update the set of recorded streams.
+ _recordedStreams.clear();
+ response['recordedStreams'].forEach(
+ (String streamName) => _recordedStreams.add(streamName));
+ }
+
+ Future _applyStreamChanges() {
+ return app.vm.invokeRpc('_setVMTimelineFlags', {
+ 'recordedStreams': '[${_recordedStreams.join(', ')}]',
+ });
+ }
+
+ HtmlElement _makeStreamToggle(String streamName) {
+ LabelElement label = new LabelElement();
+ label.style.paddingLeft = '8px';
+ SpanElement span = new SpanElement();
+ span.text = streamName;
+ InputElement checkbox = new InputElement();
+ checkbox.onChange.listen((_) {
+ if (checkbox.checked) {
+ _recordedStreams.add(streamName);
+ } else {
+ _recordedStreams.remove(streamName);
+ }
+ _applyStreamChanges();
+ _updateRecorderUI();
+ });
+ checkbox.type = 'checkbox';
+ checkbox.checked = _recordedStreams.contains(streamName);
+ label.children.add(checkbox);
+ label.children.add(span);
+ return label;
+ }
+
+ void _refreshRecorderUI() {
+ DivElement e = $['streamList'];
+ e.children.clear();
+
+ for (String streamName in _availableStreams) {
+ e.children.add(_makeStreamToggle(streamName));
+ }
+
+ streamPresetSelector = streamPresetFromRecordedStreams();
+ }
+
+ // Dart developers care about the following streams:
+ List<String> _dartPreset =
+ ['GC', 'Compiler', 'Dart'];
+
+ // VM developers care about the following streams:
+ List<String> _vmPreset =
+ ['GC', 'Compiler', 'Dart', 'Debugger', 'Embedder', 'Isolate', 'VM'];
+
+ String streamPresetFromRecordedStreams() {
+ if (_availableStreams.length == 0) {
+ return 'None';
+ }
+ if (_recordedStreams.length == 0) {
+ return 'None';
+ }
+ if (_recordedStreams.length == _availableStreams.length) {
+ return 'All';
+ }
+ if ((_vmPreset.length == _recordedStreams.length) &&
+ _recordedStreams.containsAll(_vmPreset)) {
+ return 'VM';
+ }
+ if ((_dartPreset.length == _recordedStreams.length) &&
+ _recordedStreams.containsAll(_dartPreset)) {
+ return 'Dart';
+ }
+ return 'Custom';
+ }
+
+ void _applyPreset() {
+ switch (streamPresetSelector) {
+ case 'None':
+ _recordedStreams.clear();
+ break;
+ case 'All':
+ _recordedStreams.clear();
+ _recordedStreams.addAll(_availableStreams);
+ break;
+ case 'VM':
+ _recordedStreams.clear();
+ _recordedStreams.addAll(_vmPreset);
+ break;
+ case 'Dart':
+ _recordedStreams.clear();
+ _recordedStreams.addAll(_dartPreset);
+ break;
+ case 'Custom':
+ return;
+ }
+ _applyStreamChanges();
+ _updateRecorderUI();
+ }
+
+ Future _updateRecorderUI() async {
+ // Grab the current timeline flags.
+ ServiceMap response = await app.vm.invokeRpc('_getVMTimelineFlags', {});
+ assert(response['type'] == 'TimelineFlags');
+ // Process them so we know available streams.
+ _processFlags(response);
+ // Refresh the UI.
+ _refreshRecorderUI();
+ }
+
+ Future _setupInitialState() async {
+ await _updateRecorderUI();
+ SelectElement e = $['selectPreset'];
+ e.onChange.listen((_) {
+ _applyPreset();
+ });
+ // Finally, trigger a reload so we start with the latest timeline.
+ await refresh();
+ }
+
Future refresh() async {
await app.vm.reload();
await app.vm.reloadIsolates();
@@ -61,18 +185,6 @@
return postMessage('clear');
}
- Future recordOn() async {
- return app.vm.invokeRpc('_setVMTimelineFlags', {
- 'recordedStreams': ['all'],
- });
- }
-
- Future recordOff() async {
- return app.vm.invokeRpc('_setVMTimelineFlags', {
- 'recordedStreams': [],
- });
- }
-
Future saveTimeline() async {
return postMessage('save');
}
@@ -93,4 +205,8 @@
StreamSubscription _resizeSubscription;
+ @observable String recorderName;
+ @observable String streamPresetSelector = 'None';
+ final Set<String> _availableStreams = new Set<String>();
+ final Set<String> _recordedStreams = new Set<String>();
}
diff --git a/runtime/observatory/lib/src/elements/timeline_page.html b/runtime/observatory/lib/src/elements/timeline_page.html
index d142088..433c242 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.html
+++ b/runtime/observatory/lib/src/elements/timeline_page.html
@@ -5,19 +5,41 @@
<polymer-element name="timeline-page" extends="observatory-element">
<template>
<link rel="stylesheet" href="css/shared.css">
- <style>
- </style>
<nav-bar>
<top-nav-menu></top-nav-menu>
<vm-nav-menu vm="{{ app.vm }}"></vm-nav-menu>
<nav-menu link="{{ makeLink('/timeline') }}" anchor="timeline" last="{{ true }}"></nav-menu>
- <nav-refresh id="refresh" callback="{{ refresh }}"></nav-refresh>
+ <nav-refresh id="refresh" callback="{{ refresh }}" label="Refresh"></nav-refresh>
<nav-refresh callback="{{ clear }}" label="Clear"></nav-refresh>
- <nav-refresh callback="{{ recordOn }}" label="Start recording"></nav-refresh>
- <nav-refresh callback="{{ recordOff }}" label="Stop recording"></nav-refresh>
<nav-refresh callback="{{ saveTimeline }}" label="Save"></nav-refresh>
<nav-refresh callback="{{ loadTimeline }}" label="Load"></nav-refresh>
</nav-bar>
+ <div id="control" class="content-centered-big">
+ <h2>Timeline settings</h2>
+ <div class="memberList">
+ <div class="memberItem">
+ <div class="memberName">Recorder:</div>
+ <div class="memberValue">{{ recorderName }}</div>
+ </div>
+ <div class="memberItem">
+ <div class="memberName">Recorded Streams Profile:</div>
+ <div class="memberValue">
+ <select id="selectPreset" value="{{ streamPresetSelector }}">
+ <option value="None">None</option>
+ <option value="Dart">Dart Developer</option>
+ <option value="VM">VM Developer</option>
+ <option value="All">All</option>
+ <option value="Custom">Custom</option>
+ </select>
+ </div>
+ </div>
+ <div class="memberItem">
+ <div class="memberName">Recorded Streams:</div>
+ <div id="streamList" class="memberValue"></div>
+ </div>
+ </div>
+ <br>
+ </div>
<iframe id="root" frameborder="0" src="../../../../timeline.html">
</iframe>
</template>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 0797007..b0be812 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -37,11 +37,12 @@
static const kInvalidParams = -32602;
static const kInternalError = -32603;
static const kFeatureDisabled = 100;
- static const kVMMustBePaused = 101;
static const kCannotAddBreakpoint = 102;
static const kStreamAlreadySubscribed = 103;
static const kStreamNotSubscribed = 104;
static const kIsolateMustBeRunnable = 105;
+ static const kIsolateMustBePaused = 106;
+ static const kIsolateIsReloading = 107;
int code;
Map data;
@@ -287,17 +288,17 @@
Future<ServiceObject> _inProgressReload;
- Future<ObservableMap> _fetchDirect() {
+ Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) {
Map params = {
'objectId': id,
- 'count': kDefaultFieldLimit,
+ 'count': count,
};
return isolate.invokeRpcNoUpgrade('getObject', params);
}
/// Reload [this]. Returns a future which completes to [this] or
/// an exception.
- Future<ServiceObject> reload() {
+ Future<ServiceObject> reload({int count: kDefaultFieldLimit}) {
// TODO(turnidge): Checking for a null id should be part of the
// "immmutable" check.
bool hasId = (id != null) && (id != '');
@@ -312,7 +313,7 @@
if (_inProgressReload == null) {
var completer = new Completer<ServiceObject>();
_inProgressReload = completer.future;
- _fetchDirect().then((ObservableMap map) {
+ _fetchDirect(count: count).then((ObservableMap map) {
var mapType = _stripRef(map['type']);
if (mapType == 'Sentinel') {
// An object may have been collected, etc.
@@ -622,6 +623,7 @@
@observable bool assertsEnabled = false;
@observable bool typeChecksEnabled = false;
@observable int pid = 0;
+ @observable bool profileVM = false;
@observable DateTime startTime;
@observable DateTime refreshTime;
@observable Duration get upTime {
@@ -805,7 +807,7 @@
return invokeRpc('_restartVM', {});
}
- Future<ObservableMap> _fetchDirect() async {
+ Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) async {
if (!loaded) {
// The vm service relies on these events to keep the VM and
// Isolate types up to date.
@@ -897,6 +899,7 @@
refreshTime = new DateTime.now();
notifyPropertyChange(#upTime, 0, 1);
pid = map['pid'];
+ profileVM = map['_profilerMode'] == 'VM';
assertsEnabled = map['_assertsEnabled'];
typeChecksEnabled = map['_typeChecksEnabled'];
_removeDeadIsolates(map['isolates']);
@@ -1147,6 +1150,7 @@
@observable bool loading = true;
@observable bool runnable = false;
@observable bool ioEnabled = false;
+ @observable bool reloading = false;
final List<String> extensionRPCs = new List<String>();
@@ -1190,6 +1194,22 @@
return invokeRpc('getSourceReport', params);
}
+ Future<ServiceMap> reloadSources() {
+ return invokeRpc('_reloadSources', {}).then((_) {
+ reloading = true;
+ });
+ }
+
+ void _handleIsolateReloadEvent(ServiceEvent event) {
+ reloading = false;
+ if (event.reloadError != null) {
+ // Failure.
+ print('Reload failed: ${event.reloadError}');
+ } else {
+ _cache.clear();
+ }
+ }
+
/// Fetches and builds the class hierarchy for this isolate. Returns the
/// Object class object.
Future<Class> getClassHierarchy() {
@@ -1286,24 +1306,26 @@
});
}
- Future<ServiceObject> getObject(String objectId, {bool reload: true}) {
+ Future<ServiceObject> getObject(String objectId,
+ {bool reload: true,
+ int count: kDefaultFieldLimit}) {
assert(objectId != null && objectId != '');
var obj = _cache[objectId];
if (obj != null) {
if (reload) {
- return obj.reload();
+ return obj.reload(count: count);
}
// Returned cached object.
return new Future.value(obj);
}
Map params = {
'objectId': objectId,
- 'count': kDefaultFieldLimit,
+ 'count': count,
};
return isolate.invokeRpc('getObject', params);
}
- Future<ObservableMap> _fetchDirect() {
+ Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) async {
return invokeRpcNoUpgrade('getIsolate', {});
}
@@ -1495,7 +1517,9 @@
case ServiceEvent.kInspect:
// Handled elsewhere.
break;
-
+ case ServiceEvent.kIsolateReload:
+ _handleIsolateReloadEvent(event);
+ break;
case ServiceEvent.kBreakpointAdded:
_addBreakpoint(event.breakpoint);
break;
@@ -1819,6 +1843,7 @@
static const kIsolateRunnable = 'IsolateRunnable';
static const kIsolateExit = 'IsolateExit';
static const kIsolateUpdate = 'IsolateUpdate';
+ static const kIsolateReload = 'IsolateReload';
static const kServiceExtensionAdded = 'ServiceExtensionAdded';
static const kPauseStart = 'PauseStart';
static const kPauseExit = 'PauseExit';
@@ -1850,6 +1875,7 @@
@observable Frame topFrame;
@observable String extensionRPC;
@observable Instance exception;
+ @observable Instance reloadError;
@observable bool atAsyncSuspension;
@observable ServiceObject inspectee;
@observable ByteData data;
@@ -1921,6 +1947,7 @@
if (map['count'] != null) {
count = map['count'];
}
+ reloadError = map['reloadError'];
if (map['_debuggerSettings'] != null &&
map['_debuggerSettings']['_exceptions'] != null) {
exceptions = map['_debuggerSettings']['_exceptions'];
@@ -2853,6 +2880,7 @@
final lines = new ObservableList<ScriptLine>();
@observable String uri;
@observable String kind;
+ @observable DateTime loadTime;
@observable int firstTokenPos;
@observable int lastTokenPos;
@observable int lineOffset;
@@ -2955,6 +2983,8 @@
return;
}
_loaded = true;
+ int loadTimeMillis = map['_loadTime'];
+ loadTime = new DateTime.fromMillisecondsSinceEpoch(loadTimeMillis);
lineOffset = map['lineOffset'];
columnOffset = map['columnOffset'];
_parseTokenPosTable(map['tokenPosTable']);
@@ -3558,11 +3588,11 @@
/// Reload [this]. Returns a future which completes to [this] or an
/// exception.
- Future<ServiceObject> reload() {
+ Future<ServiceObject> reload({int count: kDefaultFieldLimit}) {
assert(kind != null);
if (isDartCode) {
// We only reload Dart code.
- return super.reload();
+ return super.reload(count: count);
}
return new Future.value(this);
}
@@ -3843,7 +3873,7 @@
_removeOld();
}
- Future<ObservableMap> _fetchDirect() {
+ Future<ObservableMap> _fetchDirect({int count: kDefaultFieldLimit}) {
assert(owner is Isolate);
return isolate.invokeRpcNoUpgrade('_getIsolateMetric', { 'metricId': id });
}
diff --git a/runtime/observatory/tests/service/get_allocation_samples_test.dart b/runtime/observatory/tests/service/get_allocation_samples_test.dart
index 87615c9..85626ee 100644
--- a/runtime/observatory/tests/service/get_allocation_samples_test.dart
+++ b/runtime/observatory/tests/service/get_allocation_samples_test.dart
@@ -67,7 +67,7 @@
var tree = cpuProfile.loadCodeTree('exclusive');
var node = tree.root;
var expected =
- ['Root', 'test', 'test', '_Closure.call'];
+ ['Root', 'DRT_AllocateObject', 'test', 'test', '_Closure.call'];
for (var i = 0; i < expected.length; i++) {
expect(node.profileCode.code.name, equals(expected[i]));
// Depth first traversal.
diff --git a/runtime/observatory/web/timeline.html b/runtime/observatory/web/timeline.html
index ebcc46e..dba2b26 100644
--- a/runtime/observatory/web/timeline.html
+++ b/runtime/observatory/web/timeline.html
@@ -3,8 +3,9 @@
<head>
<meta charset="utf-8">
<title>Dart VM Observatory Timeline</title>
- <script src="timeline.js"></script>
+ <script src="timeline_message_handler.js"></script>
<link rel="import" href="third_party/trace_viewer_full.html">
+ <script src="timeline.js"></script>
<style>
html, body {
box-sizing: border-box;
diff --git a/runtime/observatory/web/timeline.js b/runtime/observatory/web/timeline.js
index dea5542..56de01d 100644
--- a/runtime/observatory/web/timeline.js
+++ b/runtime/observatory/web/timeline.js
@@ -2,17 +2,7 @@
// 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.
-// Used to delay the initial timeline load until the timeline has finished
-// loading.
-timeline_loaded = false;
-timeline_vm_address = undefined;
-timeline_isolates = undefined;
-
-function registerForMessages() {
- window.addEventListener("message", onMessage, false);
-}
-
-registerForMessages();
+// See also timeline_message_handler.js.
function onModelLoaded() {
viewer.globalMode = true;
@@ -38,8 +28,6 @@
p.then(onModelLoaded, onImportFail);
}
-
-
function fetchUri(uri, onLoad, onError) {
var xhr = new XMLHttpRequest();
xhr.open('GET', uri, true);
@@ -50,22 +38,37 @@
console.log('GET ' + uri);
}
-
var traceObject;
var pendingRequests;
+var loadingOverlay;
+
+function showLoadingOverlay(msg) {
+ if (!loadingOverlay) {
+ loadingOverlay = new tr.ui.b.Overlay();
+ }
+ loadingOverlay.textContent = msg;
+ loadingOverlay.title = 'Loading...';
+ loadingOverlay.visible = true;
+}
+
+function hideLoadingOverlay() {
+ if (!loadingOverlay) {
+ return;
+ }
+ loadingOverlay.visible = false;
+ loadingOverlay = undefined;
+}
function gotReponse() {
pendingRequests--;
if (pendingRequests == 0) {
console.log("Got all timeline parts");
updateTimeline(traceObject);
+ hideLoadingOverlay();
}
}
-function fetchTimelineOnLoad(event) {
- var xhr = event.target;
- var response = JSON.parse(xhr.responseText);
-
+function processTimelineResponse(response) {
if (response.error) {
// Maybe profiling is disabled.
console.log("ERROR " + response.error.message);
@@ -86,20 +89,46 @@
gotReponse();
}
+function fetchTimelineOnLoad(event) {
+ var xhr = event.target;
+ var response = JSON.parse(xhr.responseText);
+ processTimelineResponse(response);
+}
+
function fetchTimelineOnError(event) {
var xhr = event.target;
console.log(xhr.statusText);
gotReponse();
}
+function fetchCPUProfile(vmAddress, isolateIds, timeOrigin, timeExtent) {
+ showLoadingOverlay('Fetching CPU profile(s) from Dart VM');
+ var parser = document.createElement('a');
+ parser.href = vmAddress;
+ pendingRequests += isolateIds.length;
+ for (var i = 0; i < isolateIds.length; i++) {
+ var isolateId = isolateIds[i];
+ var requestUri = 'http://' +
+ parser.hostname +
+ ':' +
+ parser.port +
+ '/_getCpuProfileTimeline?tags=VMUser&isolateId=' +
+ isolateId +
+ '&timeOriginMicros=' + timeOrigin +
+ '&timeExtentMicros=' + timeExtent;
+ fetchUri(requestUri, fetchTimelineOnLoad, fetchTimelineOnError);
+ }
+}
+
function fetchTimeline(vmAddress, isolateIds) {
// Reset combined timeline.
traceObject = {
'stackFrames': {},
'traceEvents': []
};
- pendingRequests = 1 + isolateIds.length;
+ pendingRequests = 1;
+ showLoadingOverlay('Fetching timeline from Dart VM');
var parser = document.createElement('a');
parser.href = vmAddress;
var requestUri = 'http://' +
@@ -107,18 +136,22 @@
':' +
parser.port +
'/_getVMTimeline';
- fetchUri(requestUri, fetchTimelineOnLoad, fetchTimelineOnError);
-
- for (var i = 0; i < isolateIds.length; i++) {
- var isolateId = isolateIds[i];
- var requestUri = 'http://' +
- parser.hostname +
- ':' +
- parser.port +
- '/_getCpuProfileTimeline?tags=VMUser&isolateId=' +
- isolateId;
- fetchUri(requestUri, fetchTimelineOnLoad, fetchTimelineOnError);
- }
+ fetchUri(requestUri, function(event) {
+ // Grab the response.
+ var xhr = event.target;
+ var response = JSON.parse(xhr.responseText);
+ // Extract the time origin and extent.
+ var timeOrigin = response['result']['timeOriginMicros'];
+ var timeExtent = response['result']['timeExtentMicros'];
+ console.assert(Number.isInteger(timeOrigin), timeOrigin);
+ console.assert(Number.isInteger(timeExtent), timeExtent);
+ console.log(timeOrigin);
+ console.log(timeExtent);
+ // fetchCPUProfile.
+ fetchCPUProfile(vmAddress, isolateIds, timeOrigin, timeExtent);
+ // This must happen after 'fetchCPUProfile';
+ processTimelineResponse(response);
+ }, fetchTimelineOnError);
}
function saveTimeline() {
@@ -200,35 +233,7 @@
inputElement.click();
}
-function onMessage(event) {
- var request = JSON.parse(event.data);
- var method = request['method'];
- var params = request['params'];
- switch (method) {
- case 'refresh':
- if (!timeline_loaded) {
- timeline_vm_address = params['vmAddress'];
- timeline_isolates = params['isolateIds'];
- console.log('Delaying timeline refresh until loaded.');
- } else {
- fetchTimeline(params['vmAddress'], params['isolateIds']);
- }
- break;
- case 'clear':
- clearTimeline();
- break;
- case 'save':
- saveTimeline();
- break;
- case 'load':
- loadTimeline();
- break;
- default:
- console.log('Unknown method:' + method + '.');
- }
-}
-
-document.addEventListener('DOMContentLoaded', function() {
+window.addEventListener('DOMContentLoaded', function() {
var container = document.createElement('track-view-container');
container.id = 'track_view_container';
viewer = document.createElement('tr-ui-timeline-view');
@@ -238,6 +243,7 @@
viewer.globalMode = true;
document.body.appendChild(viewer);
timeline_loaded = true;
+ console.log('DOMContentLoaded');
if (timeline_vm_address != undefined) {
console.log('Triggering delayed timeline refresh.');
fetchTimeline(timeline_vm_address, timeline_isolates);
@@ -246,4 +252,4 @@
}
});
-console.log('loaded');
+console.log('timeline.js loaded');
diff --git a/runtime/observatory/web/timeline_message_handler.js b/runtime/observatory/web/timeline_message_handler.js
new file mode 100644
index 0000000..7ae238d
--- /dev/null
+++ b/runtime/observatory/web/timeline_message_handler.js
@@ -0,0 +1,49 @@
+// Copyright (c) 2016, 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.
+
+// This file is loaded before the about:tracing code is loaded so that we have
+// an event listener registered early.
+
+// Used to delay the initial timeline load until the timeline has finished
+// loading.
+timeline_loaded = false;
+timeline_vm_address = undefined;
+timeline_isolates = undefined;
+
+function registerForMessages() {
+ window.addEventListener("message", onMessage, false);
+}
+
+registerForMessages();
+
+function onMessage(event) {
+ var request = JSON.parse(event.data);
+ var method = request['method'];
+ var params = request['params'];
+ console.log('method: ' + method)
+ switch (method) {
+ case 'refresh':
+ if (!timeline_loaded) {
+ timeline_vm_address = params['vmAddress'];
+ timeline_isolates = params['isolateIds'];
+ console.log('Delaying timeline refresh until loaded.');
+ } else {
+ fetchTimeline(params['vmAddress'], params['isolateIds']);
+ }
+ break;
+ case 'clear':
+ clearTimeline();
+ break;
+ case 'save':
+ saveTimeline();
+ break;
+ case 'load':
+ loadTimeline();
+ break;
+ default:
+ console.log('Unknown method:' + method + '.');
+ }
+}
+
+console.log('message handler registered');
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index a0dfdd0..e3d1a34 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -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.
-#ifndef RUNTIME_PLATFORM_GLOBALS_H_
-#define RUNTIME_PLATFORM_GLOBALS_H_
+#ifndef PLATFORM_GLOBALS_H_
+#define PLATFORM_GLOBALS_H_
// __STDC_FORMAT_MACROS has to be defined before including <inttypes.h> to
// enable platform independent printf format specifiers.
@@ -359,6 +359,25 @@
#error Unknown architecture.
#endif
+// Disable background threads by default on armv5te. The relevant
+// implementations are uniprocessors.
+#if !defined(TARGET_ARCH_ARM_5TE)
+#define ARCH_IS_MULTI_CORE 1
+#endif
+
+
+#if defined(TARGET_ARCH_ARM)
+#if defined(TARGET_ABI_IOS) && defined(TARGET_ABI_EABI)
+#error Both TARGET_ABI_IOS and TARGET_ABI_EABI defined.
+#elif !defined(TARGET_ABI_IOS) && !defined(TARGET_ABI_EABI)
+#if defined(TARGET_OS_MAC)
+#define TARGET_ABI_IOS 1
+#else
+#define TARGET_ABI_EABI 1
+#endif
+#endif
+#endif // TARGET_ARCH_ARM
+
// Short form printf format specifiers
#define Pd PRIdPTR
@@ -678,4 +697,4 @@
} // namespace dart
-#endif // RUNTIME_PLATFORM_GLOBALS_H_
+#endif // PLATFORM_GLOBALS_H_
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 025a0f4..0fa725f 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -2,6 +2,13 @@
# 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.
+cc/IsolateReload_PendingUnqualifiedCall_InstanceToStatic: Fail, Crash
+cc/IsolateReload_PendingUnqualifiedCall_StaticToInstance: Fail, Crash
+cc/IsolateReload_PendingConstructorCall_AbstractToConcrete: Fail, Crash
+cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: Fail, Crash
+cc/IsolateReload_PendingStaticCall_DefinedToNSM: Fail, Crash
+cc/IsolateReload_PendingStaticCall_NSMToDefined: Fail, Crash
+
# These tests are expected to crash on all platforms.
cc/ArrayNew_Overflow_Crash: Crash, Timeout
cc/AllocGeneric_Overflow: Crash, Timeout
@@ -78,11 +85,18 @@
[ $builder_tag == asan ]
cc/CodeImmutability: Fail,OK # Address Sanitizer turns a crash into a failure.
+[ $arch == ia32 && $builder_tag == asan ]
+cc/Dart2JSCompileAll: Crash # Issue 26487 - stack overflow
+cc/Dart2JSCompilerStats: Crash # Issue 26487 - stack overflow
+
[ $noopt ]
dart/byte_array_test: Crash # Incompatible flag --disable_alloc_stubs_after_gc
[ $noopt || $compiler == precompiler || $mode == product ]
-dart/redirection_type_shuffling_test: CompileTimeError # Imports dart:mirrors
+dart/redirection_type_shuffling_test: SkipByDesign # Imports dart:mirrors
+cc/CreateMirrorSystem: SkipByDesign # Imports dart:mirrors
+cc/CoreSnapshotSize: SkipByDesign # Imports dart:mirrors
+cc/StandaloneSnapshotSize: SkipByDesign # Imports dart:mirrors
[ $noopt || $runtime == dart_precompiled ]
# Stacktraces in precompilation omit inlined frames.
@@ -95,8 +109,9 @@
[ $runtime == vm && $mode == product ]
cc/IsolateSetCheckedMode: Fail,OK # Expects exact type name.
-cc/LibraryGetClassNames: Fail,OK # Expects exact type name.
cc/StackTraceFormat: Fail,OK # Expects exact type name.
+cc/String_ScrubName: Fail,OK # Expects exact type name.
+cc/GetFunctionNames: Fail,OK # Expects exact type name.
[ $arch == simdbc || $arch == simdbc64 ]
# TODO(vegorov) Profiler is completely disabled in SIMDBC builds.
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index b6e64db..f1c2da4 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -126,6 +126,7 @@
"../tools/gen_library_src_paths.py",
"../lib/libgen_in.cc",
]
+ inputs += lib_sources
outputs = [ invoker.output, ]
args = [
"--output", rebase_path(invoker.output, root_build_dir),
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 0318786..e81ddfc 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -123,6 +123,12 @@
}
+// Returns named function that is a unique dynamic target, i.e.,
+// - the target is identified by its name alone, since it occurs only once.
+// - target's class has no subclasses, and neither is subclassed, i.e.,
+// the receiver type can be only the function's class.
+// Returns Function::null() if there is no unique dynamic target for
+// given 'fname'. 'fname' must be a symbol.
static void GetUniqueDynamicTarget(Isolate* isolate,
const String& fname,
Object* function) {
@@ -217,11 +223,10 @@
Function& target_function = Function::Handle(Z);
GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function);
// Calls with named arguments must be resolved/checked at runtime.
- String& error_message = String::Handle(Z);
if (!target_function.IsNull() &&
!target_function.HasOptionalNamedParameters() &&
target_function.AreValidArgumentCounts(call->ArgumentCount(), 0,
- &error_message)) {
+ /* error_message = */ NULL)) {
const intptr_t cid = Class::Handle(Z, target_function.Owner()).id();
const ICData& ic_data = ICData::ZoneHandle(Z,
ICData::NewFrom(*call->ic_data(), 1));
diff --git a/runtime/vm/become.cc b/runtime/vm/become.cc
new file mode 100644
index 0000000..0f4586f
--- /dev/null
+++ b/runtime/vm/become.cc
@@ -0,0 +1,238 @@
+// Copyright (c) 2016, 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/become.h"
+
+#include "platform/assert.h"
+#include "platform/utils.h"
+
+#include "vm/dart_api_state.h"
+#include "vm/freelist.h"
+#include "vm/isolate_reload.h"
+#include "vm/object.h"
+#include "vm/raw_object.h"
+#include "vm/safepoint.h"
+#include "vm/timeline.h"
+#include "vm/visitor.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, trace_reload);
+
+// Free list elements are used as a marker for forwarding objects. This is
+// safe because we cannot reach free list elements from live objects. Ideally
+// forwarding objects would have their own class id. See TODO below.
+static bool IsForwardingObject(RawObject* object) {
+ return object->IsHeapObject() && object->IsFreeListElement();
+}
+
+
+static RawObject* GetForwardedObject(RawObject* object) {
+ ASSERT(IsForwardingObject(object));
+ uword addr = reinterpret_cast<uword>(object) - kHeapObjectTag;
+ FreeListElement* forwarder = reinterpret_cast<FreeListElement*>(addr);
+ RawObject* new_target = reinterpret_cast<RawObject*>(forwarder->next());
+ return new_target;
+}
+
+
+static void ForwardObjectTo(RawObject* before_obj, RawObject* after_obj) {
+ const intptr_t size_before = before_obj->Size();
+
+ // TODO(rmacnak): We should use different cids for forwarding corpses and
+ // free list elements.
+ uword corpse_addr = reinterpret_cast<uword>(before_obj) - kHeapObjectTag;
+ FreeListElement* forwarder = FreeListElement::AsElement(corpse_addr,
+ size_before);
+ forwarder->set_next(reinterpret_cast<FreeListElement*>(after_obj));
+ if (!IsForwardingObject(before_obj)) {
+ FATAL("become: ForwardObjectTo failure.");
+ }
+ // Still need to be able to iterate over the forwarding corpse.
+ const intptr_t size_after = before_obj->Size();
+ if (size_before != size_after) {
+ FATAL("become: Before and after sizes do not match.");
+ }
+}
+
+
+class ForwardPointersVisitor : public ObjectPointerVisitor {
+ public:
+ explicit ForwardPointersVisitor(Isolate* isolate)
+ : ObjectPointerVisitor(isolate), visiting_object_(NULL), count_(0) { }
+
+ virtual void VisitPointers(RawObject** first, RawObject** last) {
+ for (RawObject** p = first; p <= last; p++) {
+ RawObject* old_target = *p;
+ if (IsForwardingObject(old_target)) {
+ RawObject* new_target = GetForwardedObject(old_target);
+ if (visiting_object_ == NULL) {
+ *p = new_target;
+ } else {
+ visiting_object_->StorePointer(p, new_target);
+ }
+ count_++;
+ }
+ }
+ }
+
+ void VisitingObject(RawObject* obj) { visiting_object_ = obj; }
+
+ intptr_t count() const { return count_; }
+
+ private:
+ RawObject* visiting_object_;
+ intptr_t count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForwardPointersVisitor);
+};
+
+
+class ForwardHeapPointersVisitor : public ObjectVisitor {
+ public:
+ explicit ForwardHeapPointersVisitor(ForwardPointersVisitor* pointer_visitor)
+ : pointer_visitor_(pointer_visitor) { }
+
+ virtual void VisitObject(RawObject* obj) {
+ pointer_visitor_->VisitingObject(obj);
+ obj->VisitPointers(pointer_visitor_);
+ }
+
+ private:
+ ForwardPointersVisitor* pointer_visitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForwardHeapPointersVisitor);
+};
+
+
+class ForwardHeapPointersHandleVisitor : public HandleVisitor {
+ public:
+ ForwardHeapPointersHandleVisitor()
+ : HandleVisitor(Thread::Current()), count_(0) { }
+
+ virtual void VisitHandle(uword addr) {
+ FinalizablePersistentHandle* handle =
+ reinterpret_cast<FinalizablePersistentHandle*>(addr);
+ if (IsForwardingObject(handle->raw())) {
+ *handle->raw_addr() = GetForwardedObject(handle->raw());
+ count_++;
+ }
+ }
+
+ intptr_t count() const { return count_; }
+
+ private:
+ int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ForwardHeapPointersHandleVisitor);
+};
+
+
+#if defined(DEBUG)
+class NoFreeListTargetsVisitor : public ObjectPointerVisitor {
+ public:
+ explicit NoFreeListTargetsVisitor(Isolate* isolate)
+ : ObjectPointerVisitor(isolate) { }
+
+ virtual void VisitPointers(RawObject** first, RawObject** last) {
+ for (RawObject** p = first; p <= last; p++) {
+ RawObject* target = *p;
+ if (target->IsHeapObject()) {
+ ASSERT(!target->IsFreeListElement());
+ }
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NoFreeListTargetsVisitor);
+};
+#endif
+
+
+void Become::ElementsForwardIdentity(const Array& before, const Array& after) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ Heap* heap = isolate->heap();
+
+ {
+ // TODO(rmacnak): Investigate why this is necessary.
+ heap->CollectGarbage(Heap::kNew);
+ }
+
+ TIMELINE_FUNCTION_GC_DURATION(thread, "Become::ElementsForwardIdentity");
+ HeapIterationScope his;
+
+#if defined(DEBUG)
+ {
+ // There should be no pointers to free list elements / forwarding corpses.
+ NoFreeListTargetsVisitor visitor(isolate);
+ isolate->VisitObjectPointers(&visitor, true);
+ heap->VisitObjectPointers(&visitor);
+ }
+#endif
+
+ // Setup forwarding pointers.
+ ASSERT(before.Length() == after.Length());
+ for (intptr_t i = 0; i < before.Length(); i++) {
+ RawObject* before_obj = before.At(i);
+ RawObject* after_obj = after.At(i);
+
+ if (before_obj == after_obj) {
+ FATAL("become: Cannot self-forward");
+ }
+ if (!before_obj->IsHeapObject()) {
+ FATAL("become: Cannot forward immediates");
+ }
+ if (!after_obj->IsHeapObject()) {
+ FATAL("become: Cannot become an immediates");
+ }
+ if (before_obj->IsVMHeapObject()) {
+ FATAL("become: Cannot forward VM heap objects");
+ }
+ if (after_obj->IsFreeListElement()) {
+ // The Smalltalk become does allow this, and for very special cases
+ // it is important (shape changes to Class or Mixin), but as these
+ // cases do not arise in Dart, better to prohibit it.
+ FATAL("become: No indirect chains of forwarding");
+ }
+
+ ForwardObjectTo(before_obj, after_obj);
+ }
+
+ {
+ // Follow forwarding pointers.
+
+ // C++ pointers
+ ForwardPointersVisitor pointer_visitor(isolate);
+ isolate->VisitObjectPointers(&pointer_visitor, true);
+
+ // Weak persistent handles.
+ ForwardHeapPointersHandleVisitor handle_visitor;
+ isolate->VisitWeakPersistentHandles(&handle_visitor);
+
+ // Heap pointers (may require updating the remembered set)
+ ForwardHeapPointersVisitor object_visitor(&pointer_visitor);
+ heap->VisitObjects(&object_visitor);
+ pointer_visitor.VisitingObject(NULL);
+
+ TIR_Print("Performed %" Pd " heap and %" Pd " handle replacements\n",
+ pointer_visitor.count(),
+ handle_visitor.count());
+ }
+
+#if defined(DEBUG)
+ for (intptr_t i = 0; i < before.Length(); i++) {
+ ASSERT(before.At(i) == after.At(i));
+ }
+
+ {
+ // There should be no pointers to forwarding corpses.
+ NoFreeListTargetsVisitor visitor(isolate);
+ isolate->VisitObjectPointers(&visitor, true);
+ heap->VisitObjectPointers(&visitor);
+ }
+#endif
+}
+
+} // namespace dart
diff --git a/runtime/vm/become.h b/runtime/vm/become.h
new file mode 100644
index 0000000..9773553
--- /dev/null
+++ b/runtime/vm/become.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2016, 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 VM_BECOME_H_
+#define VM_BECOME_H_
+
+#include "vm/allocation.h"
+
+namespace dart {
+
+class Array;
+
+// TODO(johnmccutchan): Refactor this class so that it is not all static and
+// provides utility methods for building the mapping of before and after.
+class Become : public AllStatic {
+ public:
+ // Smalltalk's one-way bulk become (Array>>#elementsForwardIdentityTo:).
+ // Redirects all pointers to elements of 'before' to the corresponding element
+ // in 'after'. Every element in 'before' is guaranteed to be not reachable.
+ // Useful for atomically applying behavior and schema changes.
+ static void ElementsForwardIdentity(const Array& before, const Array& after);
+};
+
+} // namespace dart
+
+#endif // VM_BECOME_H_
diff --git a/runtime/vm/block_scheduler.cc b/runtime/vm/block_scheduler.cc
index 9c00cfb..d792551 100644
--- a/runtime/vm/block_scheduler.cc
+++ b/runtime/vm/block_scheduler.cc
@@ -64,7 +64,10 @@
Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId,
"BlockScheduler: ICData array cleared");
}
- ASSERT(!ic_data_array.IsNull());
+ if (ic_data_array.IsNull()) {
+ ASSERT(Isolate::Current()->HasAttemptedReload());
+ return;
+ }
Array& edge_counters = Array::Handle();
edge_counters ^= ic_data_array.At(0);
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 31b800c..3855eaa 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -162,6 +162,7 @@
V(Timeline_getNextAsyncId, 0) \
V(Timeline_getTraceClock, 0) \
V(Timeline_getThreadCpuClock, 0) \
+ V(Timeline_isDartStreamEnabled, 0) \
V(Timeline_reportCompleteEvent, 5) \
V(Timeline_reportInstantEvent, 4) \
V(Timeline_reportTaskEvent, 6) \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 81cd85c..027072b 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1923,7 +1923,7 @@
inserted_class_name = Symbols::New(thread, inserted_class_name);
const Script& script = Script::Handle(zone, mixin_app_class.script());
inserted_class = Class::New(
- inserted_class_name, script, mixin_app_class.token_pos());
+ library, inserted_class_name, script, mixin_app_class.token_pos());
inserted_class.set_is_synthesized_class();
library.AddClass(inserted_class);
@@ -2814,7 +2814,8 @@
mixin_app_class = library.LookupLocalClass(mixin_app_class_name);
if (mixin_app_class.IsNull()) {
mixin_app_class_name = Symbols::New(thread, mixin_app_class_name);
- mixin_app_class = Class::New(mixin_app_class_name,
+ mixin_app_class = Class::New(library,
+ mixin_app_class_name,
script,
mixin_type.token_pos());
mixin_app_class.set_super_type(mixin_super_type);
diff --git a/runtime/vm/class_finalizer_test.cc b/runtime/vm/class_finalizer_test.cc
index eb4447c..8de73e5 100644
--- a/runtime/vm/class_finalizer_test.cc
+++ b/runtime/vm/class_finalizer_test.cc
@@ -15,7 +15,8 @@
name));
const Script& script = Script::Handle();
const Class& cls = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
+ Class::New(Library::Handle(), class_name, script,
+ TokenPosition::kNoSource));
cls.set_interfaces(Object::empty_array());
cls.SetFunctions(Object::empty_array());
cls.SetFields(Object::empty_array());
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 97e475a..af774a0 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -156,6 +156,10 @@
return table_[index];
}
+ void SetAt(intptr_t index, RawClass* raw_cls) {
+ table_[index] = raw_cls;
+ }
+
bool IsValidIndex(intptr_t index) const {
return (index > 0) && (index < top_);
}
@@ -167,6 +171,12 @@
intptr_t NumCids() const { return top_; }
+ // Used to drop recently added classes.
+ void SetNumCids(intptr_t num_cids) {
+ ASSERT(num_cids <= top_);
+ top_ = num_cids;
+ }
+
void Register(const Class& cls);
void RegisterAt(intptr_t index, const Class& cls);
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 3f01605..3a8cf41 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -20,6 +20,7 @@
#include "vm/parser.h"
#include "vm/resolver.h"
#include "vm/runtime_entry.h"
+#include "vm/service_isolate.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#include "vm/thread_registry.h"
@@ -60,6 +61,9 @@
DEFINE_FLAG(charp, deoptimize_filter, NULL,
"Deoptimize in named function on stack overflow checks");
+DECLARE_FLAG(int, reload_every);
+DECLARE_FLAG(bool, reload_every_optimized);
+
#ifdef DEBUG
DEFINE_FLAG(charp, gc_at_instance_allocation, NULL,
"Perform a GC before allocation of instances of "
@@ -668,7 +672,7 @@
const Code& orig_stub = Code::Handle(
zone, isolate->debugger()->GetPatchedStubAddress(caller_frame->pc()));
const Error& error =
- Error::Handle(zone, isolate->debugger()->SignalBpReached());
+ Error::Handle(zone, isolate->debugger()->PauseBreakpoint());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
@@ -682,7 +686,7 @@
UNREACHABLE();
return;
}
- const Error& error = Error::Handle(isolate->debugger()->SignalBpReached());
+ const Error& error = Error::Handle(isolate->debugger()->PauseBreakpoint());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
@@ -697,7 +701,7 @@
return;
}
const Error& error =
- Error::Handle(zone, isolate->debugger()->DebuggerStepCallback());
+ Error::Handle(zone, isolate->debugger()->PauseStepping());
if (!error.IsNull()) {
Exceptions::PropagateError(error);
UNREACHABLE();
@@ -1237,7 +1241,10 @@
// debugger stack tracing.
bool do_deopt = false;
bool do_stacktrace = false;
- if ((FLAG_deoptimize_every > 0) || (FLAG_stacktrace_every > 0)) {
+ bool do_reload = false;
+ if ((FLAG_deoptimize_every > 0) ||
+ (FLAG_stacktrace_every > 0) ||
+ (FLAG_reload_every > 0)) {
// TODO(turnidge): To make --deoptimize_every and
// --stacktrace-every faster we could move this increment/test to
// the generated code.
@@ -1250,8 +1257,14 @@
(count % FLAG_stacktrace_every) == 0) {
do_stacktrace = true;
}
+ if ((FLAG_reload_every > 0) &&
+ (count % FLAG_reload_every) == 0) {
+ do_reload = isolate->CanReload();
+ }
}
- if ((FLAG_deoptimize_filter != NULL) || (FLAG_stacktrace_filter != NULL)) {
+ if ((FLAG_deoptimize_filter != NULL) ||
+ (FLAG_stacktrace_filter != NULL) ||
+ FLAG_reload_every_optimized) {
DartFrameIterator iterator;
StackFrame* frame = iterator.NextFrame();
ASSERT(frame != NULL);
@@ -1261,6 +1274,10 @@
ASSERT(!function.IsNull());
const char* function_name = function.ToFullyQualifiedCString();
ASSERT(function_name != NULL);
+ if (!code.is_optimized() && FLAG_reload_every_optimized) {
+ // Don't do the reload if we aren't inside optimized code.
+ do_reload = false;
+ }
if (code.is_optimized() &&
FLAG_deoptimize_filter != NULL &&
strstr(function_name, FLAG_deoptimize_filter) != NULL) {
@@ -1279,6 +1296,9 @@
// TODO(turnidge): Consider using DeoptimizeAt instead.
DeoptimizeFunctionsOnStack();
}
+ if (do_reload) {
+ NOT_IN_PRODUCT(isolate->OnStackReload();)
+ }
if (FLAG_support_debugger && do_stacktrace) {
String& var_name = String::Handle();
Instance& var_value = Instance::Handle();
@@ -1414,20 +1434,22 @@
if (FLAG_enable_inlining_annotations) {
FATAL("Cannot enable inlining annotations and background compilation");
}
- if (FLAG_background_compilation_stop_alot) {
- BackgroundCompiler::Stop(isolate);
+ if (!BackgroundCompiler::IsDisabled()) {
+ if (FLAG_background_compilation_stop_alot) {
+ BackgroundCompiler::Stop(isolate);
+ }
+ // Reduce the chance of triggering optimization while the function is
+ // being optimized in the background. INT_MIN should ensure that it
+ // takes long time to trigger optimization.
+ // Note that the background compilation queue rejects duplicate entries.
+ function.set_usage_counter(INT_MIN);
+ BackgroundCompiler::EnsureInit(thread);
+ ASSERT(isolate->background_compiler() != NULL);
+ isolate->background_compiler()->CompileOptimized(function);
+ // Continue in the same code.
+ arguments.SetReturn(Code::Handle(zone, function.CurrentCode()));
+ return;
}
- // Reduce the chance of triggering optimization while the function is
- // being optimized in the background. INT_MIN should ensure that it takes
- // long time to trigger optimization.
- // Note that the background compilation queue rejects duplicate entries.
- function.set_usage_counter(INT_MIN);
- BackgroundCompiler::EnsureInit(thread);
- ASSERT(isolate->background_compiler() != NULL);
- isolate->background_compiler()->CompileOptimized(function);
- // Continue in the same code.
- arguments.SetReturn(Code::Handle(zone, function.CurrentCode()));
- return;
}
// Reset usage counter for reoptimization before calling optimizer to
diff --git a/runtime/vm/code_patcher_arm64_test.cc b/runtime/vm/code_patcher_arm64_test.cc
index f11b00a..3b5e61e 100644
--- a/runtime/vm/code_patcher_arm64_test.cc
+++ b/runtime/vm/code_patcher_arm64_test.cc
@@ -24,8 +24,8 @@
Thread* thread = Thread::Current();
const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
+ const Class& owner_class = Class::Handle(Class::New(
+ Library::Handle(), class_name, script, TokenPosition::kNoSource));
const String& function_name = String::Handle(Symbols::New(thread,
"callerFunction"));
const Function& function = Function::Handle(
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index a4cdfe5..b1ca06f 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -24,8 +24,8 @@
Thread* thread = Thread::Current();
const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
+ const Class& owner_class = Class::Handle(Class::New(
+ Library::Handle(), class_name, script, TokenPosition::kNoSource));
const String& function_name = String::Handle(Symbols::New(thread,
"callerFunction"));
const Function& function = Function::Handle(
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index 55fe98f..c035345 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -24,8 +24,8 @@
Thread* thread = Thread::Current();
const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
+ const Class& owner_class = Class::Handle(Class::New(
+ Library::Handle(), class_name, script, TokenPosition::kNoSource));
const String& function_name = String::Handle(Symbols::New(thread,
"callerFunction"));
const Function& function = Function::Handle(
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index 0776083..c8d65bf 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -24,8 +24,8 @@
Thread* thread = Thread::Current();
const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
+ const Class& owner_class = Class::Handle(Class::New(
+ Library::Handle(), class_name, script, TokenPosition::kNoSource));
const String& function_name = String::Handle(Symbols::New(thread,
"callerFunction"));
const Function& function = Function::Handle(
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index 5102226..410ba1a 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -24,8 +24,8 @@
Thread* thread = Thread::Current();
const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
+ const Class& owner_class = Class::Handle(Class::New(
+ Library::Handle(), class_name, script, TokenPosition::kNoSource));
const String& function_name = String::Handle(Symbols::New(thread,
"callerFunction"));
const Function& function = Function::Handle(
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index e084f16..50e2e55 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -105,7 +105,7 @@
}
-void DartCompilationPipeline::FinalizeCompilation() { }
+void DartCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) { }
void IrregexpCompilationPipeline::ParseFunction(
@@ -142,7 +142,7 @@
}
-void IrregexpCompilationPipeline::FinalizeCompilation() {
+void IrregexpCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) {
backtrack_goto_->ComputeOffsetTable();
}
@@ -1127,7 +1127,7 @@
compiler_timeline,
"CompileGraph"));
graph_compiler.CompileGraph();
- pipeline->FinalizeCompilation();
+ pipeline->FinalizeCompilation(flow_graph);
}
{
NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
@@ -1452,10 +1452,12 @@
TIMELINE_FUNCTION_COMPILATION_DURATION(thread, event_name, function);
) // !PRODUCT
- // Optimization must happen in non-mutator/Dart thread if background
- // compilation is on. OSR compilation still occurs in the main thread.
- ASSERT((osr_id != kNoOSRDeoptId) || !FLAG_background_compilation ||
- !thread->IsMutatorThread());
+ // If we are in the optimizing in the mutator/Dart thread, then
+ // this is either an OSR compilation or background compilation is
+ // not currently allowed.
+ ASSERT(!thread->IsMutatorThread() ||
+ (osr_id != kNoOSRDeoptId) ||
+ !FLAG_background_compilation || BackgroundCompiler::IsDisabled());
CompilationPipeline* pipeline =
CompilationPipeline::New(thread->zone(), function);
return CompileFunctionHelper(pipeline,
@@ -1563,24 +1565,39 @@
// evaluating the initializer value.
ASSERT(field.StaticValue() == Object::transition_sentinel().raw());
LongJumpScope jump;
+ Thread* thread = Thread::Current();
if (setjmp(*jump.Set()) == 0) {
+ NoOOBMessageScope no_msg_scope(thread);
+ NoReloadScope no_reload_scope(thread->isolate(), thread);
// Under lazy compilation initializer has not yet been created, so create
// it now, but don't bother remembering it because it won't be used again.
ASSERT(!field.HasPrecompiledInitializer());
Thread* const thread = Thread::Current();
- StackZone zone(thread);
- ParsedFunction* parsed_function =
- Parser::ParseStaticFieldInitializer(field);
+ Function& initializer = Function::Handle(thread->zone());
+ {
+ NOT_IN_PRODUCT(
+ VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
+ TimelineDurationScope tds(thread, Timeline::GetCompilerStream(),
+ "CompileStaticInitializer");
+ if (tds.enabled()) {
+ tds.SetNumArguments(1);
+ tds.CopyArgument(0, "field", field.ToCString());
+ }
+ )
- parsed_function->AllocateVariables();
- // Non-optimized code generator.
- DartCompilationPipeline pipeline;
- CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
- helper.Compile(&pipeline);
- const Function& initializer =
- Function::Handle(parsed_function->function().raw());
- Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
- Object::empty_var_descriptors());
+ StackZone zone(thread);
+ ParsedFunction* parsed_function =
+ Parser::ParseStaticFieldInitializer(field);
+
+ parsed_function->AllocateVariables();
+ // Non-optimized code generator.
+ DartCompilationPipeline pipeline;
+ CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
+ helper.Compile(&pipeline);
+ initializer = parsed_function->function().raw();
+ Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
+ Object::empty_var_descriptors());
+ }
// Invoke the function to evaluate the expression.
return DartEntry::InvokeFunction(initializer, Object::empty_array());
} else {
@@ -1609,6 +1626,10 @@
// Don't allow message interrupts while executing constant
// expressions. They can cause bogus recursive compilation.
NoOOBMessageScope no_msg_scope(thread);
+
+ // Don't allow reload requests to come in.
+ NoReloadScope no_reload_scope(thread->isolate(), thread);
+
if (FLAG_trace_compiler) {
THR_Print("compiling expression: ");
if (FLAG_support_ast_printer) {
@@ -1963,6 +1984,41 @@
}
+void BackgroundCompiler::Disable() {
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ Isolate* isolate = thread->isolate();
+ MutexLocker ml(isolate->mutex());
+ BackgroundCompiler* task = isolate->background_compiler();
+ if (task != NULL) {
+ // We should only ever have to stop the task if this is the first call to
+ // Disable.
+ ASSERT(!isolate->is_background_compiler_disabled());
+ BackgroundCompiler::Stop(isolate);
+ }
+ ASSERT(isolate->background_compiler() == NULL);
+ isolate->disable_background_compiler();
+}
+
+
+bool BackgroundCompiler::IsDisabled() {
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ Isolate* isolate = thread->isolate();
+ MutexLocker ml(isolate->mutex());
+ return isolate->is_background_compiler_disabled();
+}
+
+
+void BackgroundCompiler::Enable() {
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ Isolate* isolate = thread->isolate();
+ MutexLocker ml(isolate->mutex());
+ isolate->enable_background_compiler();
+}
+
+
void BackgroundCompiler::EnsureInit(Thread* thread) {
ASSERT(thread->IsMutatorThread());
// Finalize NoSuchMethodError, _Mint; occasionally needed in optimized
@@ -2114,6 +2170,22 @@
UNREACHABLE();
}
+
+void BackgroundCompiler::Disable() {
+ UNREACHABLE();
+}
+
+
+void BackgroundCompiler::Enable() {
+ UNREACHABLE();
+}
+
+
+bool BackgroundCompiler::IsDisabled() {
+ UNREACHABLE();
+ return true;
+}
+
#endif // DART_PRECOMPILED_RUNTIME
} // namespace dart
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index 4e2a550..1e8e3fc 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -38,7 +38,7 @@
ParsedFunction* parsed_function,
const ZoneGrowableArray<const ICData*>& ic_data_array,
intptr_t osr_id) = 0;
- virtual void FinalizeCompilation() = 0;
+ virtual void FinalizeCompilation(FlowGraph* flow_graph) = 0;
virtual ~CompilationPipeline() { }
};
@@ -53,7 +53,7 @@
const ZoneGrowableArray<const ICData*>& ic_data_array,
intptr_t osr_id);
- virtual void FinalizeCompilation();
+ virtual void FinalizeCompilation(FlowGraph* flow_graph);
};
@@ -69,7 +69,7 @@
const ZoneGrowableArray<const ICData*>& ic_data_array,
intptr_t osr_id);
- virtual void FinalizeCompilation();
+ virtual void FinalizeCompilation(FlowGraph* flow_graph);
private:
IndirectGotoInstr* backtrack_goto_;
@@ -163,8 +163,15 @@
static void EnsureInit(Thread* thread);
// Stops background compiler of the given isolate.
+ // TODO(turnidge): Give Stop and Disable more distinct names.
static void Stop(Isolate* isolate);
+ static void Disable();
+
+ static void Enable();
+
+ static bool IsDisabled();
+
// Call to optimize a function in the background, enters the function in the
// compilation queue.
void CompileOptimized(const Function& function);
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 5764745..5639af5 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -25,6 +25,41 @@
#endif
+// The Linux/Android ABI and the iOS ABI differ in their choice of frame
+// pointer, their treatment of R9, and the interproduceral stack alignment.
+
+// EABI (Linux, Android)
+// See "Procedure Call Standard for the ARM Architecture".
+// R0-R1: Argument / result / volatile
+// R2-R3: Argument / volatile
+// R4-R10: Preserved
+// R11: Frame pointer
+// R12: Volatile
+// R13: Stack pointer
+// R14: Link register
+// R15: Program counter
+// Stack alignment: 4 bytes always, 8 bytes at public interfaces
+
+// Linux (Debian armhf) and Android also differ in whether floating point
+// arguments are passed in registers. Linux uses hardfp and Android uses
+// softfp. See TargetCPUFeatures::hardfp_supported().
+
+// iOS ABI
+// See "iOS ABI Function Call Guide"
+// R0-R1: Argument / result / volatile
+// R2-R3: Argument / volatile
+// R4-R6: Preserved
+// R7: Frame pointer
+// R8-R9: Preserved
+// R12: Volatile
+// R13: Stack pointer
+// R14: Link register
+// R15: Program counter
+// Stack alignment: 4 bytes always, 4 bytes at public interfaces
+
+// iOS passes floating point arguments in registers (hardfp)
+
+
enum Register {
R0 = 0,
R1 = 1,
@@ -46,12 +81,14 @@
kNoRegister = -1, // Signals an illegal register.
// Aliases.
-#if defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_IOS)
FP = R7,
NOTFP = R11,
-#else
+#elif defined(TARGET_ABI_EABI)
FP = R11,
NOTFP = R7,
+#else
+#error Unknown ABI
#endif
IP = R12,
SP = R13,
@@ -268,16 +305,18 @@
// C++ ABI call registers.
const RegList kAbiArgumentCpuRegs =
(1 << R0) | (1 << R1) | (1 << R2) | (1 << R3);
-#if defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_IOS)
const RegList kAbiPreservedCpuRegs =
(1 << R4) | (1 << R5) | (1 << R6) | (1 << R8) |
(1 << R10) | (1 << R11);
const int kAbiPreservedCpuRegCount = 6;
-#else
+#elif defined(TARGET_ABI_EABI)
const RegList kAbiPreservedCpuRegs =
(1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) |
(1 << R8) | (1 << R9) | (1 << R10);
const int kAbiPreservedCpuRegCount = 7;
+#else
+#error Unknown ABI
#endif
const QRegister kAbiFirstPreservedFpuReg = Q4;
const QRegister kAbiLastPreservedFpuReg = Q7;
@@ -296,9 +335,9 @@
// Registers available to Dart that are not preserved by runtime calls.
const RegList kDartVolatileCpuRegs =
kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
-#if defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_IOS)
const int kDartVolatileCpuRegCount = 6;
-#else
+#elif defined(TARGET_ABI_EABI)
const int kDartVolatileCpuRegCount = 5;
#endif
const QRegister kDartFirstVolatileFpuReg = Q0;
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 0bc7a50..f4821e4 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -115,22 +115,22 @@
}
-const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
- const uint8_t* instructions_snapshot,
- const uint8_t* data_snapshot,
- Dart_IsolateCreateCallback create,
- Dart_IsolateShutdownCallback shutdown,
- Dart_ThreadExitCallback thread_exit,
- Dart_FileOpenCallback file_open,
- Dart_FileReadCallback file_read,
- Dart_FileWriteCallback file_write,
- Dart_FileCloseCallback file_close,
- Dart_EntropySource entropy_source,
- Dart_GetVMServiceAssetsArchive get_service_assets) {
+char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
+ const uint8_t* instructions_snapshot,
+ const uint8_t* data_snapshot,
+ Dart_IsolateCreateCallback create,
+ Dart_IsolateShutdownCallback shutdown,
+ Dart_ThreadExitCallback thread_exit,
+ Dart_FileOpenCallback file_open,
+ Dart_FileReadCallback file_read,
+ Dart_FileWriteCallback file_write,
+ Dart_FileCloseCallback file_close,
+ Dart_EntropySource entropy_source,
+ Dart_GetVMServiceAssetsArchive get_service_assets) {
CheckOffsets();
// TODO(iposva): Fix race condition here.
if (vm_isolate_ != NULL || !Flags::Initialized()) {
- return "VM already initialized or flags not initialized.";
+ return strdup("VM already initialized or flags not initialized.");
}
set_thread_exit_callback(thread_exit);
SetFileCallbacks(file_open, file_read, file_write, file_close);
@@ -195,42 +195,43 @@
"VMIsolateSnapshot"));
const Snapshot* snapshot = Snapshot::SetupFromBuffer(vm_isolate_snapshot);
if (snapshot == NULL) {
- return "Invalid vm isolate snapshot seen";
+ return strdup("Invalid vm isolate snapshot seen");
}
snapshot_kind_ = snapshot->kind();
+
if (Snapshot::IncludesCode(snapshot_kind_)) {
if (snapshot_kind_ == Snapshot::kAppNoJIT) {
#if defined(DART_PRECOMPILED_RUNTIME)
vm_isolate_->set_compilation_allowed(false);
if (!FLAG_precompiled_runtime) {
- return "Flag --precompilation was not specified";
+ return strdup("Flag --precompilation was not specified");
}
#else
- return "JIT runtime cannot run a precompiled snapshot";
+ return strdup("JIT runtime cannot run a precompiled snapshot");
#endif
}
if (instructions_snapshot == NULL) {
- return "Missing instructions snapshot";
+ return strdup("Missing instructions snapshot");
}
if (data_snapshot == NULL) {
- return "Missing rodata snapshot";
+ return strdup("Missing rodata snapshot");
}
vm_isolate_->SetupInstructionsSnapshotPage(instructions_snapshot);
vm_isolate_->SetupDataSnapshotPage(data_snapshot);
} else if (Snapshot::IsFull(snapshot_kind_)) {
#if defined(DART_PRECOMPILED_RUNTIME)
- return "Precompiled runtime requires a precompiled snapshot";
+ return strdup("Precompiled runtime requires a precompiled snapshot");
#else
if (instructions_snapshot != NULL) {
- return "Unexpected instructions snapshot";
+ return strdup("Unexpected instructions snapshot");
}
if (data_snapshot != NULL) {
- return "Unexpected rodata snapshot";
+ return strdup("Unexpected rodata snapshot");
}
StubCode::InitOnce();
#endif
} else {
- return "Invalid vm isolate snapshot seen";
+ return strdup("Invalid vm isolate snapshot seen");
}
VmIsolateSnapshotReader reader(snapshot->kind(),
snapshot->content(),
@@ -240,7 +241,8 @@
T);
const Error& error = Error::Handle(reader.ReadVmIsolateSnapshot());
if (!error.IsNull()) {
- return error.ToErrorCString();
+ // Must copy before leaving the zone.
+ return strdup(error.ToErrorCString());
}
NOT_IN_PRODUCT(if (tds.enabled()) {
tds.SetNumArguments(2);
@@ -262,7 +264,7 @@
}
} else {
#if defined(DART_PRECOMPILED_RUNTIME)
- return "Precompiled runtime requires a precompiled snapshot";
+ return strdup("Precompiled runtime requires a precompiled snapshot");
#else
snapshot_kind_ = Snapshot::kNone;
StubCode::InitOnce();
@@ -276,7 +278,7 @@
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
// Dart VM requires at least SSE2.
if (!TargetCPUFeatures::sse2_supported()) {
- return "SSE2 is required.";
+ return strdup("SSE2 is required.");
}
#endif
{
@@ -595,6 +597,58 @@
}
+const char* Dart::FeaturesString(Snapshot::Kind kind) {
+ TextBuffer buffer(64);
+
+ // Different fields are included for DEBUG/RELEASE/PRODUCT.
+#if defined(DEBUG)
+ buffer.AddString("debug");
+#elif defined(PRODUCT)
+ buffer.AddString("product");
+#else
+ buffer.AddString("release");
+#endif
+
+ if (Snapshot::IncludesCode(kind)) {
+ // Checked mode affects deopt ids.
+ buffer.AddString(FLAG_enable_asserts ? " asserts" : " no-asserts");
+ buffer.AddString(FLAG_enable_type_checks ? " type-checks"
+ : " no-type-checks");
+
+ // Generated code must match the host architecture and ABI.
+#if defined(TARGET_ARCH_ARM)
+#if defined(TARGET_ABI_IOS)
+ buffer.AddString(" arm-ios");
+#elif defined(TARGET_ABI_EABI)
+ buffer.AddString(" arm-eabi");
+#else
+#error Unknown ABI
+#endif
+ buffer.AddString(TargetCPUFeatures::hardfp_supported() ? " hardfp"
+ : " softfp");
+#elif defined(TARGET_ARCH_ARM64)
+ buffer.AddString(" arm64");
+#elif defined(TARGET_ARCH_MIPS)
+ buffer.AddString(" mips");
+#elif defined(TARGET_ARCH_IA32)
+ buffer.AddString(" ia32");
+#elif defined(TARGET_ARCH_X64)
+#if defined(_WIN64)
+ buffer.AddString(" x64-win");
+#else
+ buffer.AddString(" x64-sysv");
+#endif
+#elif defined(TARGET_ARCH_DBC)
+ buffer.AddString(" dbc");
+#elif defined(TARGET_ARCH_DBC64)
+ buffer.AddString(" dbc64");
+#endif
+ }
+
+ return buffer.Steal();
+}
+
+
void Dart::RunShutdownCallback() {
Isolate* isolate = Isolate::Current();
void* callback_data = isolate->init_callback_data();
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index a21dab2..ea40e43 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -21,7 +21,7 @@
class Dart : public AllStatic {
public:
- static const char* InitOnce(
+ static char* InitOnce(
const uint8_t* vm_isolate_snapshot,
const uint8_t* instructions_snapshot,
const uint8_t* data_snapshot,
@@ -61,6 +61,8 @@
static uword AllocateReadOnlyHandle();
static bool IsReadOnlyHandle(uword address);
+ static const char* FeaturesString(Snapshot::Kind kind);
+
static Snapshot::Kind snapshot_kind() {
return snapshot_kind_;
}
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index e980f09..eed7789 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1156,18 +1156,14 @@
return strdup("Dart_Initialize: "
"Setting of unhandled exception callback is not supported.");
}
- const char* err_msg = Dart::InitOnce(vm_isolate_snapshot,
- instructions_snapshot,
- data_snapshot,
- create, shutdown,
- thread_exit,
- file_open, file_read, file_write,
- file_close, entropy_source,
- get_service_assets);
- if (err_msg != NULL) {
- return strdup(err_msg);
- }
- return NULL;
+ return Dart::InitOnce(vm_isolate_snapshot,
+ instructions_snapshot,
+ data_snapshot,
+ create, shutdown,
+ thread_exit,
+ file_open, file_read, file_write, file_close,
+ entropy_source,
+ get_service_assets);
}
@@ -1463,10 +1459,13 @@
intptr_t* vm_isolate_snapshot_size,
uint8_t** isolate_snapshot_buffer,
intptr_t* isolate_snapshot_size) {
- ASSERT(FLAG_load_deferred_eagerly);
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION;
Isolate* I = T->isolate();
+ if (!FLAG_load_deferred_eagerly) {
+ return Dart_NewApiError(
+ "Creating full snapshots requires --load_deferred_eagerly");
+ }
if (vm_isolate_snapshot_buffer != NULL &&
vm_isolate_snapshot_size == NULL) {
RETURN_NULL_ERROR(vm_isolate_snapshot_size);
@@ -5239,7 +5238,7 @@
return Api::NewError("%s expects parameter 'buffer' to be a script type"
" snapshot with a valid length.", CURRENT_FUNC);
}
- if (!snapshot->IsScriptSnapshot()) {
+ if (snapshot->kind() != Snapshot::kScript) {
return Api::NewError("%s expects parameter 'buffer' to be a script type"
" snapshot.", CURRENT_FUNC);
}
@@ -5648,6 +5647,8 @@
return state;
}
+ I->DoneFinalizing();
+
// Now that the newly loaded classes are finalized, notify the debugger
// that new code has been loaded. If there are latent breakpoints in
// the new code, the debugger convert them to unresolved source breakpoints.
@@ -6156,7 +6157,6 @@
intptr_t* isolate_snapshot_size,
uint8_t** assembly_buffer,
intptr_t* assembly_size) {
- ASSERT(FLAG_load_deferred_eagerly);
API_TIMELINE_DURATION;
DARTSCOPE(Thread::Current());
Isolate* I = T->isolate();
@@ -6164,6 +6164,7 @@
return Dart_NewApiError("Isolate is not precompiled. "
"Did you forget to call Dart_Precompile?");
}
+ ASSERT(FLAG_load_deferred_eagerly);
if (vm_isolate_snapshot_buffer == NULL) {
RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
}
@@ -6182,6 +6183,9 @@
if (assembly_size == NULL) {
RETURN_NULL_ERROR(assembly_size);
}
+
+ NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
+ "WriteAppAOTSnapshot"));
AssemblyInstructionsWriter instructions_writer(assembly_buffer,
ApiReallocate,
2 * MB /* initial_size */);
@@ -6209,7 +6213,6 @@
intptr_t* instructions_blob_size,
uint8_t** rodata_blob_buffer,
intptr_t* rodata_blob_size) {
- ASSERT(FLAG_load_deferred_eagerly);
API_TIMELINE_DURATION;
DARTSCOPE(Thread::Current());
Isolate* I = T->isolate();
@@ -6217,6 +6220,7 @@
return Dart_NewApiError("Isolate is not precompiled. "
"Did you forget to call Dart_Precompile?");
}
+ ASSERT(FLAG_load_deferred_eagerly);
if (vm_isolate_snapshot_buffer == NULL) {
RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
}
@@ -6241,6 +6245,9 @@
if (rodata_blob_size == NULL) {
RETURN_NULL_ERROR(instructions_blob_size);
}
+
+ NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
+ "WriteAppAOTSnapshot"));
BlobInstructionsWriter instructions_writer(instructions_blob_buffer,
rodata_blob_buffer,
ApiReallocate,
@@ -6303,10 +6310,13 @@
intptr_t* instructions_blob_size,
uint8_t** rodata_blob_buffer,
intptr_t* rodata_blob_size) {
- ASSERT(FLAG_load_deferred_eagerly);
API_TIMELINE_DURATION;
DARTSCOPE(Thread::Current());
Isolate* I = T->isolate();
+ if (!FLAG_load_deferred_eagerly) {
+ return Dart_NewApiError(
+ "Creating full snapshots requires --load_deferred_eagerly");
+ }
if (vm_isolate_snapshot_buffer == NULL) {
RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
}
@@ -6338,6 +6348,8 @@
}
I->StopBackgroundCompiler();
+ NOT_IN_PRODUCT(TimelineDurationScope tds2(T, Timeline::GetIsolateStream(),
+ "WriteAppJITSnapshot"));
BlobInstructionsWriter instructions_writer(instructions_blob_buffer,
rodata_blob_buffer,
ApiReallocate,
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 3b0f238..f6e8bb7 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -9714,8 +9714,7 @@
GlobalTimelineThreadData()
: monitor_(new Monitor()),
data_(new AppendData()),
- running_(true),
- join_id_(OSThread::kInvalidThreadJoinId) {
+ running_(true) {
}
~GlobalTimelineThreadData() {
@@ -9733,16 +9732,13 @@
AppendData* data() const { return data_; }
uint8_t* buffer() const { return data_->buffer; }
intptr_t buffer_length() const { return data_->buffer_length; }
- ThreadJoinId join_id() const { return join_id_; }
void set_running(bool running) { running_ = running; }
- void set_join_id(ThreadJoinId join_id) { join_id_ = join_id; }
private:
Monitor* monitor_;
AppendData* data_;
bool running_;
- ThreadJoinId join_id_;
};
@@ -9758,7 +9754,6 @@
Dart_GlobalTimelineGetTrace(AppendStreamConsumer, data->data());
EXPECT(success);
data->set_running(false);
- data->set_join_id(OSThread::Current()->join_id());
ml.Notify();
}
}
@@ -9805,7 +9800,6 @@
}
buffer = reinterpret_cast<char*>(data.buffer());
buffer_length = data.buffer_length();
- OSThread::Join(data.join_id());
}
EXPECT(buffer_length > 0);
EXPECT(buffer != NULL);
@@ -9847,7 +9841,6 @@
}
buffer = reinterpret_cast<char*>(data2.buffer());
buffer_length = data2.buffer_length();
- OSThread::Join(data2.join_id());
}
EXPECT(buffer_length > 0);
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 6d11f18..64476a9 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -263,114 +263,51 @@
}
-void DebuggerEvent::UpdateTimestamp() {
- timestamp_ = OS::GetCurrentTimeMillis();
+bool Debugger::NeedsIsolateEvents() {
+ return ((isolate_ != Dart::vm_isolate()) &&
+ !ServiceIsolate::IsServiceIsolateDescendant(isolate_) &&
+ ((event_handler_ != NULL) || Service::isolate_stream.enabled()));
}
-bool Debugger::HasAnyEventHandler() {
- return ((event_handler_ != NULL) ||
- Service::isolate_stream.enabled() ||
+bool Debugger::NeedsDebugEvents() {
+ ASSERT(isolate_ != Dart::vm_isolate() &&
+ !ServiceIsolate::IsServiceIsolateDescendant(isolate_));
+ return (FLAG_warn_on_pause_with_no_debugger ||
+ (event_handler_ != NULL) ||
Service::debug_stream.enabled());
}
-bool Debugger::HasDebugEventHandler() {
- return ((event_handler_ != NULL) ||
- Service::debug_stream.enabled());
-}
+void Debugger::InvokeEventHandler(ServiceEvent* event) {
+ ASSERT(!event->IsPause()); // For pause events, call Pause instead.
+ Service::HandleEvent(event);
-
-static bool ServiceNeedsDebuggerEvent(DebuggerEvent::EventType type) {
- switch (type) {
- case DebuggerEvent::kBreakpointResolved:
- // kBreakpointResolved events are handled differently in the vm
- // service, so suppress them here.
- return false;
-
- case DebuggerEvent::kBreakpointReached:
- case DebuggerEvent::kExceptionThrown:
- case DebuggerEvent::kIsolateInterrupted:
- return (Service::debug_stream.enabled() ||
- FLAG_warn_on_pause_with_no_debugger);
-
- case DebuggerEvent::kIsolateCreated:
- case DebuggerEvent::kIsolateShutdown:
- return Service::isolate_stream.enabled();
-
- default:
- UNREACHABLE();
- return false;
- }
-}
-
-
-void Debugger::InvokeEventHandler(DebuggerEvent* event) {
- // Give the event to the Service first, as the debugger event handler
- // may go into a message loop and the Service will not.
- //
- // kBreakpointResolved events are handled differently in the vm
- // service, so suppress them here.
- if (ServiceNeedsDebuggerEvent(event->type())) {
- ServiceEvent service_event(event);
- Service::HandleEvent(&service_event);
- }
-
- {
+ // Call the embedder's event handler, if it exists.
+ if (event_handler_ != NULL) {
TransitionVMToNative transition(Thread::Current());
- if ((FLAG_steal_breakpoints || (event_handler_ == NULL)) &&
- event->IsPauseEvent()) {
- // We allow the embedder's default breakpoint handler to be overridden.
- isolate_->PauseEventHandler();
- } else if (event_handler_ != NULL) {
- (*event_handler_)(event);
- }
- }
-
- if (ServiceNeedsDebuggerEvent(event->type()) && event->IsPauseEvent()) {
- // If we were paused, notify the service that we have resumed.
- const Error& error =
- Error::Handle(Thread::Current()->sticky_error());
- ASSERT(error.IsNull() ||
- error.IsUnwindError() ||
- error.IsUnhandledException());
-
- // Only send a resume event when the isolate is not unwinding.
- if (!error.IsUnwindError()) {
- ServiceEvent service_event(event->isolate(), ServiceEvent::kResume);
- service_event.set_top_frame(event->top_frame());
- Service::HandleEvent(&service_event);
- }
+ (*event_handler_)(event);
}
}
-void Debugger::SignalIsolateEvent(DebuggerEvent::EventType type) {
- if (HasAnyEventHandler()) {
- DebuggerEvent event(isolate_, type);
- ASSERT(event.isolate_id() != ILLEGAL_ISOLATE_ID);
- if (type == DebuggerEvent::kIsolateInterrupted) {
- DebuggerStackTrace* trace = CollectStackTrace();
- if (trace->Length() > 0) {
- event.set_top_frame(trace->FrameAt(0));
- }
- ASSERT(stack_trace_ == NULL);
- stack_trace_ = trace;
- resume_action_ = kContinue;
- Pause(&event);
- HandleSteppingRequest(trace);
- stack_trace_ = NULL;
- } else {
- InvokeEventHandler(&event);
- }
+RawError* Debugger::PauseInterrupted() {
+ if (ignore_breakpoints_ || IsPaused()) {
+ // We don't let the isolate get interrupted if we are already
+ // paused or ignoring breakpoints.
+ return Error::null();
}
-}
-
-
-RawError* Debugger::SignalIsolateInterrupted() {
- if (HasDebugEventHandler()) {
- SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted);
+ ServiceEvent event(isolate_, ServiceEvent::kPauseInterrupted);
+ DebuggerStackTrace* trace = CollectStackTrace();
+ if (trace->Length() > 0) {
+ event.set_top_frame(trace->FrameAt(0));
}
+ ASSERT(stack_trace_ == NULL);
+ stack_trace_ = trace;
+ resume_action_ = kContinue;
+ Pause(&event);
+ HandleSteppingRequest(trace);
+ stack_trace_ = NULL;
// If any error occurred while in the debug message loop, return it here.
const Error& error = Error::Handle(Thread::Current()->sticky_error());
@@ -380,14 +317,14 @@
}
-// The vm service handles breakpoint notifications in a different way
-// than the regular debugger breakpoint notifications.
-static void SendServiceBreakpointEvent(ServiceEvent::EventKind kind,
- Breakpoint* bpt) {
- if (Service::debug_stream.enabled()) {
- ServiceEvent service_event(Isolate::Current(), kind);
- service_event.set_breakpoint(bpt);
- Service::HandleEvent(&service_event);
+void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind,
+ Breakpoint* bpt) {
+ if (NeedsDebugEvents()) {
+ // TODO(turnidge): Currently we send single-shot breakpoint events
+ // to the vm service. Do we want to change this?
+ ServiceEvent event(isolate_, kind);
+ event.set_breakpoint(bpt);
+ InvokeEventHandler(&event);
}
}
@@ -397,11 +334,7 @@
set_breakpoints(bpt);
dbg->SyncBreakpointLocation(this);
-
- if (IsResolved()) {
- dbg->SignalBpResolved(bpt);
- }
- SendServiceBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
+ dbg->SendBreakpointEvent(ServiceEvent::kBreakpointAdded, bpt);
}
@@ -1270,7 +1203,6 @@
: isolate_(NULL),
isolate_id_(ILLEGAL_ISOLATE_ID),
initialized_(false),
- creation_message_sent_(false),
next_id_(1),
latent_locations_(NULL),
breakpoint_locations_(NULL),
@@ -1322,10 +1254,9 @@
bpt->Disable();
delete bpt;
}
- // Signal isolate shutdown event, but only if we previously sent the creation
- // event.
- if (creation_message_sent_) {
- SignalIsolateEvent(DebuggerEvent::kIsolateShutdown);
+ if (NeedsIsolateEvents()) {
+ ServiceEvent event(isolate_, ServiceEvent::kIsolateExit);
+ InvokeEventHandler(&event);
}
}
@@ -1451,15 +1382,6 @@
}
-void Debugger::SignalBpResolved(Breakpoint* bpt) {
- if (HasDebugEventHandler() && !bpt->IsSingleShot()) {
- DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved);
- event.set_breakpoint(bpt);
- InvokeEventHandler(&event);
- }
-}
-
-
ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate,
uword pc,
StackFrame* frame,
@@ -1667,7 +1589,7 @@
}
-void Debugger::SignalExceptionThrown(const Instance& exc) {
+void Debugger::PauseException(const Instance& exc) {
// We ignore this exception event when the VM is executing code invoked
// by the debugger to evaluate variables values, when we see a nested
// breakpoint or exception event, or if the debugger is not
@@ -1681,7 +1603,7 @@
if (!ShouldPauseOnException(stack_trace, exc)) {
return;
}
- DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown);
+ ServiceEvent event(isolate_, ServiceEvent::kPauseException);
event.set_exception(&exc);
if (stack_trace->Length() > 0) {
event.set_top_frame(stack_trace->FrameAt(0));
@@ -2236,6 +2158,11 @@
Breakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
intptr_t line_number) {
+ // Prevent future tests from calling this function in the wrong
+ // execution state. If you hit this assert, consider using
+ // Dart_SetBreakpoint instead.
+ ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM);
+
BreakpointLocation* loc =
BreakpointLocationAtLineCol(script_url, line_number, -1 /* no column */);
if (loc != NULL) {
@@ -2248,6 +2175,11 @@
Breakpoint* Debugger::SetBreakpointAtLineCol(const String& script_url,
intptr_t line_number,
intptr_t column_number) {
+ // Prevent future tests from calling this function in the wrong
+ // execution state. If you hit this assert, consider using
+ // Dart_SetBreakpoint instead.
+ ASSERT(Thread::Current()->execution_state() == Thread::kThreadInVM);
+
BreakpointLocation* loc = BreakpointLocationAtLineCol(script_url,
line_number,
column_number);
@@ -2558,23 +2490,52 @@
}
-void Debugger::Pause(DebuggerEvent* event) {
- ASSERT(!IsPaused()); // No recursive pausing.
+void Debugger::Pause(ServiceEvent* event) {
+ ASSERT(event->IsPause()); // Should call InvokeEventHandler instead.
+ ASSERT(!ignore_breakpoints_); // We shouldn't get here when ignoring bpts.
+ ASSERT(!IsPaused()); // No recursive pausing.
ASSERT(obj_cache_ == NULL);
pause_event_ = event;
pause_event_->UpdateTimestamp();
obj_cache_ = new RemoteObjectCache(64);
- // We are about to invoke the debuggers event handler. Disable interrupts
- // for this thread while waiting for debug commands over the service protocol.
+ // We are about to invoke the debugger's event handler. Disable
+ // interrupts for this thread while waiting for debug commands over
+ // the service protocol.
{
Thread* thread = Thread::Current();
DisableThreadInterruptsScope dtis(thread);
TimelineDurationScope tds(thread,
Timeline::GetDebuggerStream(),
"Debugger Pause");
- InvokeEventHandler(event);
+
+ // Send the pause event.
+ Service::HandleEvent(event);
+
+ {
+ TransitionVMToNative transition(Thread::Current());
+ if (FLAG_steal_breakpoints || (event_handler_ == NULL)) {
+ // We allow the embedder's default breakpoint handler to be overridden.
+ isolate_->PauseEventHandler();
+ } else if (event_handler_ != NULL) {
+ (*event_handler_)(event);
+ }
+ }
+
+ // Notify the service that we have resumed.
+ const Error& error =
+ Error::Handle(Thread::Current()->sticky_error());
+ ASSERT(error.IsNull() ||
+ error.IsUnwindError() ||
+ error.IsUnhandledException());
+
+ // Only send a resume event when the isolate is not unwinding.
+ if (!error.IsUnwindError()) {
+ ServiceEvent resume_event(event->isolate(), ServiceEvent::kResume);
+ resume_event.set_top_frame(event->top_frame());
+ Service::HandleEvent(&resume_event);
+ }
}
pause_event_ = NULL;
@@ -2657,7 +2618,7 @@
bpt = NULL;
}
- DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached);
+ ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint);
event.set_top_frame(top_frame);
event.set_breakpoint(bpt);
event.set_at_async_jump(IsAtAsyncJump(top_frame));
@@ -2684,7 +2645,7 @@
return false;
}
-RawError* Debugger::DebuggerStepCallback() {
+RawError* Debugger::PauseStepping() {
ASSERT(isolate_->single_step());
// Don't pause recursively.
if (IsPaused()) {
@@ -2741,7 +2702,7 @@
ASSERT(stack_trace_ == NULL);
stack_trace_ = CollectStackTrace();
// If this step callback is part of stepping over an await statement,
- // we saved the synthetic async breakpoint in SignalBpReached. We report
+ // we saved the synthetic async breakpoint in PauseBreakpoint. We report
// that we are paused at that breakpoint and then delete it after continuing.
SignalPausedEvent(frame, synthetic_async_breakpoint_);
if (synthetic_async_breakpoint_ != NULL) {
@@ -2758,7 +2719,7 @@
}
-RawError* Debugger::SignalBpReached() {
+RawError* Debugger::PauseBreakpoint() {
// We ignore this breakpoint when the VM is executing code invoked
// by the debugger to evaluate variables values, or when we see a nested
// breakpoint or exception event.
@@ -2878,7 +2839,7 @@
}
-void Debugger::BreakHere(const String& msg) {
+void Debugger::PauseDeveloper(const String& msg) {
// We ignore this breakpoint when the VM is executing code invoked
// by the debugger to evaluate variables values, or when we see a nested
// breakpoint or exception event.
@@ -2886,7 +2847,7 @@
return;
}
- if (!HasDebugEventHandler()) {
+ if (!NeedsDebugEvents()) {
OS::Print("Hit debugger!");
}
@@ -2897,9 +2858,9 @@
// TODO(johnmccutchan): Send |msg| to Observatory.
- // We are in the native call to Debugger_breakHere or Debugger_breakHereIf,
- // the developer gets a better experience by not seeing this call. To
- // accomplish this, we continue execution until the call exits (step out).
+ // We are in the native call to Developer_debugger. the developer
+ // gets a better experience by not seeing this call. To accomplish
+ // this, we continue execution until the call exits (step out).
SetStepOut();
HandleSteppingRequest(stack_trace_);
@@ -2914,19 +2875,17 @@
isolate_ = isolate;
// Use the isolate's control port as the isolate_id for debugging.
- // This port will be used as a unique ID to represent the isolate in the
- // debugger wire protocol messages.
+ // This port will be used as a unique ID to represent the isolate in
+ // the debugger embedder api.
isolate_id_ = isolate_->main_port();
initialized_ = true;
}
void Debugger::NotifyIsolateCreated() {
- // Signal isolate creation event.
- if ((isolate_ != Dart::vm_isolate()) &&
- !ServiceIsolate::IsServiceIsolateDescendant(isolate_)) {
- SignalIsolateEvent(DebuggerEvent::kIsolateCreated);
- creation_message_sent_ = true;
+ if (NeedsIsolateEvents()) {
+ ServiceEvent event(isolate_, ServiceEvent::kIsolateStart);
+ InvokeEventHandler(&event);
}
}
@@ -3028,8 +2987,7 @@
requested_end_pos.ToCString(),
loc->requested_column_number());
}
- SignalBpResolved(bpt);
- SendServiceBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
+ SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
bpt = bpt->next();
}
}
@@ -3218,12 +3176,10 @@
prev_bpt->set_next(curr_bpt->next());
}
- SendServiceBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt);
+ SendBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt);
// Remove references from the current debugger pause event.
- if (pause_event_ != NULL &&
- pause_event_->type() == DebuggerEvent::kBreakpointReached &&
- pause_event_->breakpoint() == curr_bpt) {
+ if (pause_event_ != NULL && pause_event_->breakpoint() == curr_bpt) {
pause_event_->set_breakpoint(NULL);
}
break;
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index ab83339..1d7e1ce 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -9,6 +9,7 @@
#include "vm/object.h"
#include "vm/port.h"
+#include "vm/service_event.h"
namespace dart {
@@ -369,105 +370,9 @@
};
-class DebuggerEvent {
- public:
- enum EventType {
- kBreakpointReached = 1,
- kBreakpointResolved = 2,
- kExceptionThrown = 3,
- kIsolateCreated = 4,
- kIsolateShutdown = 5,
- kIsolateInterrupted = 6,
- };
-
- explicit DebuggerEvent(Isolate* isolate, EventType event_type)
- : isolate_(isolate),
- type_(event_type),
- top_frame_(NULL),
- breakpoint_(NULL),
- exception_(NULL),
- async_continuation_(NULL),
- at_async_jump_(false),
- timestamp_(-1) {}
-
- Isolate* isolate() const { return isolate_; }
-
- EventType type() const { return type_; }
-
- bool IsPauseEvent() const {
- return (type_ == kBreakpointReached ||
- type_ == kIsolateInterrupted ||
- type_ == kExceptionThrown);
- }
-
- ActivationFrame* top_frame() const {
- ASSERT(IsPauseEvent());
- return top_frame_;
- }
- void set_top_frame(ActivationFrame* frame) {
- ASSERT(IsPauseEvent());
- top_frame_ = frame;
- }
-
- Breakpoint* breakpoint() const {
- ASSERT(type_ == kBreakpointReached || type_ == kBreakpointResolved);
- return breakpoint_;
- }
- void set_breakpoint(Breakpoint* bpt) {
- ASSERT(type_ == kBreakpointReached || type_ == kBreakpointResolved);
- breakpoint_ = bpt;
- }
-
- const Object* exception() const {
- ASSERT(type_ == kExceptionThrown);
- return exception_;
- }
- void set_exception(const Object* exception) {
- ASSERT(type_ == kExceptionThrown);
- exception_ = exception;
- }
-
- const Object* async_continuation() const {
- ASSERT(type_ == kBreakpointReached);
- return async_continuation_;
- }
- void set_async_continuation(const Object* closure) {
- ASSERT(type_ == kBreakpointReached);
- async_continuation_ = closure;
- }
-
- bool at_async_jump() const {
- return at_async_jump_;
- }
- void set_at_async_jump(bool value) {
- at_async_jump_ = value;
- }
-
- Dart_Port isolate_id() const {
- return isolate_->main_port();
- }
-
- void UpdateTimestamp();
-
- int64_t timestamp() const {
- return timestamp_;
- }
-
- private:
- Isolate* isolate_;
- EventType type_;
- ActivationFrame* top_frame_;
- Breakpoint* breakpoint_;
- const Object* exception_;
- const Object* async_continuation_;
- bool at_async_jump_;
- int64_t timestamp_;
-};
-
-
class Debugger {
public:
- typedef void EventHandler(DebuggerEvent* event);
+ typedef void EventHandler(ServiceEvent* event);
Debugger();
~Debugger();
@@ -525,7 +430,7 @@
// is not paused, this returns NULL. Note that the debugger can be
// paused for breakpoints, isolate interruption, and (sometimes)
// exceptions.
- const DebuggerEvent* PauseEvent() const { return pause_event_; }
+ const ServiceEvent* PauseEvent() const { return pause_event_; }
void SetExceptionPauseInfo(Dart_ExceptionPauseInfo pause_info);
Dart_ExceptionPauseInfo GetExceptionPauseInfo() const;
@@ -580,14 +485,21 @@
RawObject* GetStaticField(const Class& cls,
const String& field_name);
- RawError* SignalBpReached();
- RawError* DebuggerStepCallback();
- RawError* SignalIsolateInterrupted();
+ // Pause execution for a breakpoint. Called from generated code.
+ RawError* PauseBreakpoint();
- void BreakHere(const String& msg);
+ // Pause execution due to stepping. Called from generated code.
+ RawError* PauseStepping();
- void SignalExceptionThrown(const Instance& exc);
- void SignalIsolateEvent(DebuggerEvent::EventType type);
+ // Pause execution due to isolate interrupt.
+ RawError* PauseInterrupted();
+
+ // Pause execution due to an uncaught exception.
+ void PauseException(const Instance& exc);
+
+ // Pause execution due to a call to the debugger() function from
+ // Dart.
+ void PauseDeveloper(const String& msg);
RawCode* GetPatchedStubAddress(uword breakpoint_address);
@@ -606,9 +518,12 @@
kSingleStep
};
- static bool HasAnyEventHandler();
- static bool HasDebugEventHandler();
- void InvokeEventHandler(DebuggerEvent* event);
+ bool NeedsIsolateEvents();
+ bool NeedsDebugEvents();
+ void InvokeEventHandler(ServiceEvent* event);
+
+ void SendBreakpointEvent(ServiceEvent::EventKind kind, Breakpoint* bpt);
+
bool IsAtAsyncJump(ActivationFrame* top_frame);
void FindCompiledFunctions(const Script& script,
TokenPosition start_pos,
@@ -655,7 +570,6 @@
StackFrame* frame,
const Code& code);
static DebuggerStackTrace* CollectStackTrace();
- void SignalBpResolved(Breakpoint *bpt);
void SignalPausedEvent(ActivationFrame* top_frame,
Breakpoint* bpt);
@@ -671,7 +585,7 @@
// Handles any events which pause vm execution. Breakpoints,
// interrupts, etc.
- void Pause(DebuggerEvent* event);
+ void Pause(ServiceEvent* event);
void HandleSteppingRequest(DebuggerStackTrace* stack_trace,
bool skip_next_step = false);
@@ -679,7 +593,6 @@
Isolate* isolate_;
Dart_Port isolate_id_; // A unique ID for the isolate in the debugger.
bool initialized_;
- bool creation_message_sent_; // The creation message has been sent.
// ID number generator.
intptr_t next_id_;
@@ -700,7 +613,7 @@
// is not paused, this is NULL. Note that the debugger can be
// paused for breakpoints, isolate interruption, and (sometimes)
// exceptions.
- DebuggerEvent* pause_event_;
+ ServiceEvent* pause_event_;
// An id -> object map. Valid only while IsPaused().
RemoteObjectCache* obj_cache_;
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 4bfcae1..957bd6f 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -110,13 +110,13 @@
static Dart_IsolateEventHandler* isolate_event_handler = NULL;
-static void DebuggerEventHandler(DebuggerEvent* event) {
+static void DebuggerEventHandler(ServiceEvent* event) {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
ASSERT(isolate != NULL);
Dart_EnterScope();
Dart_IsolateId isolate_id = isolate->debugger()->GetIsolateId();
- if (event->type() == DebuggerEvent::kBreakpointReached) {
+ if (event->kind() == ServiceEvent::kPauseBreakpoint) {
if (paused_event_handler != NULL) {
Dart_CodeLocation location;
ActivationFrame* top_frame = event->top_frame();
@@ -131,10 +131,13 @@
}
(*paused_event_handler)(isolate_id, bp_id, location);
}
- } else if (event->type() == DebuggerEvent::kBreakpointResolved) {
- if (bp_resolved_handler != NULL) {
- Breakpoint* bpt = event->breakpoint();
- ASSERT(bpt != NULL);
+ } else if (event->kind() == ServiceEvent::kBreakpointAdded ||
+ event->kind() == ServiceEvent::kBreakpointResolved) {
+ Breakpoint* bpt = event->breakpoint();
+ ASSERT(bpt != NULL);
+ if (bp_resolved_handler != NULL &&
+ bpt->bpt_location()->IsResolved() &&
+ !bpt->IsSingleShot()) {
Dart_CodeLocation location;
Zone* zone = thread->zone();
Library& library = Library::Handle(zone);
@@ -146,7 +149,9 @@
location.token_pos = token_pos.Pos();
(*bp_resolved_handler)(isolate_id, bpt->id(), location);
}
- } else if (event->type() == DebuggerEvent::kExceptionThrown) {
+ } else if (event->kind() == ServiceEvent::kBreakpointRemoved) {
+ // Ignore.
+ } else if (event->kind() == ServiceEvent::kPauseException) {
if (exc_thrown_handler != NULL) {
Dart_Handle exception =
Api::NewHandle(thread, event->exception()->raw());
@@ -154,15 +159,15 @@
reinterpret_cast<Dart_StackTrace>(isolate->debugger()->StackTrace());
(*exc_thrown_handler)(isolate_id, exception, trace);
}
- } else if (event->type() == DebuggerEvent::kIsolateCreated) {
+ } else if (event->kind() == ServiceEvent::kIsolateStart) {
if (isolate_event_handler != NULL) {
(*isolate_event_handler)(event->isolate_id(), kCreated);
}
- } else if (event->type() == DebuggerEvent::kIsolateInterrupted) {
+ } else if (event->kind() == ServiceEvent::kPauseInterrupted) {
if (isolate_event_handler != NULL) {
(*isolate_event_handler)(event->isolate_id(), kInterrupted);
}
- } else if (event->type() == DebuggerEvent::kIsolateShutdown) {
+ } else if (event->kind() == ServiceEvent::kIsolateExit) {
if (isolate_event_handler != NULL) {
(*isolate_event_handler)(event->isolate_id(), kShutdown);
}
diff --git a/runtime/vm/debugger_test.cc b/runtime/vm/debugger_test.cc
index ffe3241..8b8b84e 100644
--- a/runtime/vm/debugger_test.cc
+++ b/runtime/vm/debugger_test.cc
@@ -10,6 +10,8 @@
#ifndef PRODUCT
+DECLARE_FLAG(bool, remove_script_timestamps_for_test);
+
// Search for the formatted string in buffer.
//
// TODO(turnidge): This function obscures the line number of failing
@@ -38,6 +40,7 @@
" x.add('too');\n"
" return x.toString();\n"
"}\n";
+ SetFlagScope<bool> sfs(&FLAG_remove_script_timestamps_for_test, true);
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
EXPECT_VALID(lib);
Library& vmlib = Library::Handle();
@@ -46,7 +49,6 @@
Isolate* isolate = Isolate::Current();
Debugger* debugger = isolate->debugger();
- const String& url = String::Handle(String::New(TestCase::url()));
// Empty case.
{
@@ -59,8 +61,9 @@
}
// Test with a couple of breakpoints.
- debugger->SetBreakpointAtLine(url, 2);
- debugger->SetBreakpointAtLine(url, 3);
+ Dart_Handle url = NewString(TestCase::url());
+ EXPECT_VALID(Dart_SetBreakpoint(url, 2));
+ EXPECT_VALID(Dart_SetBreakpoint(url, 3));
{
JSONStream js;
{
@@ -73,14 +76,14 @@
"\"breakpointNumber\":2,\"resolved\":false,"
"\"location\":{\"type\":\"UnresolvedSourceLocation\","
"\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
- "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
+ "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\\/0\","
"\"uri\":\"test-lib\","
"\"_kind\":\"script\"},\"line\":3}},"
"{\"type\":\"Breakpoint\",\"fixedId\":true,\"id\":\"breakpoints\\/1\","
"\"breakpointNumber\":1,\"resolved\":false,"
"\"location\":{\"type\":\"UnresolvedSourceLocation\","
"\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
- "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
+ "\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\\/0\","
"\"uri\":\"test-lib\","
"\"_kind\":\"script\"},\"line\":2}}]",
vmlib.index(), vmlib.index());
@@ -98,9 +101,9 @@
// The debugger knows that it is paused, and why.
EXPECT(debugger->IsPaused());
- const DebuggerEvent* event = debugger->PauseEvent();
+ const ServiceEvent* event = debugger->PauseEvent();
EXPECT(event != NULL);
- EXPECT(event->type() == DebuggerEvent::kBreakpointReached);
+ EXPECT(event->kind() == ServiceEvent::kPauseBreakpoint);
saw_paused_event = true;
}
@@ -118,7 +121,6 @@
Isolate* isolate = Isolate::Current();
Debugger* debugger = isolate->debugger();
- const String& url = String::Handle(String::New(TestCase::url()));
// No pause event.
EXPECT(!debugger->IsPaused());
@@ -128,7 +130,7 @@
Dart_SetPausedEventHandler(InspectPausedEvent);
// Set a breakpoint and run.
- debugger->SetBreakpointAtLine(url, 2);
+ EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), 2));
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 614b976..1d89239 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -141,7 +141,7 @@
if (FLAG_support_timeline && (deopt_start_micros_ != 0)) {
TimelineStream* compiler_stream = Timeline::GetCompilerStream();
ASSERT(compiler_stream != NULL);
- if (compiler_stream->Enabled()) {
+ if (compiler_stream->enabled()) {
// Allocate all Dart objects needed before calling StartEvent,
// which blocks safe points until Complete is called.
const Code& code = Code::Handle(zone(), code_);
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 437bee8..2b0c103 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -114,12 +114,14 @@
// formatting, except for register alias pp (r5).
// See for example the command "objdump -d <binary file>".
static const char* reg_names[kNumberOfCpuRegisters] = {
-#if defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_IOS)
"r0", "r1", "r2", "r3", "r4", "pp", "r6", "fp",
"r8", "r9", "r10", "r11", "ip", "sp", "lr", "pc",
-#else
+#elif defined(TARGET_ABI_EABI)
"r0", "r1", "r2", "r3", "r4", "pp", "r6", "r7",
"r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc",
+#else
+#error Unknown ABI
#endif
};
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index a215851..2cb67e1 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -545,7 +545,7 @@
Isolate* isolate = thread->isolate();
if (exception.raw() != isolate->object_store()->out_of_memory() &&
exception.raw() != isolate->object_store()->stack_overflow()) {
- isolate->debugger()->SignalExceptionThrown(exception);
+ isolate->debugger()->PauseException(exception);
}
}
// Null object is a valid exception object.
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 13eeead..ee483ad 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -5,31 +5,39 @@
#ifndef VM_FLAG_LIST_H_
#define VM_FLAG_LIST_H_
+// Don't use USING_DBC outside of this file.
#if defined(TARGET_ARCH_DBC)
-#define USING_DBC 1
+#define USING_DBC true
#else
-#define USING_DBC 0
+#define USING_DBC false
+#endif
+
+// Don't use USING_MULTICORE outside of this file.
+#if defined(ARCH_IS_MULTI_CORE)
+#define USING_MULTICORE true
+#else
+#define USING_MULTICORE false
#endif
// List of all flags in the VM.
// Flags can be one of three categories:
// * P roduct flags: Can be set in any of the deployment modes, including in
// production.
-// * D ebug flags: Can only be set in debug VMs, which also have assertions
-// enabled.
// * R elease flags: Generally available flags except when building product.
+// * D ebug flags: Can only be set in debug VMs, which also have C++ assertions
+// enabled.
// * pre C ompile flags: Generally available flags except when building product
// or precompiled runtime.
//
// Usage:
// P(name, type, default_value, comment)
-// D(name, type, default_value, comment)
// R(name, product_value, type, default_value, comment)
+// D(name, type, default_value, comment)
// C(name, precompiled_value, product_value, type, default_value, comment)
#define FLAG_LIST(P, R, D, C) \
P(always_megamorphic_calls, bool, false, \
"Instance call always as megamorphic.") \
-P(background_compilation, bool, true, \
+P(background_compilation, bool, USING_MULTICORE, \
"Run optimizing compilation in background") \
R(background_compilation_stop_alot, false, bool, false, \
"Stress test system: stop background compiler often.") \
@@ -37,8 +45,10 @@
"Insert a one-time breakpoint at the entrypoint for all spawned isolates") \
C(collect_code, false, true, bool, true, \
"Attempt to GC infrequently used code.") \
-P(collect_dynamic_function_names, bool, false, \
+P(collect_dynamic_function_names, bool, true, \
"Collects all dynamic function names to identify unique targets") \
+R(concurrent_sweep, USING_MULTICORE, bool, USING_MULTICORE, \
+ "Concurrent sweep for old generation.") \
R(dedup_instructions, true, bool, false, \
"Canonicalize instructions when precompiling.") \
C(deoptimize_alot, false, false, bool, false, \
@@ -86,6 +96,11 @@
"Link native calls lazily") \
C(load_deferred_eagerly, true, true, bool, false, \
"Load deferred libraries eagerly.") \
+R(log_marker_tasks, false, bool, false, \
+ "Log debugging information for old gen GC marking tasks.") \
+R(marker_tasks, USING_MULTICORE ? 2 : 0, int, USING_MULTICORE ? 2 : 0, \
+ "The number of tasks to spawn during old gen GC marking (0 means " \
+ "perform all marking on main thread).") \
P(max_polymorphic_checks, int, 4, \
"Maximum number of polymorphic check, otherwise it is megamorphic.") \
P(max_equality_polymorphic_checks, int, 32, \
@@ -182,5 +197,4 @@
D(verify_on_transition, bool, false, \
"Verify on dart <==> VM.") \
-
#endif // VM_FLAG_LIST_H_
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index e2ba4bf..747094c 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -374,7 +374,7 @@
last_use_interval_ = first_use_interval_;
} else {
// Shrink the first use interval. It was optimistically expanded to
- // cover the the block from the start to the last use in the block.
+ // cover the block from the start to the last use in the block.
ASSERT(first_use_interval_->start_ <= pos);
first_use_interval_->start_ = pos;
}
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 71fcec4..93225db 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -62,6 +62,7 @@
DECLARE_FLAG(int, inlining_caller_size_threshold);
DECLARE_FLAG(int, inlining_constant_arguments_max_size_threshold);
DECLARE_FLAG(int, inlining_constant_arguments_min_size_threshold);
+DECLARE_FLAG(int, reload_every);
static void PrecompilationModeHandler(bool value) {
if (value) {
@@ -85,7 +86,6 @@
FLAG_background_compilation = false;
FLAG_always_megamorphic_calls = true;
- FLAG_collect_dynamic_function_names = true;
FLAG_fields_may_be_reset = true;
FLAG_ic_range_profiling = false;
FLAG_interpret_irregexp = true;
@@ -280,11 +280,6 @@
void FlowGraphCompiler::InitCompiler() {
-#ifndef PRODUCT
- TimelineDurationScope tds(thread(),
- Timeline::GetCompilerStream(),
- "InitCompiler");
-#endif // !PRODUCT
pc_descriptors_list_ = new(zone()) DescriptorList(64);
exception_handlers_list_ = new(zone()) ExceptionHandlerList();
block_info_.Clear();
@@ -359,7 +354,9 @@
bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const {
- if (FLAG_stacktrace_every > 0 || FLAG_deoptimize_every > 0) {
+ if ((FLAG_stacktrace_every > 0) ||
+ (FLAG_deoptimize_every > 0) ||
+ (FLAG_reload_every > 0)) {
return true;
}
if (FLAG_stacktrace_filter != NULL &&
@@ -1197,7 +1194,7 @@
return;
}
ASSERT(!ic_data.IsNull());
- if (is_optimizing() && (ic_data.NumberOfUsedChecks() == 0)) {
+ if (is_optimizing() && (ic_data_in.NumberOfUsedChecks() == 0)) {
// Emit IC call that will count and thus may need reoptimization at
// function entry.
ASSERT(may_reoptimize() || flow_graph().IsCompiledForOsr());
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 34172891..269e668 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -445,8 +445,8 @@
// R1: instance class.
// Check immediate superclass equality.
__ ldr(R2, FieldAddress(R1, Class::super_type_offset()));
- __ ldr(R2, FieldAddress(R2, Type::type_class_offset()));
- __ CompareObject(R2, type_class);
+ __ ldr(R2, FieldAddress(R2, Type::type_class_id_offset()));
+ __ CompareImmediate(R2, Smi::RawValue(type_class.id()));
__ b(is_instance_lbl, EQ);
const Register kTypeArgumentsReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 07cff9e..d0c066e 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -437,8 +437,8 @@
// R1: instance class.
// Check immediate superclass equality.
__ LoadFieldFromOffset(R2, R1, Class::super_type_offset());
- __ LoadFieldFromOffset(R2, R2, Type::type_class_offset());
- __ CompareObject(R2, type_class);
+ __ LoadFieldFromOffset(R2, R2, Type::type_class_id_offset());
+ __ CompareImmediate(R2, Smi::RawValue(type_class.id()));
__ b(is_instance_lbl, EQ);
const Register kTypeArgumentsReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 30cff6b2..64d92a9 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -446,8 +446,8 @@
// ECX: instance class.
// Check immediate superclass equality.
__ movl(EDI, FieldAddress(ECX, Class::super_type_offset()));
- __ movl(EDI, FieldAddress(EDI, Type::type_class_offset()));
- __ CompareObject(EDI, type_class);
+ __ movl(EDI, FieldAddress(EDI, Type::type_class_id_offset()));
+ __ cmpl(EDI, Immediate(Smi::RawValue(type_class.id())));
__ j(EQUAL, is_instance_lbl);
const Register kTypeArgumentsReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index c63f850..2376554 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -434,8 +434,9 @@
// T0: instance class.
// Check immediate superclass equality.
__ lw(T0, FieldAddress(T0, Class::super_type_offset()));
- __ lw(T0, FieldAddress(T0, Type::type_class_offset()));
- __ BranchEqual(T0, type_class, is_instance_lbl);
+ __ lw(T0, FieldAddress(T0, Type::type_class_id_offset()));
+ __ BranchEqual(T0, Immediate(Smi::RawValue(type_class.id())),
+ is_instance_lbl);
const Register kTypeArgumentsReg = kNoRegister;
const Register kTempReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index c8ce4f5..b76da0b 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -442,8 +442,8 @@
// R10: instance class.
// Check immediate superclass equality.
__ movq(R13, FieldAddress(R10, Class::super_type_offset()));
- __ movq(R13, FieldAddress(R13, Type::type_class_offset()));
- __ CompareObject(R13, type_class);
+ __ movq(R13, FieldAddress(R13, Type::type_class_id_offset()));
+ __ CompareImmediate(R13, Immediate(Smi::RawValue(type_class.id())));
__ j(EQUAL, is_instance_lbl);
const Register kTypeArgumentsReg = kNoRegister;
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index c360c98..e92bc3f 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -1418,7 +1418,7 @@
// Convert the old target entry to a new join entry.
TargetEntryInstr* old_target =
inlined_entries_[i]->AsGraphEntry()->normal_entry();
- // Unuse all inputs in the the old graph entry since it is not part of
+ // Unuse all inputs in the old graph entry since it is not part of
// the graph anymore. A new target be created instead.
inlined_entries_[i]->AsGraphEntry()->UnuseAllInputs();
diff --git a/runtime/vm/flow_graph_range_analysis_test.cc b/runtime/vm/flow_graph_range_analysis_test.cc
index 8f91943..7ebd6b4 100644
--- a/runtime/vm/flow_graph_range_analysis_test.cc
+++ b/runtime/vm/flow_graph_range_analysis_test.cc
@@ -80,7 +80,7 @@
RangeBoundary(kSmiMin),
RangeBoundary(kSmiMax));
TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
- RangeBoundary(-1 << 30),
+ RangeBoundary(-(1 << 30)),
RangeBoundary(1 << 30));
} else {
TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index d0391db..af0a03fc 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -947,13 +947,18 @@
abstract_type = &AbstractType::ZoneHandle(field.type());
}
ASSERT(field.is_static());
- if (field.is_final() && !FLAG_fields_may_be_reset) {
- const Instance& obj = Instance::Handle(field.StaticValue());
- if ((obj.raw() != Object::sentinel().raw()) &&
- (obj.raw() != Object::transition_sentinel().raw()) &&
- !obj.IsNull()) {
- is_nullable = CompileType::kNonNullable;
- cid = obj.GetClassId();
+ if (field.is_final()) {
+ if (!FLAG_fields_may_be_reset) {
+ const Instance& obj = Instance::Handle(field.StaticValue());
+ if ((obj.raw() != Object::sentinel().raw()) &&
+ (obj.raw() != Object::transition_sentinel().raw()) &&
+ !obj.IsNull()) {
+ is_nullable = CompileType::kNonNullable;
+ cid = obj.GetClassId();
+ }
+ } else if (field.guarded_cid() != kIllegalCid) {
+ cid = field.guarded_cid();
+ if (!IsNullableCid(cid)) is_nullable = CompileType::kNonNullable;
}
}
if (Field::IsExternalizableCid(cid)) {
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index cc5db20..2c2643e 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -25,12 +25,6 @@
namespace dart {
-DEFINE_FLAG(int, marker_tasks, 2,
- "The number of tasks to spawn during old gen GC marking (0 means "
- "perform all marking on main thread).");
-DEFINE_FLAG(bool, log_marker_tasks, false,
- "Log debugging information for old gen GC marking tasks.");
-
class DelaySet {
private:
typedef std::multimap<RawObject*, RawWeakProperty*> Map;
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index c5a7693..6131bf3 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -366,8 +366,11 @@
int pretenure_policy_;
+ friend class Become; // VisitObjectPointers
friend class ServiceEvent;
friend class PageSpace; // VerifyGC
+ friend class IsolateReloadContext; // VisitObjects
+
DISALLOW_COPY_AND_ASSIGN(Heap);
};
diff --git a/runtime/vm/heap_test.cc b/runtime/vm/heap_test.cc
index ad01502..1d55a13 100644
--- a/runtime/vm/heap_test.cc
+++ b/runtime/vm/heap_test.cc
@@ -5,6 +5,7 @@
#include "platform/globals.h"
#include "platform/assert.h"
+#include "vm/become.h"
#include "vm/dart_api_impl.h"
#include "vm/globals.h"
#include "vm/heap.h"
@@ -12,8 +13,6 @@
namespace dart {
-DECLARE_FLAG(int, marker_tasks);
-
TEST_CASE(OldGC) {
const char* kScriptChars =
"main() {\n"
@@ -32,7 +31,7 @@
heap->CollectGarbage(Heap::kOld);
}
-
+#if !defined(PRODUCT)
TEST_CASE(OldGC_Unsync) {
FLAG_marker_tasks = 0;
const char* kScriptChars =
@@ -51,7 +50,7 @@
Heap* heap = isolate->heap();
heap->CollectGarbage(Heap::kOld);
}
-
+#endif
TEST_CASE(LargeSweep) {
const char* kScriptChars =
@@ -289,4 +288,80 @@
EXPECT(heap->Contains(RawObject::ToAddr(obj.raw())));
}
-} // namespace dart.
+
+void TestBecomeForward(Heap::Space before_space, Heap::Space after_space) {
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+
+ const String& before_obj = String::Handle(String::New("old", before_space));
+ const String& after_obj = String::Handle(String::New("new", after_space));
+
+ EXPECT(before_obj.raw() != after_obj.raw());
+
+ // Allocate the arrays in old space to test the remembered set.
+ const Array& before = Array::Handle(Array::New(1, Heap::kOld));
+ before.SetAt(0, before_obj);
+ const Array& after = Array::Handle(Array::New(1, Heap::kOld));
+ after.SetAt(0, after_obj);
+
+ Become::ElementsForwardIdentity(before, after);
+
+ EXPECT(before_obj.raw() == after_obj.raw());
+
+ heap->CollectAllGarbage();
+
+ EXPECT(before_obj.raw() == after_obj.raw());
+}
+
+
+VM_TEST_CASE(BecomeFowardOldToOld) {
+ TestBecomeForward(Heap::kOld, Heap::kOld);
+}
+
+
+VM_TEST_CASE(BecomeFowardNewToNew) {
+ TestBecomeForward(Heap::kNew, Heap::kNew);
+}
+
+
+VM_TEST_CASE(BecomeFowardOldToNew) {
+ TestBecomeForward(Heap::kOld, Heap::kNew);
+}
+
+
+VM_TEST_CASE(BecomeFowardNewToOld) {
+ TestBecomeForward(Heap::kNew, Heap::kOld);
+}
+
+
+VM_TEST_CASE(BecomeForwardRememberedObject) {
+ Isolate* isolate = Isolate::Current();
+ Heap* heap = isolate->heap();
+
+ const String& new_element = String::Handle(String::New("new", Heap::kNew));
+ const String& old_element = String::Handle(String::New("old", Heap::kOld));
+ const Array& before_obj = Array::Handle(Array::New(1, Heap::kOld));
+ const Array& after_obj = Array::Handle(Array::New(1, Heap::kOld));
+ before_obj.SetAt(0, new_element);
+ after_obj.SetAt(0, old_element);
+ EXPECT(before_obj.raw()->IsRemembered());
+ EXPECT(!after_obj.raw()->IsRemembered());
+
+ EXPECT(before_obj.raw() != after_obj.raw());
+
+ const Array& before = Array::Handle(Array::New(1, Heap::kOld));
+ before.SetAt(0, before_obj);
+ const Array& after = Array::Handle(Array::New(1, Heap::kOld));
+ after.SetAt(0, after_obj);
+
+ Become::ElementsForwardIdentity(before, after);
+
+ EXPECT(before_obj.raw() == after_obj.raw());
+ EXPECT(!after_obj.raw()->IsRemembered());
+
+ heap->CollectAllGarbage();
+
+ EXPECT(before_obj.raw() == after_obj.raw());
+}
+
+} // namespace dart
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 3950f3e..66abf75 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -3083,28 +3083,7 @@
if (stub_entry != NULL) {
// We have a dedicated inline cache stub for this operation, add an
// an initial Smi/Smi check with count 0.
- ASSERT(call_ic_data->NumArgsTested() == 2);
- const String& name = String::Handle(zone, call_ic_data->target_name());
- const Class& smi_class = Class::Handle(zone, Smi::Class());
- const Function& smi_op_target = Function::Handle(zone,
- Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
- if (call_ic_data->NumberOfChecks() == 0) {
- GrowableArray<intptr_t> class_ids(2);
- class_ids.Add(kSmiCid);
- class_ids.Add(kSmiCid);
- call_ic_data->AddCheck(class_ids, smi_op_target);
- // 'AddCheck' sets the initial count to 1.
- call_ic_data->SetCountAt(0, 0);
- is_smi_two_args_op = true;
- } else if (call_ic_data->NumberOfChecks() == 1) {
- GrowableArray<intptr_t> class_ids(2);
- Function& target = Function::Handle(zone);
- call_ic_data->GetCheckAt(0, &class_ids, &target);
- if ((target.raw() == smi_op_target.raw()) &&
- (class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
- is_smi_two_args_op = true;
- }
- }
+ is_smi_two_args_op = call_ic_data->AddSmiSmiCheckForFastSmiStubs();
}
if (is_smi_two_args_op) {
ASSERT(ArgumentCount() == 2);
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index a7f522d..a7f3d7f 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -2586,7 +2586,7 @@
virtual void InferRange(RangeAnalysis* analysis, Range* range);
// Constraints for branches have their target block stored in order
- // to find the the comparsion that generated the constraint:
+ // to find the comparison that generated the constraint:
// target->predecessor->last_instruction->comparison.
void set_target(TargetEntryInstr* target) {
target_ = target;
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc
index 7c87f8e..c4399e0 100644
--- a/runtime/vm/intermediate_language_dbc.cc
+++ b/runtime/vm/intermediate_language_dbc.cc
@@ -60,7 +60,7 @@
M(ShiftMintOp) \
M(UnaryMintOp) \
M(StringToCharCode) \
- M(StringFromCharCode) \
+ M(OneByteStringFromCharCode) \
M(InvokeMathCFunction) \
M(MergedMath) \
M(GuardFieldClass) \
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 27631b3..bdd7c5c 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -588,7 +588,9 @@
bool Intrinsifier::Build_Float64ArraySetIndexed(FlowGraph* flow_graph) {
- if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false;
+ if (!FlowGraphCompiler::SupportsUnboxedDoubles()) {
+ return false;
+ }
GraphEntryInstr* graph_entry = flow_graph->graph_entry();
TargetEntryInstr* normal_entry = graph_entry->normal_entry();
@@ -634,7 +636,9 @@
bool Intrinsifier::Build_Float64ArrayGetIndexed(FlowGraph* flow_graph) {
- if (!FlowGraphCompiler::SupportsUnboxedDoubles()) return false;
+ if (!FlowGraphCompiler::SupportsUnboxedDoubles()) {
+ return false;
+ }
GraphEntryInstr* graph_entry = flow_graph->graph_entry();
TargetEntryInstr* normal_entry = graph_entry->normal_entry();
@@ -783,7 +787,10 @@
static bool BuildFloat32x4Shuffle(FlowGraph* flow_graph,
MethodRecognizer::Kind kind) {
- if (!FlowGraphCompiler::SupportsUnboxedSimd128()) return false;
+ if (!FlowGraphCompiler::SupportsUnboxedDoubles() ||
+ !FlowGraphCompiler::SupportsUnboxedSimd128()) {
+ return false;
+ }
GraphEntryInstr* graph_entry = flow_graph->graph_entry();
TargetEntryInstr* normal_entry = graph_entry->normal_entry();
BlockBuilder builder(flow_graph, normal_entry);
@@ -1021,6 +1028,9 @@
bool Intrinsifier::Build_DoubleFlipSignBit(FlowGraph* flow_graph) {
+ if (!FlowGraphCompiler::SupportsUnboxedDoubles()) {
+ return false;
+ }
GraphEntryInstr* graph_entry = flow_graph->graph_entry();
TargetEntryInstr* normal_entry = graph_entry->normal_entry();
BlockBuilder builder(flow_graph, normal_entry);
@@ -1044,6 +1054,9 @@
static bool BuildInvokeMathCFunction(BlockBuilder* builder,
MethodRecognizer::Kind kind,
intptr_t num_parameters = 1) {
+ if (!FlowGraphCompiler::SupportsUnboxedDoubles()) {
+ return false;
+ }
ZoneGrowableArray<Value*>* args =
new ZoneGrowableArray<Value*>(num_parameters);
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index e878d03..119fd7a 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -15,6 +15,7 @@
#include "vm/object_store.h"
#include "vm/regexp_assembler.h"
#include "vm/symbols.h"
+#include "vm/timeline.h"
namespace dart {
@@ -1557,7 +1558,7 @@
__ CompareImmediate(R3, 0);
__ b(&fall_through, NE);
- __ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
+ __ ldr(R0, FieldAddress(R2, Class::canonical_type_offset()));
__ CompareObject(R0, Object::null_object());
__ b(&fall_through, EQ);
__ Ret();
@@ -2104,6 +2105,23 @@
__ Ret();
}
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+ if (!FLAG_support_timeline) {
+ __ LoadObject(R0, Bool::False());
+ __ Ret();
+ return;
+ }
+ // Load TimelineStream*.
+ __ ldr(R0, Address(THR, Thread::dart_stream_offset()));
+ // Load uintptr_t from TimelineStream*.
+ __ ldr(R0, Address(R0, TimelineStream::enabled_offset()));
+ __ cmp(R0, Operand(0));
+ __ LoadObject(R0, Bool::True(), NE);
+ __ LoadObject(R0, Bool::False(), EQ);
+ __ Ret();
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 88512e8..0ca8c25 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -14,6 +14,7 @@
#include "vm/object_store.h"
#include "vm/regexp_assembler.h"
#include "vm/symbols.h"
+#include "vm/timeline.h"
namespace dart {
@@ -1634,7 +1635,7 @@
__ CompareImmediate(R3, 0);
__ b(&fall_through, NE);
- __ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
+ __ ldr(R0, FieldAddress(R2, Class::canonical_type_offset()));
__ CompareObject(R0, Object::null_object());
__ b(&fall_through, EQ);
__ ret();
@@ -2178,6 +2179,24 @@
__ ret();
}
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+ if (!FLAG_support_timeline) {
+ __ LoadObject(R0, Bool::False());
+ __ ret();
+ return;
+ }
+ // Load TimelineStream*.
+ __ ldr(R0, Address(THR, Thread::dart_stream_offset()));
+ // Load uintptr_t from TimelineStream*.
+ __ ldr(R0, Address(R0, TimelineStream::enabled_offset()));
+ __ cmp(R0, Operand(0));
+ __ LoadObject(R0, Bool::False());
+ __ LoadObject(TMP, Bool::True());
+ __ csel(R0, TMP, R0, NE);
+ __ ret();
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 8dc9e99..576c6a0 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -21,6 +21,7 @@
#include "vm/os.h"
#include "vm/regexp_assembler.h"
#include "vm/symbols.h"
+#include "vm/timeline.h"
namespace dart {
@@ -1697,7 +1698,7 @@
__ movzxw(EDI, FieldAddress(EBX, Class::num_type_arguments_offset()));
__ cmpl(EDI, Immediate(0));
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
- __ movl(EAX, FieldAddress(EBX, Class::canonical_types_offset()));
+ __ movl(EAX, FieldAddress(EBX, Class::canonical_type_offset()));
__ CompareObject(EAX, Object::null_object());
__ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set.
__ ret();
@@ -2131,7 +2132,31 @@
__ ret();
}
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+ if (!FLAG_support_timeline) {
+ __ LoadObject(EAX, Bool::False());
+ __ ret();
+ return;
+ }
+ Label true_label;
+ // Load TimelineStream*.
+ __ movl(EAX, Address(THR, Thread::dart_stream_offset()));
+ // Load uintptr_t from TimelineStream*.
+ __ movl(EAX, Address(EAX, TimelineStream::enabled_offset()));
+ __ cmpl(EAX, Immediate(0));
+ __ j(NOT_ZERO, &true_label, Assembler::kNearJump);
+ // Not enabled.
+ __ LoadObject(EAX, Bool::False());
+ __ ret();
+ // Enabled.
+ __ Bind(&true_label);
+ __ LoadObject(EAX, Bool::True());
+ __ ret();
+}
+
#undef __
+
} // namespace dart
#endif // defined TARGET_ARCH_IA32
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 2398a7b..ea2183c 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -14,6 +14,7 @@
#include "vm/object_store.h"
#include "vm/regexp_assembler.h"
#include "vm/symbols.h"
+#include "vm/timeline.h"
namespace dart {
@@ -1664,7 +1665,7 @@
__ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset()));
__ BranchNotEqual(T1, Immediate(0), &fall_through);
- __ lw(V0, FieldAddress(T2, Class::canonical_types_offset()));
+ __ lw(V0, FieldAddress(T2, Class::canonical_type_offset()));
__ BranchEqual(V0, Object::null_object(), &fall_through);
__ Ret();
@@ -2208,6 +2209,23 @@
__ delay_slot()->lw(V0, Address(V0, Isolate::current_tag_offset()));
}
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+ if (!FLAG_support_timeline) {
+ __ LoadObject(V0, Bool::False());
+ __ Ret();
+ return;
+ }
+ // Load TimelineStream*.
+ __ lw(V0, Address(THR, Thread::dart_stream_offset()));
+ // Load uintptr_t from TimelineStream*.
+ __ lw(T0, Address(V0, TimelineStream::enabled_offset()));
+ __ LoadObject(V0, Bool::True());
+ __ LoadObject(V1, Bool::False());
+ __ Ret();
+ __ delay_slot()->movz(V0, V1, T0); // V0 = (T0 == 0) ? V1 : V0.
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 402613e..58f096d 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -14,6 +14,7 @@
#include "vm/object_store.h"
#include "vm/regexp_assembler.h"
#include "vm/symbols.h"
+#include "vm/timeline.h"
namespace dart {
@@ -1552,7 +1553,7 @@
__ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
__ cmpq(RCX, Immediate(0));
__ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
- __ movq(RAX, FieldAddress(RDI, Class::canonical_types_offset()));
+ __ movq(RAX, FieldAddress(RDI, Class::canonical_type_offset()));
__ CompareObject(RAX, Object::null_object());
__ j(EQUAL, &fall_through, Assembler::kNearJump); // Not yet set.
__ ret();
@@ -2086,6 +2087,29 @@
__ ret();
}
+
+void Intrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler) {
+ if (!FLAG_support_timeline) {
+ __ LoadObject(RAX, Bool::False());
+ __ ret();
+ return;
+ }
+ Label true_label;
+ // Load TimelineStream*.
+ __ movq(RAX, Address(THR, Thread::dart_stream_offset()));
+ // Load uintptr_t from TimelineStream*.
+ __ movq(RAX, Address(RAX, TimelineStream::enabled_offset()));
+ __ cmpq(RAX, Immediate(0));
+ __ j(NOT_ZERO, &true_label, Assembler::kNearJump);
+ // Not enabled.
+ __ LoadObject(RAX, Bool::False());
+ __ ret();
+ // Enabled.
+ __ Bind(&true_label);
+ __ LoadObject(RAX, Bool::True());
+ __ ret();
+}
+
#undef __
} // namespace dart
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 57fb16a..11f5536 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -19,6 +19,7 @@
#include "vm/deopt_instructions.h"
#include "vm/flags.h"
#include "vm/heap.h"
+#include "vm/isolate_reload.h"
#include "vm/lockers.h"
#include "vm/log.h"
#include "vm/message_handler.h"
@@ -52,6 +53,7 @@
DECLARE_FLAG(bool, print_metrics);
DECLARE_FLAG(bool, timing);
DECLARE_FLAG(bool, trace_service);
+DECLARE_FLAG(bool, trace_reload);
DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
NOT_IN_PRODUCT(
@@ -134,7 +136,28 @@
+NoReloadScope::NoReloadScope(Isolate* isolate, Thread* thread)
+ : StackResource(thread),
+ isolate_(isolate) {
+ ASSERT(isolate_ != NULL);
+ isolate_->no_reload_scope_depth_++;
+ ASSERT(isolate_->no_reload_scope_depth_ >= 0);
+}
+
+
+NoReloadScope::~NoReloadScope() {
+ isolate_->no_reload_scope_depth_--;
+ ASSERT(isolate_->no_reload_scope_depth_ >= 0);
+}
+
+
void Isolate::RegisterClass(const Class& cls) {
+ NOT_IN_PRODUCT(
+ if (IsReloading()) {
+ reload_context()->RegisterClass(cls);
+ return;
+ }
+ )
class_table()->Register(cls);
}
@@ -338,7 +361,7 @@
// If we are already paused, don't pause again.
if (FLAG_support_debugger && (I->debugger()->PauseEvent() == NULL)) {
- return I->debugger()->SignalIsolateInterrupted();
+ return I->debugger()->PauseInterrupted();
}
break;
}
@@ -624,6 +647,12 @@
MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
const Error& result) {
+ NOT_IN_PRODUCT(
+ if (I->IsReloading()) {
+ I->ReportReloadError(result);
+ return kOK;
+ }
+ )
// Generate the error and stacktrace strings for the error message.
String& exc_str = String::Handle(T->zone());
String& stacktrace_str = String::Handle(T->zone());
@@ -670,7 +699,7 @@
(exception == I->object_store()->stack_overflow())) {
// We didn't notify the debugger when the stack was full. Do it now.
if (FLAG_support_debugger) {
- I->debugger()->SignalExceptionThrown(Instance::Handle(exception));
+ I->debugger()->PauseException(Instance::Handle(exception));
}
}
}
@@ -785,6 +814,7 @@
deoptimized_code_array_(GrowableObjectArray::null()),
sticky_error_(Error::null()),
background_compiler_(NULL),
+ background_compiler_disabled_depth_(0),
pending_service_extension_calls_(GrowableObjectArray::null()),
registered_service_extension_handlers_(GrowableObjectArray::null()),
metrics_list_head_(NULL),
@@ -799,7 +829,10 @@
boxed_field_list_(GrowableObjectArray::null()),
disabling_field_list_(GrowableObjectArray::null()),
spawn_count_monitor_(new Monitor()),
- spawn_count_(0) {
+ spawn_count_(0),
+ has_attempted_reload_(false),
+ no_reload_scope_depth_(0),
+ reload_context_(NULL) {
NOT_IN_PRODUCT(FlagsCopyFrom(api_flags));
// TODO(asiva): A Thread is not available here, need to figure out
// how the vm_tag (kEmbedderTagId) can be set, these tags need to
@@ -1016,6 +1049,60 @@
}
+bool Isolate::CanReload() const {
+#ifndef PRODUCT
+ return (!ServiceIsolate::IsServiceIsolateDescendant(this) &&
+ is_runnable() && !IsReloading() && no_reload_scope_depth_ == 0);
+#else
+ return false;
+#endif
+}
+
+
+#ifndef PRODUCT
+void Isolate::ReportReloadError(const Error& error) {
+ ASSERT(IsReloading());
+ reload_context_->AbortReload(error);
+ delete reload_context_;
+ reload_context_ = NULL;
+}
+
+
+void Isolate::OnStackReload() {
+ UNREACHABLE();
+}
+
+
+void Isolate::ReloadSources(bool test_mode) {
+ ASSERT(!IsReloading());
+ has_attempted_reload_ = true;
+ reload_context_ = new IsolateReloadContext(this, test_mode);
+ reload_context_->StartReload();
+}
+
+#endif
+
+
+void Isolate::DoneFinalizing() {
+ NOT_IN_PRODUCT(
+ if (IsReloading()) {
+ reload_context_->FinishReload();
+ if (reload_context_->has_error() && reload_context_->test_mode()) {
+ // If the reload has an error and we are in test mode keep the reload
+ // context on the isolate so that it can be used by unit tests.
+ return;
+ }
+ if (!reload_context_->has_error()) {
+ reload_context_->ReportSuccess();
+ }
+ delete reload_context_;
+ reload_context_ = NULL;
+ }
+ )
+}
+
+
+
bool Isolate::MakeRunnable() {
ASSERT(Isolate::Current() == NULL);
@@ -1690,6 +1777,13 @@
debugger()->VisitObjectPointers(visitor);
}
+ NOT_IN_PRODUCT(
+ // Visit objects that are being used for isolate reload.
+ if (reload_context() != NULL) {
+ reload_context()->VisitObjectPointers(visitor);
+ }
+ )
+
// Visit objects that are being used for deoptimization.
if (deopt_context() != NULL) {
deopt_context()->VisitObjectPointers(visitor);
@@ -1712,6 +1806,23 @@
}
+RawClass* Isolate::GetClassForHeapWalkAt(intptr_t cid) {
+ RawClass* raw_class = NULL;
+#ifndef PRODUCT
+ if (IsReloading()) {
+ raw_class = reload_context()->GetClassForHeapWalkAt(cid);
+ } else {
+ raw_class = class_table()->At(cid);
+ }
+#else
+ raw_class = class_table()->At(cid);
+#endif // !PRODUCT
+ ASSERT(raw_class != NULL);
+ ASSERT(raw_class->ptr()->id_ == cid);
+ return raw_class;
+}
+
+
static const char* ExceptionPauseInfoToServiceEnum(Dart_ExceptionPauseInfo pi) {
switch (pi) {
case kPauseOnAllExceptions:
@@ -1755,6 +1866,7 @@
jsobj.AddProperty("runnable", is_runnable());
jsobj.AddProperty("livePorts", message_handler()->live_ports());
jsobj.AddProperty("pauseOnExit", message_handler()->should_pause_on_exit());
+ jsobj.AddProperty("_isReloading", IsReloading());
if (debugger() != NULL) {
if (!is_runnable()) {
@@ -1772,8 +1884,7 @@
ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
jsobj.AddProperty("pauseEvent", &pause_event);
} else if (debugger()->PauseEvent() != NULL && !resume_request_) {
- ServiceEvent pause_event(debugger()->PauseEvent());
- jsobj.AddProperty("pauseEvent", &pause_event);
+ jsobj.AddProperty("pauseEvent", debugger()->PauseEvent());
} else {
ServiceEvent pause_event(this, ServiceEvent::kResume);
@@ -2188,6 +2299,9 @@
message_notify_callback();
set_message_notify_callback(Isolate::WakePauseEventHandler);
+ const bool had_isolate_reload_context = reload_context() != NULL;
+ const int64_t start_time_micros =
+ !had_isolate_reload_context ? 0 : reload_context()->start_time_micros();
bool resume = false;
while (true) {
// Handle all available vm service messages, up to a resume
@@ -2201,6 +2315,17 @@
break;
}
+ if (had_isolate_reload_context && (reload_context() == NULL)) {
+ if (FLAG_trace_reload) {
+ const int64_t reload_time_micros =
+ OS::GetCurrentMonotonicMicros() - start_time_micros;
+ double reload_millis =
+ MicrosecondsToMilliseconds(reload_time_micros);
+ OS::Print("Reloading has finished! (%.2f ms)\n", reload_millis);
+ }
+ break;
+ }
+
// Wait for more service messages.
Monitor::WaitResult res = ml.Wait();
ASSERT(res == Monitor::kNotified);
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index c2fc955..b418fd6 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -35,6 +35,7 @@
class Heap;
class ICData;
class IsolateProfilerData;
+class IsolateReloadContext;
class IsolateSpawnState;
class Log;
class MessageHandler;
@@ -47,12 +48,12 @@
class RawArray;
class RawContext;
class RawDouble;
+class RawError;
+class RawField;
class RawGrowableObjectArray;
class RawMint;
class RawObject;
class RawInteger;
-class RawError;
-class RawField;
class RawFloat32x4;
class RawInt32x4;
class RawUserTag;
@@ -91,6 +92,18 @@
};
+// Disallow isolate reload.
+class NoReloadScope : public StackResource {
+ public:
+ NoReloadScope(Isolate* isolate, Thread* thread);
+ ~NoReloadScope();
+
+ private:
+ Isolate* isolate_;
+ DISALLOW_COPY_AND_ASSIGN(NoReloadScope);
+};
+
+
class Isolate : public BaseIsolate {
public:
// Keep both these enums in sync with isolate_patch.dart.
@@ -150,6 +163,9 @@
return OFFSET_OF(Isolate, class_table_);
}
+ // Prefers old classes when we are in the middle of a reload.
+ RawClass* GetClassForHeapWalkAt(intptr_t cid);
+
static intptr_t ic_miss_code_offset() {
return OFFSET_OF(Isolate, ic_miss_code_);
}
@@ -237,6 +253,10 @@
// Marks all libraries as loaded.
void DoneLoading();
+ void DoneFinalizing();
+
+ void OnStackReload();
+ void ReloadSources(bool test_mode = false);
bool MakeRunnable();
void Run();
@@ -388,6 +408,22 @@
background_compiler_ = value;
}
+ void enable_background_compiler() {
+ background_compiler_disabled_depth_--;
+ if (background_compiler_disabled_depth_ < 0) {
+ FATAL("Mismatched number of calls to disable_background_compiler and "
+ "enable_background_compiler.");
+ }
+ }
+
+ void disable_background_compiler() {
+ background_compiler_disabled_depth_++;
+ }
+
+ bool is_background_compiler_disabled() const {
+ return background_compiler_disabled_depth_ > 0;
+ }
+
void UpdateLastAllocationProfileAccumulatorResetTimestamp() {
last_allocationprofile_accumulator_reset_timestamp_ =
OS::GetCurrentTimeMillis();
@@ -432,6 +468,22 @@
return &vm_tag_counters_;
}
+ bool IsReloading() const {
+ return reload_context_ != NULL;
+ }
+
+ IsolateReloadContext* reload_context() {
+ return reload_context_;
+ }
+
+ bool HasAttemptedReload() const {
+ return has_attempted_reload_;
+ }
+
+ bool CanReload() const;
+
+ void ReportReloadError(const Error& error);
+
uword user_tag() const {
return user_tag_;
}
@@ -717,6 +769,7 @@
// Background compilation.
BackgroundCompiler* background_compiler_;
+ intptr_t background_compiler_disabled_depth_;
// We use 6 list entries for each pending service extension calls.
enum {
@@ -769,6 +822,11 @@
Monitor* spawn_count_monitor_;
intptr_t spawn_count_;
+ // Has a reload ever been attempted?
+ bool has_attempted_reload_;
+ intptr_t no_reload_scope_depth_; // we can only reload when this is 0.
+ IsolateReloadContext* reload_context_;
+
#define ISOLATE_METRIC_VARIABLE(type, variable, name, unit) \
type metric_##variable##_;
ISOLATE_METRIC_LIST(ISOLATE_METRIC_VARIABLE);
@@ -795,12 +853,15 @@
REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
#undef REUSABLE_FRIEND_DECLARATION
+ friend class Become; // VisitObjectPointers
friend class GCMarker; // VisitObjectPointers
friend class SafepointHandler;
friend class Scavenger; // VisitObjectPointers
friend class ServiceIsolate;
friend class Thread;
friend class Timeline;
+ friend class NoReloadScope; // reload_block
+
DISALLOW_COPY_AND_ASSIGN(Isolate);
};
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
new file mode 100644
index 0000000..0291517
--- /dev/null
+++ b/runtime/vm/isolate_reload.cc
@@ -0,0 +1,1195 @@
+// Copyright (c) 2016, 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/isolate_reload.h"
+
+#include "vm/become.h"
+#include "vm/code_generator.h"
+#include "vm/compiler.h"
+#include "vm/dart_api_impl.h"
+#include "vm/hash_table.h"
+#include "vm/isolate.h"
+#include "vm/log.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
+#include "vm/parser.h"
+#include "vm/safepoint.h"
+#include "vm/service_event.h"
+#include "vm/stack_frame.h"
+#include "vm/thread.h"
+#include "vm/timeline.h"
+#include "vm/visitor.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, trace_reload, false, "Trace isolate reloading");
+DEFINE_FLAG(bool, identity_reload, false, "Enable checks for identity reload.");
+DEFINE_FLAG(int, reload_every, 0, "Reload every N stack overflow checks.");
+DEFINE_FLAG(bool, reload_every_optimized, true, "Only from optimized code.");
+
+#ifndef PRODUCT
+
+#define I (isolate())
+#define Z (thread->zone())
+
+#define TIMELINE_SCOPE(name) \
+ TimelineDurationScope tds##name(Thread::Current(), \
+ Timeline::GetIsolateStream(), \
+ #name)
+
+
+class ScriptUrlSetTraits {
+ public:
+ static bool ReportStats() { return false; }
+ static const char* Name() { return "ScriptUrlSetTraits"; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ if (!a.IsString() || !b.IsString()) {
+ return false;
+ }
+
+ return String::Cast(a).Equals(String::Cast(b));
+ }
+
+ static uword Hash(const Object& obj) {
+ return String::Cast(obj).Hash();
+ }
+};
+
+
+class ClassMapTraits {
+ public:
+ static bool ReportStats() { return false; }
+ static const char* Name() { return "ClassMapTraits"; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ if (!a.IsClass() || !b.IsClass()) {
+ return false;
+ }
+ return IsolateReloadContext::IsSameClass(Class::Cast(a), Class::Cast(b));
+ }
+
+ static uword Hash(const Object& obj) {
+ return String::HashRawSymbol(Class::Cast(obj).Name());
+ }
+};
+
+
+class LibraryMapTraits {
+ public:
+ static bool ReportStats() { return false; }
+ static const char* Name() { return "LibraryMapTraits"; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ if (!a.IsLibrary() || !b.IsLibrary()) {
+ return false;
+ }
+ return IsolateReloadContext::IsSameLibrary(
+ Library::Cast(a), Library::Cast(b));
+ }
+
+ static uword Hash(const Object& obj) {
+ return Library::Cast(obj).UrlHash();
+ }
+};
+
+
+class BecomeMapTraits {
+ public:
+ static bool ReportStats() { return false; }
+ static const char* Name() { return "BecomeMapTraits"; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ return a.raw() == b.raw();
+ }
+
+ static uword Hash(const Object& obj) {
+ if (obj.IsLibrary()) {
+ return Library::Cast(obj).UrlHash();
+ } else if (obj.IsClass()) {
+ if (Class::Cast(obj).id() == kFreeListElement) {
+ return 0;
+ }
+ return String::HashRawSymbol(Class::Cast(obj).Name());
+ } else if (obj.IsField()) {
+ return String::HashRawSymbol(Field::Cast(obj).name());
+ }
+ return 0;
+ }
+};
+
+
+bool IsolateReloadContext::IsSameField(const Field& a, const Field& b) {
+ if (a.is_static() != b.is_static()) {
+ return false;
+ }
+ const Class& a_cls = Class::Handle(a.Owner());
+ const Class& b_cls = Class::Handle(b.Owner());
+
+ if (!IsSameClass(a_cls, b_cls)) {
+ return false;
+ }
+
+ const String& a_name = String::Handle(a.name());
+ const String& b_name = String::Handle(b.name());
+
+ return a_name.Equals(b_name);
+}
+
+
+bool IsolateReloadContext::IsSameClass(const Class& a, const Class& b) {
+ if (a.is_patch() != b.is_patch()) {
+ // TODO(johnmccutchan): Should we just check the class kind bits?
+ return false;
+ }
+
+ // TODO(turnidge): We need to look at generic type arguments for
+ // synthetic mixin classes. Their names are not necessarily unique
+ // currently.
+ const String& a_name = String::Handle(Class::Cast(a).Name());
+ const String& b_name = String::Handle(Class::Cast(b).Name());
+
+ if (!a_name.Equals(b_name)) {
+ return false;
+ }
+
+ const Library& a_lib = Library::Handle(Class::Cast(a).library());
+ const Library& b_lib = Library::Handle(Class::Cast(b).library());
+ return IsSameLibrary(a_lib, b_lib);
+}
+
+
+bool IsolateReloadContext::IsSameLibrary(
+ const Library& a_lib, const Library& b_lib) {
+ const String& a_lib_url =
+ String::Handle(a_lib.IsNull() ? String::null() : a_lib.url());
+ const String& b_lib_url =
+ String::Handle(b_lib.IsNull() ? String::null() : b_lib.url());
+ return a_lib_url.Equals(b_lib_url);
+}
+
+
+IsolateReloadContext::IsolateReloadContext(Isolate* isolate, bool test_mode)
+ : start_time_micros_(OS::GetCurrentMonotonicMicros()),
+ isolate_(isolate),
+ test_mode_(test_mode),
+ has_error_(false),
+ saved_num_cids_(-1),
+ saved_class_table_(NULL),
+ num_saved_libs_(-1),
+ script_uri_(String::null()),
+ error_(Error::null()),
+ clean_scripts_set_storage_(Array::null()),
+ compile_time_constants_(Array::null()),
+ old_classes_set_storage_(Array::null()),
+ class_map_storage_(Array::null()),
+ old_libraries_set_storage_(Array::null()),
+ library_map_storage_(Array::null()),
+ become_map_storage_(Array::null()),
+ saved_root_library_(Library::null()),
+ saved_libraries_(GrowableObjectArray::null()) {
+ // Preallocate storage for maps.
+ clean_scripts_set_storage_ =
+ HashTables::New<UnorderedHashSet<ScriptUrlSetTraits> >(4);
+ old_classes_set_storage_ =
+ HashTables::New<UnorderedHashSet<ClassMapTraits> >(4);
+ class_map_storage_ =
+ HashTables::New<UnorderedHashMap<ClassMapTraits> >(4);
+ old_libraries_set_storage_ =
+ HashTables::New<UnorderedHashSet<LibraryMapTraits> >(4);
+ library_map_storage_ =
+ HashTables::New<UnorderedHashMap<LibraryMapTraits> >(4);
+ become_map_storage_ =
+ HashTables::New<UnorderedHashMap<BecomeMapTraits> >(4);
+}
+
+
+IsolateReloadContext::~IsolateReloadContext() {
+}
+
+
+void IsolateReloadContext::ReportError(const Error& error) {
+ has_error_ = true;
+ error_ = error.raw();
+ if (FLAG_trace_reload) {
+ THR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString());
+ }
+ ServiceEvent service_event(Isolate::Current(), ServiceEvent::kIsolateReload);
+ service_event.set_reload_error(&error);
+ Service::HandleEvent(&service_event);
+}
+
+
+void IsolateReloadContext::ReportError(const String& error_msg) {
+ ReportError(LanguageError::Handle(LanguageError::New(error_msg)));
+}
+
+
+void IsolateReloadContext::ReportSuccess() {
+ ServiceEvent service_event(Isolate::Current(), ServiceEvent::kIsolateReload);
+ Service::HandleEvent(&service_event);
+}
+
+
+void IsolateReloadContext::StartReload() {
+ Thread* thread = Thread::Current();
+
+ // Grab root library before calling CheckpointBeforeReload.
+ const Library& root_lib = Library::Handle(object_store()->root_library());
+ ASSERT(!root_lib.IsNull());
+ const String& root_lib_url = String::Handle(root_lib.url());
+
+ // Disable the background compiler while we are performing the reload.
+ BackgroundCompiler::Disable();
+
+ if (FLAG_write_protect_code) {
+ // Disable code page write protection while we are reloading.
+ I->heap()->WriteProtectCode(false);
+ }
+
+ // Ensure all functions on the stack have unoptimized code.
+ EnsuredUnoptimizedCodeForStack();
+ // Deoptimize all code that had optimizing decisions that are dependent on
+ // assumptions from field guards or CHA or deferred library prefixes.
+ // TODO(johnmccutchan): Deoptimizing dependent code here (before the reload)
+ // is paranoid. This likely can be moved to the commit phase.
+ DeoptimizeDependentCode();
+ Checkpoint();
+
+ // Block class finalization attempts when calling into the library
+ // tag handler.
+ I->BlockClassFinalization();
+ Object& result = Object::Handle(thread->zone());
+ {
+ TransitionVMToNative transition(thread);
+ Api::Scope api_scope(thread);
+
+ Dart_Handle retval =
+ (I->library_tag_handler())(Dart_kScriptTag,
+ Api::NewHandle(thread, Library::null()),
+ Api::NewHandle(thread, root_lib_url.raw()));
+ result = Api::UnwrapHandle(retval);
+ }
+ I->UnblockClassFinalization();
+ if (result.IsError()) {
+ ReportError(Error::Cast(result));
+ }
+}
+
+
+void IsolateReloadContext::RegisterClass(const Class& new_cls) {
+ const Class& old_cls = Class::Handle(OldClassOrNull(new_cls));
+ if (old_cls.IsNull()) {
+ Isolate::Current()->class_table()->Register(new_cls);
+
+ if (FLAG_identity_reload) {
+ TIR_Print("Could not find replacement class for %s\n",
+ new_cls.ToCString());
+ UNREACHABLE();
+ }
+
+ // New class maps to itself.
+ AddClassMapping(new_cls, new_cls);
+ return;
+ }
+ new_cls.set_id(old_cls.id());
+ isolate()->class_table()->SetAt(old_cls.id(), new_cls.raw());
+ if (!old_cls.is_enum_class()) {
+ new_cls.CopyCanonicalConstants(old_cls);
+ }
+ new_cls.CopyCanonicalType(old_cls);
+ AddBecomeMapping(old_cls, new_cls);
+ AddClassMapping(new_cls, old_cls);
+}
+
+
+void IsolateReloadContext::FinishReload() {
+ BuildLibraryMapping();
+ TIR_Print("---- DONE FINALIZING\n");
+ if (ValidateReload()) {
+ Commit();
+ PostCommit();
+ } else {
+ Rollback();
+ }
+ // ValidateReload mutates the direct subclass information and does
+ // not remove dead subclasses. Rebuild the direct subclass
+ // information from scratch.
+ RebuildDirectSubclasses();
+
+ if (FLAG_write_protect_code) {
+ // Disable code page write protection while we are reloading.
+ I->heap()->WriteProtectCode(true);
+ }
+
+ BackgroundCompiler::Enable();
+}
+
+
+void IsolateReloadContext::AbortReload(const Error& error) {
+ ReportError(error);
+ Rollback();
+}
+
+
+void IsolateReloadContext::EnsuredUnoptimizedCodeForStack() {
+ TIMELINE_SCOPE(EnsuredUnoptimizedCodeForStack);
+ StackFrameIterator it(StackFrameIterator::kDontValidateFrames);
+
+ Function& func = Function::Handle();
+ while (it.HasNextFrame()) {
+ StackFrame* frame = it.NextFrame();
+ if (frame->IsDartFrame()) {
+ func = frame->LookupDartFunction();
+ ASSERT(!func.IsNull());
+ func.EnsureHasCompiledUnoptimizedCode();
+ }
+ }
+}
+
+
+void IsolateReloadContext::DeoptimizeDependentCode() {
+ ClassTable* class_table = I->class_table();
+
+ const intptr_t bottom = Dart::vm_isolate()->class_table()->NumCids();
+ const intptr_t top = I->class_table()->NumCids();
+ Class& cls = Class::Handle();
+ Array& fields = Array::Handle();
+ Field& field = Field::Handle();
+ for (intptr_t cls_idx = bottom; cls_idx < top; cls_idx++) {
+ if (!class_table->HasValidClassAt(cls_idx)) {
+ // Skip.
+ continue;
+ }
+
+ // Deoptimize CHA code.
+ cls = class_table->At(cls_idx);
+ ASSERT(!cls.IsNull());
+
+ cls.DisableAllCHAOptimizedCode();
+
+ // Deoptimize field guard code.
+ fields = cls.fields();
+ ASSERT(!fields.IsNull());
+ for (intptr_t field_idx = 0; field_idx < fields.Length(); field_idx++) {
+ field = Field::RawCast(fields.At(field_idx));
+ ASSERT(!field.IsNull());
+ field.DeoptimizeDependentCode();
+ }
+ }
+
+ // TODO(johnmccutchan): Also call LibraryPrefix::InvalidateDependentCode.
+}
+
+
+void IsolateReloadContext::CheckpointClasses() {
+ TIMELINE_SCOPE(CheckpointClasses);
+ TIR_Print("---- CHECKPOINTING CLASSES\n");
+ // Checkpoint classes before a reload. We need to copy the following:
+ // 1) The size of the class table.
+ // 2) The class table itself.
+ // For efficiency, we build a set of classes before the reload. This set
+ // is used to pair new classes with old classes.
+
+ ClassTable* class_table = I->class_table();
+
+ // Copy the size of the class table.
+ saved_num_cids_ = I->class_table()->NumCids();
+
+ // Copy of the class table.
+ RawClass** local_saved_class_table =
+ reinterpret_cast<RawClass**>(malloc(sizeof(RawClass*) * saved_num_cids_));
+
+ Class& cls = Class::Handle();
+ UnorderedHashSet<ClassMapTraits> old_classes_set(old_classes_set_storage_);
+ for (intptr_t i = 0; i < saved_num_cids_; i++) {
+ if (class_table->IsValidIndex(i) &&
+ class_table->HasValidClassAt(i)) {
+ // Copy the class into the saved class table and add it to the set.
+ local_saved_class_table[i] = class_table->At(i);
+ if (i != kFreeListElement) {
+ cls = class_table->At(i);
+ bool already_present = old_classes_set.Insert(cls);
+ ASSERT(!already_present);
+ }
+ } else {
+ // No class at this index, mark it as NULL.
+ local_saved_class_table[i] = NULL;
+ }
+ }
+ old_classes_set_storage_ = old_classes_set.Release().raw();
+ // Assigning the field must be done after saving the class table.
+ saved_class_table_ = local_saved_class_table;
+ TIR_Print("---- System had %" Pd " classes\n", saved_num_cids_);
+}
+
+
+bool IsolateReloadContext::IsCleanLibrary(const Library& lib) {
+ return lib.is_dart_scheme();
+}
+
+
+void IsolateReloadContext::CheckpointLibraries() {
+ TIMELINE_SCOPE(CheckpointLibraries);
+
+ // Save the root library in case we abort the reload.
+ const Library& root_lib =
+ Library::Handle(object_store()->root_library());
+ set_saved_root_library(root_lib);
+
+ // Save the old libraries array in case we abort the reload.
+ const GrowableObjectArray& libs =
+ GrowableObjectArray::Handle(object_store()->libraries());
+ set_saved_libraries(libs);
+
+ // Make a filtered copy of the old libraries array. Keep "clean" libraries
+ // that we will use instead of reloading.
+ const GrowableObjectArray& new_libs = GrowableObjectArray::Handle(
+ GrowableObjectArray::New(Heap::kOld));
+ Library& lib = Library::Handle();
+ UnorderedHashSet<LibraryMapTraits>
+ old_libraries_set(old_libraries_set_storage_);
+ num_saved_libs_ = 0;
+ for (intptr_t i = 0; i < libs.Length(); i++) {
+ lib ^= libs.At(i);
+ if (IsCleanLibrary(lib)) {
+ // We are preserving this library across the reload, assign its new index
+ lib.set_index(new_libs.Length());
+ new_libs.Add(lib, Heap::kOld);
+ num_saved_libs_++;
+ } else {
+ // We are going to reload this library. Clear the index.
+ lib.set_index(-1);
+ }
+ // Add old library to old libraries set.
+ bool already_present = old_libraries_set.Insert(lib);
+ ASSERT(!already_present);
+ }
+ old_libraries_set_storage_ = old_libraries_set.Release().raw();
+
+ // Reset the registered libraries to the filtered array.
+ Library::RegisterLibraries(Thread::Current(), new_libs);
+ // Reset the root library to null.
+ object_store()->set_root_library(Library::Handle());
+}
+
+
+void IsolateReloadContext::BuildCleanScriptSet() {
+ const GrowableObjectArray& libs =
+ GrowableObjectArray::Handle(object_store()->libraries());
+
+ UnorderedHashSet<ScriptUrlSetTraits>
+ clean_scripts_set(clean_scripts_set_storage_);
+
+ Library& lib = Library::Handle();
+ Array& scripts = Array::Handle();
+ Script& script = Script::Handle();
+ String& script_url = String::Handle();
+ for (intptr_t lib_idx = 0; lib_idx < libs.Length(); lib_idx++) {
+ lib = Library::RawCast(libs.At(lib_idx));
+ ASSERT(!lib.IsNull());
+ ASSERT(IsCleanLibrary(lib));
+ scripts = lib.LoadedScripts();
+ ASSERT(!scripts.IsNull());
+ for (intptr_t script_idx = 0; script_idx < scripts.Length(); script_idx++) {
+ script = Script::RawCast(scripts.At(script_idx));
+ ASSERT(!script.IsNull());
+ script_url = script.url();
+ ASSERT(!script_url.IsNull());
+ bool already_present = clean_scripts_set.Insert(script_url);
+ ASSERT(!already_present);
+ }
+ }
+
+ clean_scripts_set_storage_ = clean_scripts_set.Release().raw();
+}
+
+
+void IsolateReloadContext::FilterCompileTimeConstants() {
+ // Save the compile time constants array.
+ compile_time_constants_ = I->object_store()->compile_time_constants();
+ // Clear the compile time constants array. This will be repopulated
+ // in the loop below.
+ I->object_store()->set_compile_time_constants(Array::Handle());
+
+ if (compile_time_constants_ == Array::null()) {
+ // Nothing to do.
+ return;
+ }
+
+ // Iterate over the saved compile time constants map.
+ ConstantsMap old_constants(compile_time_constants_);
+ ConstantsMap::Iterator it(&old_constants);
+
+ Array& key = Array::Handle();
+ String& url = String::Handle();
+ Smi& token_pos = Smi::Handle();
+ Instance& value = Instance::Handle();
+
+ // We filter the compile time constants map so that after it only contains
+ // constants from scripts contained in this set.
+ UnorderedHashSet<ScriptUrlSetTraits>
+ clean_scripts_set(clean_scripts_set_storage_);
+
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ ASSERT(entry != -1);
+ key = Array::RawCast(old_constants.GetKey(entry));
+ ASSERT(!key.IsNull());
+ url = String::RawCast(key.At(0));
+ ASSERT(!url.IsNull());
+ if (clean_scripts_set.ContainsKey(url)) {
+ // We've found a cached constant from a clean script, add it to the
+ // compile time constants map again.
+ token_pos = Smi::RawCast(key.At(1));
+ TokenPosition tp(token_pos.Value());
+ // Use ^= because this might be null.
+ value ^= old_constants.GetPayload(entry, 0);
+ Parser::InsertCachedConstantValue(url, tp, value);
+ }
+ }
+
+ old_constants.Release();
+ clean_scripts_set.Release();
+}
+
+
+// While reloading everything we do must be reversible so that we can abort
+// safely if the reload fails. This function stashes things to the side and
+// prepares the isolate for the reload attempt.
+void IsolateReloadContext::Checkpoint() {
+ TIMELINE_SCOPE(Checkpoint);
+ CheckpointClasses();
+ CheckpointLibraries();
+ BuildCleanScriptSet();
+ FilterCompileTimeConstants();
+}
+
+
+void IsolateReloadContext::RollbackClasses() {
+ TIR_Print("---- ROLLING BACK CLASS TABLE\n");
+ ASSERT(saved_num_cids_ > 0);
+ ASSERT(saved_class_table_ != NULL);
+ ClassTable* class_table = I->class_table();
+ class_table->SetNumCids(saved_num_cids_);
+ // Overwrite classes in class table with the saved classes.
+ for (intptr_t i = 0; i < saved_num_cids_; i++) {
+ if (class_table->IsValidIndex(i)) {
+ class_table->SetAt(i, saved_class_table_[i]);
+ }
+ }
+ free(saved_class_table_);
+ saved_class_table_ = NULL;
+ saved_num_cids_ = 0;
+}
+
+
+void IsolateReloadContext::RollbackLibraries() {
+ TIR_Print("---- ROLLING BACK LIBRARY CHANGES\n");
+ Thread* thread = Thread::Current();
+ Library& lib = Library::Handle();
+ GrowableObjectArray& saved_libs = GrowableObjectArray::Handle(
+ Z, saved_libraries());
+ if (!saved_libs.IsNull()) {
+ for (intptr_t i = 0; i < saved_libs.Length(); i++) {
+ lib = Library::RawCast(saved_libs.At(i));
+ // Restore indexes that were modified in CheckpointLibraries.
+ lib.set_index(i);
+ }
+
+ // Reset the registered libraries to the filtered array.
+ Library::RegisterLibraries(Thread::Current(), saved_libs);
+ }
+
+ Library& saved_root_lib = Library::Handle(Z, saved_root_library());
+ if (!saved_root_lib.IsNull()) {
+ object_store()->set_root_library(saved_root_lib);
+ }
+
+ set_saved_root_library(Library::Handle());
+ set_saved_libraries(GrowableObjectArray::Handle());
+}
+
+
+void IsolateReloadContext::Rollback() {
+ I->object_store()->set_compile_time_constants(
+ Array::Handle(compile_time_constants_));
+ RollbackClasses();
+ RollbackLibraries();
+}
+
+
+#ifdef DEBUG
+void IsolateReloadContext::VerifyMaps() {
+ Class& cls = Class::Handle();
+ Class& new_cls = Class::Handle();
+ Class& cls2 = Class::Handle();
+ Class& new_cls2 = Class::Handle();
+
+ // Verify that two old classes aren't both mapped to the same new
+ // class. This could happen is the IsSameClass function is broken.
+ UnorderedHashMap<ClassMapTraits> class_map(class_map_storage_);
+ {
+ UnorderedHashMap<ClassMapTraits>::Iterator it(&class_map);
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ new_cls = Class::RawCast(class_map.GetKey(entry));
+ cls = Class::RawCast(class_map.GetPayload(entry, 0));
+ if (new_cls.raw() != cls.raw()) {
+ UnorderedHashMap<ClassMapTraits>::Iterator it2(&class_map);
+ while (it2.MoveNext()) {
+ new_cls2 = Class::RawCast(class_map.GetKey(entry));
+ if (new_cls.raw() == new_cls2.raw()) {
+ cls2 = Class::RawCast(class_map.GetPayload(entry, 0));
+ if (cls.raw() != cls2.raw()) {
+ OS::PrintErr(
+ "Classes '%s' and '%s' are distinct classes but both map to "
+ "class '%s'\n",
+ cls.ToCString(), cls2.ToCString(), new_cls.ToCString());
+ UNREACHABLE();
+ }
+ }
+ }
+ }
+ }
+ }
+ class_map.Release();
+}
+#endif
+
+
+void IsolateReloadContext::Commit() {
+ TIMELINE_SCOPE(Commit);
+ TIR_Print("---- COMMITTING REVERSE MAP\n");
+
+#ifdef DEBUG
+ VerifyMaps();
+#endif
+
+ {
+ TIMELINE_SCOPE(CopyStaticFieldsAndPatchFieldsAndFunctions);
+ // Copy static field values from the old classes to the new classes.
+ // Patch fields and functions in the old classes so that they retain
+ // the old script.
+ Class& cls = Class::Handle();
+ Class& new_cls = Class::Handle();
+
+ UnorderedHashMap<ClassMapTraits> class_map(class_map_storage_);
+
+ {
+ UnorderedHashMap<ClassMapTraits>::Iterator it(&class_map);
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ new_cls = Class::RawCast(class_map.GetKey(entry));
+ cls = Class::RawCast(class_map.GetPayload(entry, 0));
+ if (new_cls.raw() != cls.raw()) {
+ ASSERT(new_cls.is_enum_class() == cls.is_enum_class());
+ if (new_cls.is_enum_class() && new_cls.is_finalized()) {
+ new_cls.ReplaceEnum(cls);
+ }
+ new_cls.CopyStaticFieldValues(cls);
+ cls.PatchFieldsAndFunctions();
+ }
+ }
+ }
+
+ class_map.Release();
+ }
+
+ // Copy over certain properties of libraries, e.g. is the library
+ // debuggable?
+ {
+ TIMELINE_SCOPE(CopyLibraryBits);
+ Library& lib = Library::Handle();
+ Library& new_lib = Library::Handle();
+
+ UnorderedHashMap<LibraryMapTraits> lib_map(library_map_storage_);
+
+ {
+ // Reload existing libraries.
+ UnorderedHashMap<LibraryMapTraits>::Iterator it(&lib_map);
+
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ ASSERT(entry != -1);
+ new_lib = Library::RawCast(lib_map.GetKey(entry));
+ lib = Library::RawCast(lib_map.GetPayload(entry, 0));
+ new_lib.set_debuggable(lib.IsDebuggable());
+ }
+ }
+
+ // Release the library map.
+ lib_map.Release();
+ }
+
+ {
+ TIMELINE_SCOPE(UpdateLibrariesArray);
+ // Update the libraries array.
+ Library& lib = Library::Handle();
+ const GrowableObjectArray& libs = GrowableObjectArray::Handle(
+ I->object_store()->libraries());
+ for (intptr_t i = 0; i < libs.Length(); i++) {
+ lib = Library::RawCast(libs.At(i));
+ TIR_Print("Lib '%s' at index %" Pd "\n", lib.ToCString(), i);
+ lib.set_index(i);
+ }
+
+ // Initialize library side table.
+ library_infos_.SetLength(libs.Length());
+ for (intptr_t i = 0; i < libs.Length(); i++) {
+ lib = Library::RawCast(libs.At(i));
+ // Mark the library dirty if it comes after the libraries we saved.
+ library_infos_[i].dirty = i >= num_saved_libs_;
+ }
+ }
+
+ {
+ UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_);
+ intptr_t replacement_count = become_map.NumOccupied();
+ const Array& before =
+ Array::Handle(Array::New(replacement_count, Heap::kOld));
+ const Array& after =
+ Array::Handle(Array::New(replacement_count, Heap::kOld));
+ Object& obj = Object::Handle();
+ intptr_t replacement_index = 0;
+ UnorderedHashMap<BecomeMapTraits>::Iterator it(&become_map);
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ obj = become_map.GetKey(entry);
+ before.SetAt(replacement_index, obj);
+ obj = become_map.GetPayload(entry, 0);
+ after.SetAt(replacement_index, obj);
+ replacement_index++;
+ }
+ ASSERT(replacement_index == replacement_count);
+ become_map.Release();
+
+ Become::ElementsForwardIdentity(before, after);
+ }
+
+ if (FLAG_identity_reload) {
+ if (saved_num_cids_ != I->class_table()->NumCids()) {
+ TIR_Print("Identity reload failed! B#C=%" Pd " A#C=%" Pd "\n",
+ saved_num_cids_,
+ I->class_table()->NumCids());
+ }
+ const GrowableObjectArray& saved_libs =
+ GrowableObjectArray::Handle(saved_libraries());
+ const GrowableObjectArray& libs =
+ GrowableObjectArray::Handle(I->object_store()->libraries());
+ if (saved_libs.Length() != libs.Length()) {
+ TIR_Print("Identity reload failed! B#L=%" Pd " A#L=%" Pd "\n",
+ saved_libs.Length(),
+ libs.Length());
+ }
+ }
+}
+
+
+bool IsolateReloadContext::IsDirty(const Library& lib) {
+ const intptr_t index = lib.index();
+ if (index == static_cast<classid_t>(-1)) {
+ // Treat deleted libraries as dirty.
+ return true;
+ }
+ ASSERT((index >= 0) && (index < library_infos_.length()));
+ return library_infos_[index].dirty;
+}
+
+
+void IsolateReloadContext::PostCommit() {
+ TIMELINE_SCOPE(PostCommit);
+ set_saved_root_library(Library::Handle());
+ set_saved_libraries(GrowableObjectArray::Handle());
+ InvalidateWorld();
+}
+
+
+bool IsolateReloadContext::ValidateReload() {
+ TIMELINE_SCOPE(ValidateReload);
+ if (has_error_) {
+ return false;
+ }
+
+ // Already built.
+ ASSERT(class_map_storage_ != Array::null());
+ UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
+ UnorderedHashMap<ClassMapTraits>::Iterator it(&map);
+ Class& cls = Class::Handle();
+ Class& new_cls = Class::Handle();
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ new_cls = Class::RawCast(map.GetKey(entry));
+ cls = Class::RawCast(map.GetPayload(entry, 0));
+ if (new_cls.raw() != cls.raw()) {
+ if (!cls.CanReload(new_cls)) {
+ map.Release();
+ return false;
+ }
+ }
+ }
+ map.Release();
+ return true;
+}
+
+
+RawClass* IsolateReloadContext::FindOriginalClass(const Class& cls) {
+ return MappedClass(cls);
+}
+
+
+RawClass* IsolateReloadContext::GetClassForHeapWalkAt(intptr_t cid) {
+ if (saved_class_table_ != NULL) {
+ ASSERT(cid > 0);
+ ASSERT(cid < saved_num_cids_);
+ return saved_class_table_[cid];
+ } else {
+ return isolate_->class_table()->At(cid);
+ }
+}
+
+
+RawLibrary* IsolateReloadContext::saved_root_library() const {
+ return saved_root_library_;
+}
+
+
+void IsolateReloadContext::set_saved_root_library(const Library& value) {
+ saved_root_library_ = value.raw();
+}
+
+
+RawGrowableObjectArray* IsolateReloadContext::saved_libraries() const {
+ return saved_libraries_;
+}
+
+
+void IsolateReloadContext::set_saved_libraries(
+ const GrowableObjectArray& value) {
+ saved_libraries_ = value.raw();
+}
+
+
+void IsolateReloadContext::VisitObjectPointers(ObjectPointerVisitor* visitor) {
+ visitor->VisitPointers(from(), to());
+ if (saved_class_table_ != NULL) {
+ visitor->VisitPointers(
+ reinterpret_cast<RawObject**>(&saved_class_table_[0]), saved_num_cids_);
+ }
+}
+
+
+ObjectStore* IsolateReloadContext::object_store() {
+ return isolate_->object_store();
+}
+
+
+static void ResetICs(const Function& function, const Code& code) {
+ // TODO(johnmccutchan): Relying on the function's ICData Map can miss ICDatas.
+ // Use the code's object pool instead.
+ if (function.ic_data_array() == Array::null()) {
+ // TODO(johnmccutchan): Even in this case, we need to scan the code's object
+ // pool instead.
+ return; // Already reset in an earlier round.
+ }
+
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+
+ ZoneGrowableArray<const ICData*>* ic_data_array =
+ new(zone) ZoneGrowableArray<const ICData*>();
+ function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
+ const intptr_t ic_data_array_length = ic_data_array->length();
+ if (ic_data_array_length == 0) {
+ return;
+ }
+ const PcDescriptors& descriptors =
+ PcDescriptors::Handle(code.pc_descriptors());
+ PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kIcCall |
+ RawPcDescriptors::kUnoptStaticCall);
+ while (iter.MoveNext()) {
+ const intptr_t index = iter.DeoptId();
+ if (index >= ic_data_array_length) {
+ // TODO(johnmccutchan): Investigate how this can happen.
+ continue;
+ }
+ const ICData* ic_data = (*ic_data_array)[index];
+ if (ic_data == NULL) {
+ // TODO(johnmccutchan): Investigate how this can happen.
+ continue;
+ }
+ bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall;
+ ic_data->Reset(is_static_call);
+ }
+}
+
+
+void IsolateReloadContext::ResetUnoptimizedICsOnStack() {
+ Code& code = Code::Handle();
+ Function& function = Function::Handle();
+ DartFrameIterator iterator;
+ StackFrame* frame = iterator.NextFrame();
+ while (frame != NULL) {
+ code = frame->LookupDartCode();
+ if (code.is_optimized()) {
+ // If this code is optimized, we need to reset the ICs in the
+ // corresponding unoptimized code, which will be executed when the stack
+ // unwinds to the the optimized code.
+ function = code.function();
+ code = function.unoptimized_code();
+ ASSERT(!code.IsNull());
+ ResetICs(function, code);
+ } else {
+ function = code.function();
+ ResetICs(function, code);
+ }
+ frame = iterator.NextFrame();
+ }
+}
+
+
+void IsolateReloadContext::ResetMegamorphicCaches() {
+ object_store()->set_megamorphic_cache_table(GrowableObjectArray::Handle());
+ // Since any current optimized code will not make any more calls, it may be
+ // better to clear the table instead of clearing each of the caches, allow
+ // the current megamorphic caches get GC'd and any new optimized code allocate
+ // new ones.
+}
+
+
+class MarkFunctionsForRecompilation : public ObjectVisitor {
+ public:
+ MarkFunctionsForRecompilation(Isolate* isolate,
+ IsolateReloadContext* reload_context)
+ : ObjectVisitor(),
+ handle_(Object::Handle()),
+ owning_class_(Class::Handle()),
+ owning_lib_(Library::Handle()),
+ code_(Code::Handle()),
+ reload_context_(reload_context) {
+ }
+
+ virtual void VisitObject(RawObject* obj) {
+ // Free-list elements cannot even be wrapped in handles.
+ if (obj->IsFreeListElement()) {
+ return;
+ }
+ handle_ = obj;
+ if (handle_.IsFunction()) {
+ const Function& func = Function::Cast(handle_);
+
+ // Switch to unoptimized code or the lazy compilation stub.
+ func.SwitchToLazyCompiledUnoptimizedCode();
+
+ // Grab the current code.
+ code_ = func.CurrentCode();
+ ASSERT(!code_.IsNull());
+ const bool clear_code = IsFromDirtyLibrary(func);
+ const bool stub_code = code_.IsStubCode();
+
+ // Zero edge counters.
+ func.ZeroEdgeCounters();
+
+ if (!stub_code) {
+ if (clear_code) {
+ ClearAllCode(func);
+ } else {
+ PreserveUnoptimizedCode(func);
+ }
+ }
+
+ // Clear counters.
+ func.set_usage_counter(0);
+ func.set_deoptimization_counter(0);
+ func.set_optimized_instruction_count(0);
+ func.set_optimized_call_site_count(0);
+ }
+ }
+
+ private:
+ void ClearAllCode(const Function& func) {
+ // Null out the ICData array and code.
+ func.ClearICDataArray();
+ func.ClearCode();
+ func.set_was_compiled(false);
+ }
+
+ void PreserveUnoptimizedCode(const Function& func) {
+ ASSERT(!code_.IsNull());
+ // We are preserving the unoptimized code, fill all ICData arrays with
+ // the sentinel values so that we have no stale type feedback.
+ func.FillICDataWithSentinels(code_);
+ }
+
+ bool IsFromDirtyLibrary(const Function& func) {
+ owning_class_ = func.Owner();
+ owning_lib_ = owning_class_.library();
+ return reload_context_->IsDirty(owning_lib_);
+ }
+
+ Object& handle_;
+ Class& owning_class_;
+ Library& owning_lib_;
+ Code& code_;
+ IsolateReloadContext* reload_context_;
+};
+
+
+void IsolateReloadContext::MarkAllFunctionsForRecompilation() {
+ TIMELINE_SCOPE(MarkAllFunctionsForRecompilation);
+ NoSafepointScope no_safepoint;
+ HeapIterationScope heap_iteration_scope;
+ MarkFunctionsForRecompilation visitor(isolate_, this);
+ isolate_->heap()->VisitObjects(&visitor);
+}
+
+
+void IsolateReloadContext::InvalidateWorld() {
+ ResetMegamorphicCaches();
+ DeoptimizeFunctionsOnStack();
+ ResetUnoptimizedICsOnStack();
+ MarkAllFunctionsForRecompilation();
+}
+
+
+RawClass* IsolateReloadContext::MappedClass(const Class& replacement_or_new) {
+ UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
+ Class& cls = Class::Handle();
+ cls ^= map.GetOrNull(replacement_or_new);
+ // No need to update storage address because no mutation occurred.
+ map.Release();
+ return cls.raw();
+}
+
+
+RawLibrary* IsolateReloadContext::MappedLibrary(
+ const Library& replacement_or_new) {
+ return Library::null();
+}
+
+
+RawClass* IsolateReloadContext::OldClassOrNull(
+ const Class& replacement_or_new) {
+ UnorderedHashSet<ClassMapTraits> old_classes_set(old_classes_set_storage_);
+ Class& cls = Class::Handle();
+ cls ^= old_classes_set.GetOrNull(replacement_or_new);
+ old_classes_set_storage_ = old_classes_set.Release().raw();
+ return cls.raw();
+}
+
+
+RawLibrary* IsolateReloadContext::OldLibraryOrNull(
+ const Library& replacement_or_new) {
+ UnorderedHashSet<LibraryMapTraits>
+ old_libraries_set(old_libraries_set_storage_);
+ Library& lib = Library::Handle();
+ lib ^= old_libraries_set.GetOrNull(replacement_or_new);
+ old_libraries_set_storage_ = old_libraries_set.Release().raw();
+ return lib.raw();
+}
+
+
+void IsolateReloadContext::BuildLibraryMapping() {
+ const GrowableObjectArray& libs =
+ GrowableObjectArray::Handle(object_store()->libraries());
+
+ Library& replacement_or_new = Library::Handle();
+ Library& old = Library::Handle();
+ for (intptr_t i = 0; i < libs.Length(); i++) {
+ replacement_or_new = Library::RawCast(libs.At(i));
+ if (IsCleanLibrary(replacement_or_new)) {
+ continue;
+ }
+ old ^= OldLibraryOrNull(replacement_or_new);
+ if (old.IsNull()) {
+ // New library.
+ AddLibraryMapping(replacement_or_new, replacement_or_new);
+ } else {
+ ASSERT(!replacement_or_new.is_dart_scheme());
+ // Replaced class.
+ AddLibraryMapping(replacement_or_new, old);
+
+ AddBecomeMapping(old, replacement_or_new);
+ }
+ }
+}
+
+
+void IsolateReloadContext::AddClassMapping(const Class& replacement_or_new,
+ const Class& original) {
+ UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
+ bool update = map.UpdateOrInsert(replacement_or_new, original);
+ ASSERT(!update);
+ // The storage given to the map may have been reallocated, remember the new
+ // address.
+ class_map_storage_ = map.Release().raw();
+}
+
+
+void IsolateReloadContext::AddLibraryMapping(const Library& replacement_or_new,
+ const Library& original) {
+ UnorderedHashMap<LibraryMapTraits> map(library_map_storage_);
+ bool update = map.UpdateOrInsert(replacement_or_new, original);
+ ASSERT(!update);
+ // The storage given to the map may have been reallocated, remember the new
+ // address.
+ library_map_storage_ = map.Release().raw();
+}
+
+
+void IsolateReloadContext::AddStaticFieldMapping(
+ const Field& old_field, const Field& new_field) {
+ ASSERT(old_field.is_static());
+ ASSERT(new_field.is_static());
+
+ AddBecomeMapping(old_field, new_field);
+}
+
+
+void IsolateReloadContext::AddBecomeMapping(const Object& old,
+ const Object& neu) {
+ ASSERT(become_map_storage_ != Array::null());
+ UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_);
+ bool update = become_map.UpdateOrInsert(old, neu);
+ ASSERT(!update);
+ become_map_storage_ = become_map.Release().raw();
+}
+
+
+void IsolateReloadContext::RebuildDirectSubclasses() {
+ ClassTable* class_table = I->class_table();
+ intptr_t num_cids = class_table->NumCids();
+
+ // Clear the direct subclasses for all classes.
+ Class& cls = Class::Handle();
+ GrowableObjectArray& subclasses = GrowableObjectArray::Handle();
+ for (intptr_t i = 1; i < num_cids; i++) {
+ if (class_table->HasValidClassAt(i)) {
+ cls = class_table->At(i);
+ subclasses = cls.direct_subclasses();
+ if (!subclasses.IsNull()) {
+ subclasses.SetLength(0);
+ }
+ }
+ }
+
+ // Recompute the direct subclasses.
+ AbstractType& super_type = AbstractType::Handle();
+ Class& super_cls = Class::Handle();
+ for (intptr_t i = 1; i < num_cids; i++) {
+ if (class_table->HasValidClassAt(i)) {
+ cls = class_table->At(i);
+ super_type = cls.super_type();
+ if (!super_type.IsNull() && !super_type.IsObjectType()) {
+ super_cls = cls.SuperClass();
+ ASSERT(!super_cls.IsNull());
+ super_cls.AddDirectSubclass(cls);
+ }
+ }
+ }
+}
+
+#endif // !PRODUCT
+
+} // namespace dart
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
new file mode 100644
index 0000000..d439414
--- /dev/null
+++ b/runtime/vm/isolate_reload.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2016, 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 VM_ISOLATE_RELOAD_H_
+#define VM_ISOLATE_RELOAD_H_
+
+#include "vm/globals.h"
+#include "vm/growable_array.h"
+#include "vm/log.h"
+
+DECLARE_FLAG(bool, trace_reload);
+
+// 'Trace Isolate Reload' TIR_Print
+#if defined(_MSC_VER)
+#define TIR_Print(format, ...) \
+ if (FLAG_trace_reload) Log::Current()->Print(format, __VA_ARGS__)
+#else
+#define TIR_Print(format, ...) \
+ if (FLAG_trace_reload) Log::Current()->Print(format, ##__VA_ARGS__)
+#endif
+
+namespace dart {
+
+class GrowableObjectArray;
+class Isolate;
+class Library;
+class RawError;
+class RawGrowableObjectArray;
+class RawLibrary;
+class RawObject;
+class RawString;
+class ObjectPointerVisitor;
+class ObjectStore;
+class UpdateClassesVisitor;
+
+class IsolateReloadContext {
+ public:
+ explicit IsolateReloadContext(Isolate* isolate, bool test_mode = false);
+ ~IsolateReloadContext();
+
+ void StartReload();
+ void FinishReload();
+ void AbortReload(const Error& error);
+
+ RawLibrary* saved_root_library() const;
+
+ RawGrowableObjectArray* saved_libraries() const;
+
+ void ReportError(const Error& error);
+ void ReportError(const String& error_msg);
+ void ReportSuccess();
+
+ bool has_error() const { return has_error_; }
+ RawError* error() const { return error_; }
+ bool test_mode() const { return test_mode_; }
+
+ static bool IsSameField(const Field& a, const Field& b);
+ static bool IsSameLibrary(const Library& a_lib, const Library& b_lib);
+ static bool IsSameClass(const Class& a, const Class& b);
+
+ RawClass* FindOriginalClass(const Class& cls);
+
+ bool IsDirty(const Library& lib);
+
+ // Prefers old classes when we are in the middle of a reload.
+ RawClass* GetClassForHeapWalkAt(intptr_t cid);
+
+ void RegisterClass(const Class& new_cls);
+
+ int64_t start_time_micros() const { return start_time_micros_; }
+
+ private:
+ void set_saved_root_library(const Library& value);
+
+ void set_saved_libraries(const GrowableObjectArray& value);
+
+ void VisitObjectPointers(ObjectPointerVisitor* visitor);
+
+ Isolate* isolate() { return isolate_; }
+ ObjectStore* object_store();
+
+ void EnsuredUnoptimizedCodeForStack();
+ void DeoptimizeDependentCode();
+
+ void Checkpoint();
+
+ void CheckpointClasses();
+
+ // Is |lib| a library whose sources have not changed?
+ bool IsCleanLibrary(const Library& lib);
+ void CheckpointLibraries();
+
+ bool ValidateReload();
+
+ void Rollback();
+
+ void RollbackClasses();
+ void RollbackLibraries();
+
+#ifdef DEBUG
+ void VerifyMaps();
+#endif
+
+ void Commit();
+
+ void PostCommit();
+
+ void ClearReplacedObjectBits();
+
+ void BuildCleanScriptSet();
+ void FilterCompileTimeConstants();
+
+ // atomic_install:
+ void MarkAllFunctionsForRecompilation();
+ void ResetUnoptimizedICsOnStack();
+ void ResetMegamorphicCaches();
+ void InvalidateWorld();
+
+ int64_t start_time_micros_;
+ Isolate* isolate_;
+ bool test_mode_;
+ bool has_error_;
+
+ intptr_t saved_num_cids_;
+ RawClass** saved_class_table_;
+
+ intptr_t num_saved_libs_;
+ struct LibraryInfo {
+ bool dirty;
+ };
+ MallocGrowableArray<LibraryInfo> library_infos_;
+
+ RawClass* OldClassOrNull(const Class& replacement_or_new);
+
+ RawLibrary* OldLibraryOrNull(const Library& replacement_or_new);
+ void BuildLibraryMapping();
+
+ void AddClassMapping(const Class& replacement_or_new,
+ const Class& original);
+
+ void AddLibraryMapping(const Library& replacement_or_new,
+ const Library& original);
+
+ void AddStaticFieldMapping(const Field& old_field, const Field& new_field);
+
+ void AddBecomeMapping(const Object& old, const Object& nue);
+
+ void RebuildDirectSubclasses();
+
+ RawClass* MappedClass(const Class& replacement_or_new);
+ RawLibrary* MappedLibrary(const Library& replacement_or_new);
+
+ RawObject** from() { return reinterpret_cast<RawObject**>(&script_uri_); }
+ RawString* script_uri_;
+ RawError* error_;
+ RawArray* clean_scripts_set_storage_;
+ RawArray* compile_time_constants_;
+ RawArray* old_classes_set_storage_;
+ RawArray* class_map_storage_;
+ RawArray* old_libraries_set_storage_;
+ RawArray* library_map_storage_;
+ RawArray* become_map_storage_;
+ RawLibrary* saved_root_library_;
+ RawGrowableObjectArray* saved_libraries_;
+ RawObject** to() { return reinterpret_cast<RawObject**>(&saved_libraries_); }
+
+ friend class Isolate;
+ friend class Class; // AddStaticFieldMapping.
+};
+
+} // namespace dart
+
+#endif // VM_ISOLATE_RELOAD_H_
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
new file mode 100644
index 0000000..b6d1382
--- /dev/null
+++ b/runtime/vm/isolate_reload_test.cc
@@ -0,0 +1,1832 @@
+// Copyright (c) 2016, 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 "include/dart_api.h"
+#include "include/dart_tools_api.h"
+#include "platform/assert.h"
+#include "vm/globals.h"
+#include "vm/isolate.h"
+#include "vm/lockers.h"
+#include "vm/thread_barrier.h"
+#include "vm/thread_pool.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+#ifndef PRODUCT
+
+// TODO(johnmccutchan):
+// - Tests involving generics.
+
+int64_t SimpleInvoke(Dart_Handle lib, const char* method) {
+ Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
+ EXPECT_VALID(result);
+ EXPECT(Dart_IsInteger(result));
+ int64_t integer_result = 0;
+ result = Dart_IntegerToInt64(result, &integer_result);
+ EXPECT_VALID(result);
+ return integer_result;
+}
+
+
+const char* SimpleInvokeStr(Dart_Handle lib, const char* method) {
+ Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
+ const char* result_str = NULL;
+ EXPECT(Dart_IsString(result));
+ EXPECT_VALID(Dart_StringToCString(result, &result_str));
+ return result_str;
+}
+
+
+Dart_Handle SimpleInvokeError(Dart_Handle lib, const char* method) {
+ Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, NULL);
+ EXPECT(Dart_IsError(result));
+ return result;
+}
+
+
+TEST_CASE(IsolateReload_FunctionReplacement) {
+ const char* kScript =
+ "main() {\n"
+ " return 4;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "var _unused;"
+ "main() {\n"
+ " return 10;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(10, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_BadClass) {
+ const char* kScript =
+ "class Foo {\n"
+ " final a;\n"
+ " Foo(this.a);\n"
+ "}\n"
+ "main() {\n"
+ " new Foo(5);\n"
+ " return 4;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "var _unused;"
+ "class Foo {\n"
+ " final a kjsdf ksjdf ;\n"
+ " Foo(this.a);\n"
+ "}\n"
+ "main() {\n"
+ " new Foo(5);\n"
+ " return 10;\n"
+ "}\n";
+
+ Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(result, "unexpected token");
+
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_StaticValuePreserved) {
+ const char* kScript =
+ "init() => 'old value';\n"
+ "var value = init();\n"
+ "main() {\n"
+ " return 'init()=${init()},value=${value}';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("init()=old value,value=old value",
+ SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "var _unused;"
+ "init() => 'new value';\n"
+ "var value = init();\n"
+ "main() {\n"
+ " return 'init()=${init()},value=${value}';\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("init()=new value,value=old value",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_SavedClosure) {
+ // Create a closure in main which only exists in the original source.
+ const char* kScript =
+ "magic() {\n"
+ " var x = 'ante';\n"
+ " return x + 'diluvian';\n"
+ "}\n"
+ "var closure;\n"
+ "main() {\n"
+ " closure = () { return magic().toString() + '!'; };\n"
+ " return closure();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("antediluvian!", SimpleInvokeStr(lib, "main"));
+
+ // Remove the original closure from the source code. The closure is
+ // able to be recompiled because its source is preserved in a
+ // special patch class.
+ const char* kReloadScript =
+ "magic() {\n"
+ " return 'postapocalyptic';\n"
+ "}\n"
+ "var closure;\n"
+ "main() {\n"
+ " return closure();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("postapocalyptic!", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_TopLevelFieldAdded) {
+ const char* kScript =
+ "var value1 = 10;\n"
+ "main() {\n"
+ " return 'value1=${value1}';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("value1=10", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "var value1 = 10;\n"
+ "var value2 = 20;\n"
+ "main() {\n"
+ " return 'value1=${value1},value2=${value2}';\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("value1=10,value2=20",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ClassFieldAdded) {
+ const char* kScript =
+ "class Foo {\n"
+ " var x;\n"
+ "}\n"
+ "main() {\n"
+ " new Foo();\n"
+ " return 44;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Foo {\n"
+ " var x;\n"
+ " var y;\n"
+ "}\n"
+ "main() {\n"
+ " new Foo();\n"
+ " return 44;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(lib, "Number of instance fields changed");
+}
+
+
+TEST_CASE(IsolateReload_ClassFieldRemoved) {
+ const char* kScript =
+ "class Foo {\n"
+ " var x;\n"
+ " var y;\n"
+ "}\n"
+ "main() {\n"
+ " new Foo();\n"
+ " return 44;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Foo {\n"
+ " var x;\n"
+ "}\n"
+ "main() {\n"
+ " new Foo();\n"
+ " return 44;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(lib, "Number of instance fields changed");
+}
+
+
+TEST_CASE(IsolateReload_ClassAdded) {
+ const char* kScript =
+ "main() {\n"
+ " return 'hello';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "var _unused;"
+ "class A {\n"
+ " toString() => 'hello from A';\n"
+ "}\n"
+ "main() {\n"
+ " return new A().toString();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LibraryImportAdded) {
+ const char* kScript =
+ "main() {\n"
+ " return max(3, 4);\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");;
+
+ const char* kReloadScript =
+ "import 'dart:math';\n"
+ "main() {\n"
+ " return max(3, 4);\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LibraryImportRemoved) {
+ const char* kScript =
+ "import 'dart:math';\n"
+ "main() {\n"
+ " return max(3, 4);\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "main() {\n"
+ " return max(3, 4);\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");;
+}
+
+
+TEST_CASE(IsolateReload_LibraryDebuggable) {
+ const char* kScript =
+ "main() {\n"
+ " return 1;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ // The library is by default debuggable. Make it not debuggable.
+ intptr_t lib_id = -1;
+ bool debuggable = false;
+ EXPECT_VALID(Dart_LibraryId(lib, &lib_id));
+ EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
+ EXPECT_EQ(true, debuggable);
+ EXPECT_VALID(Dart_SetLibraryDebuggable(lib_id, false));
+ EXPECT_VALID(Dart_GetLibraryDebuggable(lib_id, &debuggable));
+ EXPECT_EQ(false, debuggable);
+
+ EXPECT_EQ(1, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "main() {\n"
+ " return 2;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(2, SimpleInvoke(lib, "main"));
+
+ // Library debuggability is preserved.
+ intptr_t new_lib_id = -1;
+ EXPECT_VALID(Dart_LibraryId(lib, &new_lib_id));
+ EXPECT_VALID(Dart_GetLibraryDebuggable(new_lib_id, &debuggable));
+ EXPECT_EQ(false, debuggable);
+}
+
+
+TEST_CASE(IsolateReload_ImplicitConstructorChanged) {
+ // Note that we are checking that the value 20 gets cleared from the
+ // compile-time constants cache. To make this test work, "20" and
+ // "10" need to be at the same token position.
+ const char* kScript =
+ "class A {\n"
+ " int field = 20;\n"
+ "}\n"
+ "var savedA = new A();\n"
+ "main() {\n"
+ " var newA = new A();\n"
+ " return 'saved:${savedA.field} new:${newA.field}';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "class A {\n"
+ " int field = 10;\n"
+ "}\n"
+ "var savedA = new A();\n"
+ "main() {\n"
+ " var newA = new A();\n"
+ " return 'saved:${savedA.field} new:${newA.field}';\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ConstructorChanged) {
+ const char* kScript =
+ "class A {\n"
+ " int field;\n"
+ " A() { field = 20; }\n"
+ "}\n"
+ "var savedA = new A();\n"
+ "main() {\n"
+ " var newA = new A();\n"
+ " return 'saved:${savedA.field} new:${newA.field}';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "var _unused;"
+ "class A {\n"
+ " int field;\n"
+ " A() { field = 10; }\n"
+ "}\n"
+ "var savedA = new A();\n"
+ "main() {\n"
+ " var newA = new A();\n"
+ " return 'saved:${savedA.field} new:${newA.field}';\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_SuperClassChanged) {
+ const char* kScript =
+ "class A {\n"
+ "}\n"
+ "class B extends A {\n"
+ "}\n"
+ "var list = [ new A(), new B() ];\n"
+ "main() {\n"
+ " return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("(true/false, true/true)", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "var _unused;"
+ "class B{\n"
+ "}\n"
+ "class A extends B {\n"
+ "}\n"
+ "var list = [ new A(), new B() ];\n"
+ "main() {\n"
+ " return (list.map((x) => '${x is A}/${x is B}')).toString();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("(true/true, false/true)", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_Generics) {
+ // Reload a program with generics without changing the source. We
+ // do this to produce duplication TypeArguments and make sure that
+ // the system doesn't die.
+ const char* kScript =
+ "class A {\n"
+ "}\n"
+ "class B<T extends A> {\n"
+ "}\n"
+ "main() {\n"
+ " return new B<A>().toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "class A {\n"
+ "}\n"
+ "class B<T extends A> {\n"
+ "}\n"
+ "main() {\n"
+ " return new B<A>().toString();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_MixinChanged) {
+ const char* kScript =
+ "class Mixin1 {\n"
+ " var field = 'mixin1';\n"
+ " func() => 'mixin1';\n"
+ "}\n"
+ "class B extends Object with Mixin1 {\n"
+ "}\n"
+ "var saved = new B();\n"
+ "main() {\n"
+ " return 'saved:field=${saved.field},func=${saved.func()}';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("saved:field=mixin1,func=mixin1",
+ SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "class Mixin2 {\n"
+ " var field = 'mixin2';\n"
+ " func() => 'mixin2';\n"
+ "}\n"
+ "class B extends Object with Mixin2 {\n"
+ "}\n"
+ "var saved = new B();\n"
+ "main() {\n"
+ " var newer = new B();\n"
+ " return 'saved:field=${saved.field},func=${saved.func()} '\n"
+ " 'newer:field=${newer.field},func=${newer.func()}';\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ // The saved instance of B retains its old field value from mixin1,
+ // but it gets the new implementation of func from mixin2.
+ EXPECT_STREQ("saved:field=mixin1,func=mixin2 "
+ "newer:field=mixin2,func=mixin2",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ComplexInheritanceChange) {
+ const char* kScript =
+ "class A {\n"
+ " String name;\n"
+ " A(this.name);\n"
+ "}\n"
+ "class B extends A {\n"
+ " B(name) : super(name);\n"
+ "}\n"
+ "class C extends B {\n"
+ " C(name) : super(name);\n"
+ "}\n"
+ "var list = [ new A('a'), new B('b'), new C('c') ];\n"
+ "main() {\n"
+ " return (list.map((x) {\n"
+ " return '${x.name} is A(${x is A})/ B(${x is B})/ C(${x is C})';\n"
+ " })).toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("(a is A(true)/ B(false)/ C(false),"
+ " b is A(true)/ B(true)/ C(false),"
+ " c is A(true)/ B(true)/ C(true))",
+ SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "class C {\n"
+ " String name;\n"
+ " C(this.name);\n"
+ "}\n"
+ "class X extends C {\n"
+ " X(name) : super(name);\n"
+ "}\n"
+ "class A extends X {\n"
+ " A(name) : super(name);\n"
+ "}\n"
+ "var list;\n"
+ "main() {\n"
+ " list.add(new X('x'));\n"
+ " return (list.map((x) {\n"
+ " return '${x.name} is A(${x is A})/ C(${x is C})/ X(${x is X})';\n"
+ " })).toString();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("(a is A(true)/ C(true)/ X(true),"
+ " b is A(true)/ C(true)/ X(true)," // still extends A...
+ " c is A(false)/ C(true)/ X(false),"
+ " x is A(false)/ C(true)/ X(true))",
+ SimpleInvokeStr(lib, "main"));
+
+ // Revive the class B and make sure all allocated instances take
+ // their place in the inheritance hierarchy.
+ const char* kReloadScript2 =
+ "class X {\n"
+ " String name;\n"
+ " X(this.name);\n"
+ "}\n"
+ "class A extends X{\n"
+ " A(name) : super(name);\n"
+ "}\n"
+ "class B extends X {\n"
+ " B(name) : super(name);\n"
+ "}\n"
+ "class C extends A {\n"
+ " C(name) : super(name);\n"
+ "}\n"
+ "var list;\n"
+ "main() {\n"
+ " return (list.map((x) {\n"
+ " return '${x.name} is '\n"
+ " 'A(${x is A})/ B(${x is B})/ C(${x is C})/ X(${x is X})';\n"
+ " })).toString();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript2);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("(a is A(true)/ B(false)/ C(false)/ X(true),"
+ " b is A(false)/ B(true)/ C(false)/ X(true),"
+ " c is A(true)/ B(false)/ C(true)/ X(true),"
+ " x is A(false)/ B(false)/ C(false)/ X(true))",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LiveStack) {
+ const char* kScript =
+ "import 'isolate_reload_test_helper';\n"
+ "helper() => 7;\n"
+ "alpha() { var x = helper(); reloadTest(); return x + helper(); }\n"
+ "foo() => alpha();\n"
+ "bar() => foo();\n"
+ "main() {\n"
+ " return bar();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'isolate_reload_test_helper';\n"
+ "helper() => 100;\n"
+ "alpha() => 5 + helper();\n"
+ "foo() => alpha();\n"
+ "bar() => foo();\n"
+ "main() {\n"
+ " return bar();\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_EQ(107, SimpleInvoke(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(105, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LibraryLookup) {
+ const char* kScript =
+ "main() {\n"
+ " return importedFunc();\n"
+ "}\n";
+
+ Dart_Handle result;
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
+
+ // Fail to find 'importable_test_lib' in the isolate.
+ result = Dart_LookupLibrary(NewString("importable_test_lib"));
+ EXPECT(Dart_IsError(result));
+
+ const char* kReloadScript =
+ "import 'importable_test_lib';\n"
+ "main() {\n"
+ " return importedFunc();\n"
+ "}\n";
+
+ // Reload and add 'importable_test_lib' to isolate.
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
+
+ // Find 'importable_test_lib' in the isolate.
+ result = Dart_LookupLibrary(NewString("importable_test_lib"));
+ EXPECT(Dart_IsLibrary(result));
+
+ // Reload and remove 'dart:math' from isolate.
+ lib = TestCase::ReloadTestScript(kScript);
+ EXPECT_VALID(lib);
+
+ // Fail to find 'importable_test_lib' in the isolate.
+ result = Dart_LookupLibrary(NewString("importable_test_lib"));
+ EXPECT(Dart_IsError(result));
+}
+
+
+TEST_CASE(IsolateReload_LibraryHide) {
+ // Import 'importable_test_lib' with importedFunc hidden. Will result in an
+ // error.
+ const char* kScript =
+ "import 'importable_test_lib' hide importedFunc;\n"
+ "main() {\n"
+ " return importedFunc();\n"
+ "}\n";
+
+ // Dart_Handle result;
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
+
+ // Import 'importable_test_lib'.
+ const char* kReloadScript =
+ "import 'importable_test_lib';\n"
+ "main() {\n"
+ " return importedFunc();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_LibraryShow) {
+ // Import 'importable_test_lib' with importedIntFunc visible. Will result in
+ // an error when 'main' is invoked.
+ const char* kScript =
+ "import 'importable_test_lib' show importedIntFunc;\n"
+ "main() {\n"
+ " return importedFunc();\n"
+ "}\n"
+ "mainInt() {\n"
+ " return importedIntFunc();\n"
+ "}\n";
+
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ // Works.
+ EXPECT_EQ(4, SimpleInvoke(lib, "mainInt"));
+ // Results in an error.
+ EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
+
+ // Import 'importable_test_lib' with importedFunc visible. Will result in
+ // an error when 'mainInt' is invoked.
+ const char* kReloadScript =
+ "import 'importable_test_lib' show importedFunc;\n"
+ "main() {\n"
+ " return importedFunc();\n"
+ "}\n"
+ "mainInt() {\n"
+ " return importedIntFunc();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ // Works.
+ EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
+ // Results in an error.
+ EXPECT_ERROR(SimpleInvokeError(lib, "mainInt"), "importedIntFunc");
+}
+
+
+// Verifies that we clear the ICs for the functions live on the stack in a way
+// that is compatible with the fast path smi stubs.
+TEST_CASE(IsolateReload_SmiFastPathStubs) {
+ const char* kScript =
+ "import 'isolate_reload_test_helper';\n"
+ "import 'importable_test_lib' show importedIntFunc;\n"
+ "main() {\n"
+ " var x = importedIntFunc();\n"
+ " var y = importedIntFunc();\n"
+ " reloadTest();\n"
+ " return x + y;\n"
+ "}\n";
+
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ // Identity reload.
+ TestCase::SetReloadTestScript(kScript);
+
+ EXPECT_EQ(8, SimpleInvoke(lib, "main"));
+}
+
+
+// Verifies that we assign the correct patch classes for imported
+// mixins when we reload.
+TEST_CASE(IsolateReload_ImportedMixinFunction) {
+ const char* kScript =
+ "import 'importable_test_lib' show ImportedMixin;\n"
+ "class A extends Object with ImportedMixin {\n"
+ "}"
+ "var func = new A().mixinFunc;\n"
+ "main() {\n"
+ " return func();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "import 'importable_test_lib' show ImportedMixin;\n"
+ "class A extends Object with ImportedMixin {\n"
+ "}"
+ "var func;\n"
+ "main() {\n"
+ " return func();\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_TopLevelParseError) {
+ const char* kScript =
+ "main() {\n"
+ " return 4;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "kjsadkfjaksldfjklsadf;\n"
+ "main() {\n"
+ " return 4;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(lib, "unexpected token");
+}
+
+
+TEST_CASE(IsolateReload_PendingUnqualifiedCall_StaticToInstance) {
+ const char* kScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class C {\n"
+ " static foo() => 'static';\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " return new C().test();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class C {\n"
+ " foo() => 'instance';\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " return new C().test();\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_EQ("instance", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ("instance", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingUnqualifiedCall_InstanceToStatic) {
+ const char* kScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class C {\n"
+ " foo() => 'instance';\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " return new C().test();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class C {\n"
+ " static foo() => 'static';\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " return new C().test();\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingConstructorCall_AbstractToConcrete) {
+ const char* kScript =
+ "import 'isolate_reload_test_helper';\n"
+ "abstract class Foo {}\n"
+ "class C {\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return new Foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " try {\n"
+ " new C().test();\n"
+ " return 'okay';\n"
+ " } catch (e) {\n"
+ " return 'exception';\n"
+ " }\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class Foo {}\n"
+ "class C {\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return new Foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " try {\n"
+ " new C().test();\n"
+ " return 'okay';\n"
+ " } catch (e) {\n"
+ " return 'exception';\n"
+ " }\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_EQ("okay", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ("okay", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingConstructorCall_ConcreteToAbstract) {
+ const char* kScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class Foo {}\n"
+ "class C {\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return new Foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " try {\n"
+ " new C().test();\n"
+ " return 'okay';\n"
+ " } catch (e) {\n"
+ " return 'exception';\n"
+ " }\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'isolate_reload_test_helper';\n"
+ "abstract class Foo {}\n"
+ "class C {\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return new Foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " try {\n"
+ " new C().test();\n"
+ " return 'okay';\n"
+ " } catch (e) {\n"
+ " return 'exception';\n"
+ " }\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingStaticCall_DefinedToNSM) {
+ const char* kScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class C {\n"
+ " static foo() => 'static'\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return C.foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " try {\n"
+ " return new C().test();\n"
+ " } catch (e) {\n"
+ " return 'exception';\n"
+ " }\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class C {\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return C.foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " try {\n"
+ " return new C().test();\n"
+ " } catch (e) {\n"
+ " return 'exception';\n"
+ " }\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_PendingStaticCall_NSMToDefined) {
+ const char* kScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class C {\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return C.foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " try {\n"
+ " return new C().test();\n"
+ " } catch (e) {\n"
+ " return 'exception';\n"
+ " }\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'isolate_reload_test_helper';\n"
+ "class C {\n"
+ " static foo() => 'static'\n"
+ " test() {\n"
+ " reloadTest();\n"
+ " return C.foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " try {\n"
+ " return new C().test();\n"
+ " } catch (e) {\n"
+ " return 'exception';\n"
+ " }\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
+
+ lib = TestCase::GetReloadErrorOrRootLibrary();
+ EXPECT_VALID(lib);
+
+ EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumEquality) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " x = Fruit.Banana;\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " if (x == Fruit.Banana) {\n"
+ " return 'yes';\n"
+ " } else {\n"
+ " return 'no';\n"
+ " }\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumIdentical) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " x = Fruit.Banana;\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " if (identical(x, Fruit.Banana)) {\n"
+ " return 'yes';\n"
+ " } else {\n"
+ " return 'no';\n"
+ " }\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumReorderIdentical) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " x = Fruit.Banana;\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Banana,\n"
+ " Apple,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " if (identical(x, Fruit.Banana)) {\n"
+ " return 'yes';\n"
+ " } else {\n"
+ " return 'no';\n"
+ " }\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumAddition) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Cantalope,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
+ " r += '${Fruit.Cantalope.index}/${Fruit.Cantalope} ';\n"
+ " r += '${Fruit.Banana.index}/${Fruit.Banana}';\n"
+ " return r;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Cantalope 2/Fruit.Banana",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumToNotEnum) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple\n"
+ "}\n"
+ "main() {\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "class Fruit {\n"
+ " final int zero = 0;\n"
+ "}\n"
+ "main() {\n"
+ "}\n";
+
+ Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(result, "Enum class cannot be redefined to be a non-enum class");
+}
+
+
+TEST_CASE(IsolateReload_NotEnumToEnum) {
+ const char* kScript =
+ "class Fruit {\n"
+ " final int zero = 0;\n"
+ "}\n"
+ "main() {\n"
+ " return 'yes';\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Apple\n"
+ "}\n"
+ "main() {\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(result, "Class cannot be redefined to be a enum class");
+}
+
+
+TEST_CASE(IsolateReload_EnumDelete) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ " Cantalope,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ // Delete 'Cantalope'.
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
+ " r += '${Fruit.Banana.index}/${Fruit.Banana} ';\n"
+ " r += '${Fruit.Cantalope.index}/${Fruit.Cantalope}';\n"
+ " return r;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Banana 2/Fruit.Cantalope",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumComplex) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ " Cantalope,\n"
+ "}\n"
+ "var x;\n"
+ "var y;\n"
+ "var z;\n"
+ "main() {\n"
+ " x = Fruit.Apple;\n"
+ " y = Fruit.Banana;\n"
+ " z = Fruit.Cantalope;\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ // Delete 'Cantalope'. Add 'Dragon'. Move 'Apple' and 'Banana'.
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Dragon,\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "var y;\n"
+ "var z;\n"
+ "main() {\n"
+ " String r = '';\n"
+ " r += '${identical(x, Fruit.Apple)}';\n"
+ " r += ' ${identical(y, Fruit.Banana)}';\n"
+ " r += ' ${identical(z, Fruit.Cantalope)}';\n"
+ " r += ' ${Fruit.Dragon}';\n"
+ " return r;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("true true true Fruit.Dragon", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumValuesArray) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Cantalope,\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " x = Fruit.Cantalope;\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ // Delete 'Cantalope'.
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Banana,\n"
+ " Apple\n"
+ "}\n"
+ "var x;\n"
+ "bool identityCheck(Fruit f) {\n"
+ " return identical(Fruit.values[f.index], f);\n"
+ "}\n"
+ "main() {\n"
+ " if ((x is Fruit) && identical(x, Fruit.Cantalope)) {\n"
+ " String r = '${identityCheck(Fruit.Apple)}';\n"
+ " r += ' ${identityCheck(Fruit.Banana)}';\n"
+ " r += ' ${identityCheck(Fruit.Cantalope)}';\n"
+ " r += ' ${identityCheck(x)}';\n"
+ " return r;\n"
+ " }\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("true true true true",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumIdentityReload) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ " Cantalope,\n"
+ "}\n"
+ "var x;\n"
+ "var y;\n"
+ "var z;\n"
+ "var w;\n"
+ "main() {\n"
+ " x = { Fruit.Apple: Fruit.Apple.index,\n"
+ " Fruit.Banana: Fruit.Banana.index,\n"
+ " Fruit.Cantalope: Fruit.Cantalope.index};\n"
+ " y = Fruit.Apple;\n"
+ " z = Fruit.Banana;\n"
+ " w = Fruit.Cantalope;\n"
+ " return Fruit.Apple.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ " Cantalope,\n"
+ "}\n"
+ "var x;\n"
+ "var y;\n"
+ "var z;\n"
+ "var w;\n"
+ "bool identityCheck(Fruit f, int index) {\n"
+ " return identical(Fruit.values[index], f);\n"
+ "}\n"
+ "main() {\n"
+ " String r = '';\n"
+ " x.forEach((key, value) {\n"
+ " r += '${identityCheck(key, value)} ';\n"
+ " });\n"
+ " r += '${x[Fruit.Apple] == Fruit.Apple.index} ';\n"
+ " r += '${x[Fruit.Banana] == Fruit.Banana.index} ';\n"
+ " r += '${x[Fruit.Cantalope] == Fruit.Cantalope.index} ';\n"
+ " r += '${identical(y, Fruit.values[x[Fruit.Apple]])} ';\n"
+ " r += '${identical(z, Fruit.values[x[Fruit.Banana]])} ';\n"
+ " r += '${identical(w, Fruit.values[x[Fruit.Cantalope]])} ';\n"
+ " return r;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("true true true true true true true true true ",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ConstantIdentical) {
+ const char* kScript =
+ "class Fruit {\n"
+ " final String name;\n"
+ " const Fruit(this.name);\n"
+ " String toString() => name;\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " x = const Fruit('Pear');\n"
+ " return x.toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Pear", SimpleInvokeStr(lib, "main"));
+
+ const char* kReloadScript =
+ "class Fruit {\n"
+ " final String name;\n"
+ " const Fruit(this.name);\n"
+ " String toString() => name;\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " if (identical(x, const Fruit('Pear'))) {\n"
+ " return 'yes';\n"
+ " } else {\n"
+ " return 'no';\n"
+ " }\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_EnumValuesToString) {
+ const char* kScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Banana,\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " String r = '';\n"
+ " r += Fruit.Apple.toString();\n"
+ " r += ' ';\n"
+ " r += Fruit.Banana.toString();\n"
+ " return r;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple Fruit.Banana", SimpleInvokeStr(lib, "main"));
+
+ // Insert 'Cantalope'.
+
+ const char* kReloadScript =
+ "enum Fruit {\n"
+ " Apple,\n"
+ " Cantalope,\n"
+ " Banana\n"
+ "}\n"
+ "var x;\n"
+ "main() {\n"
+ " String r = '';\n"
+ " r += Fruit.Apple.toString();\n"
+ " r += ' ';\n"
+ " r += Fruit.Cantalope.toString();\n"
+ " r += ' ';\n"
+ " r += Fruit.Banana.toString();\n"
+ " return r;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+
+ EXPECT_STREQ("Fruit.Apple Fruit.Cantalope Fruit.Banana",
+ SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_DirectSubclasses_Success) {
+ Object& new_subclass = Object::Handle();
+ String& name = String::Handle();
+
+ // Lookup the Iterator class by name from the dart core library.
+ ObjectStore* object_store = Isolate::Current()->object_store();
+ const Library& core_lib = Library::Handle(object_store->core_library());
+ name = String::New("Iterator");
+ const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
+
+ // Keep track of how many subclasses an Iterator has.
+ const GrowableObjectArray& subclasses =
+ GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
+ intptr_t saved_subclass_count = subclasses.Length();
+
+ const char* kScript =
+ "class AIterator extends Iterator {\n"
+ "}\n"
+ "main() {\n"
+ " return 1;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(1, SimpleInvoke(lib, "main"));
+
+ // Iterator has one non-core subclass.
+ EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+ // The new subclass is named AIterator.
+ new_subclass = subclasses.At(subclasses.Length() - 1);
+ name = Class::Cast(new_subclass).Name();
+ EXPECT_STREQ("AIterator", name.ToCString());
+
+ const char* kReloadScript =
+ "class AIterator {\n"
+ "}\n"
+ "class BIterator extends Iterator {\n"
+ "}\n"
+ "main() {\n"
+ " return 2;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(2, SimpleInvoke(lib, "main"));
+
+ // Iterator still has only one non-core subclass (AIterator is gone).
+ EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+ // The new subclass is named BIterator.
+ new_subclass = subclasses.At(subclasses.Length() - 1);
+ name = Class::Cast(new_subclass).Name();
+ EXPECT_STREQ("BIterator", name.ToCString());
+}
+
+
+TEST_CASE(IsolateReload_DirectSubclasses_GhostSubclass) {
+ Object& new_subclass = Object::Handle();
+ String& name = String::Handle();
+
+ // Lookup the Iterator class by name from the dart core library.
+ ObjectStore* object_store = Isolate::Current()->object_store();
+ const Library& core_lib = Library::Handle(object_store->core_library());
+ name = String::New("Iterator");
+ const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
+
+ // Keep track of how many subclasses an Iterator has.
+ const GrowableObjectArray& subclasses =
+ GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
+ intptr_t saved_subclass_count = subclasses.Length();
+
+ const char* kScript =
+ "class AIterator extends Iterator {\n"
+ "}\n"
+ "main() {\n"
+ " return 1;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(1, SimpleInvoke(lib, "main"));
+
+ // Iterator has one new subclass.
+ EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+ // The new subclass is named AIterator.
+ new_subclass = subclasses.At(subclasses.Length() - 1);
+ name = Class::Cast(new_subclass).Name();
+ EXPECT_STREQ("AIterator", name.ToCString());
+
+ const char* kReloadScript =
+ "class BIterator extends Iterator {\n"
+ "}\n"
+ "main() {\n"
+ " return 2;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(2, SimpleInvoke(lib, "main"));
+
+ // Iterator has two non-core subclasses.
+ EXPECT_EQ(saved_subclass_count + 2, subclasses.Length());
+
+ // The non-core subclasses are AIterator and BIterator.
+ new_subclass = subclasses.At(subclasses.Length() - 2);
+ name = Class::Cast(new_subclass).Name();
+ EXPECT_STREQ("AIterator", name.ToCString());
+
+ new_subclass = subclasses.At(subclasses.Length() - 1);
+ name = Class::Cast(new_subclass).Name();
+ EXPECT_STREQ("BIterator", name.ToCString());
+}
+
+
+// Make sure that we restore the direct subclass info when we revert.
+TEST_CASE(IsolateReload_DirectSubclasses_Failure) {
+ Object& new_subclass = Object::Handle();
+ String& name = String::Handle();
+
+ // Lookup the Iterator class by name from the dart core library.
+ ObjectStore* object_store = Isolate::Current()->object_store();
+ const Library& core_lib = Library::Handle(object_store->core_library());
+ name = String::New("Iterator");
+ const Class& iterator_cls = Class::Handle(core_lib.LookupClass(name));
+
+ // Keep track of how many subclasses an Iterator has.
+ const GrowableObjectArray& subclasses =
+ GrowableObjectArray::Handle(iterator_cls.direct_subclasses());
+ intptr_t saved_subclass_count = subclasses.Length();
+
+ const char* kScript =
+ "class AIterator extends Iterator {\n"
+ "}\n"
+ "class Foo {\n"
+ " final a;\n"
+ " Foo(this.a);\n"
+ "}\n"
+ "main() {\n"
+ " new Foo(5);\n" // Force Foo to be finalized.
+ " return 1;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(1, SimpleInvoke(lib, "main"));
+
+ // Iterator has one non-core subclass...
+ EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+ // ... and the non-core subclass is named AIterator.
+ new_subclass = subclasses.At(subclasses.Length() - 1);
+ name = Class::Cast(new_subclass).Name();
+ EXPECT_STREQ("AIterator", name.ToCString());
+
+ // Attempt to reload with a bogus script.
+ const char* kReloadScript =
+ "class BIterator extends Iterator {\n"
+ "}\n"
+ "class Foo {\n"
+ " final a kjsdf ksjdf ;\n" // When we refinalize, we get an error.
+ " Foo(this.a);\n"
+ "}\n"
+ "main() {\n"
+ " new Foo(5);\n"
+ " return 2;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(lib, "unexpected token");
+
+ // If we don't clean up the subclasses, we would find BIterator in
+ // the list of subclasses, which would be bad. Make sure that
+ // Iterator still has only one non-core subclass...
+ EXPECT_EQ(saved_subclass_count + 1, subclasses.Length());
+
+ // ...and the non-core subclass is still named AIterator.
+ new_subclass = subclasses.At(subclasses.Length() - 1);
+ name = Class::Cast(new_subclass).Name();
+ EXPECT_STREQ("AIterator", name.ToCString());
+}
+
+#endif // !PRODUCT
+
+} // namespace dart
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index a721c7e..003f1b3 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -124,10 +124,12 @@
return "Internal error";
case kFeatureDisabled:
return "Feature is disabled";
- case kVMMustBePaused:
- return "VM must be paused";
case kCannotAddBreakpoint:
return "Cannot add breakpoint";
+ case kIsolateMustBeRunnable:
+ return "Isolate must be runnable";
+ case kIsolateMustBePaused:
+ return "Isolate must be paused";
default:
return "Extension error";
}
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 5b020b0..3c77d4b 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -47,12 +47,13 @@
kExtensionError = -32000,
- kFeatureDisabled = 100,
- kVMMustBePaused = 101,
- kCannotAddBreakpoint = 102,
- kStreamAlreadySubscribed = 103,
- kStreamNotSubscribed = 104,
- kIsolateMustBeRunnable = 105,
+ kFeatureDisabled = 100,
+ kCannotAddBreakpoint = 102,
+ kStreamAlreadySubscribed = 103,
+ kStreamNotSubscribed = 104,
+ kIsolateMustBeRunnable = 105,
+ kIsolateMustBePaused = 106,
+ kIsolateIsReloading = 107,
};
// Expected that user_data is a JSONStream*.
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 9ed5848..6d7e1e8 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -168,7 +168,7 @@
V(_Double, /, Double_div, 1220198876) \
V(_Double, get:isNaN, Double_getIsNaN, 184085483) \
V(_Double, get:isNegative, Double_getIsNegative, 978911030) \
- V(_Double, _mulFromInteger, Double_mulFromInteger, 1893886883) \
+ V(_Double, _mulFromInteger, Double_mulFromInteger, 856594998) \
V(_Double, .fromInteger, DoubleFromInteger, 2129942595) \
V(_List, []=, ObjectArraySetIndexed, 886228780) \
V(_GrowableList, .withData, GrowableArray_Allocate, 631736030) \
@@ -307,6 +307,7 @@
V(_UserTag, makeCurrent, UserTag_makeCurrent, 187721469) \
V(::, _getDefaultTag, UserTag_defaultTag, 350077879) \
V(::, _getCurrentTag, Profiler_getCurrentTag, 1215225901) \
+ V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 1072246292) \
#define ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V) \
CORE_LIB_INTRINSIC_LIST(V) \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 46320b4..a8ccce5 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -27,10 +27,12 @@
#include "vm/hash_table.h"
#include "vm/heap.h"
#include "vm/intrinsifier.h"
+#include "vm/isolate_reload.h"
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/precompiler.h"
#include "vm/profiler.h"
+#include "vm/resolver.h"
#include "vm/reusable_handles.h"
#include "vm/runtime_entry.h"
#include "vm/scopes.h"
@@ -40,6 +42,7 @@
#include "vm/thread_registry.h"
#include "vm/timeline.h"
#include "vm/timer.h"
+#include "vm/type_table.h"
#include "vm/unicode.h"
#include "vm/verified_memory.h"
#include "vm/weak_code.h"
@@ -61,9 +64,13 @@
DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false,
"Ignore patch file member signature mismatch.");
+DEFINE_FLAG(bool, remove_script_timestamps_for_test, false,
+ "Remove script timestamps to allow for deterministic testing.");
+
DECLARE_FLAG(bool, show_invisible_frames);
DECLARE_FLAG(bool, trace_deoptimization);
DECLARE_FLAG(bool, trace_deoptimization_verbose);
+DECLARE_FLAG(bool, trace_reload);
DECLARE_FLAG(bool, write_protect_code);
DECLARE_FLAG(bool, support_externalizable_strings);
@@ -1140,12 +1147,16 @@
GrowableObjectArray::type_arguments_offset());
cls.set_num_type_arguments(1);
- // canonical_type_arguments_ are Smi terminated.
- // Last element contains the count of used slots.
+ // Initialize hash set for canonical_type_.
+ const intptr_t kInitialCanonicalTypeSize = 16;
+ array = HashTables::New<CanonicalTypeSet>(
+ kInitialCanonicalTypeSize, Heap::kOld);
+ object_store->set_canonical_types(array);
+
+ // Initialize hash set for canonical_type_arguments_.
const intptr_t kInitialCanonicalTypeArgumentsSize = 4;
- array = Array::New(kInitialCanonicalTypeArgumentsSize + 1);
- array.SetAt(kInitialCanonicalTypeArgumentsSize,
- Smi::Handle(zone, Smi::New(0)));
+ array = HashTables::New<CanonicalTypeArgumentsSet>(
+ kInitialCanonicalTypeArgumentsSize, Heap::kOld);
object_store->set_canonical_type_arguments(array);
// Setup type class early in the process.
@@ -2773,13 +2784,18 @@
void Class::DisableCHAOptimizedCode(const Class& subclass) {
ASSERT(Thread::Current()->IsMutatorThread());
CHACodeArray a(*this);
- if (FLAG_trace_deoptimization && a.HasCodes()) {
+ if (FLAG_trace_deoptimization && a.HasCodes() && !subclass.IsNull()) {
THR_Print("Adding subclass %s\n", subclass.ToCString());
}
a.DisableCode();
}
+void Class::DisableAllCHAOptimizedCode() {
+ DisableCHAOptimizedCode(Class::Handle());
+}
+
+
bool Class::TraceAllocation(Isolate* isolate) const {
ClassTable* class_table = isolate->class_table();
return class_table->TraceAllocationFor(id());
@@ -3124,7 +3140,7 @@
template <class FakeInstance>
-RawClass* Class::New(intptr_t index) {
+RawClass* Class::NewCommon(intptr_t index) {
ASSERT(Object::class_class() != Class::null());
Class& result = Class::Handle();
{
@@ -3147,28 +3163,43 @@
result.set_num_native_fields(0);
result.set_token_pos(TokenPosition::kNoSource);
result.InitEmptyFields();
+ return result.raw();
+}
+
+
+template <class FakeInstance>
+RawClass* Class::New(intptr_t index) {
+ Class& result = Class::Handle(NewCommon<FakeInstance>(index));
Isolate::Current()->RegisterClass(result);
return result.raw();
}
-RawClass* Class::New(const String& name,
+RawClass* Class::New(const Library& lib,
+ const String& name,
const Script& script,
TokenPosition token_pos) {
- Class& result = Class::Handle(New<Instance>(kIllegalCid));
+ Class& result = Class::Handle(NewCommon<Instance>(kIllegalCid));
+ result.set_library(lib);
result.set_name(name);
result.set_script(script);
result.set_token_pos(token_pos);
+ Isolate::Current()->RegisterClass(result);
return result.raw();
}
+RawClass* Class::NewInstanceClass() {
+ return Class::New<Instance>(kIllegalCid);
+}
+
+
RawClass* Class::NewNativeWrapper(const Library& library,
const String& name,
int field_count) {
Class& cls = Class::Handle(library.LookupClass(name));
if (cls.IsNull()) {
- cls = New(name, Script::Handle(), TokenPosition::kNoSource);
+ cls = New(library, name, Script::Handle(), TokenPosition::kNoSource);
cls.SetFields(Object::empty_array());
cls.SetFunctions(Object::empty_array());
// Set super class to Object.
@@ -3611,96 +3642,26 @@
}
-RawObject* Class::canonical_types() const {
- return raw_ptr()->canonical_types_;
+RawType* Class::canonical_type() const {
+ return raw_ptr()->canonical_type_;
}
-void Class::set_canonical_types(const Object& value) const {
+void Class::set_canonical_type(const Type& value) const {
ASSERT(!value.IsNull());
- StorePointer(&raw_ptr()->canonical_types_, value.raw());
+ StorePointer(&raw_ptr()->canonical_type_, value.raw());
}
RawType* Class::CanonicalType() const {
- if (!IsGeneric() && !IsClosureClass()) {
- return reinterpret_cast<RawType*>(raw_ptr()->canonical_types_);
- }
- Array& types = Array::Handle();
- types ^= canonical_types();
- if (!types.IsNull() && (types.Length() > 0)) {
- return reinterpret_cast<RawType*>(types.At(0));
- }
- return reinterpret_cast<RawType*>(Object::null());
+ return raw_ptr()->canonical_type_;
}
void Class::SetCanonicalType(const Type& type) const {
- ASSERT(type.IsCanonical());
- if (!IsGeneric() && !IsClosureClass()) {
- ASSERT((canonical_types() == Object::null()) ||
- (canonical_types() == type.raw())); // Set during own finalization.
- set_canonical_types(type);
- } else {
- Array& types = Array::Handle();
- types ^= canonical_types();
- ASSERT(!types.IsNull() && (types.Length() > 1));
- ASSERT((types.At(0) == Object::null()) || (types.At(0) == type.raw()));
- types.SetAt(0, type);
- // Makes sure that 'canonical_types' has not changed.
- ASSERT(types.raw() == canonical_types());
- }
-}
-
-
-intptr_t Class::FindCanonicalTypeIndex(const AbstractType& needle) const {
- Thread* thread = Thread::Current();
- if (EnsureIsFinalized(thread) != Error::null()) {
- return -1;
- }
- if (needle.raw() == CanonicalType()) {
- // For a generic type or signature type, there exists another index with the
- // same type. It will never be returned by this function.
- return 0;
- }
- REUSABLE_OBJECT_HANDLESCOPE(thread);
- Object& types = thread->ObjectHandle();
- types = canonical_types();
- if (types.IsNull()) {
- return -1;
- }
- const intptr_t len = Array::Cast(types).Length();
- REUSABLE_ABSTRACT_TYPE_HANDLESCOPE(thread);
- AbstractType& type = thread->AbstractTypeHandle();
- for (intptr_t i = 0; i < len; i++) {
- type ^= Array::Cast(types).At(i);
- if (needle.raw() == type.raw()) {
- return i;
- }
- }
- // No type found.
- return -1;
-}
-
-
-RawAbstractType* Class::CanonicalTypeFromIndex(intptr_t idx) const {
- AbstractType& type = AbstractType::Handle();
- if (idx == 0) {
- type = CanonicalType();
- if (!type.IsNull()) {
- return type.raw();
- }
- }
- Object& types = Object::Handle(canonical_types());
- if (types.IsNull() || !types.IsArray()) {
- return Type::null();
- }
- if ((idx < 0) || (idx >= Array::Cast(types).Length())) {
- return Type::null();
- }
- type ^= Array::Cast(types).At(idx);
- ASSERT(!type.IsNull());
- return type.raw();
+ ASSERT((canonical_type() == Object::null()) ||
+ (canonical_type() == type.raw())); // Set during own finalization.
+ set_canonical_type(type);
}
@@ -4272,84 +4233,6 @@
}
-// Returns AbstractType::null() if type not found. Modifies index to the last
-// position looked up.
-RawAbstractType* Class::LookupCanonicalType(
- Zone* zone, const AbstractType& lookup_type, intptr_t* index) const {
- Array& canonical_types = Array::Handle(zone);
- canonical_types ^= this->canonical_types();
- if (canonical_types.IsNull()) {
- return AbstractType::null();
- }
- AbstractType& type = Type::Handle(zone);
- const intptr_t length = canonical_types.Length();
- while (*index < length) {
- type ^= canonical_types.At(*index);
- if (type.IsNull()) {
- break;
- }
- ASSERT(type.IsFinalized());
- if (lookup_type.Equals(type)) {
- ASSERT(type.IsCanonical());
- return type.raw();
- }
- *index = *index + 1;
- }
- return AbstractType::null();
-}
-
-
-// Canonicalizing the type arguments may have changed the index, may have
-// grown the table, or may even have canonicalized this type. Therefore
-// conrtinue search for canonical type at the last index visited.
-RawAbstractType* Class::LookupOrAddCanonicalType(
- const AbstractType& lookup_type, intptr_t start_index) const {
- Thread* thread = Thread::Current();
- Zone* zone = thread->zone();
- Isolate* isolate = thread->isolate();
- AbstractType& type = Type::Handle(zone);
- intptr_t index = start_index;
- type ^= LookupCanonicalType(zone, lookup_type, &index);
-
- if (!type.IsNull()) {
- return type.raw();
- }
- {
- SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
- // Lookup again, in case the canonicalization array changed.
- Array& canonical_types = Array::Handle(zone);
- canonical_types ^= this->canonical_types();
- if (canonical_types.IsNull()) {
- canonical_types = empty_array().raw();
- }
- const intptr_t length = canonical_types.Length();
- // Start looking after previously looked up last position ('length').
- type ^= LookupCanonicalType(zone, lookup_type, &index);
- if (!type.IsNull()) {
- return type.raw();
- }
-
- // 'lookup_type' is not canonicalized yet.
- lookup_type.SetCanonical();
-
- // The type needs to be added to the list. Grow the list if it is full.
- if (index >= length) {
- ASSERT((index == length) || ((index == 1) && (length == 0)));
- const intptr_t new_length = (length > 64) ?
- (length + 64) :
- ((length == 0) ? 2 : (length * 2));
- const Array& new_canonical_types = Array::Handle(
- zone, Array::Grow(canonical_types, new_length, Heap::kOld));
- new_canonical_types.SetAt(index, lookup_type);
- this->set_canonical_types(new_canonical_types);
- } else {
- canonical_types.SetAt(index, lookup_type);
- }
- }
- return lookup_type.raw();
-}
-
-
const char* Class::ToCString() const {
const Library& lib = Library::Handle(library());
const char* library_name = lib.IsNull() ? "" : lib.ToCString();
@@ -4627,15 +4510,16 @@
}
-static uint32_t FinalizeHash(uint32_t hash) {
+static uint32_t FinalizeHash(uint32_t hash, intptr_t hashbits) {
hash += hash << 3;
hash ^= hash >> 11; // Logical shift, unsigned hash.
hash += hash << 15;
- return hash;
+ hash &= ((static_cast<intptr_t>(1) << hashbits) - 1);
+ return (hash == 0) ? 1 : hash;
}
-intptr_t TypeArguments::Hash() const {
+intptr_t TypeArguments::ComputeHash() const {
if (IsNull()) return 0;
const intptr_t num_types = Length();
if (IsRaw(0, num_types)) return 0;
@@ -4647,7 +4531,9 @@
// purposes only) while a type argument is still temporarily null.
result = CombineHashes(result, type.IsNull() ? 0 : type.Hash());
}
- return FinalizeHash(result);
+ result = FinalizeHash(result, kHashBits);
+ SetHash(result);
+ return result;
}
@@ -5098,6 +4984,7 @@
result ^= raw;
// Length must be set before we start storing into the array.
result.SetLength(len);
+ result.SetHash(0);
}
// The zero array should have been initialized.
ASSERT(Object::zero_array().raw() != Array::null());
@@ -5123,99 +5010,6 @@
}
-static void GrowCanonicalTypeArguments(Thread* thread, const Array& table) {
- Isolate* isolate = thread->isolate();
- Zone* zone = thread->zone();
- // Last element of the array is the number of used elements.
- const intptr_t table_size = table.Length() - 1;
- const intptr_t new_table_size = table_size * 2;
- Array& new_table = Array::Handle(zone, Array::New(new_table_size + 1));
- // Copy all elements from the original table to the newly allocated
- // array.
- TypeArguments& element = TypeArguments::Handle(zone);
- Object& new_element = Object::Handle(zone);
- for (intptr_t i = 0; i < table_size; i++) {
- element ^= table.At(i);
- if (!element.IsNull()) {
- const intptr_t hash = element.Hash();
- ASSERT(Utils::IsPowerOfTwo(new_table_size));
- intptr_t index = hash & (new_table_size - 1);
- new_element = new_table.At(index);
- while (!new_element.IsNull()) {
- index = (index + 1) & (new_table_size - 1); // Move to next element.
- new_element = new_table.At(index);
- }
- new_table.SetAt(index, element);
- }
- }
- // Copy used count.
- new_element = table.At(table_size);
- new_table.SetAt(new_table_size, new_element);
- // Remember the new table now.
- isolate->object_store()->set_canonical_type_arguments(new_table);
-}
-
-
-static void InsertIntoCanonicalTypeArguments(Thread* thread,
- const Array& table,
- const TypeArguments& arguments,
- intptr_t index) {
- Zone* zone = thread->zone();
- arguments.SetCanonical(); // Mark object as being canonical.
- table.SetAt(index, arguments); // Remember the new element.
- // Update used count.
- // Last element of the array is the number of used elements.
- const intptr_t table_size = table.Length() - 1;
- const intptr_t used_elements =
- Smi::Value(Smi::RawCast(table.At(table_size))) + 1;
- const Smi& used = Smi::Handle(zone, Smi::New(used_elements));
- table.SetAt(table_size, used);
-
-#ifdef DEBUG
- // Verify that there are no duplicates.
- // Duplicates could appear if hash values are not kept constant across
- // snapshots, e.g. if class ids are not preserved by the snapshots.
- TypeArguments& other_arguments = TypeArguments::Handle();
- for (intptr_t i = 0; i < table_size; i++) {
- if ((i != index) && (table.At(i) != TypeArguments::null())) {
- other_arguments ^= table.At(i);
- if (arguments.Equals(other_arguments)) {
- // Recursive types may be equal, but have different hashes.
- ASSERT(arguments.IsRecursive());
- ASSERT(other_arguments.IsRecursive());
- ASSERT(arguments.Hash() != other_arguments.Hash());
- }
- }
- }
-#endif
-
- // Rehash if table is 75% full.
- if (used_elements > ((table_size / 4) * 3)) {
- GrowCanonicalTypeArguments(thread, table);
- }
-}
-
-
-static intptr_t FindIndexInCanonicalTypeArguments(
- Zone* zone,
- const Array& table,
- const TypeArguments& arguments,
- intptr_t hash) {
- // Last element of the array is the number of used elements.
- const intptr_t table_size = table.Length() - 1;
- ASSERT(Utils::IsPowerOfTwo(table_size));
- intptr_t index = hash & (table_size - 1);
-
- TypeArguments& current = TypeArguments::Handle(zone);
- current ^= table.At(index);
- while (!current.IsNull() && !current.Equals(arguments)) {
- index = (index + 1) & (table_size - 1); // Move to next element.
- current ^= table.At(index);
- }
- return index; // Index of element if found or slot into which to add it.
-}
-
-
RawTypeArguments* TypeArguments::CloneUnfinalized() const {
if (IsNull() || IsFinalized()) {
return raw();
@@ -5270,15 +5064,14 @@
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
ObjectStore* object_store = isolate->object_store();
- Array& table = Array::Handle(zone,
- object_store->canonical_type_arguments());
- // Last element of the array is the number of used elements.
- const intptr_t num_used =
- Smi::Value(Smi::RawCast(table.At(table.Length() - 1)));
- const intptr_t hash = Hash();
- intptr_t index = FindIndexInCanonicalTypeArguments(zone, table, *this, hash);
TypeArguments& result = TypeArguments::Handle(zone);
- result ^= table.At(index);
+ {
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+ CanonicalTypeArgumentsSet table(zone,
+ object_store->canonical_type_arguments());
+ result ^= table.GetOrNull(CanonicalTypeArgumentsKey(*this));
+ object_store->set_canonical_type_arguments(table.Release());
+ }
if (result.IsNull()) {
// Canonicalize each type argument.
AbstractType& type_arg = AbstractType::Handle(zone);
@@ -5292,21 +5085,18 @@
}
SetTypeAt(i, type_arg);
}
- // Canonicalization of a recursive type may change its hash.
- intptr_t canonical_hash = hash;
+ // Canonicalization of a type argument of a recursive type argument vector
+ // may change the hash of the vector, so recompute.
if (IsRecursive()) {
- canonical_hash = Hash();
+ ComputeHash();
}
- // Canonicalization of the type argument's own type arguments may add an
- // entry to the table, or even grow the table, and thereby change the
- // previously calculated index.
- table = object_store->canonical_type_arguments();
- if ((canonical_hash != hash) ||
- (Smi::Value(Smi::RawCast(table.At(table.Length() - 1))) != num_used)) {
- index = FindIndexInCanonicalTypeArguments(
- zone, table, *this, canonical_hash);
- result ^= table.At(index);
- }
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+ CanonicalTypeArgumentsSet table(
+ zone, object_store->canonical_type_arguments());
+ // Since we canonicalized some type arguments above we need to lookup
+ // in the table again to make sure we don't already have an equivalent
+ // canonical entry.
+ result ^= table.GetOrNull(CanonicalTypeArgumentsKey(*this));
if (result.IsNull()) {
// Make sure we have an old space object and add it to the table.
if (this->IsNew()) {
@@ -5315,8 +5105,12 @@
result ^= this->raw();
}
ASSERT(result.IsOld());
- InsertIntoCanonicalTypeArguments(thread, table, result, index);
+ result.SetCanonical(); // Mark object as being canonical.
+ // Now add this TypeArgument into the canonical list of type arguments.
+ bool present = table.Insert(result);
+ ASSERT(!present);
}
+ object_store->set_canonical_type_arguments(table.Release());
}
ASSERT(result.Equals(*this));
ASSERT(!result.IsNull());
@@ -5347,12 +5141,13 @@
if (IsNull()) {
return "NULL TypeArguments";
}
- const char* prev_cstr = "TypeArguments:";
+ Zone* zone = Thread::Current()->zone();
+ const char* prev_cstr = OS::SCreate(
+ zone, "TypeArguments: (%" Pd ")", Smi::Value(raw_ptr()->hash_));
for (int i = 0; i < Length(); i++) {
- const AbstractType& type_at = AbstractType::Handle(TypeAt(i));
+ const AbstractType& type_at = AbstractType::Handle(zone, TypeAt(i));
const char* type_cstr = type_at.IsNull() ? "null" : type_at.ToCString();
- char* chars = OS::SCreate(Thread::Current()->zone(),
- "%s [%s]", prev_cstr, type_cstr);
+ char* chars = OS::SCreate(zone, "%s [%s]", prev_cstr, type_cstr);
prev_cstr = chars;
}
return prev_cstr;
@@ -5471,6 +5266,19 @@
}
+void Function::EnsureHasCompiledUnoptimizedCode() const {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ ASSERT(thread->IsMutatorThread());
+
+ const Error& error = Error::Handle(zone,
+ Compiler::EnsureUnoptimizedCode(thread, *this));
+ if (!error.IsNull()) {
+ Exceptions::PropagateError(error);
+ }
+}
+
+
void Function::SwitchToUnoptimizedCode() const {
ASSERT(HasOptimizedCode());
Thread* thread = Thread::Current();
@@ -5497,6 +5305,34 @@
}
+void Function::SwitchToLazyCompiledUnoptimizedCode() const {
+ if (!HasOptimizedCode()) {
+ return;
+ }
+
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ ASSERT(thread->IsMutatorThread());
+
+ const Code& current_code = Code::Handle(zone, CurrentCode());
+ TIR_Print("Disabling optimized code for %s\n", ToCString());
+ current_code.DisableDartCode();
+
+ const Code& unopt_code = Code::Handle(zone, unoptimized_code());
+ if (unopt_code.IsNull()) {
+ // Set the lazy compile code.
+ TIR_Print("Switched to lazy compile stub for %s\n", ToCString());
+ SetInstructions(Code::Handle(StubCode::LazyCompile_entry()->code()));
+ return;
+ }
+
+ TIR_Print("Switched to unoptimized code for %s\n", ToCString());
+
+ AttachCode(unopt_code);
+ unopt_code.Enable();
+}
+
+
void Function::set_unoptimized_code(const Code& value) const {
ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(value.IsNull() || !value.is_optimized());
@@ -7061,6 +6897,8 @@
RawScript* Function::script() const {
+ // NOTE(turnidge): If you update this function, you probably want to
+ // update Class::PatchFieldsAndFunctions() at the same time.
if (token_pos() == TokenPosition::kMinSource) {
// Testing for position 0 is an optimization that relies on temporary
// eval functions having token position 0.
@@ -7538,6 +7376,8 @@
RawScript* Field::Script() const {
+ // NOTE(turnidge): If you update this function, you probably want to
+ // update Class::PatchFieldsAndFunctions() at the same time.
const Field& field = Field::Handle(Original());
ASSERT(field.IsOriginal());
const Object& obj = Object::Handle(field.raw_ptr()->owner_);
@@ -7569,16 +7409,14 @@
}
-RawField* Field::New(const String& name,
- bool is_static,
- bool is_final,
- bool is_const,
- bool is_reflectable,
- const Class& owner,
- const AbstractType& type,
- TokenPosition token_pos) {
- ASSERT(!owner.IsNull());
- const Field& result = Field::Handle(Field::New());
+void Field::InitializeNew(const Field& result,
+ const String& name,
+ bool is_static,
+ bool is_final,
+ bool is_const,
+ bool is_reflectable,
+ const Object& owner,
+ TokenPosition token_pos) {
result.set_name(name);
result.set_is_static(is_static);
if (!is_static) {
@@ -7589,19 +7427,47 @@
result.set_is_reflectable(is_reflectable);
result.set_is_double_initialized(false);
result.set_owner(owner);
- result.SetFieldType(type);
result.set_token_pos(token_pos);
result.set_has_initializer(false);
result.set_is_unboxing_candidate(true);
- result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid);
- result.set_is_nullable(FLAG_use_field_guards ? false : true);
+ Isolate* isolate = Isolate::Current();
+
+ // Use field guards if they are enabled and the isolate has never reloaded.
+ // TODO(johnmccutchan): The reload case assumes the worst case (everything is
+ // dynamic and possibly null). Attempt to relax this later.
+ const bool use_field_guards =
+ FLAG_use_field_guards && !isolate->HasAttemptedReload();
+ result.set_guarded_cid(use_field_guards ? kIllegalCid : kDynamicCid);
+ result.set_is_nullable(use_field_guards ? false : true);
result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
// Presently, we only attempt to remember the list length for final fields.
- if (is_final && FLAG_use_field_guards) {
+ if (is_final && use_field_guards) {
result.set_guarded_list_length(Field::kUnknownFixedLength);
} else {
result.set_guarded_list_length(Field::kNoFixedLength);
}
+}
+
+
+RawField* Field::New(const String& name,
+ bool is_static,
+ bool is_final,
+ bool is_const,
+ bool is_reflectable,
+ const Class& owner,
+ const AbstractType& type,
+ TokenPosition token_pos) {
+ ASSERT(!owner.IsNull());
+ const Field& result = Field::Handle(Field::New());
+ InitializeNew(result,
+ name,
+ is_static,
+ is_final,
+ is_const,
+ is_reflectable,
+ owner,
+ token_pos);
+ result.SetFieldType(type);
return result.raw();
}
@@ -7613,25 +7479,14 @@
TokenPosition token_pos) {
ASSERT(!owner.IsNull());
const Field& result = Field::Handle(Field::New());
- result.set_name(name);
- result.set_is_static(true);
- result.set_is_final(is_final);
- result.set_is_const(is_const);
- result.set_is_reflectable(true);
- result.set_is_double_initialized(false);
- result.set_owner(owner);
- result.set_token_pos(token_pos);
- result.set_has_initializer(false);
- result.set_is_unboxing_candidate(true);
- result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid);
- result.set_is_nullable(FLAG_use_field_guards ? false : true);
- result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
- // Presently, we only attempt to remember the list length for final fields.
- if (is_final && FLAG_use_field_guards) {
- result.set_guarded_list_length(Field::kUnknownFixedLength);
- } else {
- result.set_guarded_list_length(Field::kNoFixedLength);
- }
+ InitializeNew(result,
+ name,
+ true, /* is_static */
+ is_final,
+ is_const,
+ true, /* is_reflectable */
+ owner,
+ token_pos);
return result.raw();
}
@@ -8100,6 +7955,18 @@
}
+void Field::ForceDynamicGuardedCidAndLength() const {
+ // Assume nothing about this field.
+ set_is_unboxing_candidate(false);
+ set_guarded_cid(kDynamicCid);
+ set_is_nullable(true);
+ set_guarded_list_length(Field::kNoFixedLength);
+ set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
+ // Drop any code that relied on the above assumptions.
+ DeoptimizeDependentCode();
+}
+
+
void LiteralToken::set_literal(const String& literal) const {
StorePointer(&raw_ptr()->literal_, literal.raw());
}
@@ -8373,19 +8240,18 @@
}
-TokenPosition TokenStream::ComputeSourcePosition(
- TokenPosition tok_pos) const {
+intptr_t TokenStream::ComputeSourcePosition(TokenPosition tok_pos) const {
Zone* zone = Thread::Current()->zone();
Iterator iterator(zone,
*this,
TokenPosition::kMinSource,
Iterator::kAllTokens);
- TokenPosition src_pos = TokenPosition::kMinSource;
+ intptr_t src_pos = 0;
Token::Kind kind = iterator.CurrentTokenKind();
while ((iterator.CurrentPosition() < tok_pos) && (kind != Token::kEOS)) {
iterator.Advance();
kind = iterator.CurrentTokenKind();
- src_pos.Next();
+ src_pos++;
}
return src_pos;
}
@@ -8457,7 +8323,7 @@
// Helper class for creation of compressed token stream data.
-class CompressedTokenStreamData : public ValueObject {
+class CompressedTokenStreamData : public Scanner::TokenCollector {
public:
static const intptr_t kInitialBufferSize = 16 * KB;
static const bool kPrintTokenObjects = false;
@@ -8469,9 +8335,32 @@
token_objects_(ta),
tokens_(map),
value_(Object::Handle()),
- fresh_index_smi_(Smi::Handle()) {
+ fresh_index_smi_(Smi::Handle()),
+ num_tokens_collected_(0) {
+ }
+ virtual ~CompressedTokenStreamData() { }
+
+ virtual void AddToken(const Scanner::TokenDescriptor& token) {
+ if (token.kind == Token::kIDENT) { // Identifier token.
+ AddIdentToken(*token.literal);
+ } else if (Token::NeedsLiteralToken(token.kind)) { // Literal token.
+ AddLiteralToken(token);
+ } else { // Keyword, pseudo keyword etc.
+ ASSERT(token.kind < Token::kNumTokens);
+ AddSimpleToken(token.kind);
+ }
+ num_tokens_collected_++;
}
+ // Return the compressed token stream.
+ uint8_t* GetStream() const { return buffer_; }
+
+ // Return the compressed token stream length.
+ intptr_t Length() const { return stream_.bytes_written(); }
+
+ intptr_t NumTokens() const { return num_tokens_collected_; }
+
+ private:
// Add an IDENT token into the stream and the token hash map.
void AddIdentToken(const String& ident) {
ASSERT(ident.IsSymbol());
@@ -8522,13 +8411,6 @@
stream_.WriteUnsigned(kind);
}
- // Return the compressed token stream.
- uint8_t* GetStream() const { return buffer_; }
-
- // Return the compressed token stream length.
- intptr_t Length() const { return stream_.bytes_written(); }
-
- private:
void WriteIndex(intptr_t value) {
stream_.WriteUnsigned(value + Token::kNumTokens);
}
@@ -8546,18 +8428,17 @@
CompressedTokenMap* tokens_;
Object& value_;
Smi& fresh_index_smi_;
+ intptr_t num_tokens_collected_;
DISALLOW_COPY_AND_ASSIGN(CompressedTokenStreamData);
};
-RawTokenStream* TokenStream::New(const Scanner::GrowableTokenStream& tokens,
+RawTokenStream* TokenStream::New(const String& source,
const String& private_key,
bool use_shared_tokens) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
- // Copy the relevant data out of the scanner into a compressed stream of
- // tokens.
GrowableObjectArray& token_objects = GrowableObjectArray::Handle(zone);
Array& token_objects_map = Array::Handle(zone);
@@ -8581,20 +8462,9 @@
}
CompressedTokenMap map(token_objects_map.raw());
CompressedTokenStreamData data(token_objects, &map);
-
- intptr_t len = tokens.length();
- for (intptr_t i = 0; i < len; i++) {
- Scanner::TokenDescriptor token = tokens[i];
- if (token.kind == Token::kIDENT) { // Identifier token.
- data.AddIdentToken(*token.literal);
- } else if (Token::NeedsLiteralToken(token.kind)) { // Literal token.
- data.AddLiteralToken(token);
- } else { // Keyword, pseudo keyword etc.
- ASSERT(token.kind < Token::kNumTokens);
- data.AddSimpleToken(token.kind);
- }
- }
- data.AddSimpleToken(Token::kEOS); // End of stream.
+ Scanner scanner(source, private_key);
+ scanner.ScanAll(&data);
+ INC_STAT(thread, num_tokens_scanned, data.NumTokens());
// Create and setup the token stream object.
const ExternalTypedData& stream = ExternalTypedData::Handle(
@@ -8924,6 +8794,11 @@
}
+void Script::set_load_timestamp(int64_t value) const {
+ StoreNonPointer(&raw_ptr()->load_timestamp_, value);
+}
+
+
void Script::set_tokens(const TokenStream& value) const {
StorePointer(&raw_ptr()->tokens_, value.raw());
}
@@ -8942,11 +8817,9 @@
VMTagScope tagScope(thread, VMTag::kCompileScannerTagId);
CSTAT_TIMER_SCOPE(thread, scanner_timer);
const String& src = String::Handle(zone, Source());
- Scanner scanner(src, private_key);
- const Scanner::GrowableTokenStream& ts = scanner.GetStream();
- INC_STAT(thread, num_tokens_scanned, ts.length());
- set_tokens(TokenStream::Handle(zone,
- TokenStream::New(ts, private_key, use_shared_tokens)));
+ const TokenStream& ts = TokenStream::Handle(zone,
+ TokenStream::New(src, private_key, use_shared_tokens));
+ set_tokens(ts);
INC_STAT(thread, src_length, src.Length());
}
@@ -8994,7 +8867,7 @@
*line = cur_line;
} else {
const String& src = String::Handle(zone, Source());
- TokenPosition src_pos = tkns.ComputeSourcePosition(token_pos);
+ intptr_t src_pos = tkns.ComputeSourcePosition(token_pos);
Scanner scanner(src, Symbols::Empty());
scanner.ScanTo(src_pos);
intptr_t relative_line = scanner.CurrentPosition().line;
@@ -9179,13 +9052,16 @@
result.set_url(String::Handle(zone, Symbols::New(thread, url)));
result.set_source(source);
result.set_kind(kind);
+ result.set_load_timestamp(FLAG_remove_script_timestamps_for_test
+ ? 0 : OS::GetCurrentTimeMillis());
result.SetLocationOffset(0, 0);
return result.raw();
}
const char* Script::ToCString() const {
- return "Script";
+ const String& name = String::Handle(url());
+ return OS::SCreate(Thread::Current()->zone(), "Script(%s)", name.ToCString());
}
@@ -9373,8 +9249,6 @@
return Library::Cast(key).UrlHash();
}
};
-
-
typedef UnorderedHashSet<LibraryUrlTraits> LibraryLoadErrorSet;
@@ -9654,7 +9528,7 @@
obj = LookupLocalObject(name);
if (!obj.IsNull()) {
// Names that are in this library's dictionary and are unmangled
- // are not cached. This reduces the size of the the cache.
+ // are not cached. This reduces the size of the cache.
return obj.raw();
}
String& accessor_name = String::Handle(Field::LookupGetterSymbol(name));
@@ -12675,9 +12549,20 @@
}
+intptr_t ICData::Length() const {
+ return (Smi::Value(ic_data()->ptr()->length_) / TestEntryLength());
+}
+
+
intptr_t ICData::NumberOfChecks() const {
- // Do not count the sentinel;
- return (Smi::Value(ic_data()->ptr()->length_) / TestEntryLength()) - 1;
+ const intptr_t length = Length();
+ for (intptr_t i = 0; i < length; i++) {
+ if (IsSentinelAt(i)) {
+ return i;
+ }
+ }
+ UNREACHABLE();
+ return -1;
}
@@ -12714,6 +12599,7 @@
GetClassIdsAt(i, &class_ids);
bool matches = true;
for (intptr_t k = 0; k < class_ids.length(); k++) {
+ ASSERT(class_ids[k] != kIllegalCid);
if (class_ids[k] != cids[k]) {
matches = false;
break;
@@ -12728,6 +12614,142 @@
#endif // DEBUG
+void ICData::WriteSentinelAt(intptr_t index) const {
+ const intptr_t len = Length();
+ ASSERT(index >= 0);
+ ASSERT(index < len);
+ Array& data = Array::Handle(ic_data());
+ const intptr_t start = index * TestEntryLength();
+ const intptr_t end = start + TestEntryLength();
+ for (intptr_t i = start; i < end; i++) {
+ data.SetAt(i, smi_illegal_cid());
+ }
+}
+
+
+void ICData::ClearCountAt(intptr_t index) const {
+ const intptr_t len = NumberOfChecks();
+ ASSERT(index >= 0);
+ ASSERT(index < len);
+ SetCountAt(index, 0);
+}
+
+
+void ICData::ClearWithSentinel() const {
+ if (IsImmutable()) {
+ return;
+ }
+ // Write the sentinel value into all entries except the first one.
+ const intptr_t len = Length();
+ if (len == 0) {
+ return;
+ }
+ // The final entry is always the sentinel.
+ ASSERT(IsSentinelAt(len - 1));
+ for (intptr_t i = len - 1; i > 0; i--) {
+ WriteSentinelAt(i);
+ }
+ if (NumArgsTested() != 2) {
+ // Not the smi fast path case, write sentinel to first one and exit.
+ WriteSentinelAt(0);
+ return;
+ }
+ if (IsSentinelAt(0)) {
+ return;
+ }
+ Zone* zone = Thread::Current()->zone();
+ const String& name = String::Handle(target_name());
+ const Class& smi_class = Class::Handle(Smi::Class());
+ const Function& smi_op_target =
+ Function::Handle(Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
+ GrowableArray<intptr_t> class_ids(2);
+ Function& target = Function::Handle();
+ GetCheckAt(0, &class_ids, &target);
+ if ((target.raw() == smi_op_target.raw()) &&
+ (class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
+ // The smi fast path case, preserve the initial entry but reset the count.
+ ClearCountAt(0);
+ return;
+ }
+ WriteSentinelAt(0);
+}
+
+
+void ICData::ClearAndSetStaticTarget(const Function& func) const {
+ if (IsImmutable()) {
+ return;
+ }
+ const intptr_t len = Length();
+ if (len == 0) {
+ return;
+ }
+ // The final entry is always the sentinel.
+ ASSERT(IsSentinelAt(len - 1));
+ if (NumArgsTested() == 0) {
+ // No type feedback is being collected.
+ const Array& data = Array::Handle(ic_data());
+ // Static calls with no argument checks hold only one target and the
+ // sentinel value.
+ ASSERT(len == 2);
+ // Static calls with no argument checks only need two words.
+ ASSERT(TestEntryLength() == 2);
+ // Set the target.
+ data.SetAt(0, func);
+ // Set count to 0 as this is called during compilation, before the
+ // call has been executed.
+ const Smi& value = Smi::Handle(Smi::New(0));
+ data.SetAt(1, value);
+ } else {
+ // Type feedback on arguments is being collected.
+ const Array& data = Array::Handle(ic_data());
+
+ // Fill all but the first entry with the sentinel.
+ for (intptr_t i = len - 1; i > 0; i--) {
+ WriteSentinelAt(i);
+ }
+ // Rewrite the dummy entry.
+ const Smi& object_cid = Smi::Handle(Smi::New(kObjectCid));
+ for (intptr_t i = 0; i < NumArgsTested(); i++) {
+ data.SetAt(i, object_cid);
+ }
+ data.SetAt(NumArgsTested(), func);
+ const Smi& value = Smi::Handle(Smi::New(0));
+ data.SetAt(NumArgsTested() + 1, value);
+ }
+}
+
+
+// Add an initial Smi/Smi check with count 0.
+bool ICData::AddSmiSmiCheckForFastSmiStubs() const {
+ bool is_smi_two_args_op = false;
+
+ ASSERT(NumArgsTested() == 2);
+ const String& name = String::Handle(target_name());
+ const Class& smi_class = Class::Handle(Smi::Class());
+ Zone* zone = Thread::Current()->zone();
+ const Function& smi_op_target =
+ Function::Handle(Resolver::ResolveDynamicAnyArgs(zone, smi_class, name));
+ if (NumberOfChecks() == 0) {
+ GrowableArray<intptr_t> class_ids(2);
+ class_ids.Add(kSmiCid);
+ class_ids.Add(kSmiCid);
+ AddCheck(class_ids, smi_op_target);
+ // 'AddCheck' sets the initial count to 1.
+ SetCountAt(0, 0);
+ is_smi_two_args_op = true;
+ } else if (NumberOfChecks() == 1) {
+ GrowableArray<intptr_t> class_ids(2);
+ Function& target = Function::Handle();
+ GetCheckAt(0, &class_ids, &target);
+ if ((target.raw() == smi_op_target.raw()) &&
+ (class_ids[0] == kSmiCid) && (class_ids[1] == kSmiCid)) {
+ is_smi_two_args_op = true;
+ }
+ }
+ return is_smi_two_args_op;
+}
+
+
// Used for unoptimized static calls when no class-ids are checked.
void ICData::AddTarget(const Function& target) const {
ASSERT(!target.IsNull());
@@ -12797,10 +12819,10 @@
return;
}
}
- const intptr_t new_len = data.Length() + TestEntryLength();
- data = Array::Grow(data, new_len, Heap::kOld);
- WriteSentinel(data, TestEntryLength());
- intptr_t data_pos = old_num * TestEntryLength();
+ intptr_t index = -1;
+ data = FindFreeIndex(&index);
+ ASSERT(!data.IsNull());
+ intptr_t data_pos = index * TestEntryLength();
Smi& value = Smi::Handle();
for (intptr_t i = 0; i < class_ids.length(); i++) {
// kIllegalCid is used as terminating value, do not add it.
@@ -12818,6 +12840,57 @@
}
+RawArray* ICData::FindFreeIndex(intptr_t* index) const {
+ // The final entry is always the sentinel value, don't consider it
+ // when searching.
+ const intptr_t len = Length() - 1;
+ Array& data = Array::Handle(ic_data());
+ *index = len;
+ for (intptr_t i = 0; i < len; i++) {
+ if (IsSentinelAt(i)) {
+ *index = i;
+ break;
+ }
+ }
+ if (*index < len) {
+ // We've found a free slot.
+ return data.raw();
+ }
+ // Append case.
+ ASSERT(*index == len);
+ ASSERT(*index >= 0);
+ // Grow array.
+ const intptr_t new_len = data.Length() + TestEntryLength();
+ data = Array::Grow(data, new_len, Heap::kOld);
+ WriteSentinel(data, TestEntryLength());
+ return data.raw();
+}
+
+
+void ICData::DebugDump() const {
+ const Function& owner = Function::Handle(Owner());
+ THR_Print("ICData::DebugDump\n");
+ THR_Print("Owner = %s [deopt=%" Pd "]\n", owner.ToCString(), deopt_id());
+ THR_Print("NumArgsTested = %" Pd "\n", NumArgsTested());
+ THR_Print("Length = %" Pd "\n", Length());
+ THR_Print("NumberOfChecks = %" Pd "\n", NumberOfChecks());
+
+ GrowableArray<intptr_t> class_ids;
+ for (intptr_t i = 0; i < NumberOfChecks(); i++) {
+ THR_Print("Check[%" Pd "]:", i);
+ GetClassIdsAt(i, &class_ids);
+ for (intptr_t c = 0; c < class_ids.length(); c++) {
+ THR_Print(" %" Pd "", class_ids[c]);
+ }
+ THR_Print("--- %" Pd " hits\n", GetCountAt(i));
+ }
+}
+
+
+void ICData::ValidateSentinelLocations() const {
+}
+
+
void ICData::AddReceiverCheck(intptr_t receiver_class_id,
const Function& target,
intptr_t count) const {
@@ -12830,12 +12903,9 @@
ASSERT(NumArgsTested() == 1); // Otherwise use 'AddCheck'.
ASSERT(receiver_class_id != kIllegalCid);
- const intptr_t old_num = NumberOfChecks();
- Array& data = Array::Handle(ic_data());
- const intptr_t new_len = data.Length() + TestEntryLength();
- data = Array::Grow(data, new_len, Heap::kOld);
- WriteSentinel(data, TestEntryLength());
- intptr_t data_pos = old_num * TestEntryLength();
+ intptr_t index = -1;
+ Array& data = Array::Handle(FindFreeIndex(&index));
+ intptr_t data_pos = index * TestEntryLength();
if ((receiver_class_id == kSmiCid) && (data_pos > 0)) {
ASSERT(GetReceiverClassIdAt(0) != kSmiCid);
// Move class occupying position 0 to the data_pos.
@@ -12880,10 +12950,26 @@
}
+bool ICData::IsSentinelAt(intptr_t index) const {
+ ASSERT(index < Length());
+ const Array& data = Array::Handle(ic_data());
+ const intptr_t entry_length = TestEntryLength();
+ intptr_t data_pos = index * TestEntryLength();
+ for (intptr_t i = 0; i < entry_length; i++) {
+ if (data.At(data_pos++) != smi_illegal_cid().raw()) {
+ return false;
+ }
+ }
+ // The entry at |index| was filled with the value kIllegalCid.
+ return true;
+}
+
+
void ICData::GetClassIdsAt(intptr_t index,
GrowableArray<intptr_t>* class_ids) const {
- ASSERT(index < NumberOfChecks());
+ ASSERT(index < Length());
ASSERT(class_ids != NULL);
+ ASSERT(!IsSentinelAt(index));
class_ids->Clear();
const Array& data = Array::Handle(ic_data());
intptr_t data_pos = index * TestEntryLength();
@@ -12922,7 +13008,8 @@
intptr_t ICData::GetReceiverClassIdAt(intptr_t index) const {
- ASSERT(index < NumberOfChecks());
+ ASSERT(index < Length());
+ ASSERT(!IsSentinelAt(index));
const intptr_t data_pos = index * TestEntryLength();
NoSafepointScope no_safepoint;
RawArray* raw_data = ic_data();
@@ -13126,10 +13213,9 @@
// Room for all entries and the sentinel.
const intptr_t data_len =
result.TestEntryLength() * (aggregate.length() + 1);
+ // Allocate the array but do not assign it to result until we have populated
+ // it with the aggregate data and the terminating sentinel.
const Array& data = Array::Handle(Array::New(data_len, Heap::kOld));
- result.set_ic_data_array(data);
- ASSERT(result.NumberOfChecks() == aggregate.length());
-
intptr_t pos = 0;
for (intptr_t i = 0; i < aggregate.length(); i++) {
data.SetAt(pos + 0, Smi::Handle(Smi::New(aggregate[i].cid)));
@@ -13141,6 +13227,7 @@
}
WriteSentinel(data, result.TestEntryLength());
result.set_ic_data_array(data);
+ ASSERT(result.NumberOfChecks() == aggregate.length());
return result.raw();
}
@@ -13287,6 +13374,22 @@
}
+bool ICData::IsImmutable() const {
+ const Array& data = Array::Handle(ic_data());
+ return data.IsImmutable();
+}
+
+
+void ICData::ResetData() const {
+ // Number of array elements in one test entry.
+ intptr_t len = TestEntryLength();
+ // IC data array must be null terminated (sentinel entry).
+ const Array& ic_data = Array::Handle(Array::New(len, Heap::kOld));
+ set_ic_data_array(ic_data);
+ WriteSentinel(ic_data, len);
+}
+
+
RawICData* ICData::New() {
ICData& result = ICData::Handle();
{
@@ -15113,7 +15216,7 @@
*reinterpret_cast<RawObject**>(this_addr + offset));
hash = CombineHashes(hash, value);
}
- return FinalizeHash(hash);
+ return FinalizeHash(hash, (kBitsPerWord - 1));
}
@@ -15610,6 +15713,13 @@
}
+classid_t AbstractType::type_class_id() const {
+ // AbstractType is an abstract class.
+ UNREACHABLE();
+ return kIllegalCid;
+}
+
+
RawClass* AbstractType::type_class() const {
// AbstractType is an abstract class.
UNREACHABLE();
@@ -16475,19 +16585,18 @@
bool Type::HasResolvedTypeClass() const {
- return (raw_ptr()->type_class_->GetClassId() == kClassCid);
+ return !raw_ptr()->type_class_id_->IsHeapObject();
+}
+
+
+classid_t Type::type_class_id() const {
+ ASSERT(HasResolvedTypeClass());
+ return Smi::Value(reinterpret_cast<RawSmi*>(raw_ptr()->type_class_id_));
}
RawClass* Type::type_class() const {
-#ifdef DEBUG
- ASSERT(HasResolvedTypeClass());
- Class& type_class = Class::Handle();
- type_class ^= raw_ptr()->type_class_;
- return type_class.raw();
-#else
- return reinterpret_cast<RawClass*>(raw_ptr()->type_class_);
-#endif
+ return Isolate::Current()->class_table()->At(type_class_id());
}
@@ -16495,13 +16604,13 @@
#ifdef DEBUG
ASSERT(!HasResolvedTypeClass());
UnresolvedClass& unresolved_class = UnresolvedClass::Handle();
- unresolved_class ^= raw_ptr()->type_class_;
+ unresolved_class ^= raw_ptr()->type_class_id_;
ASSERT(!unresolved_class.IsNull());
return unresolved_class.raw();
#else
- ASSERT(!Object::Handle(raw_ptr()->type_class_).IsNull());
- ASSERT(Object::Handle(raw_ptr()->type_class_).IsUnresolvedClass());
- return reinterpret_cast<RawUnresolvedClass*>(raw_ptr()->type_class_);
+ ASSERT(!Object::Handle(raw_ptr()->type_class_id_).IsNull());
+ ASSERT(Object::Handle(raw_ptr()->type_class_id_).IsUnresolvedClass());
+ return reinterpret_cast<RawUnresolvedClass*>(raw_ptr()->type_class_id_);
#endif
}
@@ -16887,19 +16996,23 @@
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
- AbstractType& type = Type::Handle(zone);
- const Class& cls = Class::Handle(zone, type_class());
+
// Since void is a keyword, we never have to canonicalize the void type after
// it is canonicalized once by the vm isolate. The parser does the mapping.
- ASSERT((cls.raw() != Object::void_class()) ||
+ ASSERT((type_class() != Object::void_class()) ||
(isolate == Dart::vm_isolate()));
+
// Since dynamic is not a keyword, the parser builds a type that requires
// canonicalization.
- if ((cls.raw() == Object::dynamic_class()) &&
+ if ((type_class() == Object::dynamic_class()) &&
(isolate != Dart::vm_isolate())) {
ASSERT(Object::dynamic_type().IsCanonical());
return Object::dynamic_type().raw();
}
+
+ AbstractType& type = Type::Handle(zone);
+ const Class& cls = Class::Handle(zone, type_class());
+
// Fast canonical lookup/registry for simple types.
if (!cls.IsGeneric() && !cls.IsClosureClass() && !cls.IsTypedefClass()) {
ASSERT(!IsFunctionType());
@@ -16917,12 +17030,13 @@
set_arguments(type_args);
type = cls.CanonicalType(); // May be set while canonicalizing type args.
if (type.IsNull()) {
- MutexLocker ml(isolate->type_canonicalization_mutex());
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
// Recheck if type exists.
type = cls.CanonicalType();
if (type.IsNull()) {
+ ComputeHash();
SetCanonical();
- cls.set_canonical_types(*this);
+ cls.set_canonical_type(*this);
return this->raw();
}
}
@@ -16932,73 +17046,76 @@
return type.raw();
}
- Array& canonical_types = Array::Handle(zone);
- canonical_types ^= cls.canonical_types();
- if (canonical_types.IsNull()) {
- canonical_types = empty_array().raw();
+ ObjectStore* object_store = isolate->object_store();
+ {
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+ CanonicalTypeSet table(zone, object_store->canonical_types());
+ type ^= table.GetOrNull(CanonicalTypeKey(*this));
+ object_store->set_canonical_types(table.Release());
}
- intptr_t length = canonical_types.Length();
- // Linear search to see whether this type is already present in the
- // list of canonicalized types.
- // TODO(asiva): Try to re-factor this lookup code to make sharing
- // easy between the 4 versions of this loop.
- intptr_t index = 1; // Slot 0 is reserved for CanonicalType().
- while (index < length) {
- type ^= canonical_types.At(index);
- if (type.IsNull()) {
- break;
- }
- ASSERT(type.IsFinalized());
- if (this->Equals(type)) {
- ASSERT(type.IsCanonical());
- return type.raw();
- }
- index++;
- }
- // The type was not found in the table. It is not canonical yet.
+ if (type.IsNull()) {
+ // The type was not found in the table. It is not canonical yet.
- // Canonicalize the type arguments.
- TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
- // In case the type is first canonicalized at runtime, its type argument
- // vector may be longer than necessary. This is not an issue.
- ASSERT(type_args.IsNull() || (type_args.Length() >= cls.NumTypeArguments()));
- type_args = type_args.Canonicalize(trail);
- if (IsCanonical()) {
- // Canonicalizing type_args canonicalized this type as a side effect.
- ASSERT(IsRecursive());
- // Cycles via typedefs are detected and disallowed, but a function type can
- // be recursive due to a cycle in its type arguments.
- return this->raw();
- }
- set_arguments(type_args);
- ASSERT(type_args.IsNull() || type_args.IsOld());
+ // Canonicalize the type arguments.
+ TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+ // In case the type is first canonicalized at runtime, its type argument
+ // vector may be longer than necessary. This is not an issue.
+ ASSERT(type_args.IsNull() ||
+ (type_args.Length() >= cls.NumTypeArguments()));
+ type_args = type_args.Canonicalize(trail);
+ if (IsCanonical()) {
+ // Canonicalizing type_args canonicalized this type as a side effect.
+ ASSERT(IsRecursive());
+ // Cycles via typedefs are detected and disallowed, but a function type
+ // can be recursive due to a cycle in its type arguments.
+ return this->raw();
+ }
+ set_arguments(type_args);
+ ASSERT(type_args.IsNull() || type_args.IsOld());
- // In case of a function type, replace the actual function by a signature
- // function.
- if (IsFunctionType()) {
- const Function& fun = Function::Handle(zone, signature());
- if (!fun.IsSignatureFunction()) {
- Function& sig_fun = Function::Handle(zone,
- Function::NewSignatureFunction(cls, TokenPosition::kNoSource));
- type = fun.result_type();
- type = type.Canonicalize(trail);
- sig_fun.set_result_type(type);
- const intptr_t num_params = fun.NumParameters();
- sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters());
- sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(),
- fun.HasOptionalPositionalParameters());
- sig_fun.set_parameter_types(Array::Handle(Array::New(num_params,
- Heap::kOld)));
- for (intptr_t i = 0; i < num_params; i++) {
- type = fun.ParameterTypeAt(i);
+ // In case of a function type, replace the actual function by a signature
+ // function.
+ if (IsFunctionType()) {
+ const Function& fun = Function::Handle(zone, signature());
+ if (!fun.IsSignatureFunction()) {
+ Function& sig_fun = Function::Handle(
+ zone,
+ Function::NewSignatureFunction(cls, TokenPosition::kNoSource));
+ type = fun.result_type();
type = type.Canonicalize(trail);
- sig_fun.SetParameterTypeAt(i, type);
+ sig_fun.set_result_type(type);
+ const intptr_t num_params = fun.NumParameters();
+ sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters());
+ sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(),
+ fun.HasOptionalPositionalParameters());
+ sig_fun.set_parameter_types(Array::Handle(Array::New(num_params,
+ Heap::kOld)));
+ for (intptr_t i = 0; i < num_params; i++) {
+ type = fun.ParameterTypeAt(i);
+ type = type.Canonicalize(trail);
+ sig_fun.SetParameterTypeAt(i, type);
+ }
+ sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names()));
+ set_signature(sig_fun);
}
- sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names()));
- set_signature(sig_fun);
}
+
+ // Check to see if the type got added to canonical list as part of the
+ // type arguments canonicalization.
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+ CanonicalTypeSet table(zone, object_store->canonical_types());
+ type ^= table.GetOrNull(CanonicalTypeKey(*this));
+ if (type.IsNull()) {
+ // Add this Type into the canonical list of types.
+ type ^= raw();
+ ASSERT(type.IsOld());
+ type.SetCanonical(); // Mark object as being canonical.
+ bool present = table.Insert(type);
+ ASSERT(!present);
+ }
+ object_store->set_canonical_types(table.Release());
}
- return cls.LookupOrAddCanonicalType(*this, index);
+ return type.raw();
}
@@ -17039,7 +17156,7 @@
}
-intptr_t Type::Hash() const {
+intptr_t Type::ComputeHash() const {
ASSERT(IsFinalized());
uint32_t result = 1;
if (IsMalformed()) return result;
@@ -17063,13 +17180,22 @@
}
}
}
- return FinalizeHash(result);
+ result = FinalizeHash(result, kHashBits);
+ SetHash(result);
+ return result;
}
-void Type::set_type_class(const Object& value) const {
- ASSERT(!value.IsNull() && (value.IsClass() || value.IsUnresolvedClass()));
- StorePointer(&raw_ptr()->type_class_, value.raw());
+void Type::set_type_class(const Class& value) const {
+ ASSERT(!value.IsNull());
+ StorePointer(&raw_ptr()->type_class_id_,
+ reinterpret_cast<RawObject*>(Smi::New(value.id())));
+}
+
+
+void Type::set_unresolved_class(const Object& value) const {
+ ASSERT(!value.IsNull() && value.IsUnresolvedClass());
+ StorePointer(&raw_ptr()->type_class_id_, value.raw());
}
@@ -17092,8 +17218,13 @@
TokenPosition token_pos,
Heap::Space space) {
const Type& result = Type::Handle(Type::New(space));
- result.set_type_class(clazz);
+ if (clazz.IsClass()) {
+ result.set_type_class(Class::Cast(clazz));
+ } else {
+ result.set_unresolved_class(clazz);
+ }
result.set_arguments(arguments);
+ result.SetHash(0);
result.set_token_pos(token_pos);
result.StoreNonPointer(&result.raw_ptr()->type_state_, RawType::kAllocated);
return result.raw();
@@ -17273,7 +17404,7 @@
// Do not calculate the hash of the referenced type to avoid divergence.
const uint32_t result =
Class::Handle(AbstractType::Handle(type()).type_class()).id();
- return FinalizeHash(result);
+ return FinalizeHash(result, kHashBits);
}
@@ -17340,7 +17471,25 @@
void TypeParameter::set_parameterized_class(const Class& value) const {
// Set value may be null.
- StorePointer(&raw_ptr()->parameterized_class_, value.raw());
+ classid_t cid = kIllegalCid;
+ if (!value.IsNull()) {
+ cid = value.id();
+ }
+ StoreNonPointer(&raw_ptr()->parameterized_class_id_, cid);
+}
+
+
+classid_t TypeParameter::parameterized_class_id() const {
+ return raw_ptr()->parameterized_class_id_;
+}
+
+
+RawClass* TypeParameter::parameterized_class() const {
+ classid_t cid = parameterized_class_id();
+ if (cid == kIllegalCid) {
+ return Class::null();
+ }
+ return Isolate::Current()->class_table()->At(cid);
}
@@ -17503,13 +17652,15 @@
}
-intptr_t TypeParameter::Hash() const {
+intptr_t TypeParameter::ComputeHash() const {
ASSERT(IsFinalized());
uint32_t result = Class::Handle(parameterized_class()).id();
// No need to include the hash of the bound, since the type parameter is fully
// identified by its class and index.
result = CombineHashes(result, index());
- return FinalizeHash(result);
+ result = FinalizeHash(result, kHashBits);
+ SetHash(result);
+ return result;
}
@@ -17531,6 +17682,7 @@
result.set_index(index);
result.set_name(name);
result.set_bound(bound);
+ result.SetHash(0);
result.set_token_pos(token_pos);
result.StoreNonPointer(&result.raw_ptr()->type_state_,
RawTypeParameter::kAllocated);
@@ -17767,13 +17919,15 @@
}
-intptr_t BoundedType::Hash() const {
+intptr_t BoundedType::ComputeHash() const {
uint32_t result = AbstractType::Handle(type()).Hash();
// No need to include the hash of the bound, since the bound is defined by the
// type parameter (modulo instantiation state).
result = CombineHashes(result,
TypeParameter::Handle(type_parameter()).Hash());
- return FinalizeHash(result);
+ result = FinalizeHash(result, kHashBits);
+ SetHash(result);
+ return result;
}
@@ -17791,6 +17945,7 @@
const BoundedType& result = BoundedType::Handle(BoundedType::New());
result.set_type(type);
result.set_bound(bound);
+ result.SetHash(0);
result.set_type_parameter(type_parameter);
return result.raw();
}
@@ -19328,10 +19483,9 @@
// Return a non-zero hash of at most 'bits' bits.
intptr_t Finalize(int bits) {
ASSERT(1 <= bits && bits <= (kBitsPerWord - 1));
- hash_ = FinalizeHash(hash_);
- hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
+ hash_ = FinalizeHash(hash_, bits);
ASSERT(hash_ <= static_cast<uint32_t>(kMaxInt32));
- return hash_ == 0 ? 1 : hash_;
+ return hash_;
}
private:
uint32_t hash_;
@@ -19364,7 +19518,7 @@
intptr_t String::Hash(const String& str, intptr_t begin_index, intptr_t len) {
StringHasher hasher;
hasher.Add(str, begin_index, len);
- return hasher.Finalize(String::kHashBits);
+ return hasher.Finalize(kHashBits);
}
@@ -19379,7 +19533,7 @@
StringHasher hasher;
hasher.Add(str1, 0, len1);
hasher.Add(str2, 0, str2.Length());
- return hasher.Finalize(String::kHashBits);
+ return hasher.Finalize(kHashBits);
}
}
@@ -19411,7 +19565,7 @@
while (i < len) {
hasher.Add(Utf16::Next(characters, &i, len));
}
- return hasher.Finalize(String::kHashBits);
+ return hasher.Finalize(kHashBits);
}
@@ -21108,7 +21262,7 @@
value = reinterpret_cast<uword>(At(i));
hash = CombineHashes(hash, value);
}
- return FinalizeHash(hash);
+ return FinalizeHash(hash, kHashBits);
}
@@ -21765,7 +21919,7 @@
for (intptr_t i = 0; i < len; i++) {
hash = CombineHashes(len, GetUint8(i));
}
- return FinalizeHash(hash);
+ return FinalizeHash(hash, kHashBits);
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index a2f8d21..c517514 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1051,8 +1051,8 @@
// Caches the canonical type of this class.
void SetCanonicalType(const Type& type) const;
- static intptr_t canonical_types_offset() {
- return OFFSET_OF(RawClass, canonical_types_);
+ static intptr_t canonical_type_offset() {
+ return OFFSET_OF(RawClass, canonical_type_);
}
// The super type of this class, Object type if not explicitly specified.
@@ -1221,9 +1221,6 @@
intptr_t index,
const Number& constant) const;
- intptr_t FindCanonicalTypeIndex(const AbstractType& needle) const;
- RawAbstractType* CanonicalTypeFromIndex(intptr_t idx) const;
-
void RehashConstants(Zone* zone) const;
static intptr_t InstanceSize() {
@@ -1360,7 +1357,8 @@
template <class FakeObject> static RawClass* New();
// Allocate instance classes.
- static RawClass* New(const String& name,
+ static RawClass* New(const Library& lib,
+ const String& name,
const Script& script,
TokenPosition token_pos);
static RawClass* NewNativeWrapper(const Library& library,
@@ -1386,6 +1384,8 @@
void DisableCHAOptimizedCode(const Class& subclass);
+ void DisableAllCHAOptimizedCode();
+
// Return the list of code objects that were compiled using CHA of this class.
// These code objects will be invalidated if new subclasses of this class
// are finalized.
@@ -1396,8 +1396,16 @@
void SetTraceAllocation(bool trace_allocation) const;
bool ValidatePostFinalizePatch(const Class& orig_class, Error* error) const;
+ void ReplaceEnum(const Class& old_enum) const;
+ void CopyStaticFieldValues(const Class& old_cls) const;
+ void PatchFieldsAndFunctions() const;
+ void CopyCanonicalConstants(const Class& old_cls) const;
+ void CopyCanonicalType(const Class& old_cls) const;
+ bool CanReload(const Class& replacement) const;
private:
+ template <class FakeObject> static RawClass* NewCommon(intptr_t index);
+
enum MemberKind {
kAny = 0,
kStatic,
@@ -1454,8 +1462,8 @@
void set_constants(const Array& value) const;
- void set_canonical_types(const Object& value) const;
- RawObject* canonical_types() const;
+ void set_canonical_type(const Type& value) const;
+ RawType* canonical_type() const;
RawArray* invocation_dispatcher_cache() const;
void set_invocation_dispatcher_cache(const Array& cache) const;
@@ -1500,6 +1508,9 @@
// Allocate an instance class which has a VM implementation.
template <class FakeInstance> static RawClass* New(intptr_t id);
+ // Helper that calls 'Class::New<Instance>(kIllegalCid)'.
+ static RawClass* NewInstanceClass();
+
// Check the subtype or 'more specific' relationship.
bool TypeTest(TypeTestKind test_kind,
const TypeArguments& type_arguments,
@@ -1519,15 +1530,6 @@
TrailPtr bound_trail,
Heap::Space space);
- // Returns AbstractType::null() if type not found.
- RawAbstractType* LookupCanonicalType(Zone* zone,
- const AbstractType& type,
- intptr_t* index) const;
-
- // Returns canonical type. Thread safe.
- RawAbstractType* LookupOrAddCanonicalType(const AbstractType& type,
- intptr_t start_index) const;
-
FINAL_HEAP_OBJECT_IMPLEMENTATION(Class, Object);
friend class AbstractType;
friend class Instance;
@@ -1573,6 +1575,11 @@
// A TypeArguments is an array of AbstractType.
class TypeArguments : public Object {
public:
+ // We use 30 bits for the hash code so hashes in a snapshot taken on a
+ // 64-bit architecture stay in Smi range when loaded on a 32-bit
+ // architecture.
+ static const intptr_t kHashBits = 30;
+
intptr_t Length() const;
RawAbstractType* TypeAt(intptr_t index) const;
static intptr_t type_at_offset(intptr_t index) {
@@ -1717,8 +1724,9 @@
static intptr_t InstanceSize(intptr_t len) {
// Ensure that the types() is not adding to the object size, which includes
- // 2 fields: instantiations_ and length_.
- ASSERT(sizeof(RawTypeArguments) == (sizeof(RawObject) + (2 * kWordSize)));
+ // 3 fields: instantiations_, length_ and hash_.
+ ASSERT(sizeof(RawTypeArguments) ==
+ (sizeof(RawObject) + (kNumFields * kWordSize)));
ASSERT(0 <= len && len <= kMaxElements);
return RoundedAllocationSize(
sizeof(RawTypeArguments) + (len * kBytesPerElement));
@@ -1729,6 +1737,9 @@
static RawTypeArguments* New(intptr_t len, Heap::Space space = Heap::kOld);
private:
+ intptr_t ComputeHash() const;
+ void SetHash(intptr_t value) const;
+
// Check if the subvector of length 'len' starting at 'from_index' of this
// type argument vector consists solely of DynamicType.
// If raw_instantiated is true, consider each type parameter to be first
@@ -1757,6 +1768,8 @@
void set_instantiations(const Array& value) const;
RawAbstractType* const* TypeAddr(intptr_t index) const;
void SetLength(intptr_t value) const;
+ // Number of fields in the raw object=3 (instantiations_, length_ and hash_).
+ static const int kNumFields = 3;
FINAL_HEAP_OBJECT_IMPLEMENTATION(TypeArguments, Object);
friend class AbstractType;
@@ -1827,6 +1840,11 @@
return raw_ptr()->deopt_id_;
}
+ bool IsImmutable() const;
+
+ void Reset(bool is_static_call) const;
+ void ResetData() const;
+
// Note: only deopts with reasons before Unknown in this list are recorded in
// the ICData. All other reasons are used purely for informational messages
// printed during deoptimization itself.
@@ -1872,6 +1890,10 @@
bool HasDeoptReason(ICData::DeoptReasonId reason) const;
void AddDeoptReason(ICData::DeoptReasonId reason) const;
+ // The length of the array. This includes all sentinel entries including
+ // the final one.
+ intptr_t Length() const;
+
intptr_t NumberOfChecks() const;
// Discounts any checks with usage of zero.
@@ -1909,6 +1931,30 @@
return OFFSET_OF(RawICData, owner_);
}
+ // Replaces entry |index| with the sentinel.
+ void WriteSentinelAt(intptr_t index) const;
+
+ // Clears the count for entry |index|.
+ void ClearCountAt(intptr_t index) const;
+
+ // Clear all entries with the sentinel value (but will preserve initial
+ // smi smi checks).
+ void ClearWithSentinel() const;
+
+ // Clear all entries with the sentinel value and reset the first entry
+ // with the dummy target entry.
+ void ClearAndSetStaticTarget(const Function& func) const;
+
+ // Returns the first index that should be used to for a new entry. Will
+ // grow the array if necessary.
+ RawArray* FindFreeIndex(intptr_t* index) const;
+
+ void DebugDump() const;
+ void ValidateSentinelLocations() const;
+
+ // Returns true if this is a two arg smi operation.
+ bool AddSmiSmiCheckForFastSmiStubs() const;
+
// Used for unoptimized static calls when no class-ids are checked.
void AddTarget(const Function& target) const;
@@ -1924,6 +1970,9 @@
const Function& target,
intptr_t count = 1) const;
+ // Does entry |index| contain the sentinel value?
+ bool IsSentinelAt(intptr_t index) const;
+
// Retrieving checks.
void GetCheckAt(intptr_t index,
@@ -2223,6 +2272,11 @@
// visible formal parameters of the function.
RawString* UserVisibleFormalParameters() const;
+ // Reloading support:
+ void Reparent(const Class& new_cls) const;
+ void ZeroEdgeCounters() const;
+ void FillICDataWithSentinels(const Code& code) const;
+
RawClass* Owner() const;
RawClass* origin() const;
RawScript* script() const;
@@ -2261,6 +2315,13 @@
// Disables optimized code and switches to unoptimized code.
void SwitchToUnoptimizedCode() const;
+ // Disables optimized code and switches to unoptimized code (or the lazy
+ // compilation stub).
+ void SwitchToLazyCompiledUnoptimizedCode() const;
+
+ // Compiles unoptimized code (if necessary) and attaches it to the function.
+ void EnsureHasCompiledUnoptimizedCode() const;
+
// Return the most recently compiled and installed code for this function.
// It is not the only Code object that points to this function.
RawCode* CurrentCode() const {
@@ -3188,6 +3249,14 @@
static bool IsSetterName(const String& function_name);
private:
+ static void InitializeNew(const Field& result,
+ const String& name,
+ bool is_static,
+ bool is_final,
+ bool is_const,
+ bool is_reflectable,
+ const Object& owner,
+ TokenPosition token_pos);
friend class StoreInstanceFieldInstr; // Generated code access to bit field.
enum {
@@ -3214,6 +3283,9 @@
// deoptimization of dependent code is required.
bool UpdateGuardedCidAndLength(const Object& value) const;
+ // Force this field's guard to be dynamic and deoptimize dependent code.
+ void ForceDynamicGuardedCidAndLength() const;
+
void set_name(const String& value) const;
void set_is_static(bool is_static) const {
set_kind_bits(StaticBit::update(is_static, raw_ptr()->kind_bits_));
@@ -3279,7 +3351,7 @@
RawString* GenerateSource() const;
RawString* GenerateSource(TokenPosition start,
TokenPosition end) const;
- TokenPosition ComputeSourcePosition(TokenPosition tok_pos) const;
+ intptr_t ComputeSourcePosition(TokenPosition tok_pos) const;
RawString* PrivateKey() const;
@@ -3291,7 +3363,7 @@
}
static RawTokenStream* New(intptr_t length);
- static RawTokenStream* New(const Scanner::GrowableTokenStream& tokens,
+ static RawTokenStream* New(const String& source,
const String& private_key,
bool use_shared_tokens);
@@ -3377,6 +3449,9 @@
intptr_t line_offset() const { return raw_ptr()->line_offset_; }
intptr_t col_offset() const { return raw_ptr()->col_offset_; }
+ // The load time in milliseconds since epoch.
+ int64_t load_timestamp() const { return raw_ptr()->load_timestamp_; }
+
RawTokenStream* tokens() const { return raw_ptr()->tokens_; }
void Tokenize(const String& private_key,
@@ -3417,6 +3492,7 @@
void set_url(const String& value) const;
void set_source(const String& value) const;
void set_kind(RawScript::Kind value) const;
+ void set_load_timestamp(int64_t value) const;
void set_tokens(const TokenStream& value) const;
static RawScript* New();
@@ -3706,6 +3782,8 @@
// the library-specific key.
static const char kPrivateKeySeparator = '@';
+ bool CanReload(const Library& replacement) const;
+
private:
static const int kInitialImportsCapacity = 4;
static const int kImportsCapacityIncrement = 8;
@@ -5370,6 +5448,11 @@
// Subclasses of AbstractType are Type and TypeParameter.
class AbstractType : public Instance {
public:
+ // We use 30 bits for the hash code so hashes in a snapshot taken on a
+ // 64-bit architecture stay in Smi range when loaded on a 32-bit
+ // architecture.
+ static const intptr_t kHashBits = 30;
+
virtual bool IsFinalized() const;
virtual void SetIsFinalized() const;
virtual bool IsBeingFinalized() const;
@@ -5382,6 +5465,7 @@
virtual bool IsResolved() const;
virtual void SetIsResolved() const;
virtual bool HasResolvedTypeClass() const;
+ virtual classid_t type_class_id() const;
virtual RawClass* type_class() const;
virtual RawUnresolvedClass* unresolved_class() const;
virtual RawTypeArguments* arguments() const;
@@ -5570,8 +5654,8 @@
// relate to a 'raw type', as opposed to a 'cooked type' or 'rare type'.
class Type : public AbstractType {
public:
- static intptr_t type_class_offset() {
- return OFFSET_OF(RawType, type_class_);
+ static intptr_t type_class_id_offset() {
+ return OFFSET_OF(RawType, type_class_id_);
}
virtual bool IsFinalized() const {
return
@@ -5594,8 +5678,10 @@
}
virtual void SetIsResolved() const;
virtual bool HasResolvedTypeClass() const; // Own type class resolved.
+ virtual classid_t type_class_id() const;
virtual RawClass* type_class() const;
- void set_type_class(const Object& value) const;
+ void set_type_class(const Class& value) const;
+ void set_unresolved_class(const Object& value) const;
virtual RawUnresolvedClass* unresolved_class() const;
virtual RawTypeArguments* arguments() const { return raw_ptr()->arguments_; }
virtual void set_arguments(const TypeArguments& value) const;
@@ -5685,6 +5771,9 @@
Heap::Space space = Heap::kOld);
private:
+ intptr_t ComputeHash() const;
+ void SetHash(intptr_t value) const;
+
void set_token_pos(TokenPosition token_pos) const;
void set_type_state(int8_t state) const;
@@ -5786,9 +5875,8 @@
virtual bool IsMalformedOrMalbounded() const { return false; }
virtual bool IsResolved() const { return true; }
virtual bool HasResolvedTypeClass() const { return false; }
- RawClass* parameterized_class() const {
- return raw_ptr()->parameterized_class_;
- }
+ classid_t parameterized_class_id() const;
+ RawClass* parameterized_class() const;
RawString* name() const { return raw_ptr()->name_; }
intptr_t index() const { return raw_ptr()->index_; }
void set_index(intptr_t value) const;
@@ -5836,6 +5924,9 @@
TokenPosition token_pos);
private:
+ intptr_t ComputeHash() const;
+ void SetHash(intptr_t value) const;
+
void set_parameterized_class(const Class& value) const;
void set_name(const String& value) const;
void set_token_pos(TokenPosition token_pos) const;
@@ -5921,6 +6012,9 @@
const TypeParameter& type_parameter);
private:
+ intptr_t ComputeHash() const;
+ void SetHash(intptr_t value) const;
+
void set_type(const AbstractType& value) const;
void set_bound(const AbstractType& value) const;
void set_type_parameter(const TypeParameter& value) const;
@@ -6335,8 +6429,9 @@
// String may not be '\0' terminated.
class String : public Instance {
public:
- // We use 30 bits for the hash code so that we consistently use a
- // 32bit Smi representation for the hash code on all architectures.
+ // We use 30 bits for the hash code so hashes in a snapshot taken on a
+ // 64-bit architecture stay in Smi range when loaded on a 32-bit
+ // architecture.
static const intptr_t kHashBits = 30;
static const intptr_t kOneByteChar = 1;
@@ -7115,6 +7210,11 @@
class Array : public Instance {
public:
+ // We use 30 bits for the hash code so hashes in a snapshot taken on a
+ // 64-bit architecture stay in Smi range when loaded on a 32-bit
+ // architecture.
+ static const intptr_t kHashBits = 30;
+
intptr_t Length() const {
ASSERT(!IsNull());
return Smi::Value(raw_ptr()->length_);
@@ -7482,6 +7582,11 @@
class TypedData : public Instance {
public:
+ // We use 30 bits for the hash code so hashes in a snapshot taken on a
+ // 64-bit architecture stay in Smi range when loaded on a 32-bit
+ // architecture.
+ static const intptr_t kHashBits = 30;
+
intptr_t Length() const {
ASSERT(!IsNull());
return Smi::Value(raw_ptr()->length_);
@@ -8528,6 +8633,72 @@
return array.At((index * kEntryLength) + kTargetFunctionIndex);
}
+
+inline intptr_t Type::Hash() const {
+ intptr_t result = Smi::Value(raw_ptr()->hash_);
+ if (result != 0) {
+ return result;
+ }
+ return ComputeHash();
+}
+
+
+inline void Type::SetHash(intptr_t value) const {
+ // This is only safe because we create a new Smi, which does not cause
+ // heap allocation.
+ StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
+
+inline intptr_t TypeParameter::Hash() const {
+ ASSERT(IsFinalized());
+ intptr_t result = Smi::Value(raw_ptr()->hash_);
+ if (result != 0) {
+ return result;
+ }
+ return ComputeHash();
+}
+
+
+inline void TypeParameter::SetHash(intptr_t value) const {
+ // This is only safe because we create a new Smi, which does not cause
+ // heap allocation.
+ StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
+
+inline intptr_t BoundedType::Hash() const {
+ intptr_t result = Smi::Value(raw_ptr()->hash_);
+ if (result != 0) {
+ return result;
+ }
+ return ComputeHash();
+}
+
+
+inline void BoundedType::SetHash(intptr_t value) const {
+ // This is only safe because we create a new Smi, which does not cause
+ // heap allocation.
+ StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
+
+inline intptr_t TypeArguments::Hash() const {
+ if (IsNull()) return 0;
+ intptr_t result = Smi::Value(raw_ptr()->hash_);
+ if (result != 0) {
+ return result;
+ }
+ return ComputeHash();
+}
+
+
+inline void TypeArguments::SetHash(intptr_t value) const {
+ // This is only safe because we create a new Smi, which does not cause
+ // heap allocation.
+ StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
} // namespace dart
#endif // VM_OBJECT_H_
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
new file mode 100644
index 0000000..405854d
--- /dev/null
+++ b/runtime/vm/object_reload.cc
@@ -0,0 +1,548 @@
+// Copyright (c) 2016, 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/object.h"
+
+#include "vm/isolate_reload.h"
+#include "vm/log.h"
+#include "vm/resolver.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+#ifndef PRODUCT
+
+DECLARE_FLAG(bool, trace_reload);
+DECLARE_FLAG(bool, two_args_smi_icd);
+
+#define IRC (Isolate::Current()->reload_context())
+
+class ObjectReloadUtils : public AllStatic {
+ static void DumpLibraryDictionary(const Library& lib) {
+ DictionaryIterator it(lib);
+ Object& entry = Object::Handle();
+ String& name = String::Handle();
+ TIR_Print("Dumping dictionary for %s\n", lib.ToCString());
+ while (it.HasNext()) {
+ entry = it.GetNext();
+ name = entry.DictionaryName();
+ TIR_Print("%s -> %s\n", name.ToCString(), entry.ToCString());
+ }
+ }
+};
+
+
+void Function::Reparent(const Class& new_cls) const {
+ set_owner(new_cls);
+}
+
+
+void Function::ZeroEdgeCounters() const {
+ const Array& saved_ic_data = Array::Handle(ic_data_array());
+ if (saved_ic_data.IsNull()) {
+ return;
+ }
+ const intptr_t saved_ic_datalength = saved_ic_data.Length();
+ ASSERT(saved_ic_datalength > 0);
+ const Array& edge_counters_array =
+ Array::Handle(Array::RawCast(saved_ic_data.At(0)));
+ ASSERT(!edge_counters_array.IsNull());
+ // Fill edge counters array with zeros.
+ const Smi& zero = Smi::Handle(Smi::New(0));
+ for (intptr_t i = 0; i < edge_counters_array.Length(); i++) {
+ edge_counters_array.SetAt(i, zero);
+ }
+}
+
+
+static void ClearICs(const Function& function, const Code& code) {
+ if (function.ic_data_array() == Array::null()) {
+ return; // Already reset in an earlier round.
+ }
+
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+
+ ZoneGrowableArray<const ICData*>* ic_data_array =
+ new(zone) ZoneGrowableArray<const ICData*>();
+ function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
+ if (ic_data_array->length() == 0) {
+ return;
+ }
+ const PcDescriptors& descriptors =
+ PcDescriptors::Handle(code.pc_descriptors());
+ PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kIcCall |
+ RawPcDescriptors::kUnoptStaticCall);
+ while (iter.MoveNext()) {
+ const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
+ if (ic_data == NULL) {
+ continue;
+ }
+ bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall;
+ ic_data->Reset(is_static_call);
+ }
+}
+
+
+void Function::FillICDataWithSentinels(const Code& code) const {
+ ASSERT(code.raw() == CurrentCode());
+ ClearICs(*this, code);
+}
+
+
+void Class::CopyStaticFieldValues(const Class& old_cls) const {
+ // We only update values for non-enum classes.
+ const bool update_values = !is_enum_class();
+
+ IsolateReloadContext* reload_context = Isolate::Current()->reload_context();
+ ASSERT(reload_context != NULL);
+
+ const Array& old_field_list = Array::Handle(old_cls.fields());
+ Field& old_field = Field::Handle();
+ String& old_name = String::Handle();
+
+ const Array& field_list = Array::Handle(fields());
+ Field& field = Field::Handle();
+ String& name = String::Handle();
+
+ Instance& value = Instance::Handle();
+ for (intptr_t i = 0; i < field_list.Length(); i++) {
+ field = Field::RawCast(field_list.At(i));
+ name = field.name();
+ if (field.is_static()) {
+ // Find the corresponding old field, if it exists, and migrate
+ // over the field value.
+ for (intptr_t j = 0; j < old_field_list.Length(); j++) {
+ old_field = Field::RawCast(old_field_list.At(j));
+ old_name = old_field.name();
+ if (name.Equals(old_name)) {
+ if (update_values) {
+ value = old_field.StaticValue();
+ field.SetStaticValue(value);
+ }
+ reload_context->AddStaticFieldMapping(old_field, field);
+ }
+ }
+ }
+ }
+}
+
+
+void Class::CopyCanonicalConstants(const Class& old_cls) const {
+ if (is_enum_class()) {
+ return;
+ }
+#if defined(DEBUG)
+ {
+ // Class has no canonical constants allocated.
+ const Array& my_constants = Array::Handle(constants());
+ ASSERT(my_constants.Length() == 0);
+ }
+#endif // defined(DEBUG).
+ // Copy old constants into new class.
+ const Array& old_constants = Array::Handle(old_cls.constants());
+ if (old_constants.IsNull() || old_constants.Length() == 0) {
+ return;
+ }
+ TIR_Print("Copied %" Pd " canonical constants for class `%s`\n",
+ old_constants.Length(),
+ ToCString());
+ set_constants(old_constants);
+}
+
+
+void Class::CopyCanonicalType(const Class& old_cls) const {
+ const Type& old_canonical_type = Type::Handle(old_cls.canonical_type());
+ if (old_canonical_type.IsNull()) {
+ return;
+ }
+ set_canonical_type(old_canonical_type);
+}
+
+
+static intptr_t IndexOfEnum(const Array& enum_names, const String& name) {
+ ASSERT(!enum_names.IsNull());
+ ASSERT(!name.IsNull());
+ String& enum_name = String::Handle();
+ for (intptr_t i = 0; i < enum_names.Length(); i++) {
+ enum_name = String::RawCast(enum_names.At(i));
+ ASSERT(!enum_name.IsNull());
+ if (enum_name.Equals(name)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+static void UpdateEnumIndex(const Instance& enum_value,
+ const Field& enum_index_field,
+ const intptr_t index) {
+ enum_value.SetField(enum_index_field, Smi::Handle(Smi::New(index)));
+}
+
+
+// TODO(johnmccutchan): The code in the class finalizer canonicalizes all
+// instances and the values array. We probably should do the same thing.
+void Class::ReplaceEnum(const Class& old_enum) const {
+ // We only do this for finalized enum classes.
+ ASSERT(is_enum_class());
+ ASSERT(old_enum.is_enum_class());
+ ASSERT(is_finalized());
+ ASSERT(old_enum.is_finalized());
+
+ Thread* thread = Thread::Current();
+ IsolateReloadContext* reload_context = Isolate::Current()->reload_context();
+ ASSERT(reload_context != NULL);
+
+ TIR_Print("ReplaceEnum `%s` (%" Pd " and %" Pd ")\n",
+ ToCString(), id(), old_enum.id());
+
+ // Grab '_enum_names' from |old_enum|.
+ const Field& old_enum_names_field = Field::Handle(
+ old_enum.LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
+ ASSERT(!old_enum_names_field.IsNull());
+ const Array& old_enum_names =
+ Array::Handle(Array::RawCast(old_enum_names_field.StaticValue()));
+ ASSERT(!old_enum_names.IsNull());
+
+ // Grab 'values' from |old_enum|.
+ const Field& old_enum_values_field = Field::Handle(
+ old_enum.LookupStaticField(Symbols::Values()));
+ ASSERT(!old_enum_values_field.IsNull());
+ const Array& old_enum_values =
+ Array::Handle(Array::RawCast(old_enum_values_field.StaticValue()));
+ ASSERT(!old_enum_values.IsNull());
+
+ // Grab _enum_names from |this|.
+ const Field& enum_names_field = Field::Handle(
+ LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
+ ASSERT(!enum_names_field.IsNull());
+ Array& enum_names =
+ Array::Handle(Array::RawCast(enum_names_field.StaticValue()));
+ ASSERT(!enum_names.IsNull());
+
+ // Grab values from |this|.
+ const Field& enum_values_field = Field::Handle(
+ LookupStaticField(Symbols::Values()));
+ ASSERT(!enum_values_field.IsNull());
+ Array& enum_values =
+ Array::Handle(Array::RawCast(enum_values_field.StaticValue()));
+ ASSERT(!enum_values.IsNull());
+
+ // Grab the |index| field.
+ const Field& index_field =
+ Field::Handle(old_enum.LookupInstanceField(Symbols::Index()));
+ ASSERT(!index_field.IsNull());
+
+ // Build list of enum from |old_enum| that aren't present in |this|.
+ // This array holds pairs: (name, value).
+ const GrowableObjectArray& to_add =
+ GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld));
+ const String& enum_class_name = String::Handle(UserVisibleName());
+ String& enum_name = String::Handle();
+ String& enum_field_name = String::Handle();
+ Object& enum_value = Object::Handle();
+ Field& enum_field = Field::Handle();
+
+ TIR_Print("New version of enum has %" Pd " elements\n",
+ enum_values.Length());
+ TIR_Print("Old version of enum had %" Pd " elements\n",
+ old_enum_values.Length());
+
+ for (intptr_t i = 0; i < old_enum_names.Length(); i++) {
+ enum_name = String::RawCast(old_enum_names.At(i));
+ const intptr_t index_in_new_cls = IndexOfEnum(enum_names, enum_name);
+ if (index_in_new_cls < 0) {
+ // Doesn't exist in new enum, add.
+ TIR_Print("Adding enum value `%s` to %s\n",
+ enum_name.ToCString(),
+ this->ToCString());
+ enum_value = old_enum_values.At(i);
+ ASSERT(!enum_value.IsNull());
+ to_add.Add(enum_name);
+ to_add.Add(enum_value);
+ } else {
+ // Exists in both the new and the old.
+ TIR_Print("Moving enum value `%s` to %" Pd "\n",
+ enum_name.ToCString(),
+ index_in_new_cls);
+ // Grab old value.
+ enum_value = old_enum_values.At(i);
+ // Update index to the be new index.
+ UpdateEnumIndex(Instance::Cast(enum_value),
+ index_field,
+ index_in_new_cls);
+ // Chop off the 'EnumClass.'
+ enum_field_name = String::SubString(enum_name,
+ enum_class_name.Length() + 1);
+ ASSERT(!enum_field_name.IsNull());
+ // Grab the static field.
+ enum_field = LookupStaticField(enum_field_name);
+ ASSERT(!enum_field.IsNull());
+ // Use old value with updated index.
+ enum_field.SetStaticValue(Instance::Cast(enum_value), true);
+ enum_values.SetAt(index_in_new_cls, enum_value);
+ enum_names.SetAt(index_in_new_cls, enum_name);
+ }
+ }
+
+ if (to_add.Length() == 0) {
+ // Nothing to do.
+ TIR_Print("Found no missing enums in %s\n", ToCString());
+ return;
+ }
+
+ // Grow the values and enum_names arrays.
+ const intptr_t offset = enum_names.Length();
+ const intptr_t num_to_add = to_add.Length() / 2;
+ ASSERT(offset == enum_values.Length());
+ enum_names = Array::Grow(enum_names,
+ enum_names.Length() + num_to_add,
+ Heap::kOld);
+ enum_values = Array::Grow(enum_values,
+ enum_values.Length() + num_to_add,
+ Heap::kOld);
+
+ // Install new names and values into the grown arrays. Also, update
+ // the index of the new enum values and add static fields for the new
+ // enum values.
+ Field& enum_value_field = Field::Handle();
+ for (intptr_t i = 0; i < num_to_add; i++) {
+ const intptr_t target_index = offset + i;
+ enum_name = String::RawCast(to_add.At(i * 2));
+ enum_value = to_add.At(i * 2 + 1);
+
+ // Update the enum value's index into the new arrays.
+ TIR_Print("Updating index of %s in %s to %" Pd "\n",
+ enum_name.ToCString(),
+ ToCString(),
+ target_index);
+ UpdateEnumIndex(Instance::Cast(enum_value), index_field, target_index);
+
+ enum_names.SetAt(target_index, enum_name);
+ enum_values.SetAt(target_index, enum_value);
+
+ // Install new static field into class.
+ // Chop off the 'EnumClass.'
+ enum_field_name = String::SubString(enum_name,
+ enum_class_name.Length() + 1);
+ ASSERT(!enum_field_name.IsNull());
+ enum_field_name = Symbols::New(thread, enum_field_name);
+ enum_value_field = Field::New(enum_field_name,
+ /* is_static = */ true,
+ /* is_final = */ true,
+ /* is_const = */ true,
+ /* is_reflectable = */ true,
+ *this,
+ Object::dynamic_type(),
+ token_pos());
+ enum_value_field.set_has_initializer(false);
+ enum_value_field.SetStaticValue(Instance::Cast(enum_value), true);
+ enum_value_field.RecordStore(Instance::Cast(enum_value));
+ AddField(enum_value_field);
+ }
+
+ // Replace the arrays stored in the static fields.
+ enum_names_field.SetStaticValue(enum_names, true);
+ enum_values_field.SetStaticValue(enum_values, true);
+}
+
+
+void Class::PatchFieldsAndFunctions() const {
+ // Move all old functions and fields to a patch class so that they
+ // still refer to their original script.
+ const PatchClass& patch =
+ PatchClass::Handle(PatchClass::New(*this, Script::Handle(script())));
+ ASSERT(!patch.IsNull());
+
+ const Array& funcs = Array::Handle(functions());
+ Function& func = Function::Handle();
+ Object& owner = Object::Handle();
+ for (intptr_t i = 0; i < funcs.Length(); i++) {
+ func = Function::RawCast(funcs.At(i));
+ if ((func.token_pos() == TokenPosition::kMinSource) ||
+ func.IsClosureFunction()) {
+ // Eval functions do not need to have their script updated.
+ //
+ // Closure functions refer to the parent's script which we can
+ // rely on being updated for us, if necessary.
+ continue;
+ }
+
+ // If the source for this function is already patched, leave it alone.
+ owner = func.RawOwner();
+ ASSERT(!owner.IsNull());
+ if (!owner.IsPatchClass()) {
+ ASSERT(owner.raw() == this->raw());
+ func.set_owner(patch);
+ }
+ }
+
+ const Array& field_list = Array::Handle(fields());
+ Field& field = Field::Handle();
+ for (intptr_t i = 0; i < field_list.Length(); i++) {
+ field = Field::RawCast(field_list.At(i));
+ owner = field.RawOwner();
+ ASSERT(!owner.IsNull());
+ if (!owner.IsPatchClass()) {
+ ASSERT(owner.raw() == this->raw());
+ field.set_owner(patch);
+ }
+ field.ForceDynamicGuardedCidAndLength();
+ }
+}
+
+
+bool Class::CanReload(const Class& replacement) const {
+ ASSERT(IsolateReloadContext::IsSameClass(*this, replacement));
+
+ if (is_enum_class() && !replacement.is_enum_class()) {
+ IRC->ReportError(String::Handle(String::NewFormatted(
+ "Enum class cannot be redefined to be a non-enum class: %s",
+ ToCString())));
+ return false;
+ }
+
+ if (!is_enum_class() && replacement.is_enum_class()) {
+ IRC->ReportError(String::Handle(String::NewFormatted(
+ "Class cannot be redefined to be a enum class: %s",
+ ToCString())));
+ return false;
+ }
+
+ if (is_finalized()) {
+ const Error& error =
+ Error::Handle(replacement.EnsureIsFinalized(Thread::Current()));
+ if (!error.IsNull()) {
+ IRC->ReportError(error);
+ return false;
+ }
+ TIR_Print("Finalized replacement class for %s\n", ToCString());
+ }
+
+ if (is_finalized()) {
+ // Get the field maps for both classes. These field maps walk the class
+ // hierarchy.
+ const Array& fields =
+ Array::Handle(OffsetToFieldMap());
+ const Array& replacement_fields =
+ Array::Handle(replacement.OffsetToFieldMap());
+
+ // Check that we have the same number of fields.
+ if (fields.Length() != replacement_fields.Length()) {
+ IRC->ReportError(String::Handle(String::NewFormatted(
+ "Number of instance fields changed in %s", ToCString())));
+ return false;
+ }
+
+ if (NumTypeArguments() != replacement.NumTypeArguments()) {
+ IRC->ReportError(String::Handle(String::NewFormatted(
+ "Number of type arguments changed in %s", ToCString())));
+ return false;
+ }
+
+ // Verify that field names / offsets match across the entire hierarchy.
+ Field& field = Field::Handle();
+ String& field_name = String::Handle();
+ Field& replacement_field = Field::Handle();
+ String& replacement_field_name = String::Handle();
+ for (intptr_t i = 0; i < fields.Length(); i++) {
+ if (fields.At(i) == Field::null()) {
+ ASSERT(replacement_fields.At(i) == Field::null());
+ continue;
+ }
+ field = Field::RawCast(fields.At(i));
+ replacement_field = Field::RawCast(replacement_fields.At(i));
+ field_name = field.name();
+ replacement_field_name = replacement_field.name();
+ if (!field_name.Equals(replacement_field_name)) {
+ IRC->ReportError(String::Handle(String::NewFormatted(
+ "Name of instance field changed ('%s' vs '%s') in '%s'",
+ field_name.ToCString(),
+ replacement_field_name.ToCString(),
+ ToCString())));
+ return false;
+ }
+ }
+ } else if (is_prefinalized()) {
+ if (!replacement.is_prefinalized()) {
+ IRC->ReportError(String::Handle(String::NewFormatted(
+ "Original class ('%s') is prefinalized and replacement class ('%s')",
+ ToCString(), replacement.ToCString())));
+ return false;
+ }
+ if (instance_size() != replacement.instance_size()) {
+ IRC->ReportError(String::Handle(String::NewFormatted(
+ "Instance size mismatch between '%s' (%" Pd ") and replacement "
+ "'%s' ( %" Pd ")",
+ ToCString(),
+ instance_size(),
+ replacement.ToCString(),
+ replacement.instance_size())));
+ return false;
+ }
+ }
+
+ // native field count check.
+ if (num_native_fields() != replacement.num_native_fields()) {
+ IRC->ReportError(String::Handle(String::NewFormatted(
+ "Number of native fields changed in %s", ToCString())));
+ return false;
+ }
+
+ // TODO(johnmccutchan) type parameter count check.
+
+ TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n",
+ ToCString(),
+ id(),
+ replacement.id());
+ return true;
+}
+
+
+bool Library::CanReload(const Library& replacement) const {
+ return true;
+}
+
+
+static const Function* static_call_target = NULL;
+
+void ICData::Reset(bool is_static_call) const {
+ // TODO(johnmccutchan): ICData should know whether or not it's for a
+ // static call.
+ if (is_static_call) {
+ const Function& old_target = Function::Handle(GetTargetAt(0));
+ if (old_target.IsNull()) {
+ FATAL("old_target is NULL.\n");
+ }
+ static_call_target = &old_target;
+ if (!old_target.is_static()) {
+ // TODO(johnmccutchan): Improve this.
+ TIR_Print("Cannot rebind super-call to %s from %s\n",
+ old_target.ToCString(),
+ Object::Handle(Owner()).ToCString());
+ return;
+ }
+ const String& selector = String::Handle(old_target.name());
+ const Class& cls = Class::Handle(old_target.Owner());
+ const Function& new_target =
+ Function::Handle(cls.LookupStaticFunction(selector));
+ if (new_target.IsNull()) {
+ // TODO(johnmccutchan): Improve this.
+ TIR_Print("Cannot rebind static call to %s from %s\n",
+ old_target.ToCString(),
+ Object::Handle(Owner()).ToCString());
+ return;
+ }
+ ClearAndSetStaticTarget(new_target);
+ } else {
+ ClearWithSentinel();
+ }
+}
+
+#endif // !PRODUCT
+
+} // namespace dart.
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 41290fb..7eab800 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -8,6 +8,7 @@
#include "vm/object_store.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
+#include "vm/type_table.h"
namespace dart {
@@ -187,9 +188,15 @@
// The index in the canonical_type_arguments table cannot be used as part of
// the object id (as in typearguments/id), because the indices are not
// preserved when the table grows and the entries get rehashed. Use the ring.
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Isolate* isolate = thread->isolate();
ObjectStore* object_store = isolate->object_store();
- const Array& table = Array::Handle(object_store->canonical_type_arguments());
+ CanonicalTypeArgumentsSet typeargs_table(
+ zone, object_store->canonical_type_arguments());
+ const Array& table =
+ Array::Handle(HashTables::ToArray(typeargs_table, false));
+ typeargs_table.Release();
ASSERT(table.Length() > 0);
AddCommonObjectProperties(&jsobj, "TypeArguments", ref);
jsobj.AddServiceId(*this);
@@ -430,18 +437,19 @@
const String& encoded_uri = String::Handle(String::EncodeIRI(uri));
ASSERT(!encoded_uri.IsNull());
const Library& lib = Library::Handle(FindLibrary());
- if (kind() == RawScript::kEvaluateTag) {
+ if (lib.IsNull()) {
jsobj.AddServiceId(*this);
} else {
- ASSERT(!lib.IsNull());
- jsobj.AddFixedServiceId("libraries/%" Pd "/scripts/%s",
- lib.index(), encoded_uri.ToCString());
+ jsobj.AddFixedServiceId("libraries/%" Pd "/scripts/%s/%" Px64 "",
+ lib.index(), encoded_uri.ToCString(),
+ load_timestamp());
}
jsobj.AddPropertyStr("uri", uri);
jsobj.AddProperty("_kind", GetKindAsCString());
if (ref) {
return;
}
+ jsobj.AddPropertyTimeMillis("_loadTime", load_timestamp());
if (!lib.IsNull()) {
jsobj.AddProperty("library", lib);
}
@@ -1129,11 +1137,13 @@
jsobj.AddProperty("kind", "Type");
if (IsCanonical()) {
const Class& type_cls = Class::Handle(type_class());
- intptr_t id = type_cls.FindCanonicalTypeIndex(*this);
- ASSERT(id >= 0);
- intptr_t cid = type_cls.id();
- jsobj.AddFixedServiceId("classes/%" Pd "/types/%" Pd "", cid, id);
- jsobj.AddProperty("typeClass", type_cls);
+ if (type_cls.CanonicalType() == raw()) {
+ intptr_t cid = type_cls.id();
+ jsobj.AddFixedServiceId("classes/%" Pd "/types/%d", cid, 0);
+ jsobj.AddProperty("typeClass", type_cls);
+ } else {
+ jsobj.AddServiceId(*this);
+ }
} else {
jsobj.AddServiceId(*this);
}
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 95810d2..9affdcb 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -56,6 +56,7 @@
error_class_(Class::null()),
weak_property_class_(Class::null()),
symbol_table_(Array::null()),
+ canonical_types_(Array::null()),
canonical_type_arguments_(Array::null()),
async_library_(Library::null()),
builtin_library_(Library::null()),
@@ -184,6 +185,10 @@
void ObjectStore::InitKnownObjects() {
+#ifdef DART_PRECOMPILED_RUNTIME
+ // These objects are only needed for code generation.
+ return;
+#else
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
@@ -205,6 +210,7 @@
const Library& internal_lib = Library::Handle(internal_library());
cls = internal_lib.LookupClass(Symbols::Symbol());
set_symbol_class(cls);
+#endif
}
} // namespace dart
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index eb868fb..56ee2b0 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -247,6 +247,13 @@
RawArray* symbol_table() const { return symbol_table_; }
void set_symbol_table(const Array& value) { symbol_table_ = value.raw(); }
+ RawArray* canonical_types() const {
+ return canonical_types_;
+ }
+ void set_canonical_types(const Array& value) {
+ canonical_types_ = value.raw();
+ }
+
RawArray* canonical_type_arguments() const {
return canonical_type_arguments_;
}
@@ -536,6 +543,7 @@
RawClass* error_class_;
RawClass* weak_property_class_;
RawArray* symbol_table_;
+ RawArray* canonical_types_;
RawArray* canonical_type_arguments_;
RawLibrary* async_library_;
RawLibrary* builtin_library_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 7d9be08..9ad5f70 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -24,8 +24,8 @@
static RawClass* CreateDummyClass(const String& class_name,
const Script& script) {
- const Class& cls = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
+ const Class& cls = Class::Handle(Class::New(
+ Library::Handle(), class_name, script, TokenPosition::kNoSource));
cls.set_is_synthesized_class(); // Dummy class for testing.
return cls.raw();
}
@@ -165,14 +165,9 @@
Zone* zone = Thread::Current()->zone();
String& source = String::Handle(zone, String::New("= ( 9 , ."));
String& private_key = String::Handle(zone, String::New(""));
- Scanner scanner(source, private_key);
- const Scanner::GrowableTokenStream& ts = scanner.GetStream();
- EXPECT_EQ(6, ts.length());
- EXPECT_EQ(Token::kLPAREN, ts[1].kind);
const TokenStream& token_stream = TokenStream::Handle(
- zone, TokenStream::New(ts, private_key, false));
+ zone, TokenStream::New(source, private_key, false));
TokenStream::Iterator iterator(zone, token_stream, TokenPosition::kMinSource);
- // EXPECT_EQ(6, token_stream.Length());
iterator.Advance(); // Advance to '(' token.
EXPECT_EQ(Token::kLPAREN, iterator.CurrentTokenKind());
iterator.Advance();
@@ -4084,10 +4079,8 @@
EXPECT(func_b.CanBeInlined());
// After setting a breakpoint in a function A.b, it is no longer inlineable.
- Breakpoint* bpt =
- Isolate::Current()->debugger()->SetBreakpointAtLine(name,
- kBreakpointLine);
- ASSERT(bpt != NULL);
+ result = Dart_SetBreakpoint(NewString(TestCase::url()), kBreakpointLine);
+ EXPECT_VALID(result);
EXPECT(!func_b.CanBeInlined());
}
diff --git a/runtime/vm/os.h b/runtime/vm/os.h
index 9064322..ff61aaa 100644
--- a/runtime/vm/os.h
+++ b/runtime/vm/os.h
@@ -110,6 +110,7 @@
// Not all platform support strndup.
static char* StrNDup(const char* s, intptr_t n);
+ static intptr_t StrNLen(const char* s, intptr_t n);
// Print formatted output to stdout/stderr for debugging.
static void Print(const char* format, ...) PRINTF_ATTRIBUTE(1, 2);
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index 1c22b7c..89cfbe9 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -220,12 +220,12 @@
intptr_t OS::PreferredCodeAlignment() {
-#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
- defined(TARGET_ARCH_ARM64)
- const int kMinimumAlignment = 16;
-#elif defined(TARGET_ARCH_ARM)
- const int kMinimumAlignment = 16;
-#elif defined(TARGET_ARCH_DBC)
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM64) || \
+ defined(TARGET_ARCH_DBC)
+ const int kMinimumAlignment = 32;
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
const int kMinimumAlignment = 16;
#else
#error Unsupported architecture.
@@ -288,6 +288,11 @@
}
+intptr_t OS::StrNLen(const char* s, intptr_t n) {
+ return strnlen(s, n);
+}
+
+
uint16_t HostToBigEndian16(uint16_t value) {
return htobe16(value);
}
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 7d7c7e0..df05e17 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -300,6 +300,11 @@
}
+intptr_t OS::StrNLen(const char* s, intptr_t n) {
+ return strnlen(s, n);
+}
+
+
void OS::Print(const char* format, ...) {
va_list args;
va_start(args, format);
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index 6d2d02a..0ed04ec 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -109,6 +109,10 @@
origin += boottime.tv_usec;
return now - origin;
#else
+ if (timebase_info.denom == 0) {
+ kern_return_t kr = mach_timebase_info(&timebase_info);
+ ASSERT(KERN_SUCCESS == kr);
+ }
ASSERT(timebase_info.denom != 0);
// timebase_info converts absolute time tick units into nanoseconds.
int64_t result = mach_absolute_time();
@@ -204,8 +208,24 @@
intptr_t OS::PreferredCodeAlignment() {
- ASSERT(32 <= OS::kMaxPreferredCodeAlignment);
- return 32;
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM64) || \
+ defined(TARGET_ARCH_DBC)
+ const int kMinimumAlignment = 32;
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+ const int kMinimumAlignment = 16;
+#else
+#error Unsupported architecture.
+#endif
+ intptr_t alignment = kMinimumAlignment;
+ // TODO(5411554): Allow overriding default code alignment for
+ // testing purposes.
+ // Flags::DebugIsInt("codealign", &alignment);
+ ASSERT(Utils::IsPowerOfTwo(alignment));
+ ASSERT(alignment >= kMinimumAlignment);
+ ASSERT(alignment <= OS::kMaxPreferredCodeAlignment);
+ return alignment;
}
@@ -279,6 +299,23 @@
}
+intptr_t OS::StrNLen(const char* s, intptr_t n) {
+ // strnlen has only been added to Mac OS X in 10.7. We are supplying
+ // our own copy here if needed.
+#if !defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 1060
+ intptr_t len = 0;
+ while ((len <= n) && (*s != '\0')) {
+ s++;
+ len++;
+ }
+ return len;
+#else // !defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || ...
+ return strnlen(s, n);
+#endif // !defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || ...
+}
+
+
void OS::Print(const char* format, ...) {
#if TARGET_OS_IOS
va_list args;
@@ -396,8 +433,6 @@
static bool init_once_called = false;
ASSERT(init_once_called == false);
init_once_called = true;
- kern_return_t kr = mach_timebase_info(&timebase_info);
- ASSERT(KERN_SUCCESS == kr);
}
diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc
index 947b7f6..75a7a31 100644
--- a/runtime/vm/os_thread.cc
+++ b/runtime/vm/os_thread.cc
@@ -23,7 +23,9 @@
OSThread::OSThread() :
BaseThread(true),
id_(OSThread::GetCurrentThreadId()),
- join_id_(OSThread::GetCurrentThreadJoinId()),
+#if defined(DEBUG)
+ join_id_(kInvalidThreadJoinId),
+#endif
trace_id_(OSThread::GetCurrentThreadTraceId()),
name_(NULL),
timeline_block_lock_(new Mutex()),
@@ -160,8 +162,8 @@
}
-bool OSThread::IsThreadInList(ThreadJoinId join_id) {
- if (join_id == OSThread::kInvalidThreadJoinId) {
+bool OSThread::IsThreadInList(ThreadId id) {
+ if (id == OSThread::kInvalidThreadId) {
return false;
}
OSThreadIterator it;
@@ -169,8 +171,8 @@
ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread());
OSThread* t = it.Next();
// An address test is not sufficient because the allocator may recycle
- // the address for another Thread. Test against the thread's join id.
- if (t->join_id() == join_id) {
+ // the address for another Thread. Test against the thread's id.
+ if (t->id() == id) {
return true;
}
}
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 1bd2193..415cff89 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -61,13 +61,8 @@
return id_;
}
- ThreadJoinId join_id() const {
- ASSERT(join_id_ != OSThread::kInvalidThreadJoinId);
- return join_id_;
- }
-
ThreadId trace_id() const {
- ASSERT(trace_id_ != OSThread::kInvalidThreadJoinId);
+ ASSERT(trace_id_ != OSThread::kInvalidThreadId);
return trace_id_;
}
@@ -174,10 +169,14 @@
static ThreadId ThreadIdFromIntPtr(intptr_t id);
static bool Compare(ThreadId a, ThreadId b);
+ // This function can be called only once per OSThread, and should only be
+ // called when the retunred id will eventually be passed to OSThread::Join().
+ static ThreadJoinId GetCurrentThreadJoinId(OSThread* thread);
+
// Called at VM startup and shutdown.
static void InitOnce();
- static bool IsThreadInList(ThreadJoinId join_id);
+ static bool IsThreadInList(ThreadId id);
static void DisableOSThreadCreation();
static void EnableOSThreadCreation();
@@ -205,7 +204,6 @@
static void Cleanup();
static ThreadId GetCurrentThreadTraceId();
- static ThreadJoinId GetCurrentThreadJoinId();
static OSThread* GetOSThreadFromThread(Thread* thread);
static void AddThreadToListLocked(OSThread* thread);
static void RemoveThreadFromList(OSThread* thread);
@@ -214,7 +212,11 @@
static ThreadLocalKey thread_key_;
const ThreadId id_;
- const ThreadJoinId join_id_;
+#if defined(DEBUG)
+ // In DEBUG mode we use this field to ensure that GetCurrentThreadJoinId is
+ // only called once per OSThread.
+ ThreadJoinId join_id_;
+#endif
const ThreadId trace_id_; // Used to interface with tracing tools.
char* name_; // A name for this thread.
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index b184f61..5a54c59 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -193,8 +193,17 @@
}
-ThreadJoinId OSThread::GetCurrentThreadJoinId() {
- return pthread_self();
+ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
+ ASSERT(thread != NULL);
+ // Make sure we're filling in the join id for the current thread.
+ ASSERT(thread->id() == GetCurrentThreadId());
+ // Make sure the join_id_ hasn't been set, yet.
+ DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
+ pthread_t id = pthread_self();
+#if defined(DEBUG)
+ thread->join_id_ = id;
+#endif
+ return id;
}
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index bd9bfaf..9695042 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -194,8 +194,17 @@
}
-ThreadJoinId OSThread::GetCurrentThreadJoinId() {
- return pthread_self();
+ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
+ ASSERT(thread != NULL);
+ // Make sure we're filling in the join id for the current thread.
+ ASSERT(thread->id() == GetCurrentThreadId());
+ // Make sure the join_id_ hasn't been set, yet.
+ DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
+ pthread_t id = pthread_self();
+#if defined(DEBUG)
+ thread->join_id_ = id;
+#endif
+ return id;
}
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 4c7d094..b5fd6f9 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -168,8 +168,17 @@
}
-ThreadJoinId OSThread::GetCurrentThreadJoinId() {
- return pthread_self();
+ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
+ ASSERT(thread != NULL);
+ // Make sure we're filling in the join id for the current thread.
+ ASSERT(thread->id() == GetCurrentThreadId());
+ // Make sure the join_id_ hasn't been set, yet.
+ DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
+ pthread_t id = pthread_self();
+#if defined(DEBUG)
+ thread->join_id_ = id;
+#endif
+ return id;
}
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index e4083dc..ed8de4af 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -91,7 +91,7 @@
const ThreadId OSThread::kInvalidThreadId = 0;
-const ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
+const ThreadJoinId OSThread::kInvalidThreadJoinId = NULL;
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
@@ -130,27 +130,25 @@
}
-ThreadJoinId OSThread::GetCurrentThreadJoinId() {
- // TODO(zra): Use the thread handle as the join id in order to have a more
- // reliable join on windows.
- return ::GetCurrentThreadId();
+ThreadJoinId OSThread::GetCurrentThreadJoinId(OSThread* thread) {
+ ASSERT(thread != NULL);
+ // Make sure we're filling in the join id for the current thread.
+ ThreadId id = GetCurrentThreadId();
+ ASSERT(thread->id() == id);
+ // Make sure the join_id_ hasn't been set, yet.
+ DEBUG_ASSERT(thread->join_id_ == kInvalidThreadJoinId);
+ HANDLE handle = OpenThread(SYNCHRONIZE, false, id);
+ ASSERT(handle != NULL);
+#if defined(DEBUG)
+ thread->join_id_ = handle;
+#endif
+ return handle;
}
void OSThread::Join(ThreadJoinId id) {
- HANDLE handle = OpenThread(SYNCHRONIZE, false, id);
-
- // TODO(zra): OSThread::Start() closes the handle to the thread. Thus, by the
- // time we try to join the thread, its resources may have already been
- // reclaimed, and joining will fail. This can be avoided in a couple of ways.
- // First, GetCurrentThreadJoinId could call OpenThread and return a handle.
- // This is bad, because each of those handles would have to be closed.
- // Second OSThread could be refactored to no longer be AllStatic. Then the
- // handle could be cached in the object by the Start method.
- if (handle == NULL) {
- return;
- }
-
+ HANDLE handle = static_cast<HANDLE>(id);
+ ASSERT(handle != NULL);
DWORD res = WaitForSingleObject(handle, INFINITE);
CloseHandle(handle);
ASSERT(res == WAIT_OBJECT_0);
diff --git a/runtime/vm/os_thread_win.h b/runtime/vm/os_thread_win.h
index 790306d..913b074 100644
--- a/runtime/vm/os_thread_win.h
+++ b/runtime/vm/os_thread_win.h
@@ -18,7 +18,7 @@
typedef DWORD ThreadLocalKey;
typedef DWORD ThreadId;
-typedef DWORD ThreadJoinId;
+typedef HANDLE ThreadJoinId;
static const ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index bb2d634..2ea8c1d 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -259,6 +259,11 @@
}
+intptr_t OS::StrNLen(const char* s, intptr_t n) {
+ return strnlen(s, n);
+}
+
+
void OS::Print(const char* format, ...) {
va_list args;
va_start(args, format);
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index 64b1d5e..e5d1e65 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -35,8 +35,6 @@
"Emit a log message when pointers to unused code are dropped.");
DEFINE_FLAG(bool, always_drop_code, false,
"Always try to drop code if the function's usage counter is >= 0");
-DEFINE_FLAG(bool, concurrent_sweep, true,
- "Concurrent sweep for old generation.");
DEFINE_FLAG(bool, log_growth, false, "Log PageSpace growth policy decisions.");
HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) {
@@ -846,7 +844,9 @@
SpaceUsage usage_before = GetCurrentUsage();
// Mark all reachable old-gen objects.
- bool collect_code = FLAG_collect_code && ShouldCollectCode();
+ bool collect_code = FLAG_collect_code &&
+ ShouldCollectCode() &&
+ !isolate->HasAttemptedReload();
GCMarker marker(heap_);
marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code);
usage_.used_in_words = marker.marked_words();
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 0ace98b..7819cd7 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -514,8 +514,8 @@
Thread* thread = Thread::Current();
ASSERT(thread->long_jump_base()->IsSafeToJump());
CSTAT_TIMER_SCOPE(thread, parser_timer);
- VMTagScope tagScope(thread, VMTag::kCompileTopLevelTagId);
#ifndef PRODUCT
+ VMTagScope tagScope(thread, VMTag::kCompileTopLevelTagId);
TimelineDurationScope tds(thread,
Timeline::GetCompilerStream(),
"CompileTopLevel");
@@ -989,9 +989,9 @@
Zone* zone = thread->zone();
CSTAT_TIMER_SCOPE(thread, parser_timer);
INC_STAT(thread, num_functions_parsed, 1);
+#ifndef PRODUCT
VMTagScope tagScope(thread, VMTag::kCompileParseFunctionTagId,
FLAG_profile_vm);
-#ifndef PRODUCT
TimelineDurationScope tds(thread,
Timeline::GetCompilerStream(),
"ParseFunction");
@@ -1234,6 +1234,12 @@
Thread* thread = Thread::Current();
// TODO(koda): Should there be a StackZone here?
Zone* zone = thread->zone();
+#ifndef PRODUCT
+ VMTagScope tagScope(thread, VMTag::kCompileParseFunctionTagId,
+ FLAG_profile_vm);
+ TimelineDurationScope tds(thread, Timeline::GetCompilerStream(),
+ "ParseStaticFieldInitializer");
+#endif // !PRODUCT
const String& field_name = String::Handle(zone, field.name());
String& init_name = String::Handle(zone,
@@ -2416,7 +2422,7 @@
arguments->Add(implicit_argument);
// If this is a super call in a forwarding constructor, add the user-
- // defined arguments to the super call and adjust the the super
+ // defined arguments to the super call and adjust the super
// constructor name to the respective named constructor if necessary.
if (forwarding_args != NULL) {
for (int i = 0; i < forwarding_args->length(); i++) {
@@ -4384,8 +4390,7 @@
ReportError(name_pos, "'%s' is already defined", enum_name->ToCString());
}
Class& cls = Class::Handle(Z);
- cls = Class::New(*enum_name, script_, declaration_pos);
- cls.set_library(library_);
+ cls = Class::New(library_, *enum_name, script_, declaration_pos);
library_.AddClass(cls);
cls.set_is_synthesized_class();
cls.set_is_enum_class();
@@ -4428,7 +4433,7 @@
ReportError(classname_pos, "missing class '%s' cannot be patched",
class_name.ToCString());
}
- cls = Class::New(class_name, script_, declaration_pos);
+ cls = Class::New(library_, class_name, script_, declaration_pos);
library_.AddClass(cls);
} else {
if (!obj.IsClass()) {
@@ -4440,8 +4445,7 @@
// Preserve and reuse the original type parameters and bounds since the
// ones defined in the patch class will not be finalized.
orig_type_parameters = cls.type_parameters();
- cls = Class::New(class_name, script_, declaration_pos);
- cls.set_library(library_);
+ cls = Class::New(library_, class_name, script_, declaration_pos);
} else {
// Not patching a class, but it has been found. This must be one of the
// pre-registered classes from object.cc or a duplicate definition.
@@ -4911,7 +4915,8 @@
class_name.ToCString());
}
const Class& mixin_application =
- Class::Handle(Z, Class::New(class_name, script_, classname_pos));
+ Class::Handle(Z, Class::New(library_, class_name,
+ script_, classname_pos));
mixin_application.set_is_mixin_app_alias();
library_.AddClass(mixin_application);
set_current_class(mixin_application);
@@ -5039,8 +5044,9 @@
// signature function after it has been parsed. The type parameters, in order
// to be properly finalized, need to be associated to this scope class as
// they are parsed.
- const Class& function_type_alias = Class::Handle(Z,
- Class::New(*alias_name, script_, declaration_pos));
+ const Class& function_type_alias =
+ Class::Handle(Z, Class::New(
+ library_, *alias_name, script_, declaration_pos));
function_type_alias.set_is_synthesized_class();
function_type_alias.set_is_abstract();
function_type_alias.set_is_prefinalized();
@@ -6090,7 +6096,8 @@
Object& tl_owner = Object::Handle(Z);
Class& toplevel_class = Class::Handle(Z, library_.toplevel_class());
if (toplevel_class.IsNull()) {
- toplevel_class = Class::New(Symbols::TopLevel(), script_, TokenPos());
+ toplevel_class =
+ Class::New(library_, Symbols::TopLevel(), script_, TokenPos());
toplevel_class.set_library(library_);
library_.set_toplevel_class(toplevel_class);
tl_owner = toplevel_class.raw();
@@ -12005,64 +12012,22 @@
return current_class().IsGeneric();
}
-// We cache computed compile-time constants in a map so we can look them
-// up when the same code gets compiled again. The map key is a pair
-// (script url, token position) which is encoded in an array with 2
-// elements:
-// - key[0] contains the canonicalized url of the script.
-// - key[1] contains the token position of the constant in the script.
-// ConstantPosKey allows us to look up a constant in the map without
-// allocating a key pair (array).
-struct ConstantPosKey : ValueObject {
- ConstantPosKey(const String& url, TokenPosition pos)
- : script_url(url), token_pos(pos) { }
- const String& script_url;
- TokenPosition token_pos;
-};
-
-
-class ConstMapKeyEqualsTraits {
- public:
- static const char* Name() { return "ConstMapKeyEqualsTraits"; }
- static bool ReportStats() { return false; }
-
- static bool IsMatch(const Object& a, const Object& b) {
- const Array& key1 = Array::Cast(a);
- const Array& key2 = Array::Cast(b);
- // Compare raw strings of script url symbol and raw smi of token positon.
- return (key1.At(0) == key2.At(0)) && (key1.At(1) == key2.At(1));
+void Parser::InsertCachedConstantValue(const String& url,
+ TokenPosition token_pos,
+ const Instance& value) {
+ Isolate* isolate = Isolate::Current();
+ ConstantPosKey key(url, token_pos);
+ if (isolate->object_store()->compile_time_constants() == Array::null()) {
+ const intptr_t kInitialConstMapSize = 16;
+ isolate->object_store()->set_compile_time_constants(
+ Array::Handle(HashTables::New<ConstantsMap>(kInitialConstMapSize,
+ Heap::kNew)));
}
- static bool IsMatch(const ConstantPosKey& key1, const Object& b) {
- const Array& key2 = Array::Cast(b);
- // Compare raw strings of script url symbol and token positon.
- return (key1.script_url.raw() == key2.At(0))
- && (key1.token_pos.value() == Smi::Value(Smi::RawCast(key2.At(1))));
- }
- static uword Hash(const Object& obj) {
- const Array& key = Array::Cast(obj);
- intptr_t url_hash = String::HashRawSymbol(String::RawCast(key.At(0)));
- intptr_t pos = Smi::Value(Smi::RawCast(key.At(1)));
- return HashValue(url_hash, pos);
- }
- static uword Hash(const ConstantPosKey& key) {
- return HashValue(String::HashRawSymbol(key.script_url.raw()),
- key.token_pos.value());
- }
- // Used by CacheConstantValue if a new constant is added to the map.
- static RawObject* NewKey(const ConstantPosKey& key) {
- const Array& key_obj = Array::Handle(Array::New(2));
- key_obj.SetAt(0, key.script_url);
- key_obj.SetAt(1, Smi::Handle(Smi::New(key.token_pos.value())));
- return key_obj.raw();;
- }
-
- private:
- static uword HashValue(intptr_t url_hash, intptr_t pos) {
- return url_hash * pos % (Smi::kMaxValue - 13);
- }
-};
-typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
+ ConstantsMap constants(isolate->object_store()->compile_time_constants());
+ constants.InsertNewOrGetValue(key, value);
+ isolate->object_store()->set_compile_time_constants(constants.Release());
+}
void Parser::CacheConstantValue(TokenPosition token_pos,
@@ -12072,19 +12037,13 @@
// evaluated only once.
return;
}
- ConstantPosKey key(String::Handle(Z, script_.url()), token_pos);
- if (isolate()->object_store()->compile_time_constants() == Array::null()) {
- const intptr_t kInitialConstMapSize = 16;
- isolate()->object_store()->set_compile_time_constants(
- Array::Handle(Z, HashTables::New<ConstantsMap>(kInitialConstMapSize,
- Heap::kNew)));
- }
- ConstantsMap constants(isolate()->object_store()->compile_time_constants());
- constants.InsertNewOrGetValue(key, value);
+ const String& url = String::Handle(Z, script_.url());
+ InsertCachedConstantValue(url, token_pos, value);
if (FLAG_compiler_stats) {
+ ConstantsMap constants(isolate()->object_store()->compile_time_constants());
thread_->compiler_stats()->num_cached_consts = constants.NumOccupied();
+ constants.Release();
}
- isolate()->object_store()->set_compile_time_constants(constants.Release());
}
@@ -14528,6 +14487,13 @@
}
+void Parser::InsertCachedConstantValue(const String& url,
+ TokenPosition token_pos,
+ const Instance& value) {
+ UNREACHABLE();
+}
+
+
ArgumentListNode* Parser::BuildNoSuchMethodArguments(
TokenPosition call_pos,
const String& function_name,
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index eb9f54a..ba284a5 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -14,6 +14,7 @@
#include "vm/ast.h"
#include "vm/class_finalizer.h"
#include "vm/compiler_stats.h"
+#include "vm/hash_table.h"
#include "vm/object.h"
#include "vm/raw_object.h"
#include "vm/token.h"
@@ -38,6 +39,65 @@
class TopLevel;
class RecursionChecker;
+// We cache computed compile-time constants in a map so we can look them
+// up when the same code gets compiled again. The map key is a pair
+// (script url, token position) which is encoded in an array with 2
+// elements:
+// - key[0] contains the canonicalized url of the script.
+// - key[1] contains the token position of the constant in the script.
+
+// ConstantPosKey allows us to look up a constant in the map without
+// allocating a key pair (array).
+struct ConstantPosKey : ValueObject {
+ ConstantPosKey(const String& url, TokenPosition pos)
+ : script_url(url), token_pos(pos) { }
+ const String& script_url;
+ TokenPosition token_pos;
+};
+
+
+class ConstMapKeyEqualsTraits {
+ public:
+ static const char* Name() { return "ConstMapKeyEqualsTraits"; }
+ static bool ReportStats() { return false; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ const Array& key1 = Array::Cast(a);
+ const Array& key2 = Array::Cast(b);
+ // Compare raw strings of script url symbol and raw smi of token positon.
+ return (key1.At(0) == key2.At(0)) && (key1.At(1) == key2.At(1));
+ }
+ static bool IsMatch(const ConstantPosKey& key1, const Object& b) {
+ const Array& key2 = Array::Cast(b);
+ // Compare raw strings of script url symbol and token positon.
+ return (key1.script_url.raw() == key2.At(0))
+ && (key1.token_pos.value() == Smi::Value(Smi::RawCast(key2.At(1))));
+ }
+ static uword Hash(const Object& obj) {
+ const Array& key = Array::Cast(obj);
+ intptr_t url_hash = String::HashRawSymbol(String::RawCast(key.At(0)));
+ intptr_t pos = Smi::Value(Smi::RawCast(key.At(1)));
+ return HashValue(url_hash, pos);
+ }
+ static uword Hash(const ConstantPosKey& key) {
+ return HashValue(String::HashRawSymbol(key.script_url.raw()),
+ key.token_pos.value());
+ }
+ // Used by CachConstantValue if a new constant is added to the map.
+ static RawObject* NewKey(const ConstantPosKey& key) {
+ const Array& key_obj = Array::Handle(Array::New(2));
+ key_obj.SetAt(0, key.script_url);
+ key_obj.SetAt(1, Smi::Handle(Smi::New(key.token_pos.value())));
+ return key_obj.raw();;
+ }
+
+ private:
+ static uword HashValue(intptr_t url_hash, intptr_t pos) {
+ return url_hash * pos % (Smi::kMaxValue - 13);
+ }
+};
+typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
+
// The class ParsedFunction holds the result of parsing a function.
class ParsedFunction : public ZoneAllocated {
public:
@@ -216,6 +276,10 @@
// given static field.
static ParsedFunction* ParseStaticFieldInitializer(const Field& field);
+ static void InsertCachedConstantValue(const String& url,
+ TokenPosition token_pos,
+ const Instance& value);
+
// Parse a function to retrieve parameter information that is not retained in
// the dart::Function object. Returns either an error if the parse fails
// (which could be the case for local functions), or a flat array of entries
diff --git a/runtime/vm/parser_test.cc b/runtime/vm/parser_test.cc
index 120e5ca..319b13d 100644
--- a/runtime/vm/parser_test.cc
+++ b/runtime/vm/parser_test.cc
@@ -248,11 +248,8 @@
EXPECT(ClassFinalizer::ProcessPendingClasses());
bool saved_flag = FLAG_show_invisible_frames;
FLAG_show_invisible_frames = true;
- Isolate* isolate = Isolate::Current();
- Debugger* debugger = isolate->debugger();
- const String& url = String::Handle(String::New(TestCase::url()));
Dart_SetPausedEventHandler(SaveVars);
- debugger->SetBreakpointAtLine(url, line);
+ EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), line));
saved_vars = NULL;
EXPECT_VALID(Dart_Invoke(lib, NewString(entry), 0, NULL));
const char* tmp = saved_vars;
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 924d8a1..b366396 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -41,6 +41,7 @@
#include "vm/tags.h"
#include "vm/timeline.h"
#include "vm/timer.h"
+#include "vm/type_table.h"
namespace dart {
@@ -75,6 +76,33 @@
#ifdef DART_PRECOMPILER
+class DartPrecompilationPipeline : public DartCompilationPipeline {
+ public:
+ DartPrecompilationPipeline() : result_type_(CompileType::None()) { }
+
+ virtual void FinalizeCompilation(FlowGraph* flow_graph) {
+ CompileType result_type = CompileType::None();
+ for (BlockIterator block_it = flow_graph->reverse_postorder_iterator();
+ !block_it.Done();
+ block_it.Advance()) {
+ ForwardInstructionIterator it(block_it.Current());
+ for (; !it.Done(); it.Advance()) {
+ ReturnInstr* return_instr = it.Current()->AsReturn();
+ if (return_instr != NULL) {
+ result_type.Union(return_instr->InputAt(0)->Type());
+ }
+ }
+ }
+ result_type_ = result_type;
+ }
+
+ CompileType result_type() { return result_type_; }
+
+ private:
+ CompileType result_type_;
+};
+
+
class PrecompileParsedFunctionHelper : public ValueObject {
public:
PrecompileParsedFunctionHelper(ParsedFunction* parsed_function,
@@ -169,6 +197,9 @@
// because their class hasn't been finalized yet.
FinalizeAllClasses();
+ // Precompile static initializers to compute result type information.
+ PrecompileStaticInitializers();
+
for (intptr_t round = 0; round < FLAG_precompiler_rounds; round++) {
if (FLAG_trace_precompiler) {
THR_Print("Precompiler round %" Pd "\n", round);
@@ -255,9 +286,52 @@
}
+static void CompileStaticInitializerIgnoreErrors(const Field& field) {
+ LongJumpScope jump;
+ if (setjmp(*jump.Set()) == 0) {
+ Precompiler::CompileStaticInitializer(field, /* compute_type = */ true);
+ } else {
+ // Ignore compile-time errors here. If the field is actually used,
+ // the error will be reported later during Iterate().
+ }
+}
+
+
+void Precompiler::PrecompileStaticInitializers() {
+ class StaticInitializerVisitor : public ClassVisitor {
+ public:
+ explicit StaticInitializerVisitor(Zone* zone)
+ : fields_(Array::Handle(zone)),
+ field_(Field::Handle(zone)),
+ function_(Function::Handle(zone)) { }
+ void Visit(const Class& cls) {
+ fields_ = cls.fields();
+ for (intptr_t j = 0; j < fields_.Length(); j++) {
+ field_ ^= fields_.At(j);
+ if (field_.is_static() &&
+ field_.is_final() &&
+ field_.has_initializer()) {
+ if (FLAG_trace_precompiler) {
+ THR_Print("Precompiling initializer for %s\n", field_.ToCString());
+ }
+ CompileStaticInitializerIgnoreErrors(field_);
+ }
+ }
+ }
+
+ private:
+ Array& fields_;
+ Field& field_;
+ Function& function_;
+ };
+ StaticInitializerVisitor visitor(Z);
+ VisitClasses(&visitor);
+}
+
+
void Precompiler::ClearAllCode() {
class ClearCodeFunctionVisitor : public FunctionVisitor {
- void VisitFunction(const Function& function) {
+ void Visit(const Function& function) {
function.ClearCode();
function.ClearICDataArray();
}
@@ -292,14 +366,6 @@
}
Dart_QualifiedFunctionName vm_entry_points[] = {
- // TODO(rmacnak): These types are not allocated from C++ but they are
- // cached in the object store. Consider clearing them from the object store
- // before snapshotting and adjusting InitKnownObjects to allow their
- // absence.
- { "dart:async", "Future", "Future." },
- { "dart:async", "Completer", "Completer." },
- { "dart:async", "StreamIterator", "StreamIterator." },
-
// Functions
{ "dart:async", "::", "_setScheduleImmediateClosure" },
{ "dart:core", "::", "_completeDeferredLoads" },
@@ -326,6 +392,7 @@
{ "dart:isolate", "::", "_getIsolateScheduleImmediateClosure" },
{ "dart:isolate", "::", "_setupHooks" },
{ "dart:isolate", "::", "_startMainIsolate" },
+ { "dart:isolate", "::", "_startIsolate" },
{ "dart:isolate", "_RawReceivePortImpl", "_handleMessage" },
{ "dart:isolate", "_RawReceivePortImpl", "_lookupHandler" },
{ "dart:isolate", "_SendPortImpl", "send" },
@@ -336,6 +403,7 @@
{ "dart:_vmservice", "::", "_registerIsolate" },
{ "dart:_vmservice", "::", "boot" },
{ "dart:developer", "Metrics", "_printMetrics" },
+ { "dart:developer", "::", "_runExtension" },
#endif // !PRODUCT
// Fields
{ "dart:core", "Error", "_stackTrace" },
@@ -774,8 +842,8 @@
THR_Print("Precompiling initializer for %s\n", field.ToCString());
}
ASSERT(Dart::snapshot_kind() != Snapshot::kAppNoJIT);
- const Function& initializer =
- Function::Handle(Z, CompileStaticInitializer(field));
+ const Function& initializer = Function::Handle(Z,
+ CompileStaticInitializer(field, /* compute_type = */ true));
ASSERT(!initializer.IsNull());
field.SetPrecompiledInitializer(initializer);
AddCalleesOf(initializer);
@@ -785,21 +853,32 @@
}
-RawFunction* Precompiler::CompileStaticInitializer(const Field& field) {
+RawFunction* Precompiler::CompileStaticInitializer(const Field& field,
+ bool compute_type) {
ASSERT(field.is_static());
- ASSERT(!field.HasPrecompiledInitializer());
Thread* thread = Thread::Current();
StackZone zone(thread);
ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
parsed_function->AllocateVariables();
- DartCompilationPipeline pipeline;
+ DartPrecompilationPipeline pipeline;
PrecompileParsedFunctionHelper helper(parsed_function,
/* optimized = */ true);
bool success = helper.Compile(&pipeline);
ASSERT(success);
+ if (compute_type && field.is_final()) {
+ intptr_t result_cid = pipeline.result_type().ToCid();
+ if (result_cid != kDynamicCid) {
+ if (FLAG_trace_precompiler && FLAG_support_il_printer) {
+ THR_Print("Setting guarded_cid of %s to %s\n", field.ToCString(),
+ pipeline.result_type().ToCString());
+ }
+ field.set_guarded_cid(result_cid);
+ }
+ }
+
if ((FLAG_disassemble || FLAG_disassemble_optimized) &&
FlowGraphPrinter::ShouldPrint(parsed_function->function())) {
Disassembler::DisassembleCode(parsed_function->function(),
@@ -822,7 +901,7 @@
// remembering it because it won't be used again.
Function& initializer = Function::Handle();
if (!field.HasPrecompiledInitializer()) {
- initializer = CompileStaticInitializer(field);
+ initializer = CompileStaticInitializer(field, /* compute_type = */ false);
} else {
initializer ^= field.PrecompiledInitializer();
}
@@ -883,7 +962,7 @@
parsed_function->AllocateVariables();
// Non-optimized code generator.
- DartCompilationPipeline pipeline;
+ DartPrecompilationPipeline pipeline;
PrecompileParsedFunctionHelper helper(parsed_function,
/* optimized = */ false);
helper.Compile(&pipeline);
@@ -1130,6 +1209,9 @@
AddNameToFunctionsTable(zone(), &table, fname, function);
fname = Field::NameFromGetter(fname);
AddNameToFunctionsTable(zone(), &table, fname, function);
+ } else if (function.IsMethodExtractor()) {
+ // Skip. We already add getter names for regular methods below.
+ continue;
} else {
// Regular function. Enter both getter and non getter name.
AddNameToFunctionsTable(zone(), &table, fname, function);
@@ -1177,18 +1259,6 @@
}
-void Precompiler::GetUniqueDynamicTarget(Isolate* isolate,
- const String& fname,
- Object* function) {
- UniqueFunctionsSet functions_set(
- isolate->object_store()->unique_dynamic_targets());
- ASSERT(fname.IsSymbol());
- *function = functions_set.GetOrNull(fname);
- ASSERT(functions_set.Release().raw() ==
- isolate->object_store()->unique_dynamic_targets());
-}
-
-
void Precompiler::TraceConstFunctions() {
// Compilation of const accessors happens outside of the treeshakers
// queue, so we haven't previously scanned its literal pool.
@@ -1405,92 +1475,78 @@
void Precompiler::DropTypes() {
- Library& lib = Library::Handle(Z);
- Class& cls = Class::Handle(Z);
- Object& obj = Object::Handle(Z);
- Array& arr = Array::Handle(Z);
- GrowableObjectArray& retained_types = GrowableObjectArray::Handle(Z);
- AbstractType& type = AbstractType::Handle(Z);
-
- for (intptr_t i = 0; i < libraries_.Length(); i++) {
- lib ^= libraries_.At(i);
- ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
- while (it.HasNext()) {
- cls = it.GetNextClass();
- if (cls.IsDynamicClass()) {
- continue; // class 'dynamic' is in the read-only VM isolate.
- }
- obj = cls.canonical_types();
- if (!obj.IsArray()) {
- // Class only has one type, keep it.
+ ObjectStore* object_store = I->object_store();
+ GrowableObjectArray& retained_types =
+ GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+ Array& types_array = Array::Handle(Z);
+ Type& type = Type::Handle(Z);
+ // First drop all the types that are not referenced.
+ {
+ CanonicalTypeSet types_table(Z, object_store->canonical_types());
+ types_array = HashTables::ToArray(types_table, false);
+ for (intptr_t i = 0; i < (types_array.Length() - 1); i++) {
+ type ^= types_array.At(i);
+ bool retain = types_to_retain_.Lookup(&type) != NULL;
+ if (retain) {
+ retained_types.Add(type);
} else {
- // Class has many types.
- arr ^= obj.raw();
- retained_types = GrowableObjectArray::New();
-
- // Always keep the first one.
- ASSERT(arr.Length() >= 1);
- obj = arr.At(0);
- retained_types.Add(obj);
-
- for (intptr_t i = 1; i < arr.Length(); i++) {
- obj = arr.At(i);
- if (obj.IsNull()) {
- continue;
- }
- type ^= obj.raw();
- bool retain = types_to_retain_.Lookup(&type) != NULL;
- if (retain) {
- retained_types.Add(type);
- } else {
- dropped_type_count_++;
- }
- }
- arr = Array::MakeArray(retained_types);
- cls.set_canonical_types(arr);
+ dropped_type_count_++;
}
}
+ types_table.Release();
}
+
+ // Now construct a new type table and save in the object store.
+ const intptr_t dict_size =
+ Utils::RoundUpToPowerOfTwo(retained_types.Length() * 4 / 3);
+ types_array = HashTables::New<CanonicalTypeSet>(dict_size, Heap::kOld);
+ CanonicalTypeSet types_table(Z, types_array.raw());
+ bool present;
+ for (intptr_t i = 0; i < retained_types.Length(); i++) {
+ type ^= retained_types.At(i);
+ present = types_table.Insert(type);
+ ASSERT(!present);
+ }
+ object_store->set_canonical_types(types_table.Release());
}
void Precompiler::DropTypeArguments() {
- const Array& typeargs_table =
- Array::Handle(Z, I->object_store()->canonical_type_arguments());
+ ObjectStore* object_store = I->object_store();
+ Array& typeargs_array = Array::Handle(Z);
GrowableObjectArray& retained_typeargs =
GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
TypeArguments& typeargs = TypeArguments::Handle(Z);
- for (intptr_t i = 0; i < (typeargs_table.Length() - 1); i++) {
- typeargs ^= typeargs_table.At(i);
- bool retain = typeargs_to_retain_.Lookup(&typeargs) != NULL;
- if (retain) {
- retained_typeargs.Add(typeargs);
- } else {
- dropped_typearg_count_++;
+ // First drop all the type arguments that are not referenced.
+ {
+ CanonicalTypeArgumentsSet typeargs_table(
+ Z, object_store->canonical_type_arguments());
+ typeargs_array = HashTables::ToArray(typeargs_table, false);
+ for (intptr_t i = 0; i < (typeargs_array.Length() - 1); i++) {
+ typeargs ^= typeargs_array.At(i);
+ bool retain = typeargs_to_retain_.Lookup(&typeargs) != NULL;
+ if (retain) {
+ retained_typeargs.Add(typeargs);
+ } else {
+ dropped_typearg_count_++;
+ }
}
+ typeargs_table.Release();
}
+ // Now construct a new type arguments table and save in the object store.
const intptr_t dict_size =
Utils::RoundUpToPowerOfTwo(retained_typeargs.Length() * 4 / 3);
- const Array& new_table = Array::Handle(Z, Array::New(dict_size + 1));
-
- Object& element = Object::Handle(Z);
+ typeargs_array = HashTables::New<CanonicalTypeArgumentsSet>(dict_size,
+ Heap::kOld);
+ CanonicalTypeArgumentsSet typeargs_table(Z, typeargs_array.raw());
+ bool present;
for (intptr_t i = 0; i < retained_typeargs.Length(); i++) {
typeargs ^= retained_typeargs.At(i);
- intptr_t hash = typeargs.Hash();
- intptr_t index = hash & (dict_size - 1);
- element = new_table.At(index);
- while (!element.IsNull()) {
- index = (index + 1) & (dict_size - 1);
- element = new_table.At(index);
- }
- new_table.SetAt(index, typeargs);
+ present = typeargs_table.Insert(typeargs);
+ ASSERT(!present);
}
-
- const Smi& used = Smi::Handle(Z, Smi::New(retained_typeargs.Length()));
- new_table.SetAt(dict_size, used);
-
- I->object_store()->set_canonical_type_arguments(new_table);
+ object_store->set_canonical_type_arguments(typeargs_table.Release());
}
@@ -1688,7 +1744,7 @@
target_code_(Code::Handle(zone)) {
}
- void VisitFunction(const Function& function) {
+ void Visit(const Function& function) {
if (!function.HasCode()) {
return;
}
@@ -1757,7 +1813,7 @@
entry_point_(Smi::Handle(zone)) {
}
- void VisitFunction(const Function& function) {
+ void Visit(const Function& function) {
if (!function.HasCode()) {
return;
}
@@ -1826,7 +1882,7 @@
stackmap_(Stackmap::Handle(zone)) {
}
- void VisitFunction(const Function& function) {
+ void Visit(const Function& function) {
if (!function.HasCode()) {
return;
}
@@ -1876,7 +1932,7 @@
stackmap_(Stackmap::Handle(zone)) {
}
- void VisitFunction(const Function& function) {
+ void Visit(const Function& function) {
if (!function.HasCode()) {
return;
}
@@ -1923,7 +1979,7 @@
instructions_(Instructions::Handle(zone)) {
}
- void VisitFunction(const Function& function) {
+ void Visit(const Function& function) {
if (!function.HasCode()) {
ASSERT(function.HasImplicitClosureFunction());
return;
@@ -1959,6 +2015,25 @@
VisitFunctions(&visitor);
}
+
+void Precompiler::VisitClasses(ClassVisitor* visitor) {
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+ while (it.HasNext()) {
+ cls = it.GetNextClass();
+ if (cls.IsDynamicClass()) {
+ continue; // class 'dynamic' is in the read-only VM isolate.
+ }
+ visitor->Visit(cls);
+ }
+ }
+}
+
+
void Precompiler::VisitFunctions(FunctionVisitor* visitor) {
Library& lib = Library::Handle(Z);
Class& cls = Class::Handle(Z);
@@ -1981,10 +2056,10 @@
functions = cls.functions();
for (intptr_t j = 0; j < functions.Length(); j++) {
function ^= functions.At(j);
- visitor->VisitFunction(function);
+ visitor->Visit(function);
if (function.HasImplicitClosureFunction()) {
function = function.ImplicitClosureFunction();
- visitor->VisitFunction(function);
+ visitor->Visit(function);
}
}
@@ -1993,7 +2068,7 @@
object = functions.At(j);
if (object.IsFunction()) {
function ^= functions.At(j);
- visitor->VisitFunction(function);
+ visitor->Visit(function);
}
}
fields = cls.fields();
@@ -2001,7 +2076,7 @@
field ^= fields.At(j);
if (field.is_static() && field.HasPrecompiledInitializer()) {
function ^= field.PrecompiledInitializer();
- visitor->VisitFunction(function);
+ visitor->Visit(function);
}
}
}
@@ -2009,7 +2084,7 @@
closures = isolate()->object_store()->closure_functions();
for (intptr_t j = 0; j < closures.Length(); j++) {
function ^= closures.At(j);
- visitor->VisitFunction(function);
+ visitor->Visit(function);
ASSERT(!function.HasImplicitClosureFunction());
}
}
@@ -2595,7 +2670,7 @@
"CompileGraph");
#endif // !PRODUCT
graph_compiler.CompileGraph();
- pipeline->FinalizeCompilation();
+ pipeline->FinalizeCompilation(flow_graph);
}
{
#ifndef PRODUCT
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 5b6c7ac..6ec2ed3 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -265,27 +265,18 @@
Dart_QualifiedFunctionName embedder_entry_points[],
bool reset_fields);
- // Returns named function that is a unique dynamic target, i.e.,
- // - the target is identified by its name alone, since it occurs only once.
- // - target's class has no subclasses, and neither is subclassed, i.e.,
- // the receiver type can be only the function's class.
- // Returns Function::null() if there is no unique dynamic target for
- // given 'fname'. 'fname' must be a symbol.
- static void GetUniqueDynamicTarget(Isolate* isolate,
- const String& fname,
- Object* function);
-
static RawError* CompileFunction(Thread* thread, const Function& function);
static RawObject* EvaluateStaticInitializer(const Field& field);
static RawObject* ExecuteOnce(SequenceNode* fragment);
+ static RawFunction* CompileStaticInitializer(const Field& field,
+ bool compute_type);
+
private:
Precompiler(Thread* thread, bool reset_fields);
- static RawFunction* CompileStaticInitializer(const Field& field);
-
void DoCompileAll(Dart_QualifiedFunctionName embedder_entry_points[]);
void ClearAllCode();
void AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]);
@@ -327,13 +318,19 @@
void CollectDynamicFunctionNames();
- class FunctionVisitor : public ValueObject {
+ void PrecompileStaticInitializers();
+
+ template<typename T>
+ class Visitor : public ValueObject {
public:
- virtual ~FunctionVisitor() {}
- virtual void VisitFunction(const Function& function) = 0;
+ virtual ~Visitor() {}
+ virtual void Visit(const T& obj) = 0;
};
+ typedef Visitor<Function> FunctionVisitor;
+ typedef Visitor<Class> ClassVisitor;
void VisitFunctions(FunctionVisitor* visitor);
+ void VisitClasses(ClassVisitor* visitor);
void FinalizeAllClasses();
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 4d5c4a5..195149f 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -19,6 +19,7 @@
DECLARE_FLAG(int, max_profile_depth);
DECLARE_FLAG(int, profile_period);
DECLARE_FLAG(bool, show_invisible_frames);
+DECLARE_FLAG(bool, profile_vm);
#ifndef PRODUCT
@@ -1375,6 +1376,8 @@
ASSERT(code != NULL);
code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index);
}
+
+ TickExitFrame(sample->vm_tag(), sample_index);
}
SanitizeMinMaxTimes();
}
@@ -1490,6 +1493,10 @@
current = current->GetChild(index);
current->Tick();
}
+
+ if (!sample->first_frame_executing()) {
+ current = AppendExitFrame(sample->vm_tag(), current);
+ }
}
}
@@ -1510,6 +1517,10 @@
ResetKind();
+ if (!sample->first_frame_executing()) {
+ current = AppendExitFrame(sample->vm_tag(), current);
+ }
+
// Walk the sampled PCs.
Code& code = Code::Handle();
for (intptr_t frame_index = 0;
@@ -1582,6 +1593,10 @@
current = ProcessFrame(current, sample_index, sample, frame_index);
}
+ if (!sample->first_frame_executing()) {
+ current = AppendExitFrame(sample->vm_tag(), current);
+ }
+
sample->set_timeline_trie(current);
}
}
@@ -1604,6 +1619,10 @@
ResetKind();
+ if (!sample->first_frame_executing()) {
+ current = AppendExitFrame(sample->vm_tag(), current);
+ }
+
// Walk the sampled PCs.
for (intptr_t frame_index = 0;
frame_index < sample->length();
@@ -1612,6 +1631,8 @@
current = ProcessFrame(current, sample_index, sample, frame_index);
}
+ TickExitFrameFunction(sample->vm_tag(), sample_index);
+
// Truncated tag.
if (sample->truncated()) {
current = AppendTruncatedTag(current);
@@ -1750,7 +1771,8 @@
}
// Only tick the first frame's node, if we are executing OR
// vm tags have been emitted.
- return IsExecutingFrame(sample, frame_index) || vm_tags_emitted();
+ return IsExecutingFrame(sample, frame_index) ||
+ !FLAG_profile_vm || vm_tags_emitted();
}
ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current,
@@ -1912,31 +1934,89 @@
return current;
}
+ void TickExitFrame(uword vm_tag, intptr_t serial) {
+ if (FLAG_profile_vm) {
+ return;
+ }
+ if (!VMTag::IsExitFrameTag(vm_tag)) {
+ return;
+ }
+ ProfileCodeTable* tag_table = profile_->tag_code_;
+ ProfileCode* code = tag_table->FindCodeForPC(vm_tag);
+ ASSERT(code != NULL);
+ code->Tick(vm_tag, true, serial);
+ }
+
+ void TickExitFrameFunction(uword vm_tag, intptr_t serial) {
+ if (FLAG_profile_vm) {
+ return;
+ }
+ if (!VMTag::IsExitFrameTag(vm_tag)) {
+ return;
+ }
+ ProfileCodeTable* tag_table = profile_->tag_code_;
+ ProfileCode* code = tag_table->FindCodeForPC(vm_tag);
+ ASSERT(code != NULL);
+ ProfileFunction* function = code->function();
+ ASSERT(function != NULL);
+ function->Tick(true, serial, TokenPosition::kNoSource);
+ }
+
+ ProfileCodeTrieNode* AppendExitFrame(uword vm_tag,
+ ProfileCodeTrieNode* current) {
+ if (FLAG_profile_vm) {
+ return current;
+ }
+
+ if (!VMTag::IsExitFrameTag(vm_tag)) {
+ return current;
+ }
+
+ if (VMTag::IsNativeEntryTag(vm_tag) ||
+ VMTag::IsRuntimeEntryTag(vm_tag)) {
+ current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
+ } else {
+ intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
+ current = current->GetChild(tag_index);
+ // Give the tag a tick.
+ current->Tick();
+ }
+ return current;
+ }
+
ProfileCodeTrieNode* AppendTags(uword vm_tag,
uword user_tag,
ProfileCodeTrieNode* current) {
- // None.
+ if (FLAG_profile_vm) {
+ // None.
+ if (tag_order() == Profile::kNoTags) {
+ return current;
+ }
+ // User first.
+ if ((tag_order() == Profile::kUserVM) ||
+ (tag_order() == Profile::kUser)) {
+ current = AppendUserTag(user_tag, current);
+ // Only user.
+ if (tag_order() == Profile::kUser) {
+ return current;
+ }
+ return AppendVMTags(vm_tag, current);
+ }
+ // VM first.
+ ASSERT((tag_order() == Profile::kVMUser) ||
+ (tag_order() == Profile::kVM));
+ current = AppendVMTags(vm_tag, current);
+ // Only VM.
+ if (tag_order() == Profile::kVM) {
+ return current;
+ }
+ return AppendUserTag(user_tag, current);
+ }
+
if (tag_order() == Profile::kNoTags) {
return current;
}
- // User first.
- if ((tag_order() == Profile::kUserVM) ||
- (tag_order() == Profile::kUser)) {
- current = AppendUserTag(user_tag, current);
- // Only user.
- if (tag_order() == Profile::kUser) {
- return current;
- }
- return AppendVMTags(vm_tag, current);
- }
- // VM first.
- ASSERT((tag_order() == Profile::kVMUser) ||
- (tag_order() == Profile::kVM));
- current = AppendVMTags(vm_tag, current);
- // Only VM.
- if (tag_order() == Profile::kVM) {
- return current;
- }
+
return AppendUserTag(user_tag, current);
}
@@ -2031,37 +2111,66 @@
}
ProfileFunctionTrieNode* AppendVMTags(uword vm_tag,
- ProfileFunctionTrieNode* current) {
+ ProfileFunctionTrieNode* current) {
current = AppendVMTag(vm_tag, current);
current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
return current;
}
+ ProfileFunctionTrieNode* AppendExitFrame(uword vm_tag,
+ ProfileFunctionTrieNode* current) {
+ if (FLAG_profile_vm) {
+ return current;
+ }
+
+ if (!VMTag::IsExitFrameTag(vm_tag)) {
+ return current;
+ }
+ if (VMTag::IsNativeEntryTag(vm_tag) ||
+ VMTag::IsRuntimeEntryTag(vm_tag)) {
+ current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current);
+ } else {
+ intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
+ current = current->GetChild(tag_index);
+ // Give the tag a tick.
+ current->Tick();
+ }
+ return current;
+ }
+
ProfileFunctionTrieNode* AppendTags(uword vm_tag,
uword user_tag,
ProfileFunctionTrieNode* current) {
- // None.
+ if (FLAG_profile_vm) {
+ // None.
+ if (tag_order() == Profile::kNoTags) {
+ return current;
+ }
+ // User first.
+ if ((tag_order() == Profile::kUserVM) ||
+ (tag_order() == Profile::kUser)) {
+ current = AppendUserTag(user_tag, current);
+ // Only user.
+ if (tag_order() == Profile::kUser) {
+ return current;
+ }
+ return AppendVMTags(vm_tag, current);
+ }
+ // VM first.
+ ASSERT((tag_order() == Profile::kVMUser) ||
+ (tag_order() == Profile::kVM));
+ current = AppendVMTags(vm_tag, current);
+ // Only VM.
+ if (tag_order() == Profile::kVM) {
+ return current;
+ }
+ return AppendUserTag(user_tag, current);
+ }
+
if (tag_order() == Profile::kNoTags) {
return current;
}
- // User first.
- if ((tag_order() == Profile::kUserVM) ||
- (tag_order() == Profile::kUser)) {
- current = AppendUserTag(user_tag, current);
- // Only user.
- if (tag_order() == Profile::kUser) {
- return current;
- }
- return AppendVMTags(vm_tag, current);
- }
- // VM first.
- ASSERT((tag_order() == Profile::kVMUser) ||
- (tag_order() == Profile::kVM));
- current = AppendVMTags(vm_tag, current);
- // Only VM.
- if (tag_order() == Profile::kVM) {
- return current;
- }
+
return AppendUserTag(user_tag, current);
}
@@ -2334,6 +2443,8 @@
static_cast<intptr_t>(FLAG_max_profile_depth));
obj->AddProperty("sampleCount", sample_count());
obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan()));
+ obj->AddPropertyTimeMicros("timeOriginMicros", min_time());
+ obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan());
}
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 1ecac9f..4ab49bd 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -21,24 +21,6 @@
DECLARE_FLAG(bool, enable_inlining_annotations);
DECLARE_FLAG(int, optimization_counter_threshold);
-template<typename T>
-class SetFlagScope : public ValueObject {
- public:
- SetFlagScope(T* flag, T value)
- : flag_(flag),
- original_value_(*flag) {
- *flag_ = value;
- }
-
- ~SetFlagScope() {
- *flag_ = original_value_;
- }
-
- private:
- T* flag_;
- T original_value_;
-};
-
// Some tests are written assuming native stack trace profiling is disabled.
class DisableNativeProfileScope : public ValueObject {
public:
@@ -281,6 +263,8 @@
walker.Reset(Profile::kExclusiveCode);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@@ -293,12 +277,16 @@
EXPECT_STREQ("main", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
// Exclusive function: B.boo -> main.
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@@ -311,6 +299,8 @@
EXPECT_STREQ("main", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -395,6 +385,8 @@
walker.Reset(Profile::kExclusiveCode);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@@ -407,12 +399,16 @@
EXPECT_STREQ("main", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
// Exclusive function: boo -> main.
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
@@ -425,6 +421,8 @@
EXPECT_STREQ("main", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -514,6 +512,8 @@
walker.Reset(Profile::kExclusiveCode);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
@@ -538,6 +538,8 @@
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
}
@@ -609,6 +611,8 @@
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
@@ -633,6 +637,8 @@
EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
}
@@ -682,6 +688,8 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("Double_add", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("_Double._add", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("_Double.+", walker.CurrentName());
@@ -750,6 +758,8 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateArray", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("_List._List", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("List.List", walker.CurrentName());
@@ -798,6 +808,8 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateArray", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("_List._List", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("_GrowableList._GrowableList", walker.CurrentName());
@@ -857,6 +869,8 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateContext", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -921,6 +935,8 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_SUBSTRING("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_SUBSTRING("foo", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -992,6 +1008,8 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("TypedData_Float32Array_new", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("Float32List.Float32List", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("foo", walker.CurrentName());
@@ -1072,6 +1090,8 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("String_concat", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("_StringBase.+", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("foo", walker.CurrentName());
@@ -1153,6 +1173,8 @@
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("OneByteString_allocate", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("_OneByteString._allocate", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("_OneByteString._concatAll", walker.CurrentName());
@@ -1272,6 +1294,8 @@
// We have two code objects: mainA and B.boo.
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
@@ -1298,12 +1322,16 @@
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
// Inline expansion should show us the complete call chain:
// mainA -> B.boo -> B.foo -> B.choo.
walker.Reset(Profile::kExclusiveFunction);
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.choo", walker.CurrentName());
EXPECT_EQ(1, walker.SiblingCount());
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
@@ -1356,6 +1384,8 @@
EXPECT_EQ(50000, walker.CurrentNodeTickCount());
EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
@@ -1377,6 +1407,8 @@
// We have two code objects: mainA and B.boo.
walker.Reset(Profile::kExclusiveCode);
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
@@ -1395,12 +1427,16 @@
EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
// Inline expansion should show us the complete call chain:
// mainA -> B.boo -> B.foo -> B.choo.
walker.Reset(Profile::kExclusiveFunction);
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("[Inline End]", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("B.choo", walker.CurrentName());
@@ -1437,6 +1473,8 @@
EXPECT_STREQ("B.choo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Inline End]", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
}
@@ -1545,6 +1583,8 @@
// Inline expansion should show us the complete call chain:
walker.Reset(Profile::kExclusiveFunction);
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("maybeAlloc", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("right", walker.CurrentName());
@@ -1564,6 +1604,8 @@
EXPECT_STREQ("right", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("maybeAlloc", walker.CurrentName());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
EXPECT(!walker.Down());
}
}
@@ -1635,6 +1677,8 @@
walker.Reset(Profile::kExclusiveCode);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("orange", walker.CurrentName());
@@ -1734,6 +1778,8 @@
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -1824,6 +1870,8 @@
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -1907,6 +1955,8 @@
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -2028,6 +2078,8 @@
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -2132,6 +2184,8 @@
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
@@ -2262,6 +2316,8 @@
walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
+ EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 98553cd..cc880e9 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -181,16 +181,15 @@
// Get the (constant) instance size out of the class object.
// TODO(koda): Add Size(ClassTable*) interface to allow caching in loops.
Isolate* isolate = Isolate::Current();
- ClassTable* class_table = isolate->class_table();
#if defined(DEBUG)
+ ClassTable* class_table = isolate->class_table();
if (!class_table->IsValidIndex(class_id) ||
!class_table->HasValidClassAt(class_id)) {
FATAL2("Invalid class id: %" Pd " from tags %" Px "\n",
class_id, ptr()->tags_);
}
#endif // DEBUG
- RawClass* raw_class = class_table->At(class_id);
- ASSERT(raw_class->ptr()->id_ == class_id);
+ RawClass* raw_class = isolate->GetClassForHeapWalkAt(class_id);
instance_size =
raw_class->ptr()->instance_size_in_words_ << kWordSizeLog2;
}
@@ -713,7 +712,7 @@
intptr_t instance_size = SizeTag::decode(tags);
if (instance_size == 0) {
RawClass* cls =
- visitor->isolate()->class_table()->At(raw_obj->GetClassId());
+ visitor->isolate()->GetClassForHeapWalkAt(raw_obj->GetClassId());
instance_size = cls->ptr()->instance_size_in_words_ << kWordSizeLog2;
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 977ba55..ef5924e 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -625,6 +625,7 @@
friend class Closure;
friend class Code;
friend class Double;
+ friend class ForwardPointersVisitor; // StorePointer
friend class FreeListElement;
friend class Function;
friend class GCMarker;
@@ -697,9 +698,8 @@
RawAbstractType* super_type_;
RawType* mixin_; // Generic mixin type, e.g. M<T>, not M<int>.
RawFunction* signature_function_; // Associated function for typedef class.
- RawArray* constants_; // Canonicalized values of this class.
- RawObject* canonical_types_; // An array of canonicalized types of this class
- // or the canonical type.
+ RawArray* constants_; // Canonicalized const instances of this class.
+ RawType* canonical_type_; // Canonical type for this class.
RawArray* invocation_dispatcher_cache_; // Cache for dispatcher functions.
RawCode* allocation_stub_; // Stub code for allocation of instances.
RawGrowableObjectArray* direct_subclasses_; // Array of Class.
@@ -735,6 +735,7 @@
uint16_t state_bits_;
friend class Instance;
+ friend class Isolate;
friend class Object;
friend class RawInstance;
friend class RawInstructions;
@@ -771,6 +772,8 @@
// Instantiations leading to bound errors do not get cached.
RawSmi* length_;
+ RawSmi* hash_;
+
// Variable length data follows here.
RawAbstractType* const* types() const {
OPEN_ARRAY_START(RawAbstractType*, RawAbstractType*);
@@ -1038,6 +1041,7 @@
int32_t line_offset_;
int32_t col_offset_;
int8_t kind_; // Of type Kind.
+ int64_t load_timestamp_;
};
@@ -1683,10 +1687,12 @@
RAW_HEAP_OBJECT_IMPLEMENTATION(Type);
RawObject** from() {
- return reinterpret_cast<RawObject**>(&ptr()->type_class_);
+ return reinterpret_cast<RawObject**>(&ptr()->type_class_id_);
}
- RawObject* type_class_; // Either resolved class or unresolved class.
+ // Either the id of the resolved class as a Smi or an UnresolvedClass.
+ RawObject* type_class_id_;
RawTypeArguments* arguments_;
+ RawSmi* hash_;
// This type object represents a function type if its signature field is a
// non-null function object.
// If this type is malformed or malbounded, the signature field gets
@@ -1724,12 +1730,13 @@
RAW_HEAP_OBJECT_IMPLEMENTATION(TypeParameter);
RawObject** from() {
- return reinterpret_cast<RawObject**>(&ptr()->parameterized_class_);
+ return reinterpret_cast<RawObject**>(&ptr()->name_);
}
- RawClass* parameterized_class_;
RawString* name_;
+ RawSmi* hash_;
RawAbstractType* bound_; // ObjectType if no explicit bound specified.
RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->bound_); }
+ classid_t parameterized_class_id_;
TokenPosition token_pos_;
int16_t index_;
int8_t type_state_;
@@ -1745,6 +1752,7 @@
}
RawAbstractType* type_;
RawAbstractType* bound_;
+ RawSmi* hash_;
RawTypeParameter* type_parameter_; // For more detailed error reporting.
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->type_parameter_);
@@ -1760,6 +1768,7 @@
return reinterpret_cast<RawObject**>(&ptr()->super_type_);
}
RawAbstractType* super_type_;
+ RawSmi* hash_;
RawArray* mixin_types_; // Array of AbstractType.
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->mixin_types_);
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 196e145..5f5a15c 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -12,6 +12,8 @@
namespace dart {
+DECLARE_FLAG(bool, remove_script_timestamps_for_test);
+
#define NEW_OBJECT(type) \
((Snapshot::IsFull(kind)) ? reader->New##type() : type::New())
@@ -59,7 +61,7 @@
ASSERT((class_id >= kInstanceCid) && (class_id <= kMirrorReferenceCid));
cls = reader->isolate()->class_table()->At(class_id);
} else {
- cls = New<Instance>(kIllegalCid);
+ cls = Class::NewInstanceClass();
}
}
reader->AddBackRef(object_id, &cls, kIsDeserialized);
@@ -239,6 +241,11 @@
// Set all the object fields.
READ_OBJECT_FIELDS(type, type.raw()->from(), type.raw()->to(), kAsReference);
+ // Read in the type class.
+ (*reader->ClassHandle()) =
+ Class::RawCast(reader->ReadObjectImpl(kAsReference));
+ type.set_type_class(*reader->ClassHandle());
+
// Set the canonical bit.
if (!defer_canonicalization && is_canonical) {
type.SetCanonical();
@@ -257,7 +264,7 @@
// Only resolved and finalized types should be written to a snapshot.
ASSERT((ptr()->type_state_ == RawType::kFinalizedInstantiated) ||
(ptr()->type_state_ == RawType::kFinalizedUninstantiated));
- ASSERT(ptr()->type_class_ != Object::null());
+ ASSERT(ptr()->type_class_id_ != Object::null());
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -266,12 +273,17 @@
writer->WriteIndexedObject(kTypeCid);
writer->WriteTags(writer->GetObjectTags(this));
+ // Lookup the type class.
+ RawSmi* raw_type_class_id = Smi::RawCast(ptr()->type_class_id_);
+ RawClass* type_class =
+ writer->isolate()->class_table()->At(Smi::Value(raw_type_class_id));
+
// Write out typeclass_is_in_fullsnapshot first as this will
// help the reader decide on how to canonicalize the type object.
- intptr_t tags = writer->GetObjectTags(ptr()->type_class_);
+ intptr_t tags = writer->GetObjectTags(type_class);
bool typeclass_is_in_fullsnapshot =
(ClassIdTag::decode(tags) == kClassCid) &&
- Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(ptr()->type_class_));
+ Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(type_class));
writer->Write<bool>(typeclass_is_in_fullsnapshot);
// Write out all the non object pointer fields.
@@ -279,9 +291,12 @@
writer->Write<int8_t>(ptr()->type_state_);
// Write out all the object pointer fields.
- ASSERT(ptr()->type_class_ != Object::null());
+ ASSERT(ptr()->type_class_id_ != Object::null());
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
+
+ // Write out the type class.
+ writer->WriteObjectImpl(type_class, kAsReference);
}
@@ -348,6 +363,11 @@
type_parameter.raw()->from(), type_parameter.raw()->to(),
kAsReference);
+ // Read in the parameterized class.
+ (*reader->ClassHandle()) =
+ Class::RawCast(reader->ReadObjectImpl(kAsReference));
+ type_parameter.set_parameterized_class(*reader->ClassHandle());
+
return type_parameter.raw();
}
@@ -376,6 +396,11 @@
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to());
+
+ // Write out the parameterized class.
+ RawClass* param_class =
+ writer->isolate()->class_table()->At(ptr()->parameterized_class_id_);
+ writer->WriteObjectImpl(param_class, kAsReference);
}
@@ -1101,6 +1126,9 @@
reader->PassiveObjectHandle()->raw());
}
+ script.set_load_timestamp(FLAG_remove_script_timestamps_for_test
+ ? 0 : OS::GetCurrentTimeMillis());
+
return script.raw();
}
diff --git a/runtime/vm/regexp_assembler_bytecode.cc b/runtime/vm/regexp_assembler_bytecode.cc
index 9586aea..986c0e3 100644
--- a/runtime/vm/regexp_assembler_bytecode.cc
+++ b/runtime/vm/regexp_assembler_bytecode.cc
@@ -12,6 +12,7 @@
#include "vm/regexp.h"
#include "vm/regexp_parser.h"
#include "vm/regexp_interpreter.h"
+#include "vm/timeline.h"
namespace dart {
@@ -460,6 +461,13 @@
if (regexp.bytecode(is_one_byte) == TypedData::null()) {
const String& pattern = String::Handle(zone, regexp.pattern());
+ NOT_IN_PRODUCT(TimelineDurationScope tds(Thread::Current(),
+ Timeline::GetCompilerStream(),
+ "CompileIrregexpBytecode");
+ if (tds.enabled()) {
+ tds.SetNumArguments(1);
+ tds.CopyArgument(0, "pattern", pattern.ToCString());
+ }); // !PRODUCT
const bool multiline = regexp.is_multi_line();
RegExpCompileData* compile_data = new(zone) RegExpCompileData();
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index b8d043b..a082636 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -17,8 +17,9 @@
Thread* thread = Thread::Current();
const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
const Script& script = Script::Handle();
+ const Library& lib = Library::Handle(Library::CoreLibrary());
const Class& owner_class =
- Class::Handle(Class::New(class_name, script,
+ Class::Handle(Class::New(lib, class_name, script,
TokenPosition::kNoSource));
const String& function_name = String::ZoneHandle(Symbols::New(thread, name));
const Function& function = Function::ZoneHandle(
@@ -34,7 +35,6 @@
const Array& functions = Array::Handle(Array::New(1));
functions.SetAt(0, function);
owner_class.SetFunctions(functions);
- Library& lib = Library::Handle(Library::CoreLibrary());
lib.AddClass(owner_class);
function.AttachCode(code);
return function;
diff --git a/runtime/vm/scanner.cc b/runtime/vm/scanner.cc
index 4b1e550..f7ae4ac 100644
--- a/runtime/vm/scanner.cc
+++ b/runtime/vm/scanner.cc
@@ -15,9 +15,6 @@
namespace dart {
-DEFINE_FLAG(bool, print_tokens, false, "Print scanned tokens.");
-
-
// Quick access to the locally defined zone() and thread() methods.
#define Z (zone())
#define T (thread())
@@ -181,23 +178,29 @@
}
-// This method is used when parsing integers and doubles in Dart code. We
+// This method is used when parsing integers in Dart code. We
// are reusing the Scanner's handling of number literals in that situation.
-bool Scanner::IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
- Token::Kind literal_kind,
+bool Scanner::IsValidInteger(const String& str,
bool* is_positive,
const String** value) {
- if ((tokens.length() == 2) &&
- (tokens[0].kind == literal_kind) &&
+ Scanner s(str, Symbols::Empty());
+ TokenDescriptor tokens[3];
+ s.Scan();
+ tokens[0] = s.current_token();
+ s.Scan();
+ tokens[1] = s.current_token();
+ s.Scan();
+ tokens[2] = s.current_token();
+
+ if ((tokens[0].kind == Token::kINTEGER) &&
(tokens[1].kind == Token::kEOS)) {
*is_positive = true;
*value = tokens[0].literal;
return true;
}
- if ((tokens.length() == 3) &&
- ((tokens[0].kind == Token::kADD) ||
+ if (((tokens[0].kind == Token::kADD) ||
(tokens[0].kind == Token::kSUB)) &&
- (tokens[1].kind == literal_kind) &&
+ (tokens[1].kind == Token::kINTEGER) &&
(tokens[2].kind == Token::kEOS)) {
// Check there is no space between "+/-" and number.
if ((tokens[0].offset + 1) != tokens[1].offset) {
@@ -886,85 +889,58 @@
}
-void Scanner::ScanAll(GrowableTokenStream* token_stream) {
+void Scanner::ScanAll(TokenCollector* collector) {
Reset();
do {
Scan();
-
bool inserted_new_lines = false;
for (intptr_t diff = current_token_.position.line - prev_token_line_;
diff > 0;
diff--) {
newline_token_.position.line = current_token_.position.line - diff;
- token_stream->Add(newline_token_);
+ collector->AddToken(newline_token_);
inserted_new_lines = true;
}
-
if (inserted_new_lines &&
((current_token_.kind == Token::kINTERPOL_VAR) ||
(current_token_.kind == Token::kINTERPOL_START))) {
- // NOTE: If this changes, be sure to update
- // Script::GenerateLineNumberArray to stay in sync.
- empty_string_token_.position.line = current_token_.position.line;
- token_stream->Add(empty_string_token_);
- }
- token_stream->Add(current_token_);
+ // NOTE: If this changes, be sure to update
+ // Script::GenerateLineNumberArray to stay in sync.
+ empty_string_token_.position.line = current_token_.position.line;
+ collector->AddToken(empty_string_token_);
+ }
+ collector->AddToken(current_token_);
prev_token_line_ = current_token_.position.line;
} while (current_token_.kind != Token::kEOS);
}
-void Scanner::ScanTo(TokenPosition token_index) {
- TokenPosition index = TokenPosition::kMinSource;
+void Scanner::ScanTo(intptr_t token_index) {
+ ASSERT(token_index >= 0);
+ intptr_t index = 0;
Reset();
do {
Scan();
-
bool inserted_new_lines = false;
for (intptr_t diff = current_token_.position.line - prev_token_line_;
diff > 0;
diff--) {
// Advance the index to account for tokens added in ScanAll.
- index.Next();
+ index++;
inserted_new_lines = true;
}
-
if (inserted_new_lines &&
((current_token_.kind == Token::kINTERPOL_VAR) ||
(current_token_.kind == Token::kINTERPOL_START))) {
// Advance the index to account for tokens added in ScanAll.
- index.Next();
+ index++;
}
- index.Next();
+ index++;
prev_token_line_ = current_token_.position.line;
} while ((token_index >= index) && (current_token_.kind != Token::kEOS));
}
-const Scanner::GrowableTokenStream& Scanner::GetStream() {
- GrowableTokenStream* ts = new(Z) GrowableTokenStream(128);
- ScanAll(ts);
- if (FLAG_print_tokens) {
- Scanner::PrintTokens(*ts);
- }
- return *ts;
-}
-
-
-void Scanner::PrintTokens(const GrowableTokenStream& ts) {
- int currentLine = -1;
- for (int i = 0; i < ts.length(); i++) {
- const TokenDescriptor& td = ts[i];
- if (currentLine != td.position.line) {
- currentLine = td.position.line;
- OS::Print("\n%d (%d): ", currentLine, i);
- }
- OS::Print("%s ", Token::Name(td.kind));
- }
- OS::Print("\n");
-}
-
-
void Scanner::InitOnce() {
ASSERT(Isolate::Current() == Dart::vm_isolate());
for (int i = 0; i < kNumLowercaseChars; i++) {
diff --git a/runtime/vm/scanner.h b/runtime/vm/scanner.h
index 8d5c6d5..30bc81e 100644
--- a/runtime/vm/scanner.h
+++ b/runtime/vm/scanner.h
@@ -11,7 +11,6 @@
#include "vm/growable_array.h"
#include "vm/token.h"
-#include "vm/token_position.h"
namespace dart {
@@ -23,7 +22,7 @@
class String;
// A call to Scan() scans the source one token at at time.
-// The scanned token is returned by cur_token().
+// The scanned token is returned by current_token().
// GetStream() scans the entire source text and returns a stream of tokens.
class Scanner : ValueObject {
public:
@@ -45,7 +44,14 @@
const String* literal; // Identifier, number or string literal.
};
- typedef ZoneGrowableArray<TokenDescriptor> GrowableTokenStream;
+ class TokenCollector : public ValueObject {
+ public:
+ TokenCollector() { }
+ virtual ~TokenCollector() { }
+ virtual void AddToken(const TokenDescriptor& token) { }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TokenCollector);
+ };
// Initializes scanner to scan string source.
Scanner(const String& source, const String& private_key);
@@ -54,13 +60,12 @@
// Scans one token at a time.
void Scan();
- // Scans to specified token position.
- // Use CurrentPosition() to extract position.
- void ScanTo(TokenPosition token_index);
+ // Scans the entire source and collects tokens in the provided collector.
+ void ScanAll(TokenCollector* collector);
- // Scans entire source and returns a stream of tokens.
- // Should be called only once.
- const GrowableTokenStream& GetStream();
+ // Scans to specified token position.
+ // Use CurrentPosition() to extract line and column number.
+ void ScanTo(intptr_t token_index);
// Info about most recently recognized token.
const TokenDescriptor& current_token() const { return current_token_; }
@@ -78,10 +83,8 @@
// Return true if str is an identifier.
bool IsIdent(const String& str);
- // Does the token stream contain a valid literal. This is used to implement
- // the Dart methods int.parse and double.parse.
- static bool IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
- Token::Kind literal_kind,
+ // Does the token stream contain a valid integer literal.
+ static bool IsValidInteger(const String& str,
bool* is_positive,
const String** value);
@@ -116,9 +119,6 @@
void ErrorMsg(const char* msg);
- // Scans entire source into a given stream of tokens.
- void ScanAll(GrowableTokenStream* token_stream);
-
// These functions return true if the given character is a letter,
// a decimal digit, a hexadecimal digit, etc.
static bool IsLetter(int32_t c);
@@ -183,8 +183,6 @@
Thread* thread() const { return thread_; }
Zone* zone() const { return zone_; }
- static void PrintTokens(const GrowableTokenStream& ts);
-
TokenDescriptor current_token_; // Current token.
TokenDescriptor newline_token_; // Newline token.
TokenDescriptor empty_string_token_; // Token for "".
diff --git a/runtime/vm/scanner_test.cc b/runtime/vm/scanner_test.cc
index 49b8cc4..3d8d70c 100644
--- a/runtime/vm/scanner_test.cc
+++ b/runtime/vm/scanner_test.cc
@@ -10,6 +10,10 @@
namespace dart {
+
+typedef ZoneGrowableArray<Scanner::TokenDescriptor> GrowableTokenStream;
+
+
static void LogTokenDesc(Scanner::TokenDescriptor token) {
OS::Print("pos %2d:%d-%d token %s ",
token.position.line, token.position.column,
@@ -22,7 +26,7 @@
}
-static void LogTokenStream(const Scanner::GrowableTokenStream& token_stream) {
+static void LogTokenStream(const GrowableTokenStream& token_stream) {
int token_index = 0;
EXPECT_GT(token_stream.length(), 0);
while (token_index < token_stream.length()) {
@@ -35,7 +39,7 @@
}
-static void CheckKind(const Scanner::GrowableTokenStream &token_stream,
+static void CheckKind(const GrowableTokenStream &token_stream,
int index,
Token::Kind kind) {
if (token_stream[index].kind != kind) {
@@ -46,7 +50,7 @@
}
-static void CheckLiteral(const Scanner::GrowableTokenStream& token_stream,
+static void CheckLiteral(const GrowableTokenStream& token_stream,
int index,
const char* literal) {
if (token_stream[index].literal == NULL) {
@@ -59,7 +63,7 @@
}
-static void CheckIdent(const Scanner::GrowableTokenStream& token_stream,
+static void CheckIdent(const GrowableTokenStream& token_stream,
int index,
const char* literal) {
CheckKind(token_stream, index, Token::kIDENT);
@@ -67,7 +71,7 @@
}
-static void CheckInteger(const Scanner::GrowableTokenStream& token_stream,
+static void CheckInteger(const GrowableTokenStream& token_stream,
int index,
const char* literal) {
CheckKind(token_stream, index, Token::kINTEGER);
@@ -75,7 +79,7 @@
}
-static void CheckLineNumber(const Scanner::GrowableTokenStream& token_stream,
+static void CheckLineNumber(const GrowableTokenStream& token_stream,
int index,
int line_number) {
if (token_stream[index].position.line != line_number) {
@@ -85,7 +89,7 @@
}
-static void CheckNumTokens(const Scanner::GrowableTokenStream& token_stream,
+static void CheckNumTokens(const GrowableTokenStream& token_stream,
int index) {
if (token_stream.length() != index) {
OS::PrintErr("Expected %d tokens but got only %" Pd ".\n",
@@ -94,19 +98,35 @@
}
-static const Scanner::GrowableTokenStream& Scan(const char* source) {
+class Collector : public Scanner::TokenCollector {
+ public:
+ explicit Collector(GrowableTokenStream* ts) : ts_(ts) { }
+ virtual ~Collector() { }
+
+ virtual void AddToken(const Scanner::TokenDescriptor& token) {
+ ts_->Add(token);
+ }
+ private:
+ GrowableTokenStream* ts_;
+};
+
+
+static const GrowableTokenStream& Scan(const char* source) {
+ OS::Print("\nScanning: <%s>\n", source);
+
Scanner scanner(String::Handle(String::New(source)),
String::Handle(String::New("")));
+ GrowableTokenStream* tokens = new GrowableTokenStream(128);
+ Collector collector(tokens);
- OS::Print("\nScanning: <%s>\n", source);
- const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
- LogTokenStream(tokens);
- return tokens;
+ scanner.ScanAll(&collector);
+ LogTokenStream(*tokens);
+ return *tokens;
}
static void BoringTest() {
- const Scanner::GrowableTokenStream& tokens = Scan("x = iffy++;");
+ const GrowableTokenStream& tokens = Scan("x = iffy++;");
CheckNumTokens(tokens, 6);
CheckIdent(tokens, 0, "x");
@@ -118,7 +138,7 @@
static void CommentTest() {
- const Scanner::GrowableTokenStream& tokens =
+ const GrowableTokenStream& tokens =
Scan("Foo( /*block \n"
"comment*/ 0xff) // line comment;");
@@ -135,7 +155,7 @@
static void GreedIsGood() {
// means i++ + j
- const Scanner::GrowableTokenStream& tokens = Scan("x=i+++j");
+ const GrowableTokenStream& tokens = Scan("x=i+++j");
CheckNumTokens(tokens, 7);
CheckIdent(tokens, 0, "x");
@@ -149,7 +169,7 @@
static void StringEscapes() {
// sss = "\" \\ \n\r\t \'"
- const Scanner::GrowableTokenStream& tokens =
+ const GrowableTokenStream& tokens =
Scan("sss = \"\\\" \\\\ \\n\\r\\t \\\'\"");
EXPECT_EQ(4, tokens.length());
@@ -172,70 +192,70 @@
static void InvalidStringEscapes() {
- const Scanner::GrowableTokenStream& high_start_4 =
+ const GrowableTokenStream& high_start_4 =
Scan("\"\\uD800\"");
EXPECT_EQ(2, high_start_4.length());
CheckKind(high_start_4, 0, Token::kERROR);
EXPECT(high_start_4[0].literal->Equals("invalid code point"));
CheckKind(high_start_4, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& high_start_seq =
+ const GrowableTokenStream& high_start_seq =
Scan("\"\\u{D800}\"");
EXPECT_EQ(2, high_start_seq.length());
CheckKind(high_start_seq, 0, Token::kERROR);
EXPECT(high_start_seq[0].literal->Equals("invalid code point"));
CheckKind(high_start_seq, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& high_end_4 =
+ const GrowableTokenStream& high_end_4 =
Scan("\"\\uDBFF\"");
EXPECT_EQ(2, high_end_4.length());
CheckKind(high_end_4, 0, Token::kERROR);
EXPECT(high_end_4[0].literal->Equals("invalid code point"));
CheckKind(high_end_4, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& high_end_seq =
+ const GrowableTokenStream& high_end_seq =
Scan("\"\\u{DBFF}\"");
EXPECT_EQ(2, high_end_seq.length());
CheckKind(high_end_seq, 0, Token::kERROR);
EXPECT(high_end_seq[0].literal->Equals("invalid code point"));
CheckKind(high_end_seq, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& low_start_4 =
+ const GrowableTokenStream& low_start_4 =
Scan("\"\\uDC00\"");
EXPECT_EQ(2, low_start_4.length());
CheckKind(low_start_4, 0, Token::kERROR);
EXPECT(low_start_4[0].literal->Equals("invalid code point"));
CheckKind(low_start_4, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& low_start_seq =
+ const GrowableTokenStream& low_start_seq =
Scan("\"\\u{DC00}\"");
EXPECT_EQ(2, low_start_seq.length());
CheckKind(low_start_seq, 0, Token::kERROR);
EXPECT(low_start_seq[0].literal->Equals("invalid code point"));
CheckKind(low_start_seq, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& low_end_4 =
+ const GrowableTokenStream& low_end_4 =
Scan("\"\\uDFFF\"");
EXPECT_EQ(2, low_end_4.length());
CheckKind(low_end_4, 0, Token::kERROR);
EXPECT(low_end_4[0].literal->Equals("invalid code point"));
CheckKind(low_end_4, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& low_end_seq =
+ const GrowableTokenStream& low_end_seq =
Scan("\"\\u{DFFF}\"");
EXPECT_EQ(2, low_end_seq.length());
CheckKind(low_end_seq, 0, Token::kERROR);
EXPECT(low_end_seq[0].literal->Equals("invalid code point"));
CheckKind(low_end_seq, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& out_of_range_low =
+ const GrowableTokenStream& out_of_range_low =
Scan("\"\\u{110000}\"");
EXPECT_EQ(2, out_of_range_low.length());
CheckKind(out_of_range_low, 0, Token::kERROR);
EXPECT(out_of_range_low[0].literal->Equals("invalid code point"));
CheckKind(out_of_range_low, 1, Token::kEOS);
- const Scanner::GrowableTokenStream& out_of_range_high =
+ const GrowableTokenStream& out_of_range_high =
Scan("\"\\u{FFFFFF}\"");
EXPECT_EQ(2, out_of_range_high.length());
CheckKind(out_of_range_high, 0, Token::kERROR);
@@ -246,7 +266,7 @@
static void RawString() {
// rs = @"\' \\"
- const Scanner::GrowableTokenStream& tokens = Scan("rs = r\"\\\' \\\\\"");
+ const GrowableTokenStream& tokens = Scan("rs = r\"\\\' \\\\\"");
EXPECT_EQ(4, tokens.length());
CheckIdent(tokens, 0, "rs");
@@ -269,7 +289,7 @@
// |mls = '''
// |1' x
// |2''';
- const Scanner::GrowableTokenStream& tokens = Scan("mls = '''\n1' x\n2''';");
+ const GrowableTokenStream& tokens = Scan("mls = '''\n1' x\n2''';");
EXPECT_EQ(7, tokens.length());
CheckIdent(tokens, 0, "mls");
@@ -295,7 +315,7 @@
static void EmptyString() {
// es = "";
- const Scanner::GrowableTokenStream& tokens = Scan("es = \"\";");
+ const GrowableTokenStream& tokens = Scan("es = \"\";");
EXPECT_EQ(5, tokens.length());
CheckIdent(tokens, 0, "es");
@@ -308,7 +328,7 @@
static void EmptyMultilineString() {
// es = """""";
- const Scanner::GrowableTokenStream& tokens = Scan("es = \"\"\"\"\"\";");
+ const GrowableTokenStream& tokens = Scan("es = \"\"\"\"\"\";");
EXPECT_EQ(5, tokens.length());
CheckIdent(tokens, 0, "es");
@@ -321,7 +341,7 @@
static void NumberLiteral() {
- const Scanner::GrowableTokenStream& tokens =
+ const GrowableTokenStream& tokens =
Scan("5 0x5d 0.3 0.33 1E+12 .42 +5");
CheckKind(tokens, 0, Token::kINTEGER);
@@ -401,7 +421,7 @@
void InvalidText() {
- const Scanner::GrowableTokenStream& tokens =
+ const GrowableTokenStream& tokens =
Scan("\\");
EXPECT_EQ(2, tokens.length());
@@ -419,7 +439,7 @@
"d\n"
"\"\"\";";
- const Scanner::GrowableTokenStream& tokens = Scan(source);
+ const GrowableTokenStream& tokens = Scan(source);
EXPECT_EQ(11, tokens.length());
CheckKind(tokens, 0, Token::kVAR);
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index bcbb79f..2ca7b09 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -31,7 +31,6 @@
DEFINE_FLAG(int, new_gen_garbage_threshold, 90,
"Grow new gen when less than this percentage is garbage.");
DEFINE_FLAG(int, new_gen_growth_factor, 4, "Grow new gen by this factor.");
-DECLARE_FLAG(bool, concurrent_sweep);
// Scavenger uses RawObject::kMarkBit to distinguish forwaded and non-forwarded
// objects. The kMarkBit does not intersect with the target address because of
@@ -526,6 +525,13 @@
total_count += count;
while (!pending->IsEmpty()) {
RawObject* raw_object = pending->Pop();
+ if (raw_object->IsFreeListElement()) {
+ // TODO(rmacnak): Forwarding corpse from become. Probably we should also
+ // visit the store buffer blocks during become, and mark any forwardees
+ // as remembered if their forwarders are remembered to satisfy the
+ // following assert.
+ continue;
+ }
ASSERT(raw_object->IsRemembered());
raw_object->ClearRememberedBit();
visitor->VisitingOldObject(raw_object);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 197c77f..fc78a48 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -35,6 +35,7 @@
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#include "vm/timeline.h"
+#include "vm/type_table.h"
#include "vm/unicode.h"
#include "vm/version.h"
@@ -45,6 +46,7 @@
DECLARE_FLAG(bool, trace_service);
DECLARE_FLAG(bool, trace_service_pause_events);
+DECLARE_FLAG(bool, profile_vm);
DEFINE_FLAG(charp, vm_name, "vm",
"The default name of this vm as reported by the VM service "
"protocol");
@@ -1008,16 +1010,17 @@
void Service::HandleEvent(ServiceEvent* event) {
- if (event->isolate() != NULL &&
- ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) {
+ if (event->stream_info() != NULL &&
+ !event->stream_info()->enabled()) {
+ if (FLAG_warn_on_pause_with_no_debugger &&
+ event->IsPause()) {
+ // If we are about to pause a running program which has no
+ // debugger connected, tell the user about it.
+ ReportPauseOnConsole(event);
+ }
+ // Ignore events when no one is listening to the event stream.
return;
}
- if (FLAG_warn_on_pause_with_no_debugger &&
- event->IsPause() && !Service::debug_stream.enabled()) {
- // If we are about to pause a running program which has no
- // debugger connected, tell the user about it.
- ReportPauseOnConsole(event);
- }
if (!ServiceIsolate::IsRunning()) {
return;
}
@@ -1451,14 +1454,21 @@
return lib.raw();
}
if (strcmp(parts[2], "scripts") == 0) {
- // Script ids look like "libraries/35/scripts/library%2Furl.dart"
- if (num_parts != 4) {
+ // Script ids look like "libraries/35/scripts/library%2Furl.dart/12345"
+ if (num_parts != 5) {
return Object::sentinel().raw();
}
const String& id = String::Handle(String::New(parts[3]));
ASSERT(!id.IsNull());
// The id is the url of the script % encoded, decode it.
const String& requested_url = String::Handle(String::DecodeIRI(id));
+
+ // Each script id is tagged with a load time.
+ int64_t timestamp;
+ if (!GetInteger64Id(parts[4], ×tamp, 16) || (timestamp < 0)) {
+ return Object::sentinel().raw();
+ }
+
Script& script = Script::Handle();
String& script_url = String::Handle();
const Array& loaded_scripts = Array::Handle(lib.LoadedScripts());
@@ -1468,7 +1478,8 @@
script ^= loaded_scripts.At(i);
ASSERT(!script.IsNull());
script_url ^= script.url();
- if (script_url.Equals(requested_url)) {
+ if (script_url.Equals(requested_url) &&
+ (timestamp == script.load_timestamp())) {
return script.raw();
}
}
@@ -1587,12 +1598,13 @@
if (!GetIntegerId(parts[3], &id)) {
return Object::sentinel().raw();
}
- Type& type = Type::Handle(zone);
- type ^= cls.CanonicalTypeFromIndex(id);
- if (type.IsNull()) {
+ if (id != 0) {
return Object::sentinel().raw();
}
- return type.raw();
+ const Type& type = Type::Handle(zone, cls.CanonicalType());
+ if (!type.IsNull()) {
+ return type.raw();
+ }
}
// Not found.
@@ -2374,6 +2386,52 @@
}
+static const MethodParameter* reload_sources_params[] = {
+ RUNNABLE_ISOLATE_PARAMETER,
+ NULL,
+};
+
+
+static bool ReloadSources(Thread* thread, JSONStream* js) {
+ Isolate* isolate = thread->isolate();
+ if (!isolate->compilation_allowed()) {
+ js->PrintError(kFeatureDisabled,
+ "Cannot reload source when running a precompiled program.");
+ return true;
+ }
+ if (Dart::snapshot_kind() == Snapshot::kAppWithJIT) {
+ js->PrintError(kFeatureDisabled,
+ "Cannot reload source when running an app snapshot.");
+ return true;
+ }
+ Dart_LibraryTagHandler handler = isolate->library_tag_handler();
+ if (handler == NULL) {
+ js->PrintError(kFeatureDisabled,
+ "A library tag handler must be installed.");
+ return true;
+ }
+ if (isolate->IsReloading()) {
+ js->PrintError(kIsolateIsReloading,
+ "This isolate is being reloaded.");
+ return true;
+ }
+ DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
+ ASSERT(isolate->CanReload());
+
+ if (stack->Length() > 0) {
+ // TODO(turnidge): We need to support this case.
+ js->PrintError(kFeatureDisabled,
+ "Source can only be reloaded when stack is empty.");
+ return true;
+ } else {
+ isolate->ReloadSources();
+ }
+
+ PrintSuccess(js);
+ return true;
+}
+
+
static bool AddBreakpointCommon(Thread* thread,
JSONStream* js,
const String& script_uri) {
@@ -2927,7 +2985,7 @@
return true;
}
- js->PrintError(kVMMustBePaused, NULL);
+ js->PrintError(kIsolateMustBePaused, NULL);
return true;
}
@@ -3564,25 +3622,30 @@
if (js->ParamIs("onlyWithInstantiations", "true")) {
only_with_instantiations = true;
}
+ Zone* zone = thread->zone();
ObjectStore* object_store = thread->isolate()->object_store();
- const Array& table = Array::Handle(object_store->canonical_type_arguments());
- ASSERT(table.Length() > 0);
- TypeArguments& type_args = TypeArguments::Handle();
- const intptr_t table_size = table.Length() - 1;
- const intptr_t table_used = Smi::Value(Smi::RawCast(table.At(table_size)));
+ CanonicalTypeArgumentsSet typeargs_table(
+ zone, object_store->canonical_type_arguments());
+ const intptr_t table_size = typeargs_table.NumEntries();
+ const intptr_t table_used = typeargs_table.NumOccupied();
+ const Array& typeargs_array = Array::Handle(
+ zone, HashTables::ToArray(typeargs_table, false));
+ ASSERT(typeargs_array.Length() == table_used);
+ TypeArguments& typeargs = TypeArguments::Handle(zone);
JSONObject jsobj(js);
jsobj.AddProperty("type", "TypeArgumentsList");
jsobj.AddProperty("canonicalTypeArgumentsTableSize", table_size);
jsobj.AddProperty("canonicalTypeArgumentsTableUsed", table_used);
JSONArray members(&jsobj, "typeArguments");
- for (intptr_t i = 0; i < table_size; i++) {
- type_args ^= table.At(i);
- if (!type_args.IsNull()) {
- if (!only_with_instantiations || type_args.HasInstantiations()) {
- members.AddValue(type_args);
+ for (intptr_t i = 0; i < table_used; i++) {
+ typeargs ^= typeargs_array.At(i);
+ if (!typeargs.IsNull()) {
+ if (!only_with_instantiations || typeargs.HasInstantiations()) {
+ members.AddValue(typeargs);
}
}
}
+ typeargs_table.Release();
return true;
}
@@ -3642,6 +3705,7 @@
jsobj.AddProperty("targetCPU", CPU::Id());
jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
jsobj.AddProperty("version", Version::String());
+ jsobj.AddProperty("_profilerMode", FLAG_profile_vm ? "VM" : "Dart");
jsobj.AddProperty64("pid", OS::ProcessId());
int64_t start_time_millis = (vm_isolate->start_time() /
kMicrosecondsPerMillisecond);
@@ -3947,6 +4011,8 @@
remove_breakpoint_params },
{ "_restartVM", RestartVM,
restart_vm_params },
+ { "_reloadSources", ReloadSources,
+ reload_sources_params },
{ "resume", Resume,
resume_params },
{ "_requestHeapSnapshot", RequestHeapSnapshot,
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index f38f7f83..084b218 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -66,10 +66,10 @@
public:
explicit StreamInfo(const char* id) : id_(id), enabled_(false) {}
- const char* id() { return id_; }
+ const char* id() const { return id_; }
void set_enabled(bool value) { enabled_ = value; }
- bool enabled() { return enabled_; }
+ bool enabled() const { return enabled_; }
private:
const char* id_;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index e37643c..6e3c180 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -131,7 +131,7 @@
are not supported by the Dart VM.
By convention, every response returned by the Service Protocol is a subtype
-of [Response](#response) and provides a _type_ paramters which can be used
+of [Response](#response) and provides a _type_ parameter which can be used
to distinguish the exact return type. In the example above, the
[Version](#version) type is returned.
@@ -172,8 +172,7 @@
}
```
-In addition the the [error codes](http://www.jsonrpc.org/specification#error_object)
-specified in the JSON-RPC spec, we use the following application specific error codes:
+In addition to the [error codes](http://www.jsonrpc.org/specification#error_object) specified in the JSON-RPC spec, we use the following application specific error codes:
code | message | meaning
---- | ------- | -------
@@ -183,6 +182,7 @@
103 | Stream already subscribed | The client is already subscribed to the specified _streamId_
104 | Stream not subscribed | The client is not subscribed to the specified _streamId_
105 | Isolate must be runnable | This operation cannot happen until the isolate is runnable
+106 | Isolate must be paused | This operation is only valid when the isolate is paused
@@ -2216,6 +2216,10 @@
> [lineNumber, (tokenPos, columnNumber)*]
+The _tokenPos_ is an arbitrary integer value that is used to represent
+a location in the source code. A _tokenPos_ value is not meaningful
+in itself and code should not rely on the exact values returned.
+
For example, a _tokenPosTable_ with the value...
> [[1, 100, 5, 101, 8],[2, 102, 7]]
@@ -2523,5 +2527,5 @@
3.2 | Isolate objects now include the runnable bit and many debugger related RPCs will return an error if executed on an isolate before it is runnable.
3.3 | Pause event now indicates if the isolate is paused at an await, yield, or yield* suspension point via the 'atAsyncSuspension' field. Resume command now supports the step parameter 'OverAsyncSuspension'. A Breakpoint added synthetically by an 'OverAsyncSuspension' resume command identifies itself as such via the 'isSyntheticAsyncContinuation' field.
3.4 | Add the superType and mixin fields to Class. Added new pause event 'None'.
-3.5 | Add the error field to SourceReportRange.
+3.5 | Add the error field to SourceReportRange. Clarify definition of token position. Add "Isolate must be paused" error code.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index d34f439..94af480 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -4,37 +4,14 @@
#include "vm/service_event.h"
+#include "vm/debugger.h"
#include "vm/message_handler.h"
+#include "vm/service_isolate.h"
namespace dart {
#ifndef PRODUCT
-// Translate from the legacy DebugEvent to a ServiceEvent.
-static ServiceEvent::EventKind TranslateEventKind(
- DebuggerEvent::EventType kind) {
- switch (kind) {
- case DebuggerEvent::kIsolateCreated:
- return ServiceEvent::kIsolateStart;
-
- case DebuggerEvent::kIsolateShutdown:
- return ServiceEvent::kIsolateExit;
-
- case DebuggerEvent::kBreakpointReached:
- return ServiceEvent::kPauseBreakpoint;
-
- case DebuggerEvent::kIsolateInterrupted:
- return ServiceEvent::kPauseInterrupted;
-
- case DebuggerEvent::kExceptionThrown:
- return ServiceEvent::kPauseException;
- default:
- UNREACHABLE();
- return ServiceEvent::kIllegal;
- }
-}
-
-
ServiceEvent::ServiceEvent(Isolate* isolate, EventKind event_kind)
: isolate_(isolate),
kind_(event_kind),
@@ -45,12 +22,18 @@
timeline_event_block_(NULL),
extension_rpc_(NULL),
exception_(NULL),
+ reload_error_(NULL),
at_async_jump_(false),
inspectee_(NULL),
gc_stats_(NULL),
bytes_(NULL),
bytes_length_(0),
timestamp_(OS::GetCurrentTimeMillis()) {
+ // We should never generate events for the vm or service isolates.
+ ASSERT(isolate_ != Dart::vm_isolate());
+ ASSERT(isolate == NULL ||
+ !ServiceIsolate::IsServiceIsolateDescendant(isolate_));
+
if ((event_kind == ServiceEvent::kPauseStart) &&
!isolate->message_handler()->is_paused_on_start()) {
// We will pause on start but the message handler lacks a valid
@@ -65,36 +48,8 @@
}
-ServiceEvent::ServiceEvent(const DebuggerEvent* debugger_event)
- : isolate_(debugger_event->isolate()),
- kind_(TranslateEventKind(debugger_event->type())),
- breakpoint_(NULL),
- top_frame_(NULL),
- timeline_event_block_(NULL),
- extension_rpc_(NULL),
- exception_(NULL),
- at_async_jump_(false),
- inspectee_(NULL),
- gc_stats_(NULL),
- bytes_(NULL),
- bytes_length_(0),
- timestamp_(OS::GetCurrentTimeMillis()) {
- DebuggerEvent::EventType type = debugger_event->type();
- if (type == DebuggerEvent::kBreakpointReached) {
- set_breakpoint(debugger_event->breakpoint());
- set_at_async_jump(debugger_event->at_async_jump());
- }
- if (type == DebuggerEvent::kExceptionThrown) {
- set_exception(debugger_event->exception());
- }
- if (type == DebuggerEvent::kBreakpointReached ||
- type == DebuggerEvent::kIsolateInterrupted ||
- type == DebuggerEvent::kExceptionThrown) {
- set_top_frame(debugger_event->top_frame());
- }
- if (debugger_event->timestamp() != -1) {
- timestamp_ = debugger_event->timestamp();
- }
+void ServiceEvent::UpdateTimestamp() {
+ timestamp_ = OS::GetCurrentTimeMillis();
}
@@ -112,6 +67,8 @@
return "IsolateUpdate";
case kServiceExtensionAdded:
return "ServiceExtensionAdded";
+ case kIsolateReload:
+ return "IsolateReload";
case kPauseStart:
return "PauseStart";
case kPauseExit:
@@ -155,17 +112,18 @@
}
-const char* ServiceEvent::stream_id() const {
+const StreamInfo* ServiceEvent::stream_info() const {
switch (kind()) {
case kVMUpdate:
- return Service::vm_stream.id();
+ return &Service::vm_stream;
case kIsolateStart:
case kIsolateRunnable:
case kIsolateExit:
case kIsolateUpdate:
+ case kIsolateReload:
case kServiceExtensionAdded:
- return Service::isolate_stream.id();
+ return &Service::isolate_stream;
case kPauseStart:
case kPauseExit:
@@ -179,22 +137,22 @@
case kBreakpointRemoved:
case kInspect:
case kDebuggerSettingsUpdate:
- return Service::debug_stream.id();
+ return &Service::debug_stream;
case kGC:
- return Service::gc_stream.id();
-
- case kEmbedder:
- return embedder_stream_id_;
+ return &Service::gc_stream;
case kLogging:
- return Service::logging_stream.id();
+ return &Service::logging_stream;
case kExtension:
- return Service::extension_stream.id();
+ return &Service::extension_stream;
case kTimelineEvents:
- return Service::timeline_stream.id();
+ return &Service::timeline_stream;
+
+ case kEmbedder:
+ return NULL;
default:
UNREACHABLE();
@@ -203,9 +161,28 @@
}
+const char* ServiceEvent::stream_id() const {
+ const StreamInfo* stream = stream_info();
+ if (stream == NULL) {
+ ASSERT(kind() == kEmbedder);
+ return embedder_stream_id_;
+ } else {
+ return stream->id();
+ }
+}
+
+
void ServiceEvent::PrintJSON(JSONStream* js) const {
JSONObject jsobj(js);
PrintJSONHeader(&jsobj);
+ if (kind() == kIsolateReload) {
+ if (reload_error_ == NULL) {
+ jsobj.AddProperty("status", "success");
+ } else {
+ jsobj.AddProperty("status", "failure");
+ jsobj.AddProperty("reloadError", *(reload_error()));
+ }
+ }
if (kind() == kServiceExtensionAdded) {
ASSERT(extension_rpc_ != NULL);
jsobj.AddProperty("extensionRPC", extension_rpc_->ToCString());
diff --git a/runtime/vm/service_event.h b/runtime/vm/service_event.h
index 3ca26e4..d6bc92e 100644
--- a/runtime/vm/service_event.h
+++ b/runtime/vm/service_event.h
@@ -5,23 +5,30 @@
#ifndef VM_SERVICE_EVENT_H_
#define VM_SERVICE_EVENT_H_
-#include "vm/debugger.h"
-
-class DebuggerEvent;
-class TimelineEventBlock;
+#include "vm/globals.h"
+#include "vm/heap.h"
namespace dart {
+class ActivationFrame;
+class Breakpoint;
+class Instance;
+class Isolate;
+class Object;
+class StreamInfo;
+class String;
+class TimelineEventBlock;
+
class ServiceEvent {
public:
enum EventKind {
kVMUpdate, // VM identity information has changed
- kIsolateStart, // New isolate has started
- kIsolateRunnable, // Isolate is ready to run
- kIsolateExit, // Isolate has exited
- kIsolateUpdate, // Isolate identity information has changed
-
+ kIsolateStart, // New isolate has started
+ kIsolateRunnable, // Isolate is ready to run
+ kIsolateExit, // Isolate has exited
+ kIsolateUpdate, // Isolate identity information has changed
+ kIsolateReload, // Result of a reload request
kServiceExtensionAdded, // A service extension was registered
kPauseStart, // --pause-isolates-on-start
@@ -68,10 +75,13 @@
ServiceEvent(Isolate* isolate, EventKind event_kind);
- explicit ServiceEvent(const DebuggerEvent* debugger_event);
-
Isolate* isolate() const { return isolate_; }
+ // Used by the C embedding api.
+ Dart_Port isolate_id() const {
+ return isolate_->main_port();
+ }
+
EventKind kind() const { return kind_; }
bool IsPause() const {
@@ -95,6 +105,7 @@
embedder_kind_ = embedder_kind;
}
+ const StreamInfo* stream_info() const;
const char* stream_id() const;
void set_embedder_stream_id(const char* stream_id) {
@@ -138,6 +149,15 @@
exception_ = exception;
}
+ const Error* reload_error() const {
+ ASSERT(kind_ == kIsolateReload);
+ return reload_error_;
+ }
+ void set_reload_error(const Error* error) {
+ ASSERT(kind_ == kIsolateReload);
+ reload_error_ = error;
+ }
+
bool at_async_jump() const {
return at_async_jump_;
}
@@ -182,6 +202,8 @@
extension_event_ = extension_event;
}
+ void UpdateTimestamp();
+
int64_t timestamp() const {
return timestamp_;
}
@@ -209,6 +231,7 @@
const TimelineEventBlock* timeline_event_block_;
const String* extension_rpc_;
const Object* exception_;
+ const Error* reload_error_;
bool at_async_jump_;
const Object* inspectee_;
const Heap::GCStats* gc_stats_;
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index fa8cd95..e65c539 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -113,13 +113,13 @@
}
-bool ServiceIsolate::IsServiceIsolate(Isolate* isolate) {
+bool ServiceIsolate::IsServiceIsolate(const Isolate* isolate) {
MonitorLocker ml(monitor_);
return isolate == isolate_;
}
-bool ServiceIsolate::IsServiceIsolateDescendant(Isolate* isolate) {
+bool ServiceIsolate::IsServiceIsolateDescendant(const Isolate* isolate) {
MonitorLocker ml(monitor_);
return isolate->origin_id() == origin_;
}
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index 1b1a9f6..dc2e4be 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -19,8 +19,8 @@
static bool Exists();
static bool IsRunning();
- static bool IsServiceIsolate(Isolate* isolate);
- static bool IsServiceIsolateDescendant(Isolate* isolate);
+ static bool IsServiceIsolate(const Isolate* isolate);
+ static bool IsServiceIsolateDescendant(const Isolate* isolate);
static Dart_Port Port();
static Dart_Port WaitForLoadPort();
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index f11bab7..24c934b 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -3759,7 +3759,7 @@
int32_t r6_val = get_register(R6);
int32_t r7_val = get_register(R7);
int32_t r8_val = get_register(R8);
-#if !defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_EABI)
int32_t r9_val = get_register(R9);
#endif
int32_t r10_val = get_register(R10);
@@ -3793,7 +3793,7 @@
set_register(R6, callee_saved_value);
set_register(R7, callee_saved_value);
set_register(R8, callee_saved_value);
-#if !defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_EABI)
set_register(R9, callee_saved_value);
#endif
set_register(R10, callee_saved_value);
@@ -3821,7 +3821,7 @@
ASSERT(callee_saved_value == get_register(R6));
ASSERT(callee_saved_value == get_register(R7));
ASSERT(callee_saved_value == get_register(R8));
-#if !defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_EABI)
ASSERT(callee_saved_value == get_register(R9));
#endif
ASSERT(callee_saved_value == get_register(R10));
@@ -3844,7 +3844,7 @@
set_register(R6, r6_val);
set_register(R7, r7_val);
set_register(R8, r8_val);
-#if !defined(TARGET_OS_MACOS)
+#if defined(TARGET_ABI_EABI)
set_register(R9, r9_val);
#endif
set_register(R10, r10_val);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 33570ae..b1b2f4a 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -18,6 +18,7 @@
#include "vm/snapshot_ids.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
+#include "vm/timeline.h"
#include "vm/verified_memory.h"
#include "vm/version.h"
@@ -599,7 +600,7 @@
ASSERT(object_store != NULL);
// First read the version string, and check that it matches.
- RawApiError* error = VerifyVersion();
+ RawApiError* error = VerifyVersionAndFeatures();
if (error != ApiError::null()) {
return error;
}
@@ -670,7 +671,7 @@
ASSERT(kind_ == Snapshot::kScript);
// First read the version string, and check that it matches.
- RawApiError* error = VerifyVersion();
+ RawApiError* error = VerifyVersionAndFeatures();
if (error != ApiError::null()) {
return error;
}
@@ -693,7 +694,7 @@
}
-RawApiError* SnapshotReader::VerifyVersion() {
+RawApiError* SnapshotReader::VerifyVersionAndFeatures() {
// If the version string doesn't match, return an error.
// Note: New things are allocated only if we're going to return an error.
@@ -706,7 +707,7 @@
OS::SNPrint(message_buffer,
kMessageBufferSize,
"No full snapshot version found, expected '%s'",
- Version::SnapshotString());
+ expected_version);
// This can also fail while bringing up the VM isolate, so make sure to
// allocate the error message in old space.
const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
@@ -723,7 +724,7 @@
kMessageBufferSize,
"Wrong %s snapshot version, expected '%s' found '%s'",
(Snapshot::IsFull(kind_)) ? "full" : "script",
- Version::SnapshotString(),
+ expected_version,
actual_version);
free(actual_version);
// This can also fail while bringing up the VM isolate, so make sure to
@@ -732,6 +733,34 @@
return ApiError::New(msg, Heap::kOld);
}
Advance(version_len);
+
+ const char* expected_features = Dart::FeaturesString(kind_);
+ ASSERT(expected_features != NULL);
+ const intptr_t expected_len = strlen(expected_features);
+
+ const char* features = reinterpret_cast<const char*>(CurrentBufferAddress());
+ ASSERT(features != NULL);
+ intptr_t buffer_len = OS::StrNLen(features, PendingBytes());
+ if ((buffer_len != expected_len) ||
+ strncmp(features, expected_features, expected_len)) {
+ const intptr_t kMessageBufferSize = 256;
+ char message_buffer[kMessageBufferSize];
+ char* actual_features = OS::StrNDup(features, buffer_len < 128 ? buffer_len
+ : 128);
+ OS::SNPrint(message_buffer,
+ kMessageBufferSize,
+ "Wrong features in snapshot, expected '%s' found '%s'",
+ expected_features,
+ actual_features);
+ free(const_cast<char*>(expected_features));
+ free(actual_features);
+ // This can also fail while bringing up the VM isolate, so make sure to
+ // allocate the error message in old space.
+ const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
+ return ApiError::New(msg, Heap::kOld);
+ }
+ free(const_cast<char*>(expected_features));
+ Advance(expected_len + 1);
return ApiError::null();
}
@@ -1191,7 +1220,10 @@
void AssemblyInstructionsWriter::Write() {
- Zone* zone = Thread::Current()->zone();
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ NOT_IN_PRODUCT(TimelineDurationScope tds(thread,
+ Timeline::GetIsolateStream(), "WriteInstructions"));
// Handlify collected raw pointers as building the names below
// will allocate on the Dart heap.
@@ -1336,7 +1368,10 @@
void BlobInstructionsWriter::Write() {
- Zone* zone = Thread::Current()->zone();
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ NOT_IN_PRODUCT(TimelineDurationScope tds(thread,
+ Timeline::GetIsolateStream(), "WriteInstructions"));
// Handlify collected raw pointers as building the names below
// will allocate on the Dart heap.
@@ -1715,7 +1750,7 @@
ASSERT(object_store != NULL);
// First read the version string, and check that it matches.
- RawApiError* error = VerifyVersion();
+ RawApiError* error = VerifyVersionAndFeatures();
if (error != ApiError::null()) {
return error;
}
@@ -2044,6 +2079,9 @@
intptr_t first_object_id = -1;
if (vm_isolate_snapshot_buffer != NULL) {
+ NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+ Timeline::GetIsolateStream(), "PrepareNewVMIsolate"));
+
// Collect all the script objects and their accompanying token stream
// objects into an array so that we can write it out as part of the VM
// isolate snapshot. We first count the number of script objects, allocate
@@ -2094,6 +2132,9 @@
void FullSnapshotWriter::WriteVmIsolateSnapshot() {
+ NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+ Timeline::GetIsolateStream(), "WriteVmIsolateSnapshot"));
+
ASSERT(vm_isolate_snapshot_buffer_ != NULL);
SnapshotWriter writer(thread(),
kind_,
@@ -2113,7 +2154,7 @@
writer.ReserveHeader();
// Write out the version string.
- writer.WriteVersion();
+ writer.WriteVersionAndFeatures();
/*
* Now Write out the following
@@ -2143,6 +2184,9 @@
void FullSnapshotWriter::WriteIsolateFullSnapshot() {
+ NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+ Timeline::GetIsolateStream(), "WriteIsolateFullSnapshot"));
+
SnapshotWriter writer(thread(),
kind_,
isolate_snapshot_buffer_,
@@ -2164,7 +2208,7 @@
writer.ReserveHeader();
// Write out the version string.
- writer.WriteVersion();
+ writer.WriteVersionAndFeatures();
// Write out the full snapshot.
@@ -2688,11 +2732,18 @@
}
-void SnapshotWriter::WriteVersion() {
+void SnapshotWriter::WriteVersionAndFeatures() {
const char* expected_version = Version::SnapshotString();
ASSERT(expected_version != NULL);
const intptr_t version_len = strlen(expected_version);
WriteBytes(reinterpret_cast<const uint8_t*>(expected_version), version_len);
+
+ const char* expected_features = Dart::FeaturesString(kind_);
+ ASSERT(expected_features != NULL);
+ const intptr_t features_len = strlen(expected_features);
+ WriteBytes(reinterpret_cast<const uint8_t*>(expected_features),
+ features_len + 1);
+ free(const_cast<char*>(expected_features));
}
@@ -2726,7 +2777,7 @@
ReserveHeader();
// Write out the version string.
- WriteVersion();
+ WriteVersionAndFeatures();
// Write out the library object.
{
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 1c0fddb..da26ca1 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -187,11 +187,6 @@
return (kind == kAppWithJIT) || (kind == kAppNoJIT);
}
- bool IsMessageSnapshot() const { return kind() == kMessage; }
- bool IsScriptSnapshot() const { return kind() == kScript; }
- bool IsCoreSnapshot() const { return kind() == kCore; }
- bool IsAppSnapshotWithJIT() const { return kind() == kAppWithJIT; }
- bool IsAppSnapshotNoJIT() const { return kind() == kAppNoJIT; }
uint8_t* Addr() { return reinterpret_cast<uint8_t*>(this); }
static intptr_t length_offset() {
@@ -410,6 +405,7 @@
ClassTable* class_table() const { return isolate()->class_table(); }
PassiveObject* PassiveObjectHandle() { return &pobj_; }
Array* ArrayHandle() { return &array_; }
+ Class* ClassHandle() { return &cls_; }
String* StringHandle() { return &str_; }
AbstractType* TypeHandle() { return &type_; }
TypeArguments* TypeArgumentsHandle() { return &type_arguments_; }
@@ -441,7 +437,7 @@
RawObject* ReadScriptSnapshot();
// Read version number of snapshot and verify.
- RawApiError* VerifyVersion();
+ RawApiError* VerifyVersionAndFeatures();
// Helper functions for creating uninitialized versions
// of various object types. These are used when reading a
@@ -1019,7 +1015,7 @@
void ThrowException(Exceptions::ExceptionType type, const char* msg);
// Write a version string for the snapshot.
- void WriteVersion();
+ void WriteVersionAndFeatures();
int32_t GetInstructionsId(RawInstructions* instructions, RawCode* code) {
return instructions_writer_->GetOffsetFor(instructions, code);
@@ -1093,7 +1089,6 @@
friend class RawGrowableObjectArray;
friend class RawImmutableArray;
friend class RawInstructions;
- friend class RawRegExp;
friend class RawLibrary;
friend class RawLinkedHashMap;
friend class RawLiteralToken;
@@ -1101,11 +1096,14 @@
friend class RawMirrorReference;
friend class RawObjectPool;
friend class RawReceivePort;
+ friend class RawRegExp;
friend class RawScript;
friend class RawStacktrace;
friend class RawSubtypeTestCache;
friend class RawTokenStream;
+ friend class RawType;
friend class RawTypeArguments;
+ friend class RawTypeParameter;
friend class RawUserTag;
friend class SnapshotWriterVisitor;
friend class WriteInlinedObjectVisitor;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 52db512..493607a 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -18,8 +18,6 @@
namespace dart {
-DECLARE_FLAG(bool, concurrent_sweep);
-
// Check if serialized and deserialized objects are equal.
static bool Equals(const Object& expected, const Object& actual) {
if (expected.IsNull()) {
@@ -869,9 +867,8 @@
const String& str = String::Handle(zone, expected_tokens.GenerateSource());
const String& private_key =
String::Handle(zone, expected_tokens.PrivateKey());
- Scanner scanner(str, private_key);
const TokenStream& reconstructed_tokens =
- TokenStream::Handle(zone, TokenStream::New(scanner.GetStream(),
+ TokenStream::Handle(zone, TokenStream::New(str,
private_key,
false));
expected_iterator.SetCurrentPosition(TokenPosition::kMinSource);
diff --git a/runtime/vm/stack_frame_arm.h b/runtime/vm/stack_frame_arm.h
index ca89fb5..a966a29 100644
--- a/runtime/vm/stack_frame_arm.h
+++ b/runtime/vm/stack_frame_arm.h
@@ -43,14 +43,16 @@
static const int kCallerSpSlotFromFp = 2;
// Entry and exit frame layout.
-#if defined(TARGET_OS_MAC)
+#if defined(TARGET_ABI_IOS)
static const int kExitLinkSlotFromEntryFp = -26;
COMPILE_ASSERT(kAbiPreservedCpuRegCount == 6);
COMPILE_ASSERT(kAbiPreservedFpuRegCount == 4);
-#else
+#elif defined(TARGET_ABI_EABI)
static const int kExitLinkSlotFromEntryFp = -27;
COMPILE_ASSERT(kAbiPreservedCpuRegCount == 7);
COMPILE_ASSERT(kAbiPreservedFpuRegCount == 4);
+#else
+#error Unknown ABI
#endif
} // namespace dart
diff --git a/runtime/vm/store_buffer.h b/runtime/vm/store_buffer.h
index 36f17bc..2fce2d6 100644
--- a/runtime/vm/store_buffer.h
+++ b/runtime/vm/store_buffer.h
@@ -121,7 +121,7 @@
// Adds and transfers ownership of the block to the buffer.
void PushBlockImpl(Block* block);
- // If needed, trims the the global cache of empty blocks.
+ // If needed, trims the global cache of empty blocks.
static void TrimGlobalEmpty();
List full_;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 8e85852..e4e32ce 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -772,9 +772,9 @@
// kExitLinkSlotFromEntryFp must be kept in sync with the code below.
__ Push(R4);
-#if defined(TARGET_OS_MAC)
+#if defined(TARGET_ABI_IOS)
ASSERT(kExitLinkSlotFromEntryFp == -26);
-#else
+#elif defined(TARGET_ABI_EABI)
ASSERT(kExitLinkSlotFromEntryFp == -27);
#endif
__ Push(R9);
diff --git a/runtime/vm/stub_code_arm64_test.cc b/runtime/vm/stub_code_arm64_test.cc
index d3a3a46..f2d8a25 100644
--- a/runtime/vm/stub_code_arm64_test.cc
+++ b/runtime/vm/stub_code_arm64_test.cc
@@ -23,10 +23,9 @@
const String& class_name = String::Handle(Symbols::New(Thread::Current(),
"ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
const Library& lib = Library::Handle(Library::New(class_name));
- owner_class.set_library(lib);
+ const Class& owner_class = Class::Handle(
+ Class::New(lib, class_name, script, TokenPosition::kNoSource));
const String& function_name = String::ZoneHandle(
Symbols::New(Thread::Current(), name));
Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index 3f0fe4c..a0c35cc 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -23,10 +23,9 @@
const String& class_name = String::Handle(Symbols::New(Thread::Current(),
"ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
const Library& lib = Library::Handle(Library::New(class_name));
- owner_class.set_library(lib);
+ const Class& owner_class = Class::Handle(
+ Class::New(lib, class_name, script, TokenPosition::kNoSource));
const String& function_name = String::ZoneHandle(
Symbols::New(Thread::Current(), name));
Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/stub_code_ia32_test.cc b/runtime/vm/stub_code_ia32_test.cc
index 34e8ef3..6ba14dc 100644
--- a/runtime/vm/stub_code_ia32_test.cc
+++ b/runtime/vm/stub_code_ia32_test.cc
@@ -23,10 +23,9 @@
const String& class_name = String::Handle(Symbols::New(Thread::Current(),
"ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
const Library& lib = Library::Handle(Library::New(class_name));
- owner_class.set_library(lib);
+ const Class& owner_class = Class::Handle(
+ Class::New(lib, class_name, script, TokenPosition::kNoSource));
const String& function_name = String::ZoneHandle(
Symbols::New(Thread::Current(), name));
Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/stub_code_mips_test.cc b/runtime/vm/stub_code_mips_test.cc
index c058dcd..65ff616 100644
--- a/runtime/vm/stub_code_mips_test.cc
+++ b/runtime/vm/stub_code_mips_test.cc
@@ -23,10 +23,9 @@
const String& class_name = String::Handle(Symbols::New(Thread::Current(),
"ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
const Library& lib = Library::Handle(Library::New(class_name));
- owner_class.set_library(lib);
+ const Class& owner_class = Class::Handle(
+ Class::New(lib, class_name, script, TokenPosition::kNoSource));
const String& function_name = String::ZoneHandle(
Symbols::New(Thread::Current(), name));
Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index 6b9b2af..66feaeb 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -23,10 +23,9 @@
const String& class_name = String::Handle(Symbols::New(Thread::Current(),
"ownerClass"));
const Script& script = Script::Handle();
- const Class& owner_class = Class::Handle(
- Class::New(class_name, script, TokenPosition::kNoSource));
const Library& lib = Library::Handle(Library::New(class_name));
- owner_class.set_library(lib);
+ const Class& owner_class = Class::Handle(
+ Class::New(lib, class_name, script, TokenPosition::kNoSource));
const String& function_name = String::ZoneHandle(
Symbols::New(Thread::Current(), name));
Function& function = Function::ZoneHandle(
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index c90fe06..fa3cc67 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -37,6 +37,17 @@
}
+bool VMTag::IsDartTag(uword id) {
+ return id == kDartTagId;
+}
+
+
+bool VMTag::IsExitFrameTag(uword id) {
+ return (id != 0) && !IsDartTag(id) && (id != kIdleTagId) &&
+ (id != kVMTagId) && (id != kEmbedderTagId);
+}
+
+
static RuntimeEntry* runtime_entry_list = NULL;
diff --git a/runtime/vm/tags.h b/runtime/vm/tags.h
index 926aed8..3279c82 100644
--- a/runtime/vm/tags.h
+++ b/runtime/vm/tags.h
@@ -62,7 +62,8 @@
}
static const char* TagName(uword id);
static bool IsNativeEntryTag(uword id);
-
+ static bool IsDartTag(uword id);
+ static bool IsExitFrameTag(uword id);
static bool IsRuntimeEntryTag(uword id);
static const char* RuntimeEntryTagName(uword id);
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 3c7efee..69e7820 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -20,6 +20,7 @@
#include "vm/symbols.h"
#include "vm/thread_interrupter.h"
#include "vm/thread_registry.h"
+#include "vm/timeline.h"
namespace dart {
@@ -68,6 +69,7 @@
store_buffer_block_(NULL),
vm_tag_(0),
task_kind_(kUnknownTask),
+ dart_stream_(NULL),
os_thread_(NULL),
thread_lock_(new Monitor()),
zone_(NULL),
@@ -83,6 +85,7 @@
#endif
reusable_handles_(),
saved_stack_limit_(0),
+ defer_oob_messages_count_(0),
deferred_interrupts_mask_(0),
deferred_interrupts_(0),
stack_overflow_count_(0),
@@ -96,6 +99,10 @@
safepoint_state_(0),
execution_state_(kThreadInVM),
next_(NULL) {
+NOT_IN_PRODUCT(
+ dart_stream_ = Timeline::GetDartStream();
+ ASSERT(dart_stream_ != NULL);
+)
#define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \
member_name = default_init_value;
CACHED_CONSTANTS_LIST(DEFAULT_INIT)
@@ -417,6 +424,11 @@
void Thread::DeferOOBMessageInterrupts() {
MonitorLocker ml(thread_lock_);
+ defer_oob_messages_count_++;
+ if (defer_oob_messages_count_ > 1) {
+ // OOB message interrupts are already deferred.
+ return;
+ }
ASSERT(deferred_interrupts_mask_ == 0);
deferred_interrupts_mask_ = kMessageInterrupt;
@@ -441,6 +453,11 @@
void Thread::RestoreOOBMessageInterrupts() {
MonitorLocker ml(thread_lock_);
+ defer_oob_messages_count_--;
+ if (defer_oob_messages_count_ > 0) {
+ return;
+ }
+ ASSERT(defer_oob_messages_count_ == 0);
ASSERT(deferred_interrupts_mask_ == kMessageInterrupt);
deferred_interrupts_mask_ = 0;
if (deferred_interrupts_ != 0) {
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 2201f36..ea5396a 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -48,6 +48,7 @@
class Smi;
class StackResource;
class String;
+class TimelineStream;
class TypeArguments;
class TypeParameter;
class Zone;
@@ -270,6 +271,11 @@
bool IsMutatorThread() const;
bool CanCollectGarbage() const;
+ // Offset of Dart TimelineStream object.
+ static intptr_t dart_stream_offset() {
+ return OFFSET_OF(Thread, dart_stream_);
+ }
+
// Is |this| executing Dart code?
bool IsExecutingDartCode() const;
@@ -653,6 +659,7 @@
LEAF_RUNTIME_ENTRY_LIST(DECLARE_MEMBERS)
#undef DECLARE_MEMBERS
+ TimelineStream* dart_stream_;
OSThread* os_thread_;
Monitor* thread_lock_;
Zone* zone_;
@@ -668,6 +675,7 @@
#endif
VMHandles reusable_handles_;
uword saved_stack_limit_;
+ intptr_t defer_oob_messages_count_;
uint16_t deferred_interrupts_mask_;
uint16_t deferred_interrupts_;
int32_t stack_overflow_count_;
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index 1e0d8cf..fa14d2e 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -157,7 +157,7 @@
MonitorLocker startup_ml(monitor_);
OSThread* os_thread = OSThread::Current();
ASSERT(os_thread != NULL);
- interrupter_thread_id_ = os_thread->join_id();
+ interrupter_thread_id_ = OSThread::GetCurrentThreadJoinId(os_thread);
thread_running_ = true;
startup_ml.Notify();
}
diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc
index fb0f7d7..0c326d3 100644
--- a/runtime/vm/thread_pool.cc
+++ b/runtime/vm/thread_pool.cc
@@ -212,6 +212,16 @@
}
+void ThreadPool::SetIdleLocked(Worker* worker) {
+ ASSERT(mutex_.IsOwnedByCurrentThread());
+ ASSERT(worker->owned_ && !IsIdle(worker));
+ worker->idle_next_ = idle_workers_;
+ idle_workers_ = worker;
+ count_idle_++;
+ count_running_--;
+}
+
+
void ThreadPool::SetIdleAndReapExited(Worker* worker) {
JoinList* list = NULL;
{
@@ -219,17 +229,25 @@
if (shutting_down_) {
return;
}
- ASSERT(worker->owned_ && !IsIdle(worker));
- worker->idle_next_ = idle_workers_;
- idle_workers_ = worker;
- count_idle_++;
- count_running_--;
-
- // While we have the lock, opportunistically grab and clear the join_list_.
+ if (join_list_ == NULL) {
+ // Nothing to join, add to the idle list and return.
+ SetIdleLocked(worker);
+ return;
+ }
+ // There is something to join. Grab the join list, drop the lock, do the
+ // join, then grab the lock again and add to the idle list.
list = join_list_;
join_list_ = NULL;
}
JoinList::Join(&list);
+
+ {
+ MutexLocker ml(&mutex_);
+ if (shutting_down_) {
+ return;
+ }
+ SetIdleLocked(worker);
+ }
}
@@ -250,7 +268,8 @@
// so that we can join on it at the next opportunity.
OSThread* os_thread = OSThread::Current();
ASSERT(os_thread != NULL);
- JoinList::AddLocked(os_thread->join_id(), &join_list_);
+ ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId(os_thread);
+ JoinList::AddLocked(join_id, &join_list_);
count_stopped_++;
count_idle_--;
return true;
@@ -430,7 +449,6 @@
OSThread* os_thread = OSThread::Current();
ASSERT(os_thread != NULL);
ThreadId id = os_thread->id();
- ThreadJoinId join_id = os_thread->join_id();
ThreadPool* pool;
// Set the thread's stack_base based on the current stack pointer.
@@ -454,6 +472,7 @@
// Inform the thread pool that we are exiting. We remove this worker from
// shutting_down_workers_ list because there will be no need for the
// ThreadPool to take action for this worker.
+ ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId(os_thread);
{
MutexLocker ml(&pool->mutex_);
JoinList::AddLocked(join_id, &pool->join_list_);
diff --git a/runtime/vm/thread_pool.h b/runtime/vm/thread_pool.h
index 1713781..8cd29a2 100644
--- a/runtime/vm/thread_pool.h
+++ b/runtime/vm/thread_pool.h
@@ -125,6 +125,7 @@
void ReapExitedIdleThreads();
// Worker operations.
+ void SetIdleLocked(Worker* worker); // Assumes mutex_ is held.
void SetIdleAndReapExited(Worker* worker);
bool ReleaseIdleWorker(Worker* worker);
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index c765a5d..adf2a34 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -48,7 +48,7 @@
// and always schedule execution of Dart code on the same mutator thread
// object. The ApiLocalScope has been made thread specific but we still
// have scenarios where we do a temporary exit of an Isolate with live
- // zones/handles in the the API scope :
+ // zones/handles in the API scope :
// - Dart_RunLoop()
// - IsolateSaver in Dart_NewNativePort
// - Isolate spawn (function/uri) under FLAG_i_like_slow_isolate_spawn
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index aa006df..d0deba9 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -435,12 +435,13 @@
VM_TEST_CASE(ThreadIterator_FindSelf) {
OSThread* current = OSThread::Current();
- EXPECT(OSThread::IsThreadInList(current->join_id()));
+ EXPECT(OSThread::IsThreadInList(current->id()));
}
struct ThreadIteratorTestParams {
- ThreadId spawned_thread_join_id;
+ ThreadId spawned_thread_id;
+ ThreadJoinId spawned_thread_join_id;
Monitor* monitor;
};
@@ -452,9 +453,10 @@
EXPECT(thread != NULL);
MonitorLocker ml(params->monitor);
- params->spawned_thread_join_id = thread->join_id();
- EXPECT(params->spawned_thread_join_id != OSThread::kInvalidThreadJoinId);
- EXPECT(OSThread::IsThreadInList(thread->join_id()));
+ params->spawned_thread_id = thread->id();
+ params->spawned_thread_join_id = OSThread::GetCurrentThreadJoinId(thread);
+ EXPECT(params->spawned_thread_id != OSThread::kInvalidThreadId);
+ EXPECT(OSThread::IsThreadInList(thread->id()));
ml.Notify();
}
@@ -463,25 +465,25 @@
// on Windows. See |OnDartThreadExit| in os_thread_win.cc for more details.
TEST_CASE(ThreadIterator_AddFindRemove) {
ThreadIteratorTestParams params;
- params.spawned_thread_join_id = OSThread::kInvalidThreadJoinId;
+ params.spawned_thread_id = OSThread::kInvalidThreadId;
params.monitor = new Monitor();
{
MonitorLocker ml(params.monitor);
- EXPECT(params.spawned_thread_join_id == OSThread::kInvalidThreadJoinId);
- // Spawn thread and wait to receive the thread join id.
+ EXPECT(params.spawned_thread_id == OSThread::kInvalidThreadId);
+ // Spawn thread and wait to receive the thread id.
OSThread::Start("ThreadIteratorTest",
ThreadIteratorTestMain,
reinterpret_cast<uword>(¶ms));
- while (params.spawned_thread_join_id == OSThread::kInvalidThreadJoinId) {
+ while (params.spawned_thread_id == OSThread::kInvalidThreadId) {
ml.Wait();
}
+ EXPECT(params.spawned_thread_id != OSThread::kInvalidThreadId);
EXPECT(params.spawned_thread_join_id != OSThread::kInvalidThreadJoinId);
- // Join thread.
OSThread::Join(params.spawned_thread_join_id);
}
- EXPECT(!OSThread::IsThreadInList(params.spawned_thread_join_id))
+ EXPECT(!OSThread::IsThreadInList(params.spawned_thread_id))
delete params.monitor;
}
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 8b9eaf0..dbe9ef0 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -173,14 +173,12 @@
enabled_streams_ = GetEnabledByDefaultTimelineStreams();
// Global overrides.
#define TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \
- stream_##name##_enabled_ = HasStream(enabled_streams_, #name); \
stream_##name##_.Init(#name, \
- stream_##name##_enabled_, \
- &stream_##name##_enabled_);
+ HasStream(enabled_streams_, #name));
TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAG_DEFAULT)
#undef TIMELINE_STREAM_FLAG_DEFAULT
- if (stream_Embedder_enabled_ &&
+ if (Timeline::stream_Embedder_.enabled() &&
(Timeline::get_start_recording_cb() != NULL)) {
Timeline::get_start_recording_cb()();
}
@@ -206,7 +204,7 @@
void Timeline::Shutdown() {
ASSERT(recorder_ != NULL);
- if (stream_Embedder_enabled_ &&
+ if (Timeline::stream_Embedder_.enabled() &&
(Timeline::get_stop_recording_cb() != NULL)) {
Timeline::get_stop_recording_cb()();
}
@@ -217,7 +215,7 @@
// Disable global streams.
#define TIMELINE_STREAM_DISABLE(name, not_used) \
- stream_##name##_enabled_ = false;
+ Timeline::stream_##name##_.set_enabled(false);
TIMELINE_STREAM_LIST(TIMELINE_STREAM_DISABLE)
#undef TIMELINE_STREAM_DISABLE
delete recorder_;
@@ -275,7 +273,7 @@
{
JSONArray recordedStreams(&obj, "recordedStreams");
#define ADD_RECORDED_STREAM_NAME(name, not_used) \
- if (stream_##name##_enabled_) { \
+ if (stream_##name##_.enabled()) { \
recordedStreams.AddValue(#name); \
}
TIMELINE_STREAM_LIST(ADD_RECORDED_STREAM_NAME);
@@ -300,7 +298,6 @@
Dart_EmbedderTimelineStopRecording Timeline::stop_recording_cb_ = NULL;
#define TIMELINE_STREAM_DEFINE(name, enabled_by_default) \
- bool Timeline::stream_##name##_enabled_ = enabled_by_default; \
TimelineStream Timeline::stream_##name##_;
TIMELINE_STREAM_LIST(TIMELINE_STREAM_DEFINE)
#undef TIMELINE_STREAM_DEFINE
@@ -680,6 +677,20 @@
}
+int64_t TimelineEvent::LowTime() const {
+ return timestamp0_;
+}
+
+
+int64_t TimelineEvent::HighTime() const {
+ if (event_type() == kDuration) {
+ return timestamp1_;
+ } else {
+ return timestamp0_;
+ }
+}
+
+
int64_t TimelineEvent::TimeDuration() const {
if (timestamp1_ == 0) {
// This duration is still open, use current time as end.
@@ -713,23 +724,20 @@
TimelineStream::TimelineStream()
: name_(NULL),
- enabled_(false),
- globally_enabled_(NULL) {
+ enabled_(false) {
}
void TimelineStream::Init(const char* name,
- bool enabled,
- const bool* globally_enabled) {
+ bool enabled) {
name_ = name;
enabled_ = enabled;
- globally_enabled_ = globally_enabled;
}
TimelineEvent* TimelineStream::StartEvent() {
TimelineEventRecorder* recorder = Timeline::recorder();
- if (!Enabled() || (recorder == NULL)) {
+ if (!enabled() || (recorder == NULL)) {
return NULL;
}
ASSERT(name_ != NULL);
@@ -775,7 +783,7 @@
ASSERT(enabled_ == false);
ASSERT(label_ != NULL);
ASSERT(stream_ != NULL);
- if (!stream_->Enabled()) {
+ if (!stream_->enabled()) {
// Stream is not enabled, do nothing.
return;
}
@@ -870,7 +878,7 @@
TimelineDurationScope::TimelineDurationScope(TimelineStream* stream,
const char* label)
: TimelineEventScope(stream, label) {
- if (!FLAG_support_timeline) {
+ if (!FLAG_support_timeline || !enabled()) {
return;
}
timestamp_ = OS::GetCurrentMonotonicMicros();
@@ -882,7 +890,7 @@
TimelineStream* stream,
const char* label)
: TimelineEventScope(thread, stream, label) {
- if (!FLAG_support_timeline) {
+ if (!FLAG_support_timeline || !enabled()) {
return;
}
timestamp_ = OS::GetCurrentMonotonicMicros();
@@ -1008,7 +1016,9 @@
TimelineEventRecorder::TimelineEventRecorder()
- : async_id_(0) {
+ : async_id_(0),
+ time_low_micros_(0),
+ time_high_micros_(0) {
}
@@ -1088,6 +1098,38 @@
}
+void TimelineEventRecorder::ResetTimeTracking() {
+ time_high_micros_ = 0;
+ time_low_micros_ = kMaxInt64;
+}
+
+
+void TimelineEventRecorder::ReportTime(int64_t micros) {
+ if (time_high_micros_ < micros) {
+ time_high_micros_ = micros;
+ }
+ if (time_low_micros_ > micros) {
+ time_low_micros_ = micros;
+ }
+}
+
+
+int64_t TimelineEventRecorder::TimeOriginMicros() const {
+ if (time_high_micros_ == 0) {
+ return 0;
+ }
+ return time_low_micros_;
+}
+
+
+int64_t TimelineEventRecorder::TimeExtentMicros() const {
+ if (time_high_micros_ == 0) {
+ return 0;
+ }
+ return time_high_micros_ - time_low_micros_;
+}
+
+
void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) {
if (event == NULL) {
return;
@@ -1212,6 +1254,7 @@
return;
}
MutexLocker ml(&lock_);
+ ResetTimeTracking();
intptr_t block_offset = FindOldestBlockIndex();
if (block_offset == -1) {
// All blocks are empty.
@@ -1228,6 +1271,8 @@
if (filter->IncludeEvent(event) &&
event->Within(filter->time_origin_micros(),
filter->time_extent_micros())) {
+ ReportTime(event->LowTime());
+ ReportTime(event->HighTime());
events->AddValue(event);
}
}
@@ -1247,6 +1292,8 @@
PrintJSONMeta(&events);
PrintJSONEvents(&events, filter);
}
+ topLevel.AddPropertyTimeMicros("timeOriginMicros", TimeOriginMicros());
+ topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros());
}
@@ -1393,6 +1440,8 @@
PrintJSONMeta(&events);
PrintJSONEvents(&events, filter);
}
+ topLevel.AddPropertyTimeMicros("timeOriginMicros", TimeOriginMicros());
+ topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros());
}
@@ -1450,6 +1499,7 @@
return;
}
MutexLocker ml(&lock_);
+ ResetTimeTracking();
// Collect all interesting blocks.
MallocGrowableArray<TimelineEventBlock*> blocks(8);
TimelineEventBlock* current = head_;
@@ -1475,6 +1525,8 @@
if (filter->IncludeEvent(event) &&
event->Within(filter->time_origin_micros(),
filter->time_extent_micros())) {
+ ReportTime(event->LowTime());
+ ReportTime(event->HighTime());
events->AddValue(event);
}
}
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 1646d99..d91e909 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -38,6 +38,45 @@
V(Isolate, false) \
V(VM, false)
+// A stream of timeline events. A stream has a name and can be enabled or
+// disabled (globally and per isolate).
+class TimelineStream {
+ public:
+ TimelineStream();
+
+ void Init(const char* name,
+ bool enabled);
+
+ const char* name() const {
+ return name_;
+ }
+
+ bool enabled() const {
+ return enabled_ != 0;
+ }
+
+ void set_enabled(bool enabled) {
+ enabled_ = enabled ? 1 : 0;
+ }
+
+ // Records an event. Will return |NULL| if not enabled. The returned
+ // |TimelineEvent| is in an undefined state and must be initialized.
+ // NOTE: It is not allowed to call StartEvent again without completing
+ // the first event.
+ TimelineEvent* StartEvent();
+
+ static intptr_t enabled_offset() {
+ return OFFSET_OF(TimelineStream, enabled_);
+ }
+
+ private:
+ const char* name_;
+
+ // This field is accessed by generated code (intrinsic) and expects to see
+ // 0 or 1. If this becomes a BitField, the generated code must be updated.
+ uintptr_t enabled_;
+};
+
class Timeline : public AllStatic {
public:
// Initialize timeline system. Not thread safe.
@@ -57,18 +96,15 @@
// Print information about streams to JSON.
static void PrintFlagsToJSON(JSONStream* json);
-#define TIMELINE_STREAM_ACCESSOR(name, not_used) \
+#define TIMELINE_STREAM_ACCESSOR(name, not_used) \
static TimelineStream* Get##name##Stream() { return &stream_##name##_; }
TIMELINE_STREAM_LIST(TIMELINE_STREAM_ACCESSOR)
#undef TIMELINE_STREAM_ACCESSOR
#define TIMELINE_STREAM_FLAGS(name, not_used) \
- static const bool* Stream##name##EnabledFlag() { \
- return &stream_##name##_enabled_; \
- } \
static void SetStream##name##Enabled(bool enabled) { \
- StreamStateChange(#name, stream_##name##_enabled_, enabled); \
- stream_##name##_enabled_ = enabled; \
+ StreamStateChange(#name, stream_##name##_.enabled(), enabled); \
+ stream_##name##_.set_enabled(enabled); \
}
TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAGS)
#undef TIMELINE_STREAM_FLAGS
@@ -223,6 +259,11 @@
return timestamp1_;
}
+ // The lowest time value stored in this event.
+ int64_t LowTime() const;
+ // The highest time value stored in this event.
+ int64_t HighTime() const;
+
void PrintJSON(JSONStream* stream) const;
ThreadId thread() const {
@@ -378,45 +419,6 @@
};
-// A stream of timeline events. A stream has a name and can be enabled or
-// disabled (globally and per isolate).
-class TimelineStream {
- public:
- TimelineStream();
-
- void Init(const char* name,
- bool enabled,
- const bool* globally_enabled = NULL);
-
- const char* name() const {
- return name_;
- }
-
- bool Enabled() const {
- return ((globally_enabled_ != NULL) && *globally_enabled_) ||
- enabled();
- }
-
- bool enabled() const {
- return enabled_;
- }
-
- void set_enabled(bool enabled) {
- enabled_ = enabled;
- }
-
- // Records an event. Will return |NULL| if not enabled. The returned
- // |TimelineEvent| is in an undefined state and must be initialized.
- // NOTE: It is not allowed to call StartEvent again without completing
- // the first event.
- TimelineEvent* StartEvent();
-
- private:
- const char* name_;
- bool enabled_;
- const bool* globally_enabled_;
-};
-
#ifndef PRODUCT
#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function) \
TimelineDurationScope tds(thread, \
@@ -719,8 +721,15 @@
TimelineEvent* ThreadBlockStartEvent();
void ThreadBlockCompleteEvent(TimelineEvent* event);
+ void ResetTimeTracking();
+ void ReportTime(int64_t micros);
+ int64_t TimeOriginMicros() const;
+ int64_t TimeExtentMicros() const;
+
Mutex lock_;
uintptr_t async_id_;
+ int64_t time_low_micros_;
+ int64_t time_high_micros_;
friend class TimelineEvent;
friend class TimelineEventBlockIterator;
@@ -769,7 +778,7 @@
~TimelineEventRingRecorder() {}
const char* name() const {
- return "ring";
+ return "Ring";
}
protected:
@@ -786,7 +795,7 @@
~TimelineEventStartupRecorder() {}
const char* name() const {
- return "startup";
+ return "Startup";
}
protected:
@@ -809,7 +818,7 @@
virtual void OnEvent(TimelineEvent* event) = 0;
const char* name() const {
- return "callback";
+ return "Callback";
}
protected:
@@ -837,7 +846,7 @@
void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
const char* name() const {
- return "endless";
+ return "Endless";
}
protected:
diff --git a/runtime/vm/type_table.h b/runtime/vm/type_table.h
new file mode 100644
index 0000000..c33a124
--- /dev/null
+++ b/runtime/vm/type_table.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2016, 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 VM_TYPE_TABLE_H_
+#define VM_TYPE_TABLE_H_
+
+#include "platform/assert.h"
+#include "vm/hash_table.h"
+#include "vm/object.h"
+
+namespace dart {
+
+class CanonicalTypeKey {
+ public:
+ explicit CanonicalTypeKey(const Type& key) : key_(key) {
+ }
+ bool Matches(const Type& arg) const {
+ return key_.Equals(arg);
+ }
+ uword Hash() const {
+ return key_.Hash();
+ }
+ const Type& key_;
+
+ private:
+ DISALLOW_ALLOCATION();
+};
+
+
+// Traits for looking up Canonical Type based on it's hash.
+class CanonicalTypeTraits {
+ public:
+ static const char* Name() { return "CanonicalTypeTraits"; }
+ static bool ReportStats() { return false; }
+
+ // Called when growing the table.
+ static bool IsMatch(const Object& a, const Object& b) {
+ ASSERT(a.IsType() && b.IsType());
+ const Type& arg1 = Type::Cast(a);
+ const Type& arg2 = Type::Cast(b);
+ return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+ }
+ static bool IsMatch(const CanonicalTypeKey& a, const Object& b) {
+ ASSERT(b.IsType());
+ return a.Matches(Type::Cast(b));
+ }
+ static uword Hash(const Object& key) {
+ ASSERT(key.IsType());
+ return Type::Cast(key).Hash();
+ }
+ static uword Hash(const CanonicalTypeKey& key) {
+ return key.Hash();
+ }
+ static RawObject* NewKey(const CanonicalTypeKey& obj) {
+ return obj.key_.raw();
+ }
+};
+typedef UnorderedHashSet <CanonicalTypeTraits> CanonicalTypeSet;
+
+
+class CanonicalTypeArgumentsKey {
+ public:
+ explicit CanonicalTypeArgumentsKey(const TypeArguments& key) : key_(key) {
+ }
+ bool Matches(const TypeArguments& arg) const {
+ return key_.Equals(arg) && (key_.Hash() == arg.Hash());
+ }
+ uword Hash() const {
+ return key_.Hash();
+ }
+ const TypeArguments& key_;
+
+ private:
+ DISALLOW_ALLOCATION();
+};
+
+
+// Traits for looking up Canonical TypeArguments based on its hash.
+class CanonicalTypeArgumentsTraits {
+ public:
+ static const char* Name() { return "CanonicalTypeArgumentsTraits"; }
+ static bool ReportStats() { return false; }
+
+ // Called when growing the table.
+ static bool IsMatch(const Object& a, const Object& b) {
+ ASSERT(a.IsTypeArguments() && b.IsTypeArguments());
+ const TypeArguments& arg1 = TypeArguments::Cast(a);
+ const TypeArguments& arg2 = TypeArguments::Cast(b);
+ return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+ }
+ static bool IsMatch(const CanonicalTypeArgumentsKey& a, const Object& b) {
+ ASSERT(b.IsTypeArguments());
+ return a.Matches(TypeArguments::Cast(b));
+ }
+ static uword Hash(const Object& key) {
+ ASSERT(key.IsTypeArguments());
+ return TypeArguments::Cast(key).Hash();
+ }
+ static uword Hash(const CanonicalTypeArgumentsKey& key) {
+ return key.Hash();
+ }
+ static RawObject* NewKey(const CanonicalTypeArgumentsKey& obj) {
+ return obj.key_.raw();
+ }
+};
+typedef UnorderedHashSet<CanonicalTypeArgumentsTraits>
+ CanonicalTypeArgumentsSet;
+
+} // namespace dart
+
+#endif // VM_TYPE_TABLE_H_
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 54352e5..c6b6bdb 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -17,6 +17,7 @@
#include "vm/compiler.h"
#include "vm/dart_api_impl.h"
#include "vm/disassembler.h"
+#include "vm/isolate_reload.h"
#include "vm/parser.h"
#include "vm/symbols.h"
#include "vm/thread.h"
@@ -66,11 +67,62 @@
static const char* kPackageScheme = "package:";
+
static bool IsPackageSchemeURL(const char* url_name) {
static const intptr_t kPackageSchemeLen = strlen(kPackageScheme);
return (strncmp(url_name, kPackageScheme, kPackageSchemeLen) == 0);
}
+
+static bool IsImportableTestLib(const char* url_name) {
+ const char* kImportTestLibUri = "importable_test_lib";
+ static const intptr_t kImportTestLibUriLen = strlen(kImportTestLibUri);
+ return (strncmp(url_name, kImportTestLibUri, kImportTestLibUriLen) == 0);
+}
+
+
+static Dart_Handle ImportableTestLibSource() {
+ const char* kScript =
+ "importedFunc() => 'a';\n"
+ "importedIntFunc() => 4;\n"
+ "class ImportedMixin {\n"
+ " mixinFunc() => 'mixin';\n"
+ "}\n";
+ return DartUtils::NewString(kScript);
+}
+
+
+static bool IsIsolateReloadTestLib(const char* url_name) {
+ const char* kIsolateReloadTestLibUri = "isolate_reload_test_helper";
+ static const intptr_t kIsolateReloadTestLibUriLen =
+ strlen(kIsolateReloadTestLibUri);
+ return (strncmp(url_name,
+ kIsolateReloadTestLibUri,
+ kIsolateReloadTestLibUriLen) == 0);
+}
+
+
+#ifndef PRODUCT
+static Dart_Handle IsolateReloadTestLibSource() {
+ // Special library with one function.
+ return DartUtils::NewString("void reloadTest() native 'Reload_Test';\n");
+}
+
+
+static void ReloadTest(Dart_NativeArguments native_args) {
+ DART_CHECK_VALID(TestCase::TriggerReload());
+}
+
+
+static Dart_NativeFunction IsolateReloadTestNativeResolver(
+ Dart_Handle name,
+ int num_of_arguments,
+ bool* auto_setup_scope) {
+ return ReloadTest;
+}
+#endif // !PRODUCT
+
+
static Dart_Handle ResolvePackageUri(const char* uri_chars) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
@@ -81,9 +133,25 @@
dart_args);
}
+
+static ThreadLocalKey script_reload_key = kUnsetThreadLocalKey;
+
static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
+ if (tag == Dart_kScriptTag) {
+ // Reload request.
+ ASSERT(script_reload_key != kUnsetThreadLocalKey);
+ const char* script_source =
+ reinterpret_cast<const char*>(
+ OSThread::GetThreadLocal(script_reload_key));
+ ASSERT(script_source != NULL);
+ OSThread::SetThreadLocal(script_reload_key, NULL);
+ return Dart_LoadScript(url,
+ NewString(script_source),
+ 0,
+ 0);
+ }
if (!Dart_IsLibrary(library)) {
return Dart_NewApiError("not a library");
}
@@ -105,6 +173,10 @@
bool is_dart_scheme_url = DartUtils::IsDartSchemeURL(url_chars);
bool is_io_library = DartUtils::IsDartIOLibURL(library_url_string);
if (tag == Dart_kCanonicalizeUrl) {
+ // Already canonicalized.
+ if (IsImportableTestLib(url_chars) || IsIsolateReloadTestLib(url_chars)) {
+ return url;
+ }
// If this is a Dart Scheme URL then it is not modified as it will be
// handled by the VM internally.
if (is_dart_scheme_url || is_io_library) {
@@ -128,6 +200,17 @@
return DartUtils::NewError("Do not know how to load '%s'", url_chars);
}
}
+ if (IsImportableTestLib(url_chars)) {
+ return Dart_LoadLibrary(url, ImportableTestLibSource(), 0, 0);
+ }
+ NOT_IN_PRODUCT(
+ if (IsIsolateReloadTestLib(url_chars)) {
+ Dart_Handle library =
+ Dart_LoadLibrary(url, IsolateReloadTestLibSource(), 0, 0);
+ DART_CHECK_VALID(library);
+ Dart_SetNativeResolver(library, IsolateReloadTestNativeResolver, 0);
+ return library;
+ })
if (is_io_library) {
ASSERT(tag == Dart_kSourceTag);
return Dart_LoadSource(library,
@@ -177,6 +260,61 @@
}
+#ifndef PRODUCT
+
+
+void TestCase::SetReloadTestScript(const char* script) {
+ if (script_reload_key == kUnsetThreadLocalKey) {
+ script_reload_key = OSThread::CreateThreadLocal();
+ }
+ ASSERT(script_reload_key != kUnsetThreadLocalKey);
+ ASSERT(OSThread::GetThreadLocal(script_reload_key) == 0);
+ // Store the new script in TLS.
+ OSThread::SetThreadLocal(script_reload_key, reinterpret_cast<uword>(script));
+}
+
+
+Dart_Handle TestCase::TriggerReload() {
+ Isolate* isolate = Isolate::Current();
+
+ {
+ TransitionNativeToVM transition(Thread::Current());
+ isolate->ReloadSources(/* test_mode = */ true);
+ }
+
+ return Dart_FinalizeLoading(false);
+}
+
+
+Dart_Handle TestCase::GetReloadErrorOrRootLibrary() {
+ Isolate* isolate = Isolate::Current();
+
+ if (isolate->reload_context() != NULL) {
+ // We should only have a reload context hanging around if an error occurred.
+ ASSERT(isolate->reload_context()->has_error());
+ // Return a handle to the error.
+ return Api::NewHandle(Thread::Current(),
+ isolate->reload_context()->error());
+ }
+ return Dart_RootLibrary();
+}
+
+
+Dart_Handle TestCase::ReloadTestScript(const char* script) {
+ SetReloadTestScript(script);
+
+ Dart_Handle result = TriggerReload();
+ if (Dart_IsError(result)) {
+ return result;
+ }
+
+ return GetReloadErrorOrRootLibrary();
+}
+
+
+#endif // !PRODUCT
+
+
Dart_Handle TestCase::LoadCoreTestScript(const char* script,
Dart_NativeEntryResolver resolver) {
return LoadTestScript(script, resolver, CORELIB_TEST_URI);
@@ -219,13 +357,12 @@
String::Handle(String::New(kDummyScript)),
RawScript::kSourceTag));
script.Tokenize(String::Handle());
-
+ const Library& lib = Library::Handle(Library::CoreLibrary());
const Class& cls = Class::ZoneHandle(
- Class::New(function_name,
+ Class::New(lib,
+ function_name,
script,
TokenPosition::kMinSource));
- const Library& lib = Library::ZoneHandle(Library::New(function_name));
- cls.set_library(lib);
Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kRegularFunction,
true, false, false, false, false, cls,
@@ -254,8 +391,9 @@
Symbols::New(Thread::Current(), name));
// Add function to a class and that class to the class dictionary so that
// frame walking can be used.
+ Library& lib = Library::Handle(Library::CoreLibrary());
const Class& cls = Class::ZoneHandle(
- Class::New(function_name, Script::Handle(),
+ Class::New(lib, function_name, Script::Handle(),
TokenPosition::kMinSource));
function_ = Function::New(
function_name, RawFunction::kRegularFunction,
@@ -264,7 +402,6 @@
const Array& functions = Array::Handle(Array::New(1));
functions.SetAt(0, function_);
cls.SetFunctions(functions);
- Library& lib = Library::Handle(Library::CoreLibrary());
lib.AddClass(cls);
}
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index a8224c5..ac7645a 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -286,7 +286,6 @@
Dart_NativeEntryResolver resolver,
const char* lib_uri = USER_TEST_URI,
bool finalize = true);
-
static Dart_Handle LoadCoreTestScript(const char* script,
Dart_NativeEntryResolver resolver);
static Dart_Handle lib();
@@ -305,6 +304,16 @@
virtual void Run();
+ // Sets |script| to be the source used at next reload.
+ static void SetReloadTestScript(const char* script);
+ // Initiates the reload.
+ static Dart_Handle TriggerReload();
+ // Gets the result of a reload.
+ static Dart_Handle GetReloadErrorOrRootLibrary();
+
+ // Helper function which reloads the current isolate using |script|.
+ static Dart_Handle ReloadTestScript(const char* script);
+
private:
static Dart_Isolate CreateIsolate(const uint8_t* buffer, const char* name);
@@ -586,6 +595,24 @@
void ElideJSONSubstring(const char* prefix, const char* in, char* out);
+template<typename T>
+class SetFlagScope : public ValueObject {
+ public:
+ SetFlagScope(T* flag, T value)
+ : flag_(flag),
+ original_value_(*flag) {
+ *flag_ = value;
+ }
+
+ ~SetFlagScope() {
+ *flag_ = original_value_;
+ }
+
+ private:
+ T* flag_;
+ T original_value_;
+};
+
} // namespace dart
#endif // VM_UNIT_TEST_H_
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 210cfcd..edb97e4 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -49,6 +49,8 @@
'atomic_test.cc',
'atomic_win.h',
'base_isolate.h',
+ 'become.h',
+ 'become.cc',
'benchmark_test.cc',
'benchmark_test.h',
'bigint_test.cc',
@@ -256,6 +258,9 @@
'intrinsifier_x64.cc',
'isolate.cc',
'isolate.h',
+ 'isolate_reload.cc',
+ 'isolate_reload.h',
+ 'isolate_reload_test.cc',
'isolate_test.cc',
'jit_optimizer.cc',
'jit_optimizer.h',
@@ -313,6 +318,7 @@
'object_id_ring.h',
'object_id_ring_test.cc',
'object_mips_test.cc',
+ 'object_reload.cc',
'object_service.cc',
'object_set.h',
'object_store.cc',
@@ -490,6 +496,7 @@
'token.h',
'token_position.cc',
'token_position.h',
+ 'type_table.h',
'unibrow.cc',
'unibrow.h',
'unibrow-inl.h',
diff --git a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
index 7d15ab8..beb67f2 100644
--- a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
@@ -839,7 +839,7 @@
// When iterating over the hash set, it is very convenient to have a
// list of all the elements. We cache that on the instance and clear
- // the the cache whenever the set changes. This is also used to
+ // the cache whenever the set changes. This is also used to
// guard against concurrent modifications.
List _elements;
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index 7a2c5a6..b1073b2 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -52,6 +52,11 @@
@patch
+bool _isDartStreamEnabled() {
+ return false;
+}
+
+@patch
int _getTraceClock() {
// TODO.
return _clockValue++;
diff --git a/sdk/lib/_internal/js_runtime/lib/interceptors.dart b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
index 25fbb11..23025ad 100644
--- a/sdk/lib/_internal/js_runtime/lib/interceptors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
@@ -373,9 +373,9 @@
* have a type mask that contains the objects that we can use the
* native JS [] operator and length on.
*/
-abstract class JSIndexable {
+abstract class JSIndexable<E> {
int get length;
- operator[](int index);
+ E operator[](int index);
}
/**
@@ -383,8 +383,8 @@
* JavaScriptIndexingBehavior. Used by the backend to have a type mask
* that contains the objects we can use the JS []= operator on.
*/
-abstract class JSMutableIndexable extends JSIndexable {
- operator[]=(int index, var value);
+abstract class JSMutableIndexable<E> extends JSIndexable<E> {
+ operator[]=(int index, E value);
}
/**
diff --git a/sdk/lib/_internal/js_runtime/lib/io_patch.dart b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
index 4487e15..d941bb2 100644
--- a/sdk/lib/_internal/js_runtime/lib/io_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
@@ -39,8 +39,10 @@
throw new UnsupportedError("Directory._rename");
}
@patch
- static List _list(String path, bool recursive, bool followLinks) {
- throw new UnsupportedError("Directory._list");
+ static void _fillWithDirectoryListing(
+ List<FileSystemEntity> list, String path, bool recursive,
+ bool followLinks) {
+ throw new UnsupportedError("Directory._fillWithDirectoryListing");
}
}
@@ -308,6 +310,11 @@
String host, {InternetAddressType type: InternetAddressType.ANY}) {
throw new UnsupportedError("InternetAddress.lookup");
}
+ @patch
+ static InternetAddress _cloneWithNewHost(
+ InternetAddress address, String host) {
+ throw new UnsupportedError("InternetAddress._cloneWithNewHost");
+ }
}
@patch
@@ -427,7 +434,7 @@
throw new UnsupportedError("StdIOUtils._getStdioOutputStream");
}
@patch
- static int _socketType(nativeSocket) {
+ static int _socketType(Socket socket) {
throw new UnsupportedError("StdIOUtils._socketType");
}
@patch
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 7d2e968..5e4d69a 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -1299,6 +1299,19 @@
return JS('', '#[#](#[0],#[1],#[2])', function, selectorName,
arguments, arguments, arguments);
}
+ } else if (argumentCount == 4) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX4);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1],#[2],#[3])', function, selectorName,
+ arguments, arguments, arguments, arguments);
+ }
+ } else if (argumentCount == 5) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX5);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1],#[2],#[3],#[4])',
+ function, selectorName,
+ arguments, arguments, arguments, arguments, arguments);
+ }
}
String selectorName =
'${JS_GET_NAME(JsGetName.CALL_PREFIX)}\$$argumentCount';
@@ -1465,6 +1478,18 @@
return JS('', '#[#](#[0],#[1],#[2])', function, selectorName,
arguments, arguments, arguments);
}
+ } else if (arguments.length == 4) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX4);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1],#[2],#[3])', function, selectorName,
+ arguments, arguments, arguments, arguments);
+ }
+ } else if (arguments.length == 5) {
+ String selectorName = JS_GET_NAME(JsGetName.CALL_PREFIX5);
+ if (JS('bool', '!!#[#]', function, selectorName)) {
+ return JS('', '#[#](#[0],#[1],#[2],#[3],#[4])', function, selectorName,
+ arguments, arguments, arguments, arguments, arguments);
+ }
}
return _genericApplyFunctionWithPositionalArguments(function, arguments);
}
@@ -3328,7 +3353,7 @@
* objects that support integer indexing. This interface is not
* visible to anyone, and is only injected into special libraries.
*/
-abstract class JavaScriptIndexingBehavior extends JSMutableIndexable {
+abstract class JavaScriptIndexingBehavior<E> extends JSMutableIndexable<E> {
}
// TODO(lrn): These exceptions should be implemented in core.
diff --git a/sdk/lib/_internal/js_runtime/lib/js_string.dart b/sdk/lib/_internal/js_runtime/lib/js_string.dart
index ed8189d..e82868c 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_string.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_string.dart
@@ -246,7 +246,7 @@
return index;
}
- /// Finds the index after the the last non-whitespace character, or 0.
+ /// Finds the index after the last non-whitespace character, or 0.
/// Start looking at position [index - 1].
static int _skipTrailingWhitespace(String string, int index) {
const int SPACE = 0x20;
diff --git a/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart b/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
index cef7f93..ada768f 100644
--- a/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
+++ b/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
@@ -26,8 +26,8 @@
// The keys and values are stored in cells that are linked together
// to form a double linked list.
- LinkedHashMapCell _first;
- LinkedHashMapCell _last;
+ LinkedHashMapCell/*<K, V>*/ _first;
+ LinkedHashMapCell/*<K, V>*/ _last;
// We track the number of modifications done to the key set of the
// hash map to be able to throw when the map is modified while being
@@ -92,16 +92,16 @@
});
}
- V operator[](Object key) {
+ V operator [](Object key) {
if (_isStringKey(key)) {
var strings = _strings;
if (strings == null) return null;
- LinkedHashMapCell cell = _getTableEntry(strings, key);
+ LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(strings, key);
return (cell == null) ? null : cell.hashMapCellValue;
} else if (_isNumericKey(key)) {
var nums = _nums;
if (nums == null) return null;
- LinkedHashMapCell cell = _getTableEntry(nums, key);
+ LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(nums, key);
return (cell == null) ? null : cell.hashMapCellValue;
} else {
return internalGet(key);
@@ -114,11 +114,11 @@
var bucket = _getBucket(rest, key);
int index = internalFindBucketIndex(bucket, key);
if (index < 0) return null;
- LinkedHashMapCell cell = JS('var', '#[#]', bucket, index);
+ LinkedHashMapCell/*<K, V>*/ cell = JS('var', '#[#]', bucket, index);
return cell.hashMapCellValue;
}
- void operator[]=(K key, V value) {
+ void operator []=(K key, V value) {
if (_isStringKey(key)) {
var strings = _strings;
if (strings == null) _strings = strings = _newHashTable();
@@ -136,17 +136,17 @@
var rest = _rest;
if (rest == null) _rest = rest = _newHashTable();
var hash = internalComputeHashCode(key);
- var bucket = _getTableEntry(rest, hash);
+ var bucket = _getTableBucket(rest, hash);
if (bucket == null) {
- LinkedHashMapCell cell = _newLinkedCell(key, value);
+ LinkedHashMapCell/*<K, V>*/ cell = _newLinkedCell(key, value);
_setTableEntry(rest, hash, JS('var', '[#]', cell));
} else {
int index = internalFindBucketIndex(bucket, key);
if (index >= 0) {
- LinkedHashMapCell cell = JS('var', '#[#]', bucket, index);
+ LinkedHashMapCell/*<K, V>*/ cell = JS('var', '#[#]', bucket, index);
cell.hashMapCellValue = value;
} else {
- LinkedHashMapCell cell = _newLinkedCell(key, value);
+ LinkedHashMapCell/*<K, V>*/ cell = _newLinkedCell(key, value);
JS('void', '#.push(#)', bucket, cell);
}
}
@@ -177,7 +177,8 @@
if (index < 0) return null;
// Use splice to remove the [cell] element at the index and
// unlink the cell before returning its value.
- LinkedHashMapCell cell = JS('var', '#.splice(#, 1)[0]', bucket, index);
+ LinkedHashMapCell/*<K, V>*/ cell =
+ JS('var', '#.splice(#, 1)[0]', bucket, index);
_unlinkCell(cell);
// TODO(kasperl): Consider getting rid of the bucket list when
// the length reaches zero.
@@ -193,7 +194,7 @@
}
void forEach(void action(K key, V value)) {
- LinkedHashMapCell cell = _first;
+ LinkedHashMapCell/*<K, V>*/ cell = _first;
int modifications = _modifications;
while (cell != null) {
action(cell.hashMapCellKey, cell.hashMapCellValue);
@@ -205,7 +206,7 @@
}
void _addHashTableEntry(var table, K key, V value) {
- LinkedHashMapCell cell = _getTableEntry(table, key);
+ LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(table, key);
if (cell == null) {
_setTableEntry(table, key, _newLinkedCell(key, value));
} else {
@@ -215,7 +216,7 @@
V _removeHashTableEntry(var table, Object key) {
if (table == null) return null;
- LinkedHashMapCell cell = _getTableEntry(table, key);
+ LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(table, key);
if (cell == null) return null;
_unlinkCell(cell);
_deleteTableEntry(table, key);
@@ -231,12 +232,13 @@
}
// Create a new cell and link it in as the last one in the list.
- LinkedHashMapCell _newLinkedCell(K key, V value) {
- LinkedHashMapCell cell = new LinkedHashMapCell(key, value);
+ LinkedHashMapCell/*<K, V>*/ _newLinkedCell(K key, V value) {
+ LinkedHashMapCell/*<K, V>*/ cell =
+ new LinkedHashMapCell/*<K, V>*/(key, value);
if (_first == null) {
_first = _last = cell;
} else {
- LinkedHashMapCell last = _last;
+ LinkedHashMapCell/*<K, V>*/ last = _last;
cell._previous = last;
_last = last._next = cell;
}
@@ -246,9 +248,9 @@
}
// Unlink the given cell from the linked list of cells.
- void _unlinkCell(LinkedHashMapCell cell) {
- LinkedHashMapCell previous = cell._previous;
- LinkedHashMapCell next = cell._next;
+ void _unlinkCell(LinkedHashMapCell/*<K, V>*/ cell) {
+ LinkedHashMapCell/*<K, V>*/ previous = cell._previous;
+ LinkedHashMapCell/*<K, V>*/ next = cell._next;
if (previous == null) {
assert(cell == _first);
_first = next;
@@ -283,16 +285,16 @@
return JS('int', '# & 0x3ffffff', key.hashCode);
}
- List _getBucket(var table, var key) {
+ List<dynamic/*=LinkedHashMapCell<K, V>*/ > _getBucket(var table, var key) {
var hash = internalComputeHashCode(key);
- return _getTableEntry(table, hash);
+ return _getTableBucket(table, hash);
}
int internalFindBucketIndex(var bucket, var key) {
if (bucket == null) return -1;
int length = JS('int', '#.length', bucket);
for (int i = 0; i < length; i++) {
- LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+ LinkedHashMapCell/*<K, V>*/ cell = JS('var', '#[#]', bucket, i);
if (cell.hashMapCellKey == key) return i;
}
return -1;
@@ -300,7 +302,11 @@
String toString() => Maps.mapToString(this);
- _getTableEntry(var table, var key) {
+ /*=LinkedHashMapCell<K, V>*/ _getTableCell(var table, var key) {
+ return JS('var', '#[#]', table, key);
+ }
+
+ /*=List<LinkedHashMapCell<K, V>>*/ _getTableBucket(var table, var key) {
return JS('var', '#[#]', table, key);
}
@@ -314,7 +320,7 @@
}
bool _containsTableEntry(var table, var key) {
- LinkedHashMapCell cell = _getTableEntry(table, key);
+ LinkedHashMapCell/*<K, V>*/ cell = _getTableCell(table, key);
return cell != null;
}
@@ -333,9 +339,13 @@
}
class Es6LinkedHashMap<K, V> extends JsLinkedHashMap<K, V> {
+ @override
+ /*=LinkedHashMapCell<K, V>*/ _getTableCell(var table, var key) {
+ return JS('var', '#.get(#)', table, key);
+ }
@override
- _getTableEntry(var table, var key) {
+ /*=List<LinkedHashMapCell<K, V>>*/ _getTableBucket(var table, var key) {
return JS('var', '#.get(#)', table, key);
}
@@ -360,19 +370,19 @@
}
}
-class LinkedHashMapCell {
- final hashMapCellKey;
- var hashMapCellValue;
+class LinkedHashMapCell<K, V> {
+ final dynamic/*=K*/ hashMapCellKey;
+ dynamic/*=V*/ hashMapCellValue;
- LinkedHashMapCell _next;
- LinkedHashMapCell _previous;
+ LinkedHashMapCell/*<K, V>*/ _next;
+ LinkedHashMapCell/*<K, V>*/ _previous;
LinkedHashMapCell(this.hashMapCellKey, this.hashMapCellValue);
}
class LinkedHashMapKeyIterable<E> extends Iterable<E>
- implements EfficientLength {
- final _map;
+ implements EfficientLength {
+ final dynamic/*=JsLinkedHashMap<E, dynamic>*/ _map;
LinkedHashMapKeyIterable(this._map);
int get length => _map._length;
@@ -387,7 +397,7 @@
}
void forEach(void f(E element)) {
- LinkedHashMapCell cell = _map._first;
+ LinkedHashMapCell/*<E, dynamic>*/ cell = _map._first;
int modifications = _map._modifications;
while (cell != null) {
f(cell.hashMapCellKey);
@@ -400,9 +410,9 @@
}
class LinkedHashMapKeyIterator<E> implements Iterator<E> {
- final _map;
+ final dynamic/*=JsLinkedHashMap<E, dynamic>*/ _map;
final int _modifications;
- LinkedHashMapCell _cell;
+ LinkedHashMapCell/*<E, dynamic>*/ _cell;
E _current;
LinkedHashMapKeyIterator(this._map, this._modifications) {
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
index b08e3a3..54e7935 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -304,6 +304,8 @@
CALL_PREFIX1,
CALL_PREFIX2,
CALL_PREFIX3,
+ CALL_PREFIX4,
+ CALL_PREFIX5,
CALL_CATCH_ALL,
REFLECTABLE,
CLASS_DESCRIPTOR_PROPERTY,
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 23bf531..e0e0617 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -363,18 +363,19 @@
}
/**
- * Perform an async operation repeatedly until it returns `false`.
+ * Performs an async operation repeatedly until it returns `false`.
*
- * Runs [f] repeatedly, starting the next iteration only when the [Future]
- * returned by [f] completes to `true`. Returns a [Future] that completes once
- * [f] returns `false`.
+ * The function [f] is called repeatedly while it returns either the [bool]
+ * value `true` or a [Future] which completes with the value `true`.
*
- * The return values of all [Future]s are discarded. Any errors will cause the
- * iteration to stop and will be piped through the returned [Future].
+ * If a call to [f] returns `false` or a [Future] that completes to `false`,
+ * iteration ends and the future returned by [doWhile] is completed.
*
- * The function [f] may return either a [bool] or a [Future] that completes to
- * a [bool]. If it returns a non-[Future], iteration continues immediately.
- * Otherwise it waits for the returned [Future] to complete.
+ * If a future returned by [f] completes with an error, iteration ends and
+ * the future returned by [doWhile] completes with the same error.
+ *
+ * The [f] function must return either a `bool` value or a [Future] completing
+ * with a `bool` value.
*/
static Future doWhile(f()) {
_Future doneSignal = new _Future();
@@ -459,7 +460,7 @@
*
* If `test` is omitted, it defaults to a function that always returns true.
* The `test` function should not throw, but if it does, it is handled as
- * if the the `onError` function had thrown.
+ * if the `onError` function had thrown.
*
* Example:
*
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index eb4d6cf..dd07720 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -277,6 +277,11 @@
_state = _PENDING_COMPLETE;
}
+ void _clearPendingComplete() {
+ assert(_isPendingComplete);
+ _state = _INCOMPLETE;
+ }
+
AsyncError get _error {
assert(_hasError);
return _resultOrListeners;
@@ -405,7 +410,11 @@
try {
source.then((value) {
assert(target._isPendingComplete);
- target._completeWithValue(value);
+ // The "value" may be another future if the foreign future
+ // implementation is mis-behaving,
+ // so use _complete instead of _completeWithValue.
+ target._clearPendingComplete(); // Clear this first, it's set again.
+ target._complete(value);
},
// TODO(floitsch): eventually we would like to make this non-optional
// and dependent on the listeners of the target future. If none of
@@ -650,7 +659,7 @@
}
}
-
+
if (listener.handlesComplete) {
handleWhenCompleteCallback();
} else if (!hasError) {
@@ -662,7 +671,7 @@
handleError();
}
}
-
+
// If we changed zone, oldZone will not be null.
if (oldZone != null) Zone._leave(oldZone);
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 6931373..eca6c34 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -503,7 +503,7 @@
*
* The [onError] callback must be of type `void onError(error)` or
* `void onError(error, StackTrace stackTrace)`. Depending on the function
- * type the the stream either invokes [onError] with or without a stack
+ * type the stream either invokes [onError] with or without a stack
* trace. The stack trace argument might be `null` if the stream itself
* received an error without stack trace.
*
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index dffaa12..8c9af64 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -145,7 +145,9 @@
void onError(Function handleError) {
if (handleError == null) handleError = _nullErrorHandler;
- _onError = _registerErrorHandler/*<T>*/(handleError, _zone);
+ // We are not allowed to use 'void' as type argument for the generic type,
+ // so we use 'dynamic' instead.
+ _onError = _registerErrorHandler/*<dynamic>*/(handleError, _zone);
}
void onDone(void handleDone()) {
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index a5f31b6..c8c31c5 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -102,7 +102,7 @@
*/
factory HashMap.from(Map other) {
HashMap<K, V> result = new HashMap<K, V>();
- other.forEach((k, v) { result[k] = v; });
+ other.forEach((k, v) { result[k as Object/*=K*/] = v as Object/*=V*/; });
return result;
}
diff --git a/sdk/lib/collection/hash_set.dart b/sdk/lib/collection/hash_set.dart
index 3ecb82c..8e2a2a1 100644
--- a/sdk/lib/collection/hash_set.dart
+++ b/sdk/lib/collection/hash_set.dart
@@ -121,7 +121,10 @@
*/
factory HashSet.from(Iterable elements) {
HashSet<E> result = new HashSet<E>();
- for (E e in elements) result.add(e);
+ for (final e in elements) {
+ E element = e as Object/*=E*/;
+ result.add(element);
+ }
return result;
}
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index c0d2ee0..26ccb5c 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.dart
@@ -121,7 +121,7 @@
}
E get first {
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) {
throw IterableElementError.noElement();
}
@@ -129,7 +129,7 @@
}
E get last {
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) {
throw IterableElementError.noElement();
}
@@ -141,7 +141,7 @@
}
E get single {
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) throw IterableElementError.noElement();
E result = it.current;
if (it.moveNext()) throw IterableElementError.tooMany();
diff --git a/sdk/lib/collection/iterator.dart b/sdk/lib/collection/iterator.dart
index 1fe49cd..f870711 100644
--- a/sdk/lib/collection/iterator.dart
+++ b/sdk/lib/collection/iterator.dart
@@ -15,7 +15,7 @@
static const int _NO_NEXT = 1;
static const int _NOT_MOVED_YET = 2;
- Iterator _iterator;
+ Iterator<E> _iterator;
int _state = _NOT_MOVED_YET;
HasNextIterator(this._iterator);
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index 0f76652..91814ed 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -89,7 +89,7 @@
*/
factory LinkedHashMap.from(Map other) {
LinkedHashMap<K, V> result = new LinkedHashMap<K, V>();
- other.forEach((k, v) { result[k] = v; });
+ other.forEach((k, v) { result[k as Object/*=K*/] = v as Object/*=V*/; });
return result;
}
diff --git a/sdk/lib/collection/linked_hash_set.dart b/sdk/lib/collection/linked_hash_set.dart
index e087b5f..3bc170f 100644
--- a/sdk/lib/collection/linked_hash_set.dart
+++ b/sdk/lib/collection/linked_hash_set.dart
@@ -104,8 +104,9 @@
*/
factory LinkedHashSet.from(Iterable elements) {
LinkedHashSet<E> result = new LinkedHashSet<E>();
- for (final E element in elements) {
- result.add(element);
+ for (final element in elements) {
+ E e = element as Object/*=E*/;
+ result.add(e);
}
return result;
}
diff --git a/sdk/lib/collection/linked_list.dart b/sdk/lib/collection/linked_list.dart
index e2139c0..481f04d 100644
--- a/sdk/lib/collection/linked_list.dart
+++ b/sdk/lib/collection/linked_list.dart
@@ -29,40 +29,37 @@
* and a constant time length getter.
*/
class LinkedList<E extends LinkedListEntry<E>>
- extends Iterable<E>
- implements _LinkedListLink {
+ extends Iterable<E> {
int _modificationCount = 0;
int _length = 0;
- _LinkedListLink _next;
- _LinkedListLink _previous;
+ E _first;
/**
* Construct a new empty linked list.
*/
- LinkedList() {
- _next = _previous = this;
- }
+ LinkedList();
/**
* Add [entry] to the beginning of the linked list.
*/
void addFirst(E entry) {
- _insertAfter(this, entry);
+ _insertBefore(_first, entry, updateFirst: true);
+ _first = entry;
}
/**
* Add [entry] to the end of the linked list.
*/
void add(E entry) {
- _insertAfter(_previous, entry);
+ _insertBefore(_first, entry, updateFirst: false);
}
/**
* Add [entries] to the end of the linked list.
*/
void addAll(Iterable<E> entries) {
- entries.forEach((entry) => _insertAfter(_previous, entry));
+ entries.forEach(add);
}
/**
@@ -88,38 +85,41 @@
*/
void clear() {
_modificationCount++;
- _LinkedListLink next = _next;
- while (!identical(next, this)) {
+ if (isEmpty) return;
+
+ E next = _first;
+ do {
E entry = next;
next = entry._next;
entry._next = entry._previous = entry._list = null;
- }
- _next = _previous = this;
+ } while (!identical(next, _first));
+
+ _first = null;
_length = 0;
}
E get first {
- if (identical(_next, this)) {
+ if (isEmpty) {
throw new StateError('No such element');
}
- return _next;
+ return _first;
}
E get last {
- if (identical(_previous, this)) {
+ if (isEmpty) {
throw new StateError('No such element');
}
- return _previous;
+ return _first._previous;
}
E get single {
- if (identical(_previous, this)) {
+ if (isEmpty) {
throw new StateError('No such element');
}
- if (!identical(_previous, _next)) {
+ if (_length > 1) {
throw new StateError('Too many elements');
}
- return _next;
+ return _first;
}
/**
@@ -129,40 +129,62 @@
*/
void forEach(void action(E entry)) {
int modificationCount = _modificationCount;
- _LinkedListLink current = _next;
- while (!identical(current, this)) {
+ if (isEmpty) return;
+
+ E current = _first;
+ do {
action(current);
if (modificationCount != _modificationCount) {
throw new ConcurrentModificationError(this);
}
current = current._next;
- }
+ } while (!identical(current, _first));
}
bool get isEmpty => _length == 0;
- void _insertAfter(_LinkedListLink entry, E newEntry) {
+ /// Inserts [newEntry] as last entry of the list.
+ ///
+ /// If [updateFirst] is true and [entry] is the first entry in the list,
+ /// updates the [_first] field to point to the [newEntry] as first entry.
+ void _insertBefore(E entry, E newEntry, {bool updateFirst}) {
if (newEntry.list != null) {
throw new StateError(
'LinkedListEntry is already in a LinkedList');
}
_modificationCount++;
+
newEntry._list = this;
- var predecessor = entry;
- var successor = entry._next;
- successor._previous = newEntry;
+ if (isEmpty) {
+ assert(entry == null);
+ newEntry._previous = newEntry._next = newEntry;
+ _first = newEntry;
+ _length++;
+ return;
+ }
+ E predecessor = entry._previous;
+ E successor = entry;
newEntry._previous = predecessor;
newEntry._next = successor;
predecessor._next = newEntry;
+ successor._previous = newEntry;
+ if (updateFirst && identical(entry, _first)) {
+ _first = newEntry;
+ }
_length++;
}
- void _unlink(LinkedListEntry<E> entry) {
+ void _unlink(E entry) {
_modificationCount++;
entry._next._previous = entry._previous;
- entry._previous._next = entry._next;
+ E next = entry._previous._next = entry._next;
_length--;
entry._list = entry._next = entry._previous = null;
+ if (isEmpty) {
+ _first = null;
+ } else if (identical(entry, _first)) {
+ _first = next;
+ }
}
}
@@ -172,23 +194,27 @@
final LinkedList<E> _list;
final int _modificationCount;
E _current;
- _LinkedListLink _next;
+ LinkedListEntry<E> _next;
+ bool _visitedFirst;
_LinkedListIterator(LinkedList<E> list)
: _list = list,
_modificationCount = list._modificationCount,
- _next = list._next;
+ _next = list._first,
+ _visitedFirst = false;
E get current => _current;
bool moveNext() {
- if (identical(_next, _list)) {
- _current = null;
- return false;
- }
if (_modificationCount != _list._modificationCount) {
throw new ConcurrentModificationError(this);
}
+ if (_list.isEmpty ||
+ (_visitedFirst && identical(_next, _list.first))) {
+ _current = null;
+ return false;
+ }
+ _visitedFirst = true;
_current = _next;
_next = _next._next;
return true;
@@ -196,12 +222,6 @@
}
-class _LinkedListLink {
- _LinkedListLink _next;
- _LinkedListLink _previous;
-}
-
-
/**
* An object that can be an element in a [LinkedList].
*
@@ -216,11 +236,10 @@
*
* When created, an entry is not in any linked list.
*/
-abstract class LinkedListEntry<E extends LinkedListEntry<E>>
- implements _LinkedListLink {
+abstract class LinkedListEntry<E extends LinkedListEntry<E>> {
LinkedList<E> _list;
- _LinkedListLink _next;
- _LinkedListLink _previous;
+ E _next;
+ E _previous;
/**
* Get the linked list containing this element.
@@ -245,9 +264,8 @@
* entry is not currently in any list.
*/
E get next {
- if (identical(_next, _list)) return null;
- E result = _next;
- return result;
+ if (identical(this, _next)) return null;
+ return _next;
}
/**
@@ -257,8 +275,8 @@
* entry is not currently in any list.
*/
E get previous {
- if (identical(_previous, _list)) return null;
- return _previous as E;
+ if (identical(this, _previous)) return null;
+ return _previous;
}
/**
@@ -268,7 +286,7 @@
* The [entry] must not be in a linked list.
*/
void insertAfter(E entry) {
- _list._insertAfter(this, entry);
+ _list._insertBefore(_next, entry, updateFirst: false);
}
/**
@@ -278,6 +296,6 @@
* The [entry] must not be in a linked list.
*/
void insertBefore(E entry) {
- _list._insertAfter(_previous, entry);
+ _list._insertBefore(this as dynamic/*=E*/, entry, updateFirst: true);
}
}
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index 64586d3..7e6dbd3a 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -309,10 +309,10 @@
void sort([int compare(E a, E b)]) {
if (compare == null) {
- var defaultCompare = Comparable.compare;
- compare = defaultCompare;
+ Sort.sort(this, Comparable.compare);
+ } else {
+ Sort.sort(this, compare);
}
- Sort.sort(this, compare);
}
void shuffle([Random random]) {
@@ -368,10 +368,10 @@
if (length == 0) return;
RangeError.checkNotNegative(skipCount, "skipCount");
- List otherList;
+ List<E> otherList;
int otherStart;
// TODO(floitsch): Make this accept more.
- if (iterable is List) {
+ if (iterable is List/*<E>*/) {
otherList = iterable;
otherStart = skipCount;
} else {
diff --git a/sdk/lib/collection/maps.dart b/sdk/lib/collection/maps.dart
index bd2e736..7871b87 100644
--- a/sdk/lib/collection/maps.dart
+++ b/sdk/lib/collection/maps.dart
@@ -78,7 +78,7 @@
int get length => keys.length;
bool get isEmpty => keys.isEmpty;
bool get isNotEmpty => keys.isNotEmpty;
- Iterable<V> get values => new _MapBaseValueIterable<V>(this);
+ Iterable<V> get values => new _MapBaseValueIterable<K, V>(this);
String toString() => Maps.mapToString(this);
}
@@ -111,9 +111,9 @@
* It accesses the values by iterating over the keys of the map, and using the
* map's `operator[]` to lookup the keys.
*/
-class _MapBaseValueIterable<V> extends Iterable<V>
- implements EfficientLength {
- final Map _map;
+class _MapBaseValueIterable<K, V> extends Iterable<V>
+ implements EfficientLength {
+ final Map<K, V> _map;
_MapBaseValueIterable(this._map);
int get length => _map.length;
@@ -123,7 +123,7 @@
V get single => _map[_map.keys.single];
V get last => _map[_map.keys.last];
- Iterator<V> get iterator => new _MapBaseValueIterator<V>(_map);
+ Iterator<V> get iterator => new _MapBaseValueIterator<K, V>(_map);
}
/**
@@ -132,12 +132,14 @@
* Iterates over the values of a map by iterating its keys and lookup up the
* values.
*/
-class _MapBaseValueIterator<V> implements Iterator<V> {
- final Iterator _keys;
- final Map _map;
+class _MapBaseValueIterator<K, V> implements Iterator<V> {
+ final Iterator<K> _keys;
+ final Map<K, V> _map;
V _current = null;
- _MapBaseValueIterator(Map map) : _map = map, _keys = map.keys.iterator;
+ _MapBaseValueIterator(Map<K, V> map)
+ : _map = map,
+ _keys = map.keys.iterator;
bool moveNext() {
if (_keys.moveNext()) {
diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart
index af8e07a..816f62e 100644
--- a/sdk/lib/collection/queue.dart
+++ b/sdk/lib/collection/queue.dart
@@ -96,12 +96,11 @@
}
-class _DoubleLink {
- _DoubleLink _previousLink;
- _DoubleLink _nextLink;
+class _DoubleLink<Link extends _DoubleLink> {
+ Link _previousLink;
+ Link _nextLink;
- void _link(_DoubleLink previous,
- _DoubleLink next) {
+ void _link(Link previous, Link next) {
_nextLink = next;
_previousLink = previous;
if (previous != null) previous._nextLink = this;
@@ -120,15 +119,18 @@
* An entry in a doubly linked list. It contains a pointer to the next
* entry, the previous entry, and the boxed element.
*/
-class DoubleLinkedQueueEntry<E> extends _DoubleLink {
+class DoubleLinkedQueueEntry<E> extends _DoubleLink<DoubleLinkedQueueEntry<E>> {
+ /// The element in the queue.
E element;
DoubleLinkedQueueEntry(this.element);
+ /// Appends the given [e] as entry just after this entry.
void append(E e) {
new DoubleLinkedQueueEntry<E>(e)._link(this, _nextLink);
}
+ /// Prepends the given [e] as entry just before this entry.
void prepend(E e) {
new DoubleLinkedQueueEntry<E>(e)._link(_previousLink, this);
}
@@ -138,28 +140,27 @@
return element;
}
- DoubleLinkedQueueEntry<E> previousEntry() {
- return _previousLink;
- }
+ /// Returns the previous entry or `null` if there is none.
+ DoubleLinkedQueueEntry<E> previousEntry() => _previousLink;
- DoubleLinkedQueueEntry<E> nextEntry() {
- return _nextLink;
- }
+ /// Returns the next entry or `null` if there is none.
+ DoubleLinkedQueueEntry<E> nextEntry() => _nextLink;
}
/**
* Interface for the link classes used by [DoubleLinkedQueue].
*
* Both the [_DoubleLinkedQueueElement] and [_DoubleLinkedQueueSentinel]
- * implements this interface.
+ * implement this interface.
* The entry contains a link back to the queue, so calling `append`
* or `prepend` can correctly update the element count.
*/
-abstract class _DoubleLinkedQueueEntry<E> extends _DoubleLink {
+abstract class _DoubleLinkedQueueEntry<E>
+ extends DoubleLinkedQueueEntry<E> {
DoubleLinkedQueue<E> _queue;
- _DoubleLinkedQueueEntry(this._queue);
+ _DoubleLinkedQueueEntry(E element, this._queue) : super(element);
- _DoubleLinkedQueueElement _asNonSentinelEntry();
+ DoubleLinkedQueueEntry<E> _asNonSentinelEntry();
void _append(E e) {
new _DoubleLinkedQueueElement<E>(e, _queue)._link(this, _nextLink);
@@ -171,16 +172,18 @@
E _remove();
- E get element;
+ E get _element => element;
DoubleLinkedQueueEntry<E> nextEntry() {
- _DoubleLinkedQueueEntry next = _nextLink;
- return next._asNonSentinelEntry();
+ _DoubleLinkedQueueEntry<E> entry =
+ _nextLink as dynamic/*=DoubleLinkedQueueEntry<E>*/;
+ return entry._asNonSentinelEntry();
}
DoubleLinkedQueueEntry<E> previousEntry() {
- _DoubleLinkedQueueEntry previous = _previousLink;
- return previous._asNonSentinelEntry();
+ _DoubleLinkedQueueEntry<E> entry =
+ _previousLink as dynamic/*=DoubleLinkedQueueEntry<E>*/;
+ return entry._asNonSentinelEntry();
}
}
@@ -190,11 +193,9 @@
* The entry contains a reference to the queue, allowing
* [append]/[prepend] to update the list length.
*/
-class _DoubleLinkedQueueElement<E> extends _DoubleLinkedQueueEntry<E>
- implements DoubleLinkedQueueEntry<E> {
- E element;
- _DoubleLinkedQueueElement(this.element, DoubleLinkedQueue<E> queue)
- : super(queue);
+class _DoubleLinkedQueueElement<E> extends _DoubleLinkedQueueEntry<E> {
+ _DoubleLinkedQueueElement(E element, DoubleLinkedQueue<E> queue)
+ : super(element, queue);
void append(E e) {
_append(e);
@@ -217,7 +218,7 @@
return _remove();
}
- _DoubleLinkedQueueElement _asNonSentinelEntry() {
+ _DoubleLinkedQueueElement<E> _asNonSentinelEntry() {
return this;
}
}
@@ -231,12 +232,13 @@
* A sentinel does not box any user element.
*/
class _DoubleLinkedQueueSentinel<E> extends _DoubleLinkedQueueEntry<E> {
- _DoubleLinkedQueueSentinel(DoubleLinkedQueue queue) : super(queue) {
+ _DoubleLinkedQueueSentinel(DoubleLinkedQueue<E> queue)
+ : super(null, queue) {
_previousLink = this;
_nextLink = this;
}
- _DoubleLinkedQueueElement _asNonSentinelEntry() {
+ DoubleLinkedQueueEntry<E> _asNonSentinelEntry() {
return null;
}
@@ -246,7 +248,7 @@
}
/** Hit by, e.g., [DoubleLinkedQueue.first] if the queue is empty. */
- E get element {
+ E get _element {
throw IterableElementError.noElement();
}
}
@@ -272,8 +274,9 @@
*/
factory DoubleLinkedQueue.from(Iterable elements) {
Queue<E> list = new DoubleLinkedQueue<E>();
- for (final E e in elements) {
- list.addLast(e);
+ for (final e in elements) {
+ E element = e as Object/*=E*/;
+ list.addLast(element);
}
return list;
}
@@ -303,14 +306,14 @@
}
E removeLast() {
- _DoubleLinkedQueueEntry lastEntry = _sentinel._previousLink;
+ _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
E result = lastEntry._remove();
_elementCount--;
return result;
}
E removeFirst() {
- _DoubleLinkedQueueEntry firstEntry = _sentinel._nextLink;
+ _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
E result = firstEntry._remove();
_elementCount--;
return result;
@@ -319,7 +322,7 @@
bool remove(Object o) {
_DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
while (!identical(entry, _sentinel)) {
- if (entry.element == o) {
+ if (entry._element == o) {
entry._remove();
_elementCount--;
return true;
@@ -333,7 +336,7 @@
_DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
while (!identical(entry, _sentinel)) {
_DoubleLinkedQueueEntry<E> next = entry._nextLink;
- if (identical(removeMatching, test(entry.element))) {
+ if (identical(removeMatching, test(entry._element))) {
entry._remove();
_elementCount--;
}
@@ -350,21 +353,21 @@
}
E get first {
- _DoubleLinkedQueueEntry firstEntry = _sentinel._nextLink;
- return firstEntry.element;
+ _DoubleLinkedQueueEntry<E> firstEntry = _sentinel._nextLink;
+ return firstEntry._element;
}
E get last {
- _DoubleLinkedQueueEntry lastEntry = _sentinel._previousLink;
- return lastEntry.element;
+ _DoubleLinkedQueueEntry<E> lastEntry = _sentinel._previousLink;
+ return lastEntry._element;
}
E get single {
// Note that this throws correctly if the queue is empty
// because reading element on the sentinel throws.
if (identical(_sentinel._nextLink, _sentinel._previousLink)) {
- _DoubleLinkedQueueEntry entry = _sentinel._nextLink;
- return entry.element;
+ _DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
+ return entry._element;
}
throw IterableElementError.tooMany();
}
@@ -391,7 +394,7 @@
_DoubleLinkedQueueEntry<E> entry = _sentinel._nextLink;
while (!identical(entry, _sentinel)) {
_DoubleLinkedQueueEntry<E> nextEntry = entry._nextLink;
- _DoubleLinkedQueueElement element = entry;
+ _DoubleLinkedQueueElement<E> element = entry;
f(element);
entry = nextEntry;
}
@@ -410,7 +413,8 @@
E _current;
_DoubleLinkedQueueIterator(_DoubleLinkedQueueSentinel<E> sentinel)
- : _sentinel = sentinel, _nextEntry = sentinel._nextLink;
+ : _sentinel = sentinel,
+ _nextEntry = sentinel._nextLink;
bool moveNext() {
if (identical(_nextEntry, _sentinel)) {
@@ -419,11 +423,11 @@
_sentinel = null;
return false;
}
- _DoubleLinkedQueueElement elementEntry = _nextEntry;
+ _DoubleLinkedQueueElement<E> elementEntry = _nextEntry;
if (elementEntry._queue == null) {
throw new ConcurrentModificationError(_sentinel._queue);
}
- _current = elementEntry.element;
+ _current = elementEntry._element;
_nextEntry = elementEntry._nextLink;
return true;
}
@@ -476,8 +480,9 @@
int length = elements.length;
ListQueue<E> queue = new ListQueue(length + 1);
assert(queue._table.length > length);
- List sourceList = elements;
- queue._table.setRange(0, length, sourceList, 0);
+ for (int i = 0; i < length; i++) {
+ queue._table[i] = elements[i] as Object/*=E*/;
+ }
queue._tail = length;
return queue;
} else {
@@ -486,8 +491,8 @@
capacity = elements.length;
}
ListQueue<E> result = new ListQueue<E>(capacity);
- for (final E element in elements) {
- result.addLast(element);
+ for (final element in elements) {
+ result.addLast(element as Object/*=E*/);
}
return result;
}
@@ -548,8 +553,8 @@
}
void addAll(Iterable<E> elements) {
- if (elements is List) {
- List list = elements;
+ if (elements is List/*<E>*/) {
+ List<E> list = elements;
int addCount = list.length;
int length = this.length;
if (length + addCount >= _table.length) {
@@ -792,13 +797,13 @@
* Considers any add or remove operation a concurrent modification.
*/
class _ListQueueIterator<E> implements Iterator<E> {
- final ListQueue _queue;
+ final ListQueue<E> _queue;
final int _end;
final int _modificationCount;
int _position;
E _current;
- _ListQueueIterator(ListQueue queue)
+ _ListQueueIterator(ListQueue<E> queue)
: _queue = queue,
_end = queue._tail,
_modificationCount = queue._modificationCount,
diff --git a/sdk/lib/collection/set.dart b/sdk/lib/collection/set.dart
index 4dd32cb..499225d 100644
--- a/sdk/lib/collection/set.dart
+++ b/sdk/lib/collection/set.dart
@@ -33,7 +33,7 @@
bool contains(Object element);
- E lookup(E element);
+ E lookup(Object element);
bool remove(Object element);
@@ -125,7 +125,7 @@
E get single {
if (length > 1) throw IterableElementError.tooMany();
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) throw IterableElementError.noElement();
E result = it.current;
return result;
@@ -213,7 +213,7 @@
}
E get first {
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) {
throw IterableElementError.noElement();
}
@@ -221,7 +221,7 @@
}
E get last {
- Iterator it = iterator;
+ Iterator<E> it = iterator;
if (!it.moveNext()) {
throw IterableElementError.noElement();
}
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 223e58c..72a2f52 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -36,14 +36,15 @@
* It performs basic operations such as insertion, look-up and
* removal, in O(log(n)) amortized time.
*/
-abstract class _SplayTree<K> {
+abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
// The root node of the splay tree. It will contain either the last
// element inserted or the last element looked up.
- _SplayTreeNode<K> _root;
+ Node get _root;
+ set _root(Node newValue);
// The dummy node used when performing a splay on the tree. Reusing it
// avoids allocating a node each time a splay is performed.
- _SplayTreeNode<K> _dummy = new _SplayTreeNode<K>(null);
+ Node get _dummy;
// Number of elements in the splay tree.
int _count = 0;
@@ -63,6 +64,12 @@
*/
int _splayCount = 0;
+ /** The comparator that is used for this splay tree. */
+ Comparator<K> get _comparator;
+
+ /** The predicate to determine that a given object is a valid key. */
+ _Predicate get _validKey;
+
/** Comparison used to compare keys. */
int _compare(K key1, K key2);
@@ -83,9 +90,9 @@
// the L tree of the algorithm. The left child of the dummy node
// will hold the R tree of the algorithm. Using a dummy node, left
// and right will always be nodes and we avoid special cases.
- _SplayTreeNode<K> left = _dummy;
- _SplayTreeNode<K> right = _dummy;
- _SplayTreeNode<K> current = _root;
+ Node left = _dummy;
+ Node right = _dummy;
+ Node current = _root;
int comp;
while (true) {
comp = _compare(current.key, key);
@@ -109,7 +116,7 @@
comp = _compare(current.right.key, key);
if (comp < 0) {
// Rotate left.
- _SplayTreeNode<K> tmp = current.right;
+ Node tmp = current.right;
current.right = tmp.left;
tmp.left = current;
current = tmp;
@@ -140,10 +147,10 @@
// anchored at [node].
// and that node is returned. It should replace the reference to [node]
// in any parent tree or root pointer.
- _SplayTreeNode<K> _splayMin(_SplayTreeNode<K> node) {
- _SplayTreeNode current = node;
+ Node _splayMin(Node node) {
+ Node current = node;
while (current.left != null) {
- _SplayTreeNode left = current.left;
+ Node left = current.left;
current.left = left.right;
left.right = current;
current = left;
@@ -156,10 +163,10 @@
// After this, the largest element in the tree is the root of the subtree,
// and that node is returned. It should replace the reference to [node]
// in any parent tree or root pointer.
- _SplayTreeNode<K> _splayMax(_SplayTreeNode<K> node) {
- _SplayTreeNode current = node;
+ Node _splayMax(Node node) {
+ Node current = node;
while (current.right != null) {
- _SplayTreeNode right = current.right;
+ Node right = current.right;
current.right = right.left;
right.left = current;
current = right;
@@ -167,17 +174,17 @@
return current;
}
- _SplayTreeNode _remove(K key) {
+ Node _remove(K key) {
if (_root == null) return null;
int comp = _splay(key);
if (comp != 0) return null;
- _SplayTreeNode result = _root;
+ Node result = _root;
_count--;
// assert(_count >= 0);
if (_root.left == null) {
_root = _root.right;
} else {
- _SplayTreeNode<K> right = _root.right;
+ Node right = _root.right;
// Splay to make sure that the new root has an empty right child.
_root = _splayMax(_root.left);
// Insert the original right child as the right child of the new
@@ -194,7 +201,7 @@
* The [comp] value is the result of comparing the existing root's key
* with key.
*/
- void _addNewRoot(_SplayTreeNode<K> node, int comp) {
+ void _addNewRoot(Node node, int comp) {
_count++;
_modificationCount++;
if (_root == null) {
@@ -214,13 +221,13 @@
_root = node;
}
- _SplayTreeNode get _first {
+ Node get _first {
if (_root == null) return null;
_root = _splayMin(_root);
return _root;
}
- _SplayTreeNode get _last {
+ Node get _last {
if (_root == null) return null;
_root = _splayMax(_root);
return _root;
@@ -260,13 +267,18 @@
* value. If omitted, the `isValidKey` function defaults to testing if the
* value is a [K].
*/
-class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
+class SplayTreeMap<K, V> extends _SplayTree<K, _SplayTreeMapNode<K, V>>
+ implements Map<K, V> {
+ _SplayTreeMapNode<K, V> _root;
+ final _SplayTreeMapNode<K, V> _dummy =
+ new _SplayTreeMapNode<K, V>(null, null);
+
Comparator<K> _comparator;
_Predicate _validKey;
SplayTreeMap([int compare(K key1, K key2), bool isValidKey(potentialKey)])
- : _comparator = (compare == null) ? Comparable.compare : compare,
- _validKey = (isValidKey != null) ? isValidKey : ((v) => v is K);
+ : _comparator = compare ?? Comparable.compare as Comparator<K>,
+ _validKey = isValidKey ?? ((v) => v is K);
/**
* Creates a [SplayTreeMap] that contains all key/value pairs of [other].
@@ -275,7 +287,7 @@
[int compare(K key1, K key2),
bool isValidKey(potentialKey)]) {
SplayTreeMap<K, V> result = new SplayTreeMap<K, V>(compare, isValidKey);
- other.forEach((k, v) { result[k] = v; });
+ other.forEach((k, v) { result[k as Object/*=K*/] = v as Object/*=V*/; });
return result;
}
@@ -327,10 +339,9 @@
V operator [](Object key) {
if (!_validKey(key)) return null;
if (_root != null) {
- int comp = _splay(key);
+ int comp = _splay(key as dynamic/*=K*/);
if (comp == 0) {
- _SplayTreeMapNode mapRoot = _root;
- return mapRoot.value;
+ return _root.value;
}
}
return null;
@@ -338,7 +349,7 @@
V remove(Object key) {
if (!_validKey(key)) return null;
- _SplayTreeMapNode mapRoot = _remove(key);
+ _SplayTreeMapNode<K, V> mapRoot = _remove(key as dynamic/*=K*/);
if (mapRoot != null) return mapRoot.value;
return null;
}
@@ -349,8 +360,7 @@
// the key to the root of the tree.
int comp = _splay(key);
if (comp == 0) {
- _SplayTreeMapNode mapRoot = _root;
- mapRoot.value = value;
+ _root.value = value;
return;
}
_addNewRoot(new _SplayTreeMapNode(key, value), comp);
@@ -361,8 +371,7 @@
if (key == null) throw new ArgumentError(key);
int comp = _splay(key);
if (comp == 0) {
- _SplayTreeMapNode mapRoot = _root;
- return mapRoot.value;
+ return _root.value;
}
int modificationCount = _modificationCount;
int splayCount = _splayCount;
@@ -407,7 +416,7 @@
}
bool containsKey(Object key) {
- return _validKey(key) && _splay(key) == 0;
+ return _validKey(key) && _splay(key as dynamic/*=K*/) == 0;
}
bool containsValue(Object value) {
@@ -486,8 +495,8 @@
}
}
-abstract class _SplayTreeIterator<T> implements Iterator<T> {
- final _SplayTree _tree;
+abstract class _SplayTreeIterator<K, T> implements Iterator<T> {
+ final _SplayTree<K, _SplayTreeNode<K>> _tree;
/**
* Worklist of nodes to visit.
*
@@ -498,7 +507,7 @@
*
* Only valid as long as the original tree isn't reordered.
*/
- final List<_SplayTreeNode> _workList = <_SplayTreeNode>[];
+ final List<_SplayTreeNode<K>> _workList = <_SplayTreeNode<K>>[];
/**
* Original modification counter of [_tree].
@@ -519,16 +528,16 @@
int _splayCount;
/** Current node. */
- _SplayTreeNode _currentNode;
+ _SplayTreeNode<K> _currentNode;
- _SplayTreeIterator(_SplayTree tree)
+ _SplayTreeIterator(_SplayTree<K, _SplayTreeNode<K>> tree)
: _tree = tree,
_modificationCount = tree._modificationCount,
_splayCount = tree._splayCount {
_findLeftMostDescendent(tree._root);
}
- _SplayTreeIterator.startAt(_SplayTree tree, var startKey)
+ _SplayTreeIterator.startAt(_SplayTree<K, _SplayTreeNode<K>> tree, K startKey)
: _tree = tree,
_modificationCount = tree._modificationCount {
if (tree._root == null) return;
@@ -547,7 +556,7 @@
return _getValue(_currentNode);
}
- void _findLeftMostDescendent(_SplayTreeNode node) {
+ void _findLeftMostDescendent(_SplayTreeNode<K> node) {
while (node != null) {
_workList.add(node);
node = node.left;
@@ -562,7 +571,7 @@
* here, so we know that the keys are the same as before, it's
* only the tree that has been reordered.
*/
- void _rebuildWorkList(_SplayTreeNode currentNode) {
+ void _rebuildWorkList(_SplayTreeNode<K> currentNode) {
assert(!_workList.isEmpty);
_workList.clear();
if (currentNode == null) {
@@ -595,21 +604,20 @@
return true;
}
- T _getValue(_SplayTreeNode node);
+ T _getValue(_SplayTreeNode<K> node);
}
class _SplayTreeKeyIterable<K> extends Iterable<K>
implements EfficientLength {
- _SplayTree<K> _tree;
+ _SplayTree<K, _SplayTreeNode<K>> _tree;
_SplayTreeKeyIterable(this._tree);
int get length => _tree._count;
bool get isEmpty => _tree._count == 0;
Iterator<K> get iterator => new _SplayTreeKeyIterator<K>(_tree);
Set<K> toSet() {
- var setOrMap = _tree; // Both have _comparator and _validKey.
SplayTreeSet<K> set =
- new SplayTreeSet<K>(setOrMap._comparator, setOrMap._validKey);
+ new SplayTreeSet<K>(_tree._comparator, _tree._validKey);
set._count = _tree._count;
set._root = set._copyNode(_tree._root);
return set;
@@ -625,22 +633,27 @@
Iterator<V> get iterator => new _SplayTreeValueIterator<K, V>(_map);
}
-class _SplayTreeKeyIterator<K> extends _SplayTreeIterator<K> {
- _SplayTreeKeyIterator(_SplayTree<K> map): super(map);
- K _getValue(_SplayTreeNode node) => node.key;
+class _SplayTreeKeyIterator<K> extends _SplayTreeIterator<K, K> {
+ _SplayTreeKeyIterator(_SplayTree<K, _SplayTreeNode<K>> map): super(map);
+ K _getValue(_SplayTreeNode<K> node) => node.key;
}
-class _SplayTreeValueIterator<K, V> extends _SplayTreeIterator<V> {
+class _SplayTreeValueIterator<K, V> extends _SplayTreeIterator<K, V> {
_SplayTreeValueIterator(SplayTreeMap<K, V> map): super(map);
- V _getValue(_SplayTreeMapNode node) => node.value;
+ V _getValue(_SplayTreeNode<K> node) {
+ _SplayTreeMapNode<K, V> mapNode =
+ node as dynamic/*=_SplayTreeMapNode<K, V>*/;
+ return mapNode.value;
+ }
}
class _SplayTreeNodeIterator<K>
- extends _SplayTreeIterator<_SplayTreeNode<K>> {
- _SplayTreeNodeIterator(_SplayTree<K> tree): super(tree);
- _SplayTreeNodeIterator.startAt(_SplayTree<K> tree, var startKey)
+ extends _SplayTreeIterator<K, _SplayTreeNode<K>> {
+ _SplayTreeNodeIterator(_SplayTree<K, _SplayTreeNode<K>> tree): super(tree);
+ _SplayTreeNodeIterator.startAt(
+ _SplayTree<K, _SplayTreeNode<K>> tree, K startKey)
: super.startAt(tree, startKey);
- _SplayTreeNode<K> _getValue(_SplayTreeNode node) => node;
+ _SplayTreeNode<K> _getValue(_SplayTreeNode<K> node) => node;
}
@@ -660,8 +673,12 @@
* Non-comparable objects (including `null`) will not work as an element
* in that case.
*/
-class SplayTreeSet<E> extends _SplayTree<E> with IterableMixin<E>, SetMixin<E> {
- Comparator _comparator;
+class SplayTreeSet<E> extends _SplayTree<E, _SplayTreeNode<E>>
+ with IterableMixin<E>, SetMixin<E> {
+ _SplayTreeNode<E> _root;
+ final _SplayTreeNode<E> _dummy = new _SplayTreeNode<E>(null);
+
+ Comparator<E> _comparator;
_Predicate _validKey;
/**
@@ -689,8 +706,9 @@
* type parameter: `other is E`.
*/
SplayTreeSet([int compare(E key1, E key2), bool isValidKey(potentialKey)])
- : _comparator = (compare == null) ? Comparable.compare : compare,
- _validKey = (isValidKey != null) ? isValidKey : ((v) => v is E);
+ : _comparator =
+ compare ?? Comparable.compare as dynamic/*=Comparator<E>*/,
+ _validKey = isValidKey ?? ((v) => v is E);
/**
* Creates a [SplayTreeSet] that contains all [elements].
@@ -703,8 +721,9 @@
[int compare(E key1, E key2),
bool isValidKey(potentialKey)]) {
SplayTreeSet<E> result = new SplayTreeSet<E>(compare, isValidKey);
- for (final E element in elements) {
- result.add(element);
+ for (final element in elements) {
+ E e = element as Object/*=E*/;
+ result.add(e);
}
return result;
}
@@ -737,7 +756,7 @@
// From Set.
bool contains(Object object) {
- return _validKey(object) && _splay(object) == 0;
+ return _validKey(object) && _splay(object as dynamic/*=E*/) == 0;
}
bool add(E element) {
@@ -749,7 +768,7 @@
bool remove(Object object) {
if (!_validKey(object)) return false;
- return _remove(object) != null;
+ return _remove(object as dynamic/*=E*/) != null;
}
void addAll(Iterable<E> elements) {
@@ -763,7 +782,7 @@
void removeAll(Iterable<Object> elements) {
for (Object element in elements) {
- if (_validKey(element)) _remove(element);
+ if (_validKey(element)) _remove(element as dynamic/*=E*/);
}
}
@@ -777,7 +796,9 @@
throw new ConcurrentModificationError(this);
}
// Equivalent to this.contains(object).
- if (_validKey(object) && _splay(object) == 0) retainSet.add(_root.key);
+ if (_validKey(object) && _splay(object as dynamic/*=E*/) == 0) {
+ retainSet.add(_root.key);
+ }
}
// Take over the elements from the retained set, if it differs.
if (retainSet._count != _count) {
@@ -789,12 +810,12 @@
E lookup(Object object) {
if (!_validKey(object)) return null;
- int comp = _splay(object);
+ int comp = _splay(object as dynamic/*=E*/);
if (comp != 0) return null;
return _root.key;
}
- Set<E> intersection(Set<E> other) {
+ Set<E> intersection(Set<Object> other) {
Set<E> result = new SplayTreeSet<E>(_comparator, _validKey);
for (E element in this) {
if (other.contains(element)) result.add(element);
@@ -802,7 +823,7 @@
return result;
}
- Set<E> difference(Set<E> other) {
+ Set<E> difference(Set<Object> other) {
Set<E> result = new SplayTreeSet<E>(_comparator, _validKey);
for (E element in this) {
if (!other.contains(element)) result.add(element);
diff --git a/sdk/lib/convert/ascii.dart b/sdk/lib/convert/ascii.dart
index 6302333..a076210 100644
--- a/sdk/lib/convert/ascii.dart
+++ b/sdk/lib/convert/ascii.dart
@@ -69,8 +69,7 @@
// Superclass for [AsciiEncoder] and [Latin1Encoder].
// Generalizes common operations that only differ by a mask;
-class _UnicodeSubsetEncoder extends
- ChunkedConverter<String, List<int>, String, List<int>> {
+class _UnicodeSubsetEncoder extends Converter<String, List<int>> {
final int _subsetMask;
const _UnicodeSubsetEncoder(this._subsetMask);
@@ -86,7 +85,7 @@
RangeError.checkValidRange(start, end, stringLength);
if (end == null) end = stringLength;
int length = end - start;
- List result = new Uint8List(length);
+ List<int> result = new Uint8List(length);
for (int i = 0; i < length; i++) {
var codeUnit = string.codeUnitAt(start + i);
if ((codeUnit & ~_subsetMask) != 0) {
@@ -155,8 +154,7 @@
* This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
* to a string.
*/
-abstract class _UnicodeSubsetDecoder extends
- ChunkedConverter<List<int>, String, List<int>, String> {
+abstract class _UnicodeSubsetDecoder extends Converter<List<int>, String> {
final bool _allowInvalid;
final int _subsetMask;
diff --git a/sdk/lib/convert/base64.dart b/sdk/lib/convert/base64.dart
index f3d7019..3fe1357 100644
--- a/sdk/lib/convert/base64.dart
+++ b/sdk/lib/convert/base64.dart
@@ -70,8 +70,7 @@
*
* The results are ASCII strings using a restricted alphabet.
*/
-class Base64Encoder extends
- ChunkedConverter<List<int>, String, List<int>, String> {
+class Base64Encoder extends Converter<List<int>, String> {
final bool _urlSafe;
const Base64Encoder() : _urlSafe = false;
@@ -341,8 +340,7 @@
*
* The encoding is required to be properly padded.
*/
-class Base64Decoder extends
- ChunkedConverter<String, List<int>, String, List<int>> {
+class Base64Decoder extends Converter<String, List<int>> {
const Base64Decoder();
diff --git a/sdk/lib/convert/chunked_conversion.dart b/sdk/lib/convert/chunked_conversion.dart
index 95e561c..ee71f4f 100644
--- a/sdk/lib/convert/chunked_conversion.dart
+++ b/sdk/lib/convert/chunked_conversion.dart
@@ -6,55 +6,14 @@
typedef void _ChunkedConversionCallback<T>(T accumulated);
-/**
- * A converter that supports chunked conversions.
- *
- * In addition to immediate conversions from [S] to [T], a chunked converter
- * also supports longer-running conversions from [S2] to [T2].
- *
- * Frequently, the source and target types are the same, but this is not a
- * requirement. In particular, converters that work with lists in the
- * immediate conversion, could flatten the type for the chunked conversion.
- *
- * For example, the [LineSplitter] class returns a `List<String>` for the
- * immediate conversion, but returns individual `String`s in the chunked
- * conversion.
- */
+/// This class is deprecated. Extend [Converter] directly.
+@deprecated
abstract class ChunkedConverter<S, T, S2, T2> extends Converter<S, T> {
+ const ChunkedConverter(): super();
- const ChunkedConverter();
-
- /**
- * Starts a chunked conversion.
- *
- * The returned sink serves as input for the long-running conversion. The
- * given [sink] serves as output.
- */
- ChunkedConversionSink<S2> startChunkedConversion(Sink<T2> sink) {
- throw new UnsupportedError(
- "This converter does not support chunked conversions: $this");
- }
-
- Stream<T2> bind(Stream<S2> stream) {
- return new Stream<T2>.eventTransformed(
- stream,
- (EventSink<T2> sink) =>
- new _ConverterStreamEventSink<S2, T2>(this, sink));
- }
-
- /**
- * Fuses this instance with the given [other] converter.
- *
- * If [other] is a ChunkedConverter (with matching generic types), returns a
- * [ChunkedConverter].
- */
- Converter<S, dynamic> fuse(Converter<T, dynamic> other) {
- if (other is ChunkedConverter<T, dynamic, T2, dynamic>) {
- return new _FusedChunkedConverter<S, T, dynamic, S2, T2, dynamic>(
- this, other);
- }
- return super.fuse(other);
- }
+ dynamic bind(dynamic other) => super.bind(other);
+ dynamic startChunkedConversion(dynamic sink) =>
+ super.startChunkedConversion(sink);
}
/**
@@ -65,13 +24,13 @@
* work with a plain `Sink`, but may work more efficiently with certain
* specialized types of `ChunkedConversionSink`.
*
- * It is recommended that implementations of `ChunkedConversionSink` extends
+ * It is recommended that implementations of `ChunkedConversionSink` extend
* this class, to inherit any further methods that may be added to the class.
*/
abstract class ChunkedConversionSink<T> implements Sink<T> {
ChunkedConversionSink();
factory ChunkedConversionSink.withCallback(
- void callback(List<T> accumulated)) = _SimpleCallbackSink;
+ void callback(List<T> accumulated)) = _SimpleCallbackSink<T>;
/**
* Adds chunked data to this sink.
@@ -122,10 +81,10 @@
* The input sink for new data. All data that is received with
* [handleData] is added into this sink.
*/
- final ChunkedConversionSink<S> _chunkedSink;
+ final Sink<S> _chunkedSink;
_ConverterStreamEventSink(
- Converter/*=ChunkedConverter<dynamic, dynamic, S, T>*/ converter,
+ Converter/*=Converter<S, T>*/ converter,
EventSink<T> sink)
: this._eventSink = sink,
_chunkedSink = converter.startChunkedConversion(sink);
@@ -136,20 +95,3 @@
}
void close() { _chunkedSink.close(); }
}
-
-/**
- * Fuses two chunked converters.
- */
-class _FusedChunkedConverter<S, M, T, S2, M2, T2> extends
- ChunkedConverter<S, T, S2, T2> {
- final ChunkedConverter<S, M, S2, M2> _first;
- final ChunkedConverter<M, T, M2, T2> _second;
-
- _FusedChunkedConverter(this._first, this._second);
-
- T convert(S input) => _second.convert(_first.convert(input));
-
- ChunkedConversionSink<S2> startChunkedConversion(Sink<T2> sink) {
- return _first.startChunkedConversion(_second.startChunkedConversion(sink));
- }
-}
diff --git a/sdk/lib/convert/codec.dart b/sdk/lib/convert/codec.dart
index 1afe63a..3fc2d31 100644
--- a/sdk/lib/convert/codec.dart
+++ b/sdk/lib/convert/codec.dart
@@ -84,8 +84,8 @@
final Codec<S, M> _first;
final Codec<M, T> _second;
- Converter<S, T> get encoder => _first.encoder.fuse(_second.encoder);
- Converter<T, S> get decoder => _second.decoder.fuse(_first.decoder);
+ Converter<S, T> get encoder => _first.encoder.fuse/*<T>*/(_second.encoder);
+ Converter<T, S> get decoder => _second.decoder.fuse/*<S>*/(_first.decoder);
_FusedCodec(this._first, this._second);
}
diff --git a/sdk/lib/convert/converter.dart b/sdk/lib/convert/converter.dart
index d6d9a9b..dfcfcdf 100644
--- a/sdk/lib/convert/converter.dart
+++ b/sdk/lib/convert/converter.dart
@@ -10,7 +10,7 @@
* It is recommended that implementations of `Converter` extend this class,
* to inherit any further methods that may be added to the class.
*/
-abstract class Converter<S, T> implements StreamTransformer {
+abstract class Converter<S, T> implements StreamTransformer/*<S, T>*/ {
const Converter();
/**
@@ -24,29 +24,24 @@
* Encoding with the resulting converter is equivalent to converting with
* `this` before converting with `other`.
*/
- Converter<S, dynamic> fuse(Converter<T, dynamic> other) {
- return new _FusedConverter<S, T, dynamic>(this, other);
+ Converter<S, dynamic/*=TT*/> fuse/*<TT>*/(
+ Converter<T, dynamic/*=TT*/> other) {
+ return new _FusedConverter<S, T, dynamic/*=TT*/>(this, other);
}
/**
- * Deprecated.
+ * Starts a chunked conversion.
*
- * Use the [ChunkedConverter] interface instead.
+ * The returned sink serves as input for the long-running conversion. The
+ * given [sink] serves as output.
*/
- @deprecated
- ChunkedConversionSink startChunkedConversion(Sink sink) {
+ Sink/*<S>*/ startChunkedConversion(Sink/*<T>*/ sink) {
throw new UnsupportedError(
"This converter does not support chunked conversions: $this");
}
- /**
- * Deprecated.
- *
- * Use the [ChunkedConverter] interface instead.
- */
- @deprecated
- Stream bind(Stream stream) {
- return new Stream.eventTransformed(
+ Stream/*<T>*/ bind(Stream/*<S>*/ stream) {
+ return new Stream/*<T>*/.eventTransformed(
stream,
(EventSink sink) => new _ConverterStreamEventSink(this, sink));
}
@@ -64,4 +59,8 @@
_FusedConverter(this._first, this._second);
T convert(S input) => _second.convert(_first.convert(input));
+
+ Sink/*<S>*/ startChunkedConversion(Sink/*<T>*/ sink) {
+ return _first.startChunkedConversion(_second.startChunkedConversion(sink));
+ }
}
diff --git a/sdk/lib/convert/encoding.dart b/sdk/lib/convert/encoding.dart
index fd6f91f..11ae300 100644
--- a/sdk/lib/convert/encoding.dart
+++ b/sdk/lib/convert/encoding.dart
@@ -10,8 +10,8 @@
abstract class Encoding extends Codec<String, List<int>> {
const Encoding();
- ChunkedConverter<String, List<int>, String, List<int>> get encoder;
- ChunkedConverter<List<int>, String, List<int>, String> get decoder;
+ Converter<String, List<int>> get encoder;
+ Converter<List<int>, String> get decoder;
Future<String> decodeStream(Stream<List<int>> byteStream) {
return byteStream
diff --git a/sdk/lib/convert/html_escape.dart b/sdk/lib/convert/html_escape.dart
index 7efe317..ff74442 100644
--- a/sdk/lib/convert/html_escape.dart
+++ b/sdk/lib/convert/html_escape.dart
@@ -152,7 +152,7 @@
* found to be easier to read if greater-than is also escaped whenever
* less-than is.
*/
-class HtmlEscape extends ChunkedConverter<String, String, String, String> {
+class HtmlEscape extends Converter<String, String> {
/** The [HtmlEscapeMode] used by the converter. */
final HtmlEscapeMode mode;
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index e80a986..24931df 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.dart
@@ -139,7 +139,7 @@
* If [toEncodable] is omitted, it defaults to a function that returns the
* result of calling `.toJson()` on the unencodable object.
*/
- String encode(Object value, {toEncodable(var object)}) {
+ String encode(Object value, {toEncodable(object)}) {
if (toEncodable == null) toEncodable = _toEncodable;
if (toEncodable == null) return encoder.convert(value);
return new JsonEncoder(toEncodable).convert(value);
@@ -159,7 +159,7 @@
/**
* This class converts JSON objects to strings.
*/
-class JsonEncoder extends ChunkedConverter<Object, String, Object, String> {
+class JsonEncoder extends Converter<Object, String> {
/**
* The string used for indention.
*
@@ -174,7 +174,7 @@
* Function called on non-encodable objects to return a replacement
* encodable object that will be encoded in the orignal's place.
*/
- final Function _toEncodable;
+ final _ToEncodable _toEncodable;
/**
* Creates a JSON encoder.
@@ -188,7 +188,7 @@
* If [toEncodable] is omitted, it defaults to calling `.toJson()` on
* the object.
*/
- const JsonEncoder([Object toEncodable(Object nonSerializable)])
+ const JsonEncoder([toEncodable(nonSerializable)])
: this.indent = null,
this._toEncodable = toEncodable;
@@ -210,8 +210,7 @@
* If [toEncodable] is omitted, it defaults to calling `.toJson()` on
* the object.
*/
- const JsonEncoder.withIndent(this.indent,
- [Object toEncodable(Object nonSerializable)])
+ const JsonEncoder.withIndent(this.indent, [toEncodable(nonSerializable)])
: this._toEncodable = toEncodable;
/**
@@ -268,11 +267,13 @@
// Override the base class's bind, to provide a better type.
Stream<String> bind(Stream<Object> stream) => super.bind(stream);
- Converter<Object, dynamic> fuse(Converter<String, dynamic> other) {
+ Converter<Object, dynamic/*=T*/> fuse/*<T>*/(
+ Converter<String, dynamic/*=T*/> other) {
if (other is Utf8Encoder) {
- return new JsonUtf8Encoder(indent, _toEncodable);
+ return new JsonUtf8Encoder(indent, _toEncodable)
+ as dynamic/*=Converter<Object, T>*/;
}
- return super.fuse(other);
+ return super.fuse/*<T>*/(other);
}
}
@@ -283,14 +284,13 @@
* a JSON string, and then UTF-8 encoding the string, but without
* creating an intermediate string.
*/
-class JsonUtf8Encoder extends
- ChunkedConverter<Object, List<int>, Object, List<int>> {
+class JsonUtf8Encoder extends Converter<Object, List<int>> {
/** Default buffer size used by the JSON-to-UTF-8 encoder. */
static const int DEFAULT_BUFFER_SIZE = 256;
/** Indentation used in pretty-print mode, `null` if not pretty. */
final List<int> _indent;
/** Function called with each un-encodable object encountered. */
- final Function _toEncodable;
+ final _ToEncodable _toEncodable;
/** UTF-8 buffer size. */
final int _bufferSize;
@@ -320,7 +320,7 @@
* object.
*/
JsonUtf8Encoder([String indent,
- toEncodable(Object object),
+ toEncodable(object),
int bufferSize = DEFAULT_BUFFER_SIZE])
: _indent = _utf8Encode(indent),
_toEncodable = toEncodable,
@@ -395,10 +395,6 @@
Stream<List<int>> bind(Stream<Object> stream) {
return super.bind(stream);
}
-
- Converter<Object, dynamic> fuse(Converter<List<int>, dynamic> other) {
- return super.fuse(other);
- }
}
/**
@@ -408,7 +404,7 @@
*/
class _JsonEncoderSink extends ChunkedConversionSink<Object> {
final String _indent;
- final Function _toEncodable;
+ final _ToEncodable _toEncodable;
final StringConversionSink _sink;
bool _isDone = false;
@@ -441,7 +437,7 @@
/** The byte sink receiveing the encoded chunks. */
final ByteConversionSink _sink;
final List<int> _indent;
- final Function _toEncodable;
+ final _ToEncodable _toEncodable;
final int _bufferSize;
bool _isDone = false;
_JsonUtf8EncoderSink(this._sink, this._toEncodable, this._indent,
@@ -474,7 +470,7 @@
/**
* This class parses JSON strings and builds the corresponding objects.
*/
-class JsonDecoder extends ChunkedConverter<String, Object, String, Object> {
+class JsonDecoder extends Converter<String, Object> {
final _Reviver _reviver;
/**
* Constructs a new JsonDecoder.
@@ -517,7 +513,7 @@
// Implementation of encoder/stringifier.
-Object _defaultToEncodable(object) => object.toJson();
+dynamic _defaultToEncodable(dynamic object) => object.toJson();
/**
* JSON encoder that traverses an object structure and writes JSON source.
@@ -545,11 +541,10 @@
/** List of objects currently being traversed. Used to detect cycles. */
final List _seen = new List();
/** Function called for each un-encodable object encountered. */
- final Function _toEncodable;
+ final _ToEncodable _toEncodable;
- _JsonStringifier(Object _toEncodable(Object o))
- : _toEncodable = (_toEncodable != null) ? _toEncodable
- : _defaultToEncodable;
+ _JsonStringifier(toEncodable(o))
+ : _toEncodable = toEncodable ?? _defaultToEncodable;
/** Append a string to the JSON output. */
void writeString(String characters);
@@ -719,7 +714,7 @@
}
/** Serialize a [Map]. */
- bool writeMap(Map<String, Object> map) {
+ bool writeMap(Map map) {
if (map.isEmpty) {
writeString("{}");
return true;
@@ -761,7 +756,7 @@
/**
* Add [indentLevel] indentations to the JSON output.
*/
- void writeIndentation(indentLevel);
+ void writeIndentation(int indentLevel);
void writeList(List list) {
if (list.isEmpty) {
@@ -838,7 +833,7 @@
* for each indentation level. It should only contain valid JSON whitespace
* characters (space, tab, carriage return or line feed).
*/
- static String stringify(object, toEncodable(object), String indent) {
+ static String stringify(object, toEncodable(o), String indent) {
StringBuffer output = new StringBuffer();
printOn(object, output, toEncodable, indent);
return output.toString();
@@ -849,8 +844,8 @@
*
* The result is written piecemally to the sink.
*/
- static void printOn(object, StringSink output, toEncodable(object),
- String indent) {
+ static void printOn(
+ object, StringSink output, toEncodable(o), String indent) {
var stringifier;
if (indent == null) {
stringifier = new _JsonStringStringifier(output, toEncodable);
@@ -879,8 +874,7 @@
with _JsonPrettyPrintMixin {
final String _indent;
- _JsonStringStringifierPretty(StringSink sink, Function toEncodable,
- this._indent)
+ _JsonStringStringifierPretty(StringSink sink, toEncodable(o), this._indent)
: super(sink, toEncodable);
void writeIndentation(int count) {
@@ -888,6 +882,8 @@
}
}
+typedef void _AddChunk(Uint8List list, int start, int end);
+
/**
* Specialization of [_JsonStringifier] that writes the JSON as UTF-8.
*
@@ -896,11 +892,11 @@
*/
class _JsonUtf8Stringifier extends _JsonStringifier {
final int bufferSize;
- final Function addChunk;
+ final _AddChunk addChunk;
Uint8List buffer;
int index = 0;
- _JsonUtf8Stringifier(toEncodable, int bufferSize, this.addChunk)
+ _JsonUtf8Stringifier(toEncodable(o), int bufferSize, this.addChunk)
: this.bufferSize = bufferSize,
buffer = new Uint8List(bufferSize),
super(toEncodable);
@@ -918,16 +914,15 @@
*/
static void stringify(Object object,
List<int> indent,
- toEncodableFunction(Object o),
+ toEncodable(o),
int bufferSize,
void addChunk(Uint8List chunk, int start, int end)) {
_JsonUtf8Stringifier stringifier;
if (indent != null) {
- stringifier = new _JsonUtf8StringifierPretty(toEncodableFunction, indent,
+ stringifier = new _JsonUtf8StringifierPretty(toEncodable, indent,
bufferSize, addChunk);
} else {
- stringifier = new _JsonUtf8Stringifier(toEncodableFunction,
- bufferSize, addChunk);
+ stringifier = new _JsonUtf8Stringifier(toEncodable, bufferSize, addChunk);
}
stringifier.writeObject(object);
stringifier.flush();
@@ -1037,9 +1032,10 @@
class _JsonUtf8StringifierPretty extends _JsonUtf8Stringifier
with _JsonPrettyPrintMixin {
final List<int> indent;
- _JsonUtf8StringifierPretty(toEncodableFunction, this.indent,
- bufferSize, addChunk)
- : super(toEncodableFunction, bufferSize, addChunk);
+ _JsonUtf8StringifierPretty(
+ toEncodable(o), this.indent,
+ bufferSize, void addChunk(Uint8List buffer, int start, int end))
+ : super(toEncodable, bufferSize, addChunk);
void writeIndentation(int count) {
List<int> indent = this.indent;
diff --git a/sdk/lib/convert/line_splitter.dart b/sdk/lib/convert/line_splitter.dart
index a9c9448..b728d8f 100644
--- a/sdk/lib/convert/line_splitter.dart
+++ b/sdk/lib/convert/line_splitter.dart
@@ -17,8 +17,9 @@
*
* The returned lines do not contain the line terminators.
*/
-class LineSplitter extends
- ChunkedConverter<String, List<String>, String, String> {
+class LineSplitter
+ extends Converter<String, List<String>>/*=Object*/
+ implements Object/*=StreamTransformer<String, String>*/ {
const LineSplitter();
@@ -80,6 +81,12 @@
}
return new _LineSplitterSink(sink);
}
+
+ Stream/*<String>*/ bind(Stream/*<String>*/ stream) {
+ return new Stream<String>.eventTransformed(
+ stream,
+ (EventSink<String> sink) => new _LineSplitterEventSink(sink));
+ }
}
// TODO(floitsch): deal with utf8.
@@ -157,3 +164,16 @@
}
}
}
+
+class _LineSplitterEventSink extends _LineSplitterSink
+ implements EventSink<String> {
+ final EventSink<String> _eventSink;
+
+ _LineSplitterEventSink(EventSink<String> eventSink)
+ : _eventSink = eventSink,
+ super(new StringConversionSink.from(eventSink));
+
+ void addError(Object o, [StackTrace stackTrace]) {
+ _eventSink.addError(o, stackTrace);
+ }
+}
diff --git a/sdk/lib/convert/string_conversion.dart b/sdk/lib/convert/string_conversion.dart
index bdfd39b..6eb27d9 100644
--- a/sdk/lib/convert/string_conversion.dart
+++ b/sdk/lib/convert/string_conversion.dart
@@ -17,8 +17,7 @@
* [StringConversionSinkMixin], to ensure that their class covers the newly
* added methods.
*/
-abstract class StringConversionSink
- extends ChunkedConversionSink<String> {
+abstract class StringConversionSink extends ChunkedConversionSink<String> {
StringConversionSink();
factory StringConversionSink.withCallback(void callback(String accumulated))
= _StringCallbackSink;
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index a93c9ae..69bb72c 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -76,8 +76,7 @@
* This class converts strings to their UTF-8 code units (a list of
* unsigned 8-bit integers).
*/
-class Utf8Encoder extends
- ChunkedConverter<String, List<int>, String, List<int>> {
+class Utf8Encoder extends Converter<String, List<int>> {
const Utf8Encoder();
@@ -305,8 +304,7 @@
* This class converts UTF-8 code units (lists of unsigned 8-bit integers)
* to a string.
*/
-class Utf8Decoder extends
- ChunkedConverter<List<int>, String, List<int>, String> {
+class Utf8Decoder extends Converter<List<int>, String> {
final bool _allowMalformed;
/**
@@ -369,7 +367,8 @@
// Override the base-classes bind, to provide a better type.
Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
- external Converter<List<int>,dynamic> fuse(Converter<String, dynamic> next);
+ external Converter<List<int>, dynamic/*=T*/> fuse/*<T>*/(
+ Converter<String, dynamic/*=T*/> next);
external static String _convertIntercepted(
bool allowMalformed, List<int> codeUnits, int start, int end);
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index b5614af..35e93e0 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -102,7 +102,7 @@
* the [intl](http://pub.dartlang.org/packages/intl) package.
*
*/
-class DateTime implements Comparable {
+class DateTime implements Comparable<DateTime> {
// Weekday constants that are returned by [weekday] method:
static const int MONDAY = 1;
static const int TUESDAY = 2;
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index fdc7727..0884d8f 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -149,7 +149,7 @@
* for non-negative (unsigned) values. Negative values are complemented to
* return the bit position of the first bit that differs from the sign bit.
*
- * To find the the number of bits needed to store the value as a signed value,
+ * To find the number of bits needed to store the value as a signed value,
* add one, i.e. use `x.bitLength + 1`.
*
* x.bitLength == (-x-1).bitLength
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index a1967b7..300b2ef 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -14,7 +14,7 @@
* the iterator has now moved to the next element,
* which is then available as [Iterator.current].
* If the call returns `false`, there are no more elements,
- * and `iterator.currrent` returns `null`.
+ * and `iterator.current` returns `null`.
*
* You can create more than one iterator from the same `Iterable`.
* Each time `iterator` is read, it returns a new iterator,
@@ -83,15 +83,16 @@
const Iterable();
/**
- * Creates an `Iterable` that generates its elements dynamically.
+ * Creates an `Iterable` which generates its elements dynamically.
*
- * An `Iterator` created by [iterator] will count from
- * zero to [:count - 1:], and call [generator]
- * with each index in turn to create the next value.
+ * The generated iterable has [count] elements,
+ * and the element at index `n` is computed by calling `generator(n)`.
+ * Values are not cached, so each iteration computes the values again.
*
* If [generator] is omitted, it defaults to an identity function
- * on integers `(int x) => x`, so it should only be omitted if the type
- * parameter allows integer values.
+ * on integers `(int x) => x`, so it may only be omitted if the type
+ * parameter allows integer values. That is, if [E] is one of
+ * `int`, `num`, `Object` or `dynamic`.
*
* As an `Iterable`, `new Iterable.generate(n, generator))` is equivalent to
* `const [0, ..., n - 1].map(generator)`.
@@ -146,7 +147,7 @@
* This method returns a view of the mapped elements. As long as the
* returned [Iterable] is not iterated over, the supplied function [f] will
* not be invoked. The transformed elements will not be cached. Iterating
- * multiple times over the the returned [Iterable] will invoke the supplied
+ * multiple times over the returned [Iterable] will invoke the supplied
* function [f] multiple times on the same element.
*
* Methods on the returned iterable are allowed to omit calling `f`
@@ -163,13 +164,14 @@
* The matching elements have the same order in the returned iterable
* as they have in [iterator].
*
- * This method returns a view of the mapped elements. As long as the
- * returned [Iterable] is not iterated over, the supplied function [test] will
- * not be invoked. Iterating will not cache results, and thus iterating
- * multiple times over the returned [Iterable] will invoke the supplied
+ * This method returns a view of the mapped elements.
+ * As long as the returned [Iterable] is not iterated over,
+ * the supplied function [test] will not be invoked.
+ * Iterating will not cache results, and thus iterating multiple times over
+ * the returned [Iterable] may invoke the supplied
* function [test] multiple times on the same element.
*/
- Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);
+ Iterable<E> where(bool test(E element)) => new WhereIterable<E>(this, test);
/**
* Expands each element of this [Iterable] into zero or more elements.
@@ -409,7 +411,7 @@
}
/**
- * Returns an Iterable that provides all but the first [count] elements.
+ * Returns an [Iterable] that provides all but the first [count] elements.
*
* When the returned iterable is iterated, it starts iterating over `this`,
* first skipping past the initial [count] elements.
@@ -418,23 +420,27 @@
* After that, the remaining elements are iterated in the same order as
* in this iterable.
*
- * The `count` must not be negative.
+ * Some iterables may be able to find later elements without first iterating
+ * through earlier elements, for example when iterating a [List].
+ * Such iterables are allowed to ignore the initial skipped elements.
+ *
+ * The [count] must not be negative.
*/
Iterable<E> skip(int count) {
return new SkipIterable<E>(this, count);
}
/**
- * Returns an Iterable that skips leading elements while [test] is satisfied.
+ * Returns an `Iterable` that skips leading elements while [test] is satisfied.
*
- * The filtering happens lazily. Every new Iterator of the returned
- * Iterable iterates over all elements of `this`.
+ * The filtering happens lazily. Every new [Iterator] of the returned
+ * iterable iterates over all elements of `this`.
*
* The returned iterable provides elements by iterating this iterable,
* but skipping over all initial elements where `test(element)` returns
* true. If all elements satisfy `test` the resulting iterable is empty,
* otherwise it iterates the remaining elements in their original order,
- * starting with the first element for which `test(element)` returns false,
+ * starting with the first element for which `test(element)` returns `false`.
*/
Iterable<E> skipWhile(bool test(E value)) {
return new SkipWhileIterable<E>(this, test);
@@ -493,7 +499,7 @@
/**
* Returns the first element that satisfies the given predicate [test].
*
- * Iterates through elements and returns the first to satsify [test].
+ * Iterates through elements and returns the first to satisfy [test].
*
* If no element satisfies [test], the result of invoking the [orElse]
* function is returned.
@@ -517,7 +523,7 @@
* checks `test(element)` for each,
* and finally returns that last one that matched.
*
- * If no element satsfies [test], the result of invoking the [orElse]
+ * If no element satisfies [test], the result of invoking the [orElse]
* function is returned.
* If [orElse] is omitted, it defaults to throwing a [StateError].
*/
@@ -602,72 +608,30 @@
typedef E _Generator<E>(int index);
-class _GeneratorIterable<E> extends Iterable<E>
- implements EfficientLength {
- final int _start;
- final int _end;
+class _GeneratorIterable<E> extends ListIterable<E> {
+ /// The length of the generated iterable.
+ final int length;
+
+ /// The function mapping indices to values.
final _Generator<E> _generator;
- /// Creates an iterable that builds the elements from a generator function.
+ /// Creates the generated iterable.
///
- /// The [generator] may be null, in which case the default generator
- /// enumerating the integer positions is used. This means that [int] must
- /// be assignable to [E] when no generator is provided. In practice this means
- /// that the generator can only be emitted when [E] is equal to `dynamic`,
- /// `int`, or `num`. The constructor will check that the types match.
- _GeneratorIterable(this._end, E generator(int n))
- : _start = 0,
- // The `as` below is used as check to make sure that `int` is assignable
+ /// If [generator] is `null`, it is checked that `int` is assignable to [E].
+ _GeneratorIterable(this.length, E generator(int index))
+ : // The `as` below is used as check to make sure that `int` is assignable
// to [E].
_generator = (generator != null) ? generator : _id as _Generator<E>;
- _GeneratorIterable.slice(this._start, this._end, this._generator);
-
- Iterator<E> get iterator =>
- new _GeneratorIterator<E>(_start, _end, _generator);
- int get length => _end - _start;
-
- Iterable<E> skip(int count) {
- RangeError.checkNotNegative(count, "count");
- if (count == 0) return this;
- int newStart = _start + count;
- if (newStart >= _end) return new EmptyIterable<E>();
- return new _GeneratorIterable<E>.slice(newStart, _end, _generator);
+ E elementAt(int index) {
+ RangeError.checkValidIndex(index, this);
+ return _generator(index);
}
- Iterable<E> take(int count) {
- RangeError.checkNotNegative(count, "count");
- if (count == 0) return new EmptyIterable<E>();
- int newEnd = _start + count;
- if (newEnd >= _end) return this;
- return new _GeneratorIterable<E>.slice(_start, newEnd, _generator);
- }
-
+ /// Helper function used as default _generator function.
static int _id(int n) => n;
}
-class _GeneratorIterator<E> implements Iterator<E> {
- final int _end;
- final _Generator<E> _generator;
- int _index;
- E _current;
-
- _GeneratorIterator(this._index, this._end, this._generator);
-
- bool moveNext() {
- if (_index < _end) {
- _current = _generator(_index);
- _index++;
- return true;
- } else {
- _current = null;
- return false;
- }
- }
-
- E get current => _current;
-}
-
/**
* An Iterator that allows moving backwards as well as forwards.
*/
diff --git a/sdk/lib/core/set.dart b/sdk/lib/core/set.dart
index 984c416..7e2508c 100644
--- a/sdk/lib/core/set.dart
+++ b/sdk/lib/core/set.dart
@@ -180,7 +180,7 @@
Set<E> union(Set<E> other);
/**
- * Returns a new set with the the elements of this that are not in [other].
+ * Returns a new set with the elements of this that are not in [other].
*
* That is, the returned set contains all the elements of this [Set] that
* are not elements of [other] according to `other.contains`.
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 0cfeceb..1d35106 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -3198,7 +3198,7 @@
/**
* A map representing the parameters of the media type.
*
- * A data URI may contain parameters between the the MIME type and the
+ * A data URI may contain parameters between the MIME type and the
* data. This converts these parameters to a map from parameter name
* to parameter value.
* The map only contains parameters that actually occur in the URI.
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index fbdad8b..b6118af 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -23,6 +23,11 @@
'name',
'Must be a String');
}
+ 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) {
block._appendArguments(arguments);
@@ -41,6 +46,10 @@
}
// Pop top item off of stack.
var block = _stack.removeLast();
+ if (block == null) {
+ // Dart stream was disabled when startSync was called.
+ return;
+ }
// Finish it.
block.finish();
}
@@ -55,6 +64,10 @@
'name',
'Must be a String');
}
+ if (!_isDartStreamEnabled()) {
+ // Stream is disabled.
+ return;
+ }
Map instantArguments;
if (arguments is Map) {
instantArguments = new Map.from(arguments);
@@ -278,6 +291,9 @@
return JSON.encode(arguments);
}
+/// Returns true if the Dart Timeline stream is enabled.
+external bool _isDartStreamEnabled();
+
/// Returns the next async task id.
external int _getNextAsyncId();
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 7be7e5d..0bc3749 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -105,12 +105,6 @@
HtmlElement.created() : super.created();
}
-// EntryArray type was removed, so explicitly adding it to allow support for
-// older Chrome versions.
-// Issue #12573.
-@Native("EntryArray")
-abstract class _EntryArray implements List<Entry> {}
-
/**
* Spawn a DOM isolate using the given URI in the same window.
* This isolate is not concurrent. It runs on the browser thread
@@ -11639,17 +11633,27 @@
@DocsEditable()
@DomName('DOMStringMap')
-abstract class DomStringMap extends Interceptor {
+@Native("DOMStringMap")
+class DomStringMap extends Interceptor {
// To suppress missing implicit constructor warnings.
factory DomStringMap._() { throw new UnsupportedError("Not supported"); }
- void __delete__(index_OR_name);
+ @DomName('DOMStringMap.__delete__')
+ @DocsEditable()
+ void __delete__(index_OR_name) native;
- String __getter__(int index);
+ @DomName('DOMStringMap.__getter__')
+ @DocsEditable()
+ String __getter__(int index) native;
- void __setter__(index_OR_name, String value);
+ @DomName('DOMStringMap.__setter__')
+ @DocsEditable()
+ void __setter__(index_OR_name, String value) native;
- String item(String name);
+ @DomName('DOMStringMap.item')
+ @DocsEditable()
+ @Experimental() // untriaged
+ String item(String name) native;
}
// 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
@@ -16852,7 +16856,7 @@
@DocsEditable()
@DomName('FileList')
@Native("FileList")
-class FileList extends Interceptor with ListMixin<File>, ImmutableListMixin<File> implements JavaScriptIndexingBehavior, List<File> {
+class FileList extends Interceptor with ListMixin<File>, ImmutableListMixin<File> implements List<File>, JavaScriptIndexingBehavior<File> {
// To suppress missing implicit constructor warnings.
factory FileList._() { throw new UnsupportedError("Not supported"); }
@@ -18887,7 +18891,7 @@
@DocsEditable()
@DomName('HTMLCollection')
@Native("HTMLCollection")
-class HtmlCollection extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior, List<Node> {
+class HtmlCollection extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior<Node>, List<Node> {
// To suppress missing implicit constructor warnings.
factory HtmlCollection._() { throw new UnsupportedError("Not supported"); }
@@ -23801,7 +23805,7 @@
@DomName('MimeTypeArray')
@Experimental() // non-standard
@Native("MimeTypeArray")
-class MimeTypeArray extends Interceptor with ListMixin<MimeType>, ImmutableListMixin<MimeType> implements JavaScriptIndexingBehavior, List<MimeType> {
+class MimeTypeArray extends Interceptor with ListMixin<MimeType>, ImmutableListMixin<MimeType> implements List<MimeType>, JavaScriptIndexingBehavior<MimeType> {
// To suppress missing implicit constructor warnings.
factory MimeTypeArray._() { throw new UnsupportedError("Not supported"); }
@@ -25434,7 +25438,7 @@
@DocsEditable()
@DomName('NodeList')
@Native("NodeList,RadioNodeList")
-class NodeList extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior, List<Node> {
+class NodeList extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior<Node>, List<Node> {
// To suppress missing implicit constructor warnings.
factory NodeList._() { throw new UnsupportedError("Not supported"); }
@@ -26938,7 +26942,7 @@
@DomName('PluginArray')
@Experimental() // non-standard
@Native("PluginArray")
-class PluginArray extends Interceptor with ListMixin<Plugin>, ImmutableListMixin<Plugin> implements JavaScriptIndexingBehavior, List<Plugin> {
+class PluginArray extends Interceptor with ListMixin<Plugin>, ImmutableListMixin<Plugin> implements JavaScriptIndexingBehavior<Plugin>, List<Plugin> {
// To suppress missing implicit constructor warnings.
factory PluginArray._() { throw new UnsupportedError("Not supported"); }
@@ -28031,24 +28035,6 @@
@DocsEditable()
-@DomName('ResourceProgressEvent')
-// https://chromiumcodereview.appspot.com/14773025/
-@deprecated // experimental
-@Native("ResourceProgressEvent")
-class ResourceProgressEvent extends ProgressEvent {
- // To suppress missing implicit constructor warnings.
- factory ResourceProgressEvent._() { throw new UnsupportedError("Not supported"); }
-
- @DomName('ResourceProgressEvent.url')
- @DocsEditable()
- final String url;
-}
-// 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.
-
-
-@DocsEditable()
@DomName('RTCDataChannel')
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannel
@Experimental()
@@ -28358,7 +28344,7 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@Experimental()
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCPeerConnection
-@Native("RTCPeerConnection,mozRTCPeerConnection")
+@Native("RTCPeerConnection,webkitRTCPeerConnection,mozRTCPeerConnection")
class RtcPeerConnection extends EventTarget {
factory RtcPeerConnection(Map rtcIceServers, [Map mediaConstraints]) {
var constructorName = JS('RtcPeerConnection', 'window[#]',
@@ -30176,7 +30162,7 @@
// https://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html#sourcebufferlist
@Experimental()
@Native("SourceBufferList")
-class SourceBufferList extends EventTarget with ListMixin<SourceBuffer>, ImmutableListMixin<SourceBuffer> implements JavaScriptIndexingBehavior, List<SourceBuffer> {
+class SourceBufferList extends EventTarget with ListMixin<SourceBuffer>, ImmutableListMixin<SourceBuffer> implements JavaScriptIndexingBehavior<SourceBuffer>, List<SourceBuffer> {
// To suppress missing implicit constructor warnings.
factory SourceBufferList._() { throw new UnsupportedError("Not supported"); }
@@ -30370,7 +30356,7 @@
// https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html#dfn-speechgrammarlist
@Experimental()
@Native("SpeechGrammarList")
-class SpeechGrammarList extends Interceptor with ListMixin<SpeechGrammar>, ImmutableListMixin<SpeechGrammar> implements JavaScriptIndexingBehavior, List<SpeechGrammar> {
+class SpeechGrammarList extends Interceptor with ListMixin<SpeechGrammar>, ImmutableListMixin<SpeechGrammar> implements JavaScriptIndexingBehavior<SpeechGrammar>, List<SpeechGrammar> {
// To suppress missing implicit constructor warnings.
factory SpeechGrammarList._() { throw new UnsupportedError("Not supported"); }
@@ -32451,7 +32437,7 @@
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#texttrackcuelist
@Experimental()
@Native("TextTrackCueList")
-class TextTrackCueList extends Interceptor with ListMixin<TextTrackCue>, ImmutableListMixin<TextTrackCue> implements List<TextTrackCue>, JavaScriptIndexingBehavior {
+class TextTrackCueList extends Interceptor with ListMixin<TextTrackCue>, ImmutableListMixin<TextTrackCue> implements List<TextTrackCue>, JavaScriptIndexingBehavior<TextTrackCue> {
// To suppress missing implicit constructor warnings.
factory TextTrackCueList._() { throw new UnsupportedError("Not supported"); }
@@ -32521,7 +32507,7 @@
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#texttracklist
@Experimental()
@Native("TextTrackList")
-class TextTrackList extends EventTarget with ListMixin<TextTrack>, ImmutableListMixin<TextTrack> implements JavaScriptIndexingBehavior, List<TextTrack> {
+class TextTrackList extends EventTarget with ListMixin<TextTrack>, ImmutableListMixin<TextTrack> implements List<TextTrack>, JavaScriptIndexingBehavior<TextTrack> {
// To suppress missing implicit constructor warnings.
factory TextTrackList._() { throw new UnsupportedError("Not supported"); }
@@ -32863,7 +32849,7 @@
// http://www.w3.org/TR/touch-events/, http://www.chromestatus.com/features
@Experimental()
@Native("TouchList")
-class TouchList extends Interceptor with ListMixin<Touch>, ImmutableListMixin<Touch> implements JavaScriptIndexingBehavior, List<Touch> {
+class TouchList extends Interceptor with ListMixin<Touch>, ImmutableListMixin<Touch> implements JavaScriptIndexingBehavior<Touch>, List<Touch> {
/// NB: This constructor likely does not work as you might expect it to! This
/// constructor will simply fail (returning null) if you are not on a device
/// with touch enabled. See dartbug.com/8314.
@@ -36553,7 +36539,9 @@
const _BeforeUnloadEventStreamProvider(this._eventType);
Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
- var stream = new _EventStream(e, _eventType, useCapture);
+ // Specify the generic type for EventStream only in dart2js to avoid
+ // checked mode errors in dartium.
+ var stream = new _EventStream<BeforeUnloadEvent>(e, _eventType, useCapture);
var controller = new StreamController<BeforeUnloadEvent>(sync: true);
stream.listen((event) {
@@ -36569,12 +36557,16 @@
}
ElementStream<BeforeUnloadEvent> forElement(Element e, {bool useCapture: false}) {
- return new _ElementEventStreamImpl(e, _eventType, useCapture);
+ // Specify the generic type for _ElementEventStreamImpl only in dart2js to
+ // avoid checked mode errors in dartium.
+ return new _ElementEventStreamImpl<BeforeUnloadEvent>(e, _eventType, useCapture);
}
ElementStream<BeforeUnloadEvent> _forElementList(ElementList e,
{bool useCapture: false}) {
- return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+ // Specify the generic type for _ElementEventStreamImpl only in dart2js to
+ // avoid checked mode errors in dartium.
+ return new _ElementListEventStreamImpl<BeforeUnloadEvent>(e, _eventType, useCapture);
}
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -37642,7 +37634,7 @@
@DocsEditable()
@DomName('CSSRuleList')
@Native("CSSRuleList")
-class _CssRuleList extends Interceptor with ListMixin<CssRule>, ImmutableListMixin<CssRule> implements JavaScriptIndexingBehavior, List<CssRule> {
+class _CssRuleList extends Interceptor with ListMixin<CssRule>, ImmutableListMixin<CssRule> implements JavaScriptIndexingBehavior<CssRule>, List<CssRule> {
// To suppress missing implicit constructor warnings.
factory _CssRuleList._() { throw new UnsupportedError("Not supported"); }
@@ -37896,7 +37888,7 @@
// https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html
@Experimental()
@Native("GamepadList")
-class _GamepadList extends Interceptor with ListMixin<Gamepad>, ImmutableListMixin<Gamepad> implements JavaScriptIndexingBehavior, List<Gamepad> {
+class _GamepadList extends Interceptor with ListMixin<Gamepad>, ImmutableListMixin<Gamepad> implements List<Gamepad>, JavaScriptIndexingBehavior<Gamepad> {
// To suppress missing implicit constructor warnings.
factory _GamepadList._() { throw new UnsupportedError("Not supported"); }
@@ -38103,7 +38095,7 @@
// http://dom.spec.whatwg.org/#namednodemap
@deprecated // deprecated
@Native("NamedNodeMap,MozNamedAttrMap")
-class _NamedNodeMap extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior, List<Node> {
+class _NamedNodeMap extends Interceptor with ListMixin<Node>, ImmutableListMixin<Node> implements JavaScriptIndexingBehavior<Node>, List<Node> {
// To suppress missing implicit constructor warnings.
factory _NamedNodeMap._() { throw new UnsupportedError("Not supported"); }
@@ -38271,6 +38263,20 @@
@DocsEditable()
+@DomName('ResourceProgressEvent')
+// https://chromiumcodereview.appspot.com/14773025/
+@deprecated // experimental
+@Native("ResourceProgressEvent")
+abstract class _ResourceProgressEvent extends ProgressEvent {
+ // To suppress missing implicit constructor warnings.
+ factory _ResourceProgressEvent._() { throw new UnsupportedError("Not supported"); }
+}
+// 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.
+
+
+@DocsEditable()
@DomName('Response')
@Experimental() // untriaged
@Native("Response")
@@ -38319,7 +38325,7 @@
// https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html#speechrecognitionresultlist
@Experimental()
@Native("SpeechRecognitionResultList")
-class _SpeechRecognitionResultList extends Interceptor with ListMixin<SpeechRecognitionResult>, ImmutableListMixin<SpeechRecognitionResult> implements JavaScriptIndexingBehavior, List<SpeechRecognitionResult> {
+class _SpeechRecognitionResultList extends Interceptor with ListMixin<SpeechRecognitionResult>, ImmutableListMixin<SpeechRecognitionResult> implements JavaScriptIndexingBehavior<SpeechRecognitionResult>, List<SpeechRecognitionResult> {
// To suppress missing implicit constructor warnings.
factory _SpeechRecognitionResultList._() { throw new UnsupportedError("Not supported"); }
@@ -38383,7 +38389,7 @@
@DocsEditable()
@DomName('StyleSheetList')
@Native("StyleSheetList")
-class _StyleSheetList extends Interceptor with ListMixin<StyleSheet>, ImmutableListMixin<StyleSheet> implements JavaScriptIndexingBehavior, List<StyleSheet> {
+class _StyleSheetList extends Interceptor with ListMixin<StyleSheet>, ImmutableListMixin<StyleSheet> implements List<StyleSheet>, JavaScriptIndexingBehavior<StyleSheet> {
// To suppress missing implicit constructor warnings.
factory _StyleSheetList._() { throw new UnsupportedError("Not supported"); }
@@ -39916,7 +39922,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
ElementStream<T> _forElementList(ElementList e, {bool useCapture: false}) {
- return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+ return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
}
/**
@@ -40134,9 +40140,9 @@
}
}
- Future asFuture([var futureValue]) {
+ Future/*<E>*/ asFuture/*<E>*/([var/*=E*/ futureValue]) {
// We just need a future that will never succeed or fail.
- Completer completer = new Completer();
+ var completer = new Completer/*<E>*/();
return completer.future;
}
}
@@ -42512,7 +42518,7 @@
// Iterable APIs
- Iterator<E> get iterator => new _WrappedIterator(_list.iterator);
+ Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
int get length => _list.length;
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 6d8873e..bc92d6d 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -474,7 +474,7 @@
'ReadableStreamReader': () => ReadableStreamReader.instanceRuntimeType,
'RelatedEvent': () => RelatedEvent.instanceRuntimeType,
'Request': () => _Request.instanceRuntimeType,
- 'ResourceProgressEvent': () => ResourceProgressEvent.instanceRuntimeType,
+ 'ResourceProgressEvent': () => _ResourceProgressEvent.instanceRuntimeType,
'Response': () => _Response.instanceRuntimeType,
'Screen': () => Screen.instanceRuntimeType,
'ScreenOrientation': () => ScreenOrientation.instanceRuntimeType,
@@ -12308,6 +12308,13 @@
// To suppress missing implicit constructor warnings.
factory DomStringMap._() { throw new UnsupportedError("Not supported"); }
+
+ @Deprecated("Internal Use Only")
+ external static Type get instanceRuntimeType;
+
+ @Deprecated("Internal Use Only")
+ DomStringMap.internal_() { }
+
void __delete__(index_OR_name) {
if ((index_OR_name is String || index_OR_name == null)) {
_blink.BlinkDOMStringMap.instance.$__delete___Callback_1_(this, index_OR_name);
@@ -12322,8 +12329,8 @@
@DomName('DOMStringMap.__getter__')
@DocsEditable()
- String __getter__(int index);
-
+ String __getter__(int index) => _blink.BlinkDOMStringMap.instance.$__getter___Callback_1_(this, index);
+
void __setter__(index_OR_name, String value) {
if ((value is String || value == null) && (index_OR_name is String || index_OR_name == null)) {
_blink.BlinkDOMStringMap.instance.$__setter___Callback_2_(this, index_OR_name, value);
@@ -12339,8 +12346,8 @@
@DomName('DOMStringMap.item')
@DocsEditable()
@Experimental() // untriaged
- String item(String name);
-
+ String item(String name) => _blink.BlinkDOMStringMap.instance.item_Callback_1_(this, name);
+
}
// 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
@@ -31455,34 +31462,6 @@
@DocsEditable()
-@DomName('ResourceProgressEvent')
-// https://chromiumcodereview.appspot.com/14773025/
-@deprecated // experimental
-class ResourceProgressEvent extends ProgressEvent {
- // To suppress missing implicit constructor warnings.
- factory ResourceProgressEvent._() { throw new UnsupportedError("Not supported"); }
-
-
- @Deprecated("Internal Use Only")
- external static Type get instanceRuntimeType;
-
- @Deprecated("Internal Use Only")
- ResourceProgressEvent.internal_() : super.internal_();
-
-
- @DomName('ResourceProgressEvent.url')
- @DocsEditable()
- String get url => _blink.BlinkResourceProgressEvent.instance.url_Getter_(this);
-
-}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable()
@DomName('RTCDataChannel')
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannel
@Experimental()
@@ -37683,10 +37662,10 @@
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaSource)) {
+ if ((blob_OR_source_OR_stream is MediaStream)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
- if ((blob_OR_source_OR_stream is MediaStream)) {
+ if ((blob_OR_source_OR_stream is MediaSource)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
throw new ArgumentError("Incorrect number or type of arguments");
@@ -42851,6 +42830,30 @@
@DocsEditable()
+@DomName('ResourceProgressEvent')
+// https://chromiumcodereview.appspot.com/14773025/
+@deprecated // experimental
+class _ResourceProgressEvent extends ProgressEvent {
+ // To suppress missing implicit constructor warnings.
+ factory _ResourceProgressEvent._() { throw new UnsupportedError("Not supported"); }
+
+
+ @Deprecated("Internal Use Only")
+ external static Type get instanceRuntimeType;
+
+ @Deprecated("Internal Use Only")
+ _ResourceProgressEvent.internal_() : super.internal_();
+
+
+}
+// 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.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable()
@DomName('Response')
@Experimental() // untriaged
class _Response extends Body {
@@ -44447,7 +44450,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
ElementStream<T> _forElementList(ElementList e, {bool useCapture: false}) {
- return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+ return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
}
/**
@@ -44665,9 +44668,9 @@
}
}
- Future asFuture([var futureValue]) {
+ Future/*<E>*/ asFuture/*<E>*/([var/*=E*/ futureValue]) {
// We just need a future that will never succeed or fail.
- Completer completer = new Completer();
+ var completer = new Completer/*<E>*/();
return completer.future;
}
}
@@ -47349,7 +47352,7 @@
// Iterable APIs
- Iterator<E> get iterator => new _WrappedIterator(_list.iterator);
+ Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
int get length => _list.length;
diff --git a/sdk/lib/io/bytes_builder.dart b/sdk/lib/io/bytes_builder.dart
index a4b611f..0c97748 100644
--- a/sdk/lib/io/bytes_builder.dart
+++ b/sdk/lib/io/bytes_builder.dart
@@ -45,7 +45,7 @@
/**
* Returns the contents of `this` and clears `this`.
*
- * The list returned is a view of the the internal buffer, limited to the
+ * The list returned is a view of the internal buffer, limited to the
* [length].
*/
List<int> takeBytes();
@@ -153,14 +153,17 @@
class _BytesBuilder implements BytesBuilder {
int _length = 0;
- final _chunks = <List<int>>[];
+ final List<Uint8List> _chunks = [];
void add(List<int> bytes) {
- if (bytes is! Uint8List) {
+ Uint8List typedBytes;
+ if (bytes is Uint8List) {
+ typedBytes = bytes;
+ } else {
bytes = new Uint8List.fromList(bytes);
}
- _chunks.add(bytes);
- _length += bytes.length;
+ _chunks.add(typedBytes);
+ _length += typedBytes.length;
}
void addByte(int byte) { add([byte]); }
diff --git a/sdk/lib/io/common.dart b/sdk/lib/io/common.dart
index ea35580..6258bcf 100644
--- a/sdk/lib/io/common.dart
+++ b/sdk/lib/io/common.dart
@@ -90,7 +90,7 @@
// Object for holding a buffer and an offset.
class _BufferAndStart {
- List buffer;
+ List<int> buffer;
int start;
_BufferAndStart(this.buffer, this.start);
}
@@ -100,7 +100,7 @@
// All other lists are first copied into a Uint8List. This has the added
// benefit that it is faster to access from the C code as well.
_BufferAndStart _ensureFastAndSerializableByteData(
- List buffer, int start, int end) {
+ List<int> buffer, int start, int end) {
if (buffer is Uint8List || buffer is Int8List) {
return new _BufferAndStart(buffer, start);
}
diff --git a/sdk/lib/io/crypto.dart b/sdk/lib/io/crypto.dart
index 82cff5e..96e4bd14 100644
--- a/sdk/lib/io/crypto.dart
+++ b/sdk/lib/io/crypto.dart
@@ -234,8 +234,8 @@
// Compute the final result as a list of bytes from the hash words.
- _resultAsBytes() {
- var result = [];
+ List<int> _resultAsBytes() {
+ var result = <int>[];
for (var i = 0; i < _h.length; i++) {
result.addAll(_wordToBytes(_h[i]));
}
@@ -261,7 +261,7 @@
}
// Convert a 32-bit word to four bytes.
- _wordToBytes(int word) {
+ List<int> _wordToBytes(int word) {
List<int> bytes = new List(_BYTES_PER_WORD);
bytes[0] = (word >> (_bigEndianWords ? 24 : 0)) & _MASK_8;
bytes[1] = (word >> (_bigEndianWords ? 16 : 8)) & _MASK_8;
diff --git a/sdk/lib/io/data_transformer.dart b/sdk/lib/io/data_transformer.dart
index 12d623a..6a50af4 100644
--- a/sdk/lib/io/data_transformer.dart
+++ b/sdk/lib/io/data_transformer.dart
@@ -275,8 +275,7 @@
* The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress
* data.
*/
-class ZLibEncoder extends
- ChunkedConverter<List<int>, List<int>, List<int>, List<int>> {
+class ZLibEncoder extends Converter<List<int>, List<int>> {
/**
* When true, `GZip` frames will be added to the compressed data.
*/
@@ -379,8 +378,7 @@
/**
* The [ZLibDecoder] is used by [ZLibCodec] and [GZipCodec] to decompress data.
*/
-class ZLibDecoder extends
- ChunkedConverter<List<int>, List<int>, List<int>, List<int>> {
+class ZLibDecoder extends Converter<List<int>, List<int>> {
/**
* Base two logarithm of the window size (the size of the history buffer). It
* should be in the range `8..15`. Larger values result in better compression
@@ -494,7 +492,7 @@
_filter.process(bufferAndStart.buffer,
bufferAndStart.start,
end - (start - bufferAndStart.start));
- var out;
+ List<int> out;
while ((out = _filter.processed(flush: false)) != null) {
_sink.add(out);
}
@@ -512,7 +510,7 @@
// message would not have a GZip frame (if compressed with GZip).
if (_empty) _filter.process(const [], 0, 0);
try {
- var out;
+ List<int> out;
while ((out = _filter.processed(end: true)) != null) {
_sink.add(out);
}
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index 2ff3928..e890fcf 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -160,7 +160,7 @@
* resolved by the OS.
*
* Note that setting the current working directory is a synchronous
- * operation and that it changes the the working directory of *all*
+ * operation and that it changes the working directory of *all*
* isolates.
*
* Use this with care - especially when working with asynchronous
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index d76b86d..c1fc540 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -22,7 +22,9 @@
external static _create(String path);
external static _deleteNative(String path, bool recursive);
external static _rename(String path, String newPath);
- external static List _list(String path, bool recursive, bool followLinks);
+ external static void _fillWithDirectoryListing(
+ List<FileSystemEntity> list, String path, bool recursive,
+ bool followLinks);
static Directory get current {
var result = _current();
@@ -70,30 +72,6 @@
FileStat statSync() => FileStat.statSync(path);
- // Compute the index of the first directory in the list that exists. If
- // none of the directories exist dirsToCreate.length is returned.
- Future<int> _computeExistingIndex(List dirsToCreate) {
- var future;
- var notFound = dirsToCreate.length;
- for (var i = 0; i < dirsToCreate.length; i++) {
- if (future == null) {
- future = dirsToCreate[i].exists().then((e) => e ? i : notFound);
- } else {
- future = future.then((index) {
- if (index != notFound) {
- return new Future.value(index);
- }
- return dirsToCreate[i].exists().then((e) => e ? i : notFound);
- });
- }
- }
- if (future == null) {
- return new Future.value(notFound);
- } else {
- return future;
- }
- }
-
Future<Directory> create({bool recursive: false}) {
if (recursive) {
return exists().then((exists) {
@@ -222,14 +200,18 @@
followLinks).stream;
}
- List listSync({bool recursive: false, bool followLinks: true}) {
+ List<FileSystemEntity> listSync(
+ {bool recursive: false, bool followLinks: true}) {
if (recursive is! bool || followLinks is! bool) {
throw new ArgumentError();
}
- return _list(
+ var result = <FileSystemEntity>[];
+ _fillWithDirectoryListing(
+ result,
FileSystemEntity._ensureTrailingPathSeparators(path),
recursive,
followLinks);
+ return result;
}
String toString() => "Directory: '$path'";
@@ -274,7 +256,7 @@
final bool recursive;
final bool followLinks;
- StreamController controller;
+ StreamController<FileSystemEntity> controller;
bool canceled = false;
bool nextRunning = false;
bool closed = false;
@@ -282,10 +264,10 @@
Completer closeCompleter = new Completer();
_AsyncDirectoryLister(this.path, this.recursive, this.followLinks) {
- controller = new StreamController(onListen: onListen,
- onResume: onResume,
- onCancel: onCancel,
- sync: true);
+ controller = new StreamController<FileSystemEntity>(onListen: onListen,
+ onResume: onResume,
+ onCancel: onCancel,
+ sync: true);
}
// Calling this function will increase the reference count on the native
@@ -296,7 +278,7 @@
return (_ops == null) ? null : _ops.getPointer();
}
- Stream get stream => controller.stream;
+ Stream<FileSystemEntity> get stream => controller.stream;
void onListen() {
_IOService._dispatch(_DIRECTORY_LIST_START, [path, recursive, followLinks])
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index a6fdde8..bb00477 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -213,7 +213,7 @@
}
Future<File> close() =>
- _openFuture.then((openedFile) => openedFile.close());
+ _openFuture.then/*<File>*/((openedFile) => openedFile.close());
}
@@ -441,9 +441,9 @@
}
Future<List<int>> readAsBytes() {
- Future<List<int>> readDataChunked(file) {
+ Future<List<int>> readDataChunked(RandomAccessFile file) {
var builder = new BytesBuilder(copy: false);
- var completer = new Completer();
+ var completer = new Completer<List<int>>();
void read() {
file.read(_BLOCK_SIZE).then((data) {
if (data.length > 0) {
@@ -472,7 +472,7 @@
List<int> readAsBytesSync() {
var opened = openSync();
try {
- var data;
+ List<int> data;
var length = opened.lengthSync();
if (length == 0) {
// May be character device, try to read it in chunks.
@@ -670,7 +670,7 @@
throw _exceptionFromResponse(response, "read failed", path);
}
_resourceInfo.addRead(response[1].length);
- return response[1];
+ return response[1] as Object/*=List<int>*/;
});
}
@@ -684,7 +684,7 @@
throw new FileSystemException("readSync failed", path, result);
}
_resourceInfo.addRead(result.length);
- return result;
+ return result as Object/*=List<int>*/;
}
Future<int> readInto(List<int> buffer, [int start = 0, int end]) {
@@ -703,7 +703,7 @@
throw _exceptionFromResponse(response, "readInto failed", path);
}
var read = response[1];
- var data = response[2];
+ var data = response[2] as Object/*=List<int>*/;
buffer.setRange(start, start + read, data);
_resourceInfo.addRead(read);
return read;
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index c63d28b..07257ea 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -1660,7 +1660,7 @@
*
* If a bad certificate is received on a connection attempt, the library calls
* the function that was the value of badCertificateCallback at the time
- * the the request is made, even if the value of badCertificateCallback
+ * the request is made, even if the value of badCertificateCallback
* has changed since then.
*/
set badCertificateCallback(bool callback(X509Certificate cert,
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 846b724..96005c95 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -6,6 +6,8 @@
const int _OUTGOING_BUFFER_SIZE = 8 * 1024;
+typedef void _BytesConsumer(List<int> bytes);
+
class _HttpIncoming extends Stream<List<int>> {
final int _transferLength;
final Completer _dataCompleter = new Completer();
@@ -129,13 +131,14 @@
var proto = headers['x-forwarded-proto'];
var scheme = proto != null ? proto.first :
_httpConnection._socket is SecureSocket ? "https" : "http";
- var host = headers['x-forwarded-host'];
- if (host != null) {
- host = host.first;
+ var hostList = headers['x-forwarded-host'];
+ String host;
+ if (hostList != null) {
+ host = hostList.first;
} else {
- host = headers['host'];
- if (host != null) {
- host = host.first;
+ hostList = headers['host'];
+ if (hostList != null) {
+ host = hostList.first;
} else {
host = "${_httpServer.address.host}:${_httpServer.port}";
}
@@ -182,8 +185,6 @@
// The HttpClientRequest of this response.
final _HttpClientRequest _httpRequest;
- List<Cookie> _cookies;
-
_HttpClientResponse(_HttpIncoming _incoming, this._httpRequest,
this._httpClient) : super(_incoming) {
// Set uri for potential exceptions.
@@ -194,9 +195,9 @@
String get reasonPhrase => _incoming.reasonPhrase;
X509Certificate get certificate {
- // The peerCertificate isn't on a plain socket, so cast to dynamic.
var socket = _httpRequest._httpClientConnection._socket;
- return socket.peerCertificate;
+ if (socket is SecureSocket) return socket.peerCertificate;
+ throw new UnsupportedError("Socket is not a SecureSocket");
}
List<Cookie> get cookies {
@@ -267,7 +268,7 @@
// Since listening to upgraded data is 'bogus', simply close and
// return empty stream subscription.
_httpRequest._httpClientConnection.destroy();
- return new Stream.fromIterable([]).listen(null, onDone: onDone);
+ return new Stream<List<int>>.empty().listen(null, onDone: onDone);
}
var stream = _incoming;
if (_httpClient.autoUncompress &&
@@ -762,13 +763,16 @@
if (followRedirects && response.isRedirect) {
if (response.redirects.length < maxRedirects) {
// Redirect and drain response.
- future = response.drain().then((_) => response.redirect());
+ future = response.drain()
+ .then/*<HttpClientResponse>*/((_) => response.redirect());
} else {
// End with exception, too many redirects.
future = response.drain()
- .then((_) => new Future.error(
- new RedirectException("Redirect limit exceeded",
- response.redirects)));
+ .then/*<HttpClientResponse>*/((_) {
+ return new Future<HttpClientResponse>.error(
+ new RedirectException("Redirect limit exceeded",
+ response.redirects));
+ });
}
} else if (response._shouldAuthenticateProxy) {
future = response._authenticate(true);
@@ -862,15 +866,19 @@
// Used by _HttpOutgoing as a target of a chunked converter for gzip
// compression.
class _HttpGZipSink extends ByteConversionSink {
- final Function _consume;
+ final _BytesConsumer _consume;
_HttpGZipSink(this._consume);
void add(List<int> chunk) {
_consume(chunk);
}
- void addSlice(Uint8List chunk, int start, int end, bool isLast) {
- _consume(new Uint8List.view(chunk.buffer, start, end - start));
+ void addSlice(List<int> chunk, int start, int end, bool isLast) {
+ if (chunk is Uint8List) {
+ _consume(new Uint8List.view(chunk.buffer, start, end - start));
+ } else {
+ _consume(chunk.sublist(start, end - start));
+ }
}
void close() {}
@@ -893,7 +901,7 @@
static const List<int> _chunk0Length =
const [0x30, _CharCode.CR, _CharCode.LF, _CharCode.CR, _CharCode.LF];
- final Completer _doneCompleter = new Completer();
+ final Completer<Socket> _doneCompleter = new Completer<Socket>();
final Socket socket;
bool ignoreBody = false;
@@ -914,7 +922,7 @@
ByteConversionSink _gzipSink;
// _gzipAdd is set iff the sink is being added to. It's used to specify where
// gzipped data should be taken (sometimes a controller, sometimes a socket).
- Function _gzipAdd;
+ _BytesConsumer _gzipAdd;
Uint8List _gzipBuffer;
int _gzipBufferLength = 0;
@@ -936,14 +944,16 @@
"Headers size exceeded the of '$_OUTGOING_BUFFER_SIZE'"
" bytes"));
}
+ return null;
}
+
if (headersWritten) return null;
headersWritten = true;
Future drainFuture;
- bool isServerSide = outbound is _HttpResponse;
bool gzip = false;
- if (isServerSide) {
- var response = outbound;
+ if (outbound is _HttpResponse) {
+ // Server side.
+ _HttpResponse response = outbound;
if (response._httpRequest._httpServer.autoCompress &&
outbound.bufferOutput &&
outbound.headers.chunkedTransferEncoding) {
@@ -997,16 +1007,16 @@
}
return close();
}
- var sub;
+ StreamSubscription<List<int>> sub;
// Use new stream so we are able to pause (see below listen). The
// alternative is to use stream.extand, but that won't give us a way of
// pausing.
- var controller = new StreamController(
+ var controller = new StreamController<List<int>>(
onPause: () => sub.pause(),
onResume: () => sub.resume(),
sync: true);
- void onData(data) {
+ void onData(List<int> data) {
if (_socketError) return;
if (data.length == 0) return;
if (chunked) {
@@ -1146,7 +1156,7 @@
return _closeFuture = finalize();
}
- Future get done => _doneCompleter.future;
+ Future<Socket> get done => _doneCompleter.future;
void setHeader(List<int> data, int length) {
assert(_length == 0);
@@ -1176,7 +1186,7 @@
=> (error is SocketException || error is TlsException) &&
outbound is HttpResponse;
- void _addGZipChunk(chunk, void add(List<int> data)) {
+ void _addGZipChunk(List<int> chunk, void add(List<int> data)) {
if (!outbound.bufferOutput) {
add(chunk);
return;
@@ -1197,7 +1207,7 @@
}
}
- void _addChunk(chunk, void add(List<int> data)) {
+ void _addChunk(List<int> chunk, void add(List<int> data)) {
if (!outbound.bufferOutput) {
if (_buffer != null) {
// If _buffer is not null, we have not written the header yet. Write
@@ -1266,7 +1276,7 @@
Uri _currentUri;
Completer<_HttpIncoming> _nextResponseCompleter;
- Future _streamFuture;
+ Future<Socket> _streamFuture;
_HttpClientConnection(this.key, this._socket, this._httpClient,
[this._proxyTunnel = false, this._context])
@@ -1381,7 +1391,7 @@
// data).
_httpParser.isHead = method == "HEAD";
_streamFuture = outgoing.done
- .then((s) {
+ .then/*<Socket>*/((Socket s) {
// Request sent, set up response completer.
_nextResponseCompleter = new Completer();
@@ -1476,7 +1486,8 @@
.then((_) => _socket.destroy());
}
- Future<_HttpClientConnection> createProxyTunnel(host, port, proxy, callback) {
+ Future<_HttpClientConnection> createProxyTunnel(String host, int port,
+ _Proxy proxy, bool callback(X509Certificate certificate)) {
_HttpClientRequest request =
send(new Uri(host: host, port: port),
port,
@@ -1495,7 +1506,8 @@
throw "Proxy failed to establish tunnel "
"(${response.statusCode} ${response.reasonPhrase})";
}
- var socket = response._httpRequest._httpClientConnection._socket;
+ var socket = (response as _HttpClientResponse)._httpRequest
+ ._httpClientConnection._socket;
return SecureSocket.secure(
socket,
host: host,
@@ -1621,17 +1633,19 @@
}
if (client.maxConnectionsPerHost != null &&
_active.length + _connecting >= client.maxConnectionsPerHost) {
- var completer = new Completer();
+ var completer = new Completer<_ConnectionInfo>();
_pending.add(() {
- connect(uriHost, uriPort, proxy, client)
- .then(completer.complete, onError: completer.completeError);
+ completer.complete(connect(uriHost, uriPort, proxy, client));
});
return completer.future;
}
var currentBadCertificateCallback = client._badCertificateCallback;
- callback(X509Certificate certificate) =>
- currentBadCertificateCallback == null ? false :
- currentBadCertificateCallback(certificate, uriHost, uriPort);
+
+ bool callback(X509Certificate certificate) {
+ if (currentBadCertificateCallback == null) return false;
+ return currentBadCertificateCallback(certificate, uriHost, uriPort);
+ }
+
Future socketFuture = (isSecure && proxy.isDirect
? SecureSocket.connect(host,
port,
@@ -1664,6 +1678,7 @@
}
}
+typedef bool BadCertificateCallback(X509Certificate cr, String host, int port);
class _HttpClient implements HttpClient {
bool _closing = false;
@@ -1677,7 +1692,7 @@
Function _authenticateProxy;
Function _findProxy = HttpClient.findProxyFromEnvironment;
Duration _idleTimeout = const Duration(seconds: 15);
- Function _badCertificateCallback;
+ BadCertificateCallback _badCertificateCallback;
Duration get idleTimeout => _idleTimeout;
@@ -1734,9 +1749,8 @@
return _openUrl(method, uri);
}
- Future<HttpClientRequest> openUrl(String method, Uri url) {
- return _openUrl(method, url);
- }
+ Future<HttpClientRequest> openUrl(String method, Uri url)
+ => _openUrl(method, url);
Future<HttpClientRequest> get(String host, int port, String path)
=> open("get", host, port, path);
@@ -1799,7 +1813,7 @@
set findProxy(String f(Uri uri)) => _findProxy = f;
- Future<HttpClientRequest> _openUrl(String method, Uri uri) {
+ Future<_HttpClientRequest> _openUrl(String method, Uri uri) {
// Ignore any fragments on the request URI.
uri = uri.removeFragment();
@@ -1834,13 +1848,15 @@
}
}
return _getConnection(uri.host, port, proxyConf, isSecure)
- .then((info) {
- send(info) {
+ .then((_ConnectionInfo info) {
+
+ _HttpClientRequest send(_ConnectionInfo info) {
return info.connection.send(uri,
port,
method.toUpperCase(),
info.proxy);
}
+
// If the connection was closed before the request was sent, create
// and use another connection.
if (info.connection.closed) {
@@ -1851,13 +1867,13 @@
});
}
- Future<HttpClientRequest> _openUrlFromRequest(String method,
+ Future<_HttpClientRequest> _openUrlFromRequest(String method,
Uri uri,
_HttpClientRequest previous) {
// If the new URI is relative (to either '/' or some sub-path),
// construct a full URI from the previous one.
Uri resolved = previous.uri.resolveUri(uri);
- return openUrl(method, resolved).then((_HttpClientRequest request) {
+ return _openUrl(method, resolved).then((_HttpClientRequest request) {
request
// Only follow redirects if initial request did.
@@ -1935,16 +1951,20 @@
// connection from the pool. For long-running synchronous code the
// server might have closed the connection, so this lowers the
// probability of getting a connection that was already closed.
- return new Future(() => connect(new HttpException("No proxies given")));
+ return new Future<_ConnectionInfo>(
+ () => connect(new HttpException("No proxies given")));
}
_SiteCredentials _findCredentials(Uri url, [_AuthenticationScheme scheme]) {
// Look for credentials.
_SiteCredentials cr =
- _credentials.fold(null, (prev, value) {
- if (value.applies(url, scheme)) {
+ _credentials.fold(null, (_SiteCredentials prev, value) {
+ var siteCredentials = value as _SiteCredentials;
+ if (siteCredentials.applies(url, scheme)) {
if (prev == null) return value;
- return value.uri.path.length > prev.uri.path.length ? value : prev;
+ return siteCredentials.uri.path.length > prev.uri.path.length
+ ? siteCredentials
+ : prev;
} else {
return prev;
}
@@ -1961,6 +1981,7 @@
return it.current;
}
}
+ return null;
}
void _removeCredentials(_Credentials cr) {
@@ -2059,7 +2080,7 @@
static Map<int, _HttpConnection> _connections =
new HashMap<int, _HttpConnection>();
- final _socket;
+ final /*_ServerSocket*/ _socket;
final _HttpServer _httpServer;
final _HttpParser _httpParser;
int _state = _IDLE;
@@ -2071,7 +2092,7 @@
: _httpParser = new _HttpParser.requestParser() {
try { _socket._owner = this; } catch (_) { print(_); }
_connections[_serviceId] = this;
- _httpParser.listenToStream(_socket);
+ _httpParser.listenToStream(_socket as Object/*=Socket*/);
_subscription = _httpParser.listen(
(incoming) {
_httpServer._markActive(this);
@@ -2166,7 +2187,7 @@
Map _toJSON(bool ref) {
var name = "${_socket.address.host}:${_socket.port} <-> "
"${_socket.remoteAddress.host}:${_socket.remotePort}";
- var r = {
+ var r = <String, dynamic>{
'id': _servicePath,
'type': _serviceType(ref),
'name': name,
@@ -2412,8 +2433,8 @@
String get _serviceTypePath => 'io/http/servers';
String get _serviceTypeName => 'HttpServer';
- Map _toJSON(bool ref) {
- var r = {
+ Map<String, dynamic> _toJSON(bool ref) {
+ var r = <String, dynamic>{
'id': _servicePath,
'type': _serviceType(ref),
'name': '${address.host}:$port',
@@ -2447,7 +2468,7 @@
// The server listen socket. Untyped as it can be both ServerSocket and
// SecureServerSocket.
- final _serverSocket;
+ final dynamic/*ServerSocket|SecureServerSocket*/ _serverSocket;
final bool _closeServer;
// Set of currently connected clients.
@@ -2562,7 +2583,7 @@
class _DetachedSocket extends Stream<List<int>> implements Socket {
final Stream<List<int>> _incoming;
- final _socket;
+ final Socket _socket;
_DetachedSocket(this._socket, this._incoming);
@@ -2597,7 +2618,7 @@
void addError(error, [StackTrace stackTrace]) =>
_socket.addError(error, stackTrace);
- Future<Socket> addStream(Stream<List<int>> stream) {
+ Future addStream(Stream<List<int>> stream) {
return _socket.addStream(stream);
}
@@ -2605,7 +2626,7 @@
Future flush() => _socket.flush();
- Future close() => _socket.close();
+ Future<Socket> close() => _socket.close();
Future<Socket> get done => _socket.done;
@@ -2621,8 +2642,12 @@
return _socket.setOption(option, enabled);
}
- Map _toJSON(bool ref) => _socket._toJSON(ref);
- void set _owner(owner) { _socket._owner = owner; }
+ Map _toJSON(bool ref) {
+ return (_socket as dynamic)._toJSON(ref);
+ }
+ void set _owner(owner) {
+ (_socket as dynamic)._owner = owner;
+ }
}
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index 97d4fd7..c2b08e4 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -120,7 +120,8 @@
bool get isPaused => _subscription.isPaused;
- Future asFuture([futureValue]) => _subscription.asFuture(futureValue);
+ Future/*<T>*/ asFuture/*<T>*/([/*=T*/ futureValue]) =>
+ _subscription.asFuture/*<T>*/(futureValue);
Future cancel() {
_isCanceled = true;
@@ -182,7 +183,7 @@
class _HttpDetachedIncoming extends Stream<List<int>> {
- final StreamSubscription subscription;
+ final StreamSubscription<List<int>> subscription;
final List<int> bufferedData;
_HttpDetachedIncoming(this.subscription, this.bufferedData);
@@ -204,7 +205,8 @@
onData)
..resume();
} else {
- return new Stream.fromIterable(bufferedData)
+ // TODO(26379): add test for this branch.
+ return new Stream<List<int>>.fromIterable([bufferedData])
.listen(onData,
onError: onError,
onDone: onDone,
@@ -266,7 +268,7 @@
// The current incoming connection.
_HttpIncoming _incoming;
- StreamSubscription _socketSubscription;
+ StreamSubscription<List<int>> _socketSubscription;
bool _paused = true;
bool _bodyPaused = false;
StreamController<_HttpIncoming> _controller;
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index 04cc6f2..c0d63de 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -190,7 +190,7 @@
* tour](https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartio---io-for-command-line-apps).
*
* To learn more about I/O in Dart, refer to the [tutorial about writing
- * command-line apps](https://www.dartlang.org/docs/tutorials/io/).
+ * command-line apps](https://www.dartlang.org/docs/tutorials/cmdline/).
*/
library dart.io;
diff --git a/sdk/lib/io/io_resource_info.dart b/sdk/lib/io/io_resource_info.dart
index 7cea231..317cf13 100644
--- a/sdk/lib/io/io_resource_info.dart
+++ b/sdk/lib/io/io_resource_info.dart
@@ -19,11 +19,11 @@
/// Get the full set of values for a specific implementation. This is normally
/// looked up based on an id from a referenceValueMap.
- Map<String, String> get fullValueMap;
+ Map<String, dynamic> get fullValueMap;
/// The reference map, used to return a list of values, e.g., getting
/// all open sockets. The structure of this is shared among all subclasses.
- Map<String, String> get referenceValueMap =>
+ Map<String, dynamic> get referenceValueMap =>
{
// The type for a reference object is prefixed with @ in observatory.
'type': '@$type',
@@ -71,7 +71,7 @@
lastWrite = 0.0,
super(type);
- Map<String, String> get fullValueMap =>
+ Map<String, dynamic> get fullValueMap =>
{
'type': type,
'id': id,
@@ -118,9 +118,8 @@
return new Future.value(new ServiceExtensionResponse.result(json));
}
- Map<String, String> getFileInfoMap() {
- var result = fullValueMap;
- return result;
+ Map<String, dynamic> getFileInfoMap() {
+ return fullValueMap;
}
static Future<ServiceExtensionResponse> getFileInfoMapByID(function, params) {
@@ -155,7 +154,7 @@
void stopped() { ProcessStopped(this); }
- Map<String, String> get fullValueMap =>
+ Map<String, dynamic> get fullValueMap =>
{
'type': type,
'id': id,
@@ -204,7 +203,7 @@
static const String UDP_STRING = 'UDP';
static const String TYPE = '_socket';
- final socket;
+ final /*_NativeSocket|*/ socket;
static Map<int, _SocketResourceInfo> openSockets =
new Map<int, _SocketResourceInfo>();
@@ -230,7 +229,7 @@
return new List.from(openSockets.values.map((e) => e.referenceValueMap));
}
- Map<String, String> getSocketInfoMap() {
+ Map<String, dynamic> getSocketInfoMap() {
var result = fullValueMap;
result['socketType'] = socket.isTcp ? TCP_STRING : UDP_STRING;
result['listening'] = socket.isListening;
@@ -279,5 +278,4 @@
assert(openSockets.containsKey(info.id));
openSockets.remove(info.id);
}
-
}
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 25be38c..7c93725 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -223,7 +223,7 @@
// Atomically changing a link can be done by creating the new link, with
// a different name, and using the rename() posix call to move it to
// the old name atomically.
- return delete().then((_) => create(target));
+ return delete().then/*<Link>*/((_) => create(target));
}
Future<Link> _delete({bool recursive: false}) {
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index 8c9d30c..7527844 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -39,7 +39,7 @@
// Cache the OS environemnt. This can be an OSError instance if
// retrieving the environment failed.
- static var _environmentCache;
+ static var/*OSError|Map<String,String>*/ _environmentCache;
static int get numberOfProcessors => _numberOfProcessors();
static String get pathSeparator => _pathSeparator();
@@ -62,7 +62,9 @@
var env = _environment();
if (env is !OSError) {
var isWindows = operatingSystem == 'windows';
- var result = isWindows ? new _CaseInsensitiveStringMap() : new Map();
+ var result = isWindows
+ ? new _CaseInsensitiveStringMap<String>()
+ : new Map<String, String>();
for (var str in env) {
// The Strings returned by [_environment()] are expected to be
// valid environment entries, but exceptions have been seen
@@ -84,7 +86,7 @@
if (_environmentCache is OSError) {
throw _environmentCache;
} else {
- return _environmentCache;
+ return _environmentCache as Object/*=Map<String, String>*/;
}
}
@@ -96,19 +98,20 @@
class _CaseInsensitiveStringMap<V> implements Map<String, V> {
final Map<String, V> _map = new Map<String, V>();
- bool containsKey(String key) => _map.containsKey(key.toUpperCase());
+ bool containsKey(Object key) =>
+ key is String && _map.containsKey(key.toUpperCase());
bool containsValue(Object value) => _map.containsValue(value);
- V operator [](String key) => _map[key.toUpperCase()];
+ V operator [](Object key) => key is String ? _map[key.toUpperCase()] : null;
void operator []=(String key, V value) {
_map[key.toUpperCase()] = value;
}
V putIfAbsent(String key, V ifAbsent()) {
- _map.putIfAbsent(key.toUpperCase(), ifAbsent);
+ return _map.putIfAbsent(key.toUpperCase(), ifAbsent);
}
- addAll(Map other) {
+ void addAll(Map<String, V> other) {
other.forEach((key, value) => this[key.toUpperCase()] = value);
}
- V remove(String key) => _map.remove(key.toUpperCase());
+ V remove(Object key) => key is String ? _map.remove(key.toUpperCase()) : null;
void clear() { _map.clear(); }
void forEach(void f(String key, V value)) { _map.forEach(f); }
Iterable<String> get keys => _map.keys;
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 679aa71..a2d6d78 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -74,21 +74,17 @@
{host,
SecurityContext context,
bool onBadCertificate(X509Certificate certificate)}) {
- var completer = new Completer();
- (socket as dynamic)._detachRaw()
- .then((detachedRaw) {
+ return ((socket as dynamic/*_Socket*/)._detachRaw() as Future)
+ .then/*<RawSecureSocket>*/((detachedRaw) {
return RawSecureSocket.secure(
- detachedRaw[0],
- subscription: detachedRaw[1],
+ detachedRaw[0] as RawSocket,
+ subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
host: host,
context: context,
onBadCertificate: onBadCertificate);
})
- .then((raw) {
- completer.complete(new SecureSocket._(raw));
- });
- return completer.future;
- }
+ .then/*<SecureSocket>*/((raw) => new SecureSocket._(raw));
+ }
/**
* Takes an already connected [socket] and starts server side TLS
@@ -118,22 +114,18 @@
bool requestClientCertificate: false,
bool requireClientCertificate: false,
List<String> supportedProtocols}) {
- var completer = new Completer();
- (socket as dynamic)._detachRaw()
- .then((detachedRaw) {
+ return ((socket as dynamic/*_Socket*/)._detachRaw() as Future)
+ .then/*<RawSecureSocket>*/((detachedRaw) {
return RawSecureSocket.secureServer(
- detachedRaw[0],
+ detachedRaw[0] as RawSocket,
context,
- subscription: detachedRaw[1],
+ subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
bufferedData: bufferedData,
requestClientCertificate: requestClientCertificate,
requireClientCertificate: requireClientCertificate,
supportedProtocols: supportedProtocols);
})
- .then((raw) {
- completer.complete(new SecureSocket._(raw));
- });
- return completer.future;
+ .then/*<SecureSocket>*/((raw) => new SecureSocket._(raw));
}
/**
@@ -244,7 +236,7 @@
*/
static Future<RawSecureSocket> secure(
RawSocket socket,
- {StreamSubscription subscription,
+ {StreamSubscription<RawSocketEvent> subscription,
host,
SecurityContext context,
bool onBadCertificate(X509Certificate certificate),
@@ -288,7 +280,7 @@
static Future<RawSecureSocket> secureServer(
RawSocket socket,
SecurityContext context,
- {StreamSubscription subscription,
+ {StreamSubscription<RawSocketEvent> subscription,
List<int> bufferedData,
bool requestClientCertificate: false,
bool requireClientCertificate: false,
@@ -405,7 +397,8 @@
bool _socketClosedWrite = false; // The network socket is closed for writing.
bool _closedRead = false; // The secure socket has fired an onClosed event.
bool _closedWrite = false; // The secure socket has been closed for writing.
- Completer _closeCompleter = new Completer(); // The network socket is gone.
+ // The network socket is gone.
+ Completer<RawSecureSocket> _closeCompleter = new Completer<RawSecureSocket>();
_FilterStatus _filterStatus = new _FilterStatus();
bool _connectPending = true;
bool _filterPending = false;
@@ -415,12 +408,12 @@
String _selectedProtocol;
static Future<_RawSecureSocket> connect(
- host,
+ dynamic/*String|InternetAddress*/ host,
int requestedPort,
{bool is_server,
SecurityContext context,
RawSocket socket,
- StreamSubscription subscription,
+ StreamSubscription<RawSocketEvent> subscription,
List<int> bufferedData,
bool requestClientCertificate: false,
bool requireClientCertificate: false,
@@ -430,8 +423,10 @@
requestClientCertificate, requireClientCertificate,
onBadCertificate);
if (host is InternetAddress) host = host.host;
- var address = socket.address;
- if (host != null) address = address._cloneWithNewHost(host);
+ InternetAddress address = socket.address;
+ if (host != null) {
+ address = InternetAddress._cloneWithNewHost(address, host);
+ }
return new _RawSecureSocket(address,
requestedPort,
is_server,
@@ -517,10 +512,10 @@
}
}
- StreamSubscription listen(void onData(RawSocketEvent data),
- {Function onError,
- void onDone(),
- bool cancelOnError}) {
+ StreamSubscription<RawSocketEvent> listen(void onData(RawSocketEvent data),
+ {Function onError,
+ void onDone(),
+ bool cancelOnError}) {
_sendWriteEvent();
return _stream.listen(onData,
onError: onError,
@@ -574,7 +569,7 @@
return _closeCompleter.future;
}
- void _completeCloseCompleter([dummy]) {
+ void _completeCloseCompleter([RawSocket dummy]) {
if (!_closeCompleter.isCompleted) _closeCompleter.complete(this);
}
@@ -1060,7 +1055,8 @@
* and one writing. All updates to start and end are done by Dart code.
*/
class _ExternalBuffer {
- List data; // This will be a ExternalByteArray, backed by C allocated data.
+ // This will be an ExternalByteArray, backed by C allocated data.
+ List<int> data;
int start;
int end;
final size;
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 30e4eb2..0a112d5 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -141,6 +141,15 @@
*/
external static Future<List<InternetAddress>> lookup(
String host, {InternetAddressType type: InternetAddressType.ANY});
+
+ /**
+ * Clones the given [address] with the new [host].
+ *
+ * The [address] must be an [InternetAddress] that was created with one
+ * of the static methods of this class.
+ */
+ external static InternetAddress _cloneWithNewHost(
+ InternetAddress address, String host);
}
@@ -559,6 +568,10 @@
* Returns the remote [InternetAddress] connected to by this socket.
*/
InternetAddress get remoteAddress;
+
+ Future<Socket> close();
+
+ Future<Socket> get done;
}
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index feea4ff..67f4370 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.dart
@@ -57,7 +57,7 @@
bool retainNewlines: false}) {
const CR = 13;
const LF = 10;
- final List line = [];
+ final List<int> line = <int>[];
// On Windows, if lineMode is disabled, only CR is received.
bool crIsNewline = Platform.isWindows &&
(stdioType(stdin) == StdioType.TERMINAL) &&
@@ -328,13 +328,18 @@
return StdioType.FILE;
}
if (object is Socket) {
- switch (_StdIOUtils._socketType(object._nativeSocket)) {
- case _STDIO_HANDLE_TYPE_TERMINAL: return StdioType.TERMINAL;
- case _STDIO_HANDLE_TYPE_PIPE: return StdioType.PIPE;
- case _STDIO_HANDLE_TYPE_FILE: return StdioType.FILE;
+ int socketType = _StdIOUtils._socketType(object);
+ if (socketType == null) return StdioType.OTHER;
+ switch (socketType) {
+ case _STDIO_HANDLE_TYPE_TERMINAL:
+ return StdioType.TERMINAL;
+ case _STDIO_HANDLE_TYPE_PIPE:
+ return StdioType.PIPE;
+ case _STDIO_HANDLE_TYPE_FILE:
+ return StdioType.FILE;
}
}
- if (object is IOSink) {
+ if (object is _IOSinkImpl) {
try {
if (object._target is _FileStreamConsumer) {
return StdioType.FILE;
@@ -350,6 +355,7 @@
class _StdIOUtils {
external static _getStdioOutputStream(int fd);
external static Stdin _getStdioInputStream();
- external static int _socketType(nativeSocket);
+ /// Returns the socket type or `null` if [socket] is not a builtin socket.
+ external static int _socketType(Socket socket);
external static _getStdioHandleType(int fd);
}
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
index b6f4524..ab17eaf 100644
--- a/sdk/lib/io/string_transformer.dart
+++ b/sdk/lib/io/string_transformer.dart
@@ -25,7 +25,7 @@
List<int> encode(String input) => encoder.convert(input);
String decode(List<int> encoded) => decoder.convert(encoded);
- ChunkedConverter<String, List<int>, String, List<int>> get encoder {
+ Converter<String, List<int>> get encoder {
if (Platform.operatingSystem == "windows") {
return const _WindowsCodePageEncoder();
} else {
@@ -33,7 +33,7 @@
}
}
- ChunkedConverter<List<int>, String, List<int>, String> get decoder {
+ Converter<List<int>, String> get decoder {
if (Platform.operatingSystem == "windows") {
return const _WindowsCodePageDecoder();
} else {
@@ -42,8 +42,7 @@
}
}
-class _WindowsCodePageEncoder
- extends ChunkedConverter<String, List<int>, String, List<int>> {
+class _WindowsCodePageEncoder extends Converter<String, List<int>> {
const _WindowsCodePageEncoder();
@@ -62,9 +61,6 @@
return new _WindowsCodePageEncoderSink(sink);
}
- // Override the base-class' bind, to provide a better type.
- Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
-
external static List<int> _encodeString(String string);
}
@@ -98,8 +94,7 @@
}
-class _WindowsCodePageDecoder
- extends ChunkedConverter<List<int>, String, List<int>, String> {
+class _WindowsCodePageDecoder extends Converter<List<int>, String> {
const _WindowsCodePageDecoder();
@@ -114,9 +109,6 @@
return new _WindowsCodePageDecoderSink(sink);
}
- // Override the base-class' bind, to provide a better type.
- Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
-
external static String _decodeBytes(List<int> bytes);
}
diff --git a/sdk/lib/io/websocket.dart b/sdk/lib/io/websocket.dart
index 183714f..df6c8cf 100644
--- a/sdk/lib/io/websocket.dart
+++ b/sdk/lib/io/websocket.dart
@@ -212,9 +212,10 @@
* then the [WebSocket] will be created with the default [CompressionOptions].
*/
factory WebSocketTransformer(
- {protocolSelector(List<String> protocols),
- CompressionOptions compression: CompressionOptions.DEFAULT}) =>
- new _WebSocketTransformerImpl(protocolSelector, compression);
+ {/*String|Future<String>*/ protocolSelector(List<String> protocols),
+ CompressionOptions compression: CompressionOptions.DEFAULT}) {
+ return new _WebSocketTransformerImpl(protocolSelector, compression);
+ }
/**
* Upgrades a [HttpRequest] to a [WebSocket] connection. If the
@@ -252,9 +253,11 @@
* A two-way HTTP communication object for client or server applications.
*
* The stream exposes the messages received. A text message will be of type
- * [:String:] and a binary message will be of type [:List<int>:].
+ * `String` and a binary message will be of type `List<int>`.
*/
-abstract class WebSocket implements Stream, StreamSink {
+abstract class WebSocket
+ implements Stream<dynamic/*String|List<int>*/>,
+ StreamSink<dynamic/*String|List<int>*/> {
/**
* Possible states of the connection.
*/
@@ -389,14 +392,14 @@
/**
* Sends data on the WebSocket connection. The data in [data] must
- * be either a [:String:], or a [:List<int>:] holding bytes.
+ * be either a `String`, or a `List<int>` holding bytes.
*/
- void add(data);
+ void add(/*String|List<int>*/ data);
/**
* Sends data from a stream on WebSocket connection. Each data event from
* [stream] will be send as a single WebSocket frame. The data from [stream]
- * must be either [:String:]s, or [:List<int>:]s holding bytes.
+ * must be either `String`s, or `List<int>`s holding bytes.
*/
Future addStream(Stream stream);
}
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index ec1320a..d593b58 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -50,7 +50,7 @@
/**
* The web socket protocol transformer handles the protocol byte stream
- * which is supplied through the [:handleData:]. As the protocol is processed,
+ * which is supplied through the `handleData`. As the protocol is processed,
* it'll output frame data as either a List<int> or String.
*
* Important information about usage: Be sure you use cancelOnError, so the
@@ -59,7 +59,8 @@
*/
// TODO(ajohnsen): make this transformer reusable?
class _WebSocketProtocolTransformer
- implements StreamTransformer<List<int>, dynamic>, EventSink<List<int>> {
+ implements EventSink<List<int>>, StreamTransformer<
+ List<int>, dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> {
static const int START = 0;
static const int LEN_FIRST = 1;
static const int LEN_REST = 2;
@@ -87,7 +88,7 @@
int closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
String closeReason = "";
- EventSink _eventSink;
+ EventSink<dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> _eventSink;
final bool _serverSide;
final List _maskingBytes = new List(4);
@@ -96,7 +97,8 @@
_WebSocketPerMessageDeflate _deflate;
_WebSocketProtocolTransformer([this._serverSide = false, this._deflate]);
- Stream bind(Stream stream) {
+ Stream<dynamic/*List<int>|_WebSocketPing|_WebSocketPong>*/> bind(
+ Stream<List<int>> stream) {
return new Stream.eventTransformed(stream, (EventSink eventSink) {
if (_eventSink != null) {
throw new StateError("WebSocket transformer already used.");
@@ -394,10 +396,12 @@
_WebSocketPong([this.payload = null]);
}
+typedef /*String|Future<String>*/ _ProtocolSelector(List<String> protocols);
+
class _WebSocketTransformerImpl implements WebSocketTransformer {
final StreamController<WebSocket> _controller =
new StreamController<WebSocket>(sync: true);
- final Function _protocolSelector;
+ final _ProtocolSelector _protocolSelector;
final CompressionOptions _compression;
_WebSocketTransformerImpl(this._protocolSelector, this._compression);
@@ -414,8 +418,8 @@
return _controller.stream;
}
- static Future<WebSocket> _upgrade(
- HttpRequest request, _protocolSelector, CompressionOptions compression) {
+ static Future<WebSocket> _upgrade(HttpRequest request,
+ _ProtocolSelector _protocolSelector, CompressionOptions compression) {
var response = request.response;
if (!_isUpgradeRequest(request)) {
// Send error response.
@@ -426,7 +430,7 @@
new WebSocketException("Invalid WebSocket upgrade request"));
}
- Future upgrade(String protocol) {
+ Future<WebSocket> upgrade(String protocol) {
// Send the upgrade response.
response
..statusCode = HttpStatus.SWITCHING_PROTOCOLS
@@ -444,7 +448,7 @@
var deflate = _negotiateCompression(request, response, compression);
response.headers.contentLength = 0;
- return response.detachSocket().then((socket) =>
+ return response.detachSocket().then/*<WebSocket>*/((socket) =>
new _WebSocketImpl._fromSocket(
socket, protocol, compression, true, deflate));
}
@@ -455,7 +459,8 @@
// consisting of multiple protocols. To unify all of them, first join
// the lists with ', ' and then tokenize.
protocols = _HttpParser._tokenizeFieldValue(protocols.join(', '));
- return new Future(() => _protocolSelector(protocols)).then((protocol) {
+ return new Future<String>(() => _protocolSelector(protocols))
+ .then/*<String>*/((protocol) {
if (protocols.indexOf(protocol) < 0) {
throw new WebSocketException(
"Selected protocol is not in the list of available protocols");
@@ -466,7 +471,7 @@
..statusCode = HttpStatus.INTERNAL_SERVER_ERROR
..close();
throw error;
- }).then(upgrade);
+ }).then/*<WebSocket>*/(upgrade);
} else {
return upgrade(null);
}
@@ -570,13 +575,13 @@
Uint8List processIncomingMessage(List<int> msg) {
_ensureDecoder();
- var data = [];
+ var data = <int>[];
data.addAll(msg);
data.addAll(const [0x00, 0x00, 0xff, 0xff]);
decoder.process(data, 0, data.length);
- var result = [];
- var out;
+ var result = <int>[];
+ List<int> out;
while ((out = decoder.processed()) != null) {
result.addAll(out);
@@ -592,9 +597,8 @@
List<int> processOutgoingMessage(List<int> msg) {
_ensureEncoder();
- var result = [];
+ var result = <int>[];
Uint8List buffer;
- var out;
if (msg is! Uint8List) {
for (var i = 0; i < msg.length; i++) {
@@ -610,6 +614,7 @@
encoder.process(buffer, 0, buffer.length);
+ List<int> out;
while ((out = encoder.processed()) != null) {
result.addAll(out);
}
@@ -640,7 +645,8 @@
}
Stream<List<int>> bind(Stream stream) {
- return new Stream.eventTransformed(stream, (eventSink) {
+ return new Stream<List<int>>.eventTransformed(
+ stream, (EventSink<List<int>> eventSink) {
if (_eventSink != null) {
throw new StateError("WebSocket transformer already used");
}
@@ -666,8 +672,8 @@
data = UTF8.encode(message);
} else {
if (message is List<int>) {
- data = message;
opcode = _WebSocketOpcode.BINARY;
+ data = message;
} else {
throw new ArgumentError(message);
}
@@ -702,15 +708,16 @@
_eventSink.close();
}
- void addFrame(int opcode, List<int> data) => createFrame(
- opcode,
- data,
- webSocket._serverSide,
- _deflateHelper != null &&
- (opcode == _WebSocketOpcode.TEXT ||
- opcode == _WebSocketOpcode.BINARY)).forEach((e) {
- _eventSink.add(e);
- });
+ void addFrame(int opcode, List<int> data) {
+ createFrame(
+ opcode,
+ data,
+ webSocket._serverSide,
+ _deflateHelper != null &&
+ (opcode == _WebSocketOpcode.TEXT ||
+ opcode == _WebSocketOpcode.BINARY))
+ .forEach((e) { _eventSink.add(e); });
+ }
static Iterable<List<int>> createFrame(
int opcode, List<int> data, bool serverSide, bool compressed) {
@@ -1000,6 +1007,7 @@
return request.close();
}).then((response) {
+
void error(String message) {
// Flush data.
response.detachSocket().then((socket) {
@@ -1007,6 +1015,7 @@
});
throw new WebSocketException(message);
}
+
if (response.statusCode != HttpStatus.SWITCHING_PROTOCOLS ||
response.headers[HttpHeaders.CONNECTION] == null ||
!response.headers[HttpHeaders.CONNECTION]
@@ -1036,7 +1045,7 @@
_WebSocketPerMessageDeflate deflate =
negotiateClientCompression(response, compression);
- return response.detachSocket().then((socket) =>
+ return response.detachSocket().then/*<WebSocket>*/((socket) =>
new _WebSocketImpl._fromSocket(
socket, protocol, compression, false, deflate));
});
@@ -1064,8 +1073,7 @@
return DEFAULT_WINDOW_BITS;
}
- o = int.parse(o, onError: (s) => DEFAULT_WINDOW_BITS);
- return o;
+ return int.parse(o, onError: (s) => DEFAULT_WINDOW_BITS);
}
return new _WebSocketPerMessageDeflate(
@@ -1220,7 +1228,7 @@
String get _serviceTypePath => 'io/websockets';
String get _serviceTypeName => 'WebSocket';
- Map _toJSON(bool ref) {
+ Map<String, dynamic> _toJSON(bool ref) {
var name = '${_socket.address.host}:${_socket.port}';
var r = <String, dynamic>{
'id': _servicePath,
diff --git a/sdk/lib/js/dartium/cached_patches.dart b/sdk/lib/js/dartium/cached_patches.dart
index 81edc87..f9a46f2 100644
--- a/sdk/lib/js/dartium/cached_patches.dart
+++ b/sdk/lib/js/dartium/cached_patches.dart
@@ -2644,15 +2644,6 @@
get runtimeType => RelatedEvent;
toString() => super.toString();
}
-patch class ResourceProgressEvent {
- static Type get instanceRuntimeType => ResourceProgressEventImpl;
-
-}
-class ResourceProgressEventImpl extends ResourceProgressEvent implements js_library.JSObjectInterfacesDom {
- ResourceProgressEventImpl.internal_() : super.internal_();
- get runtimeType => ResourceProgressEvent;
- toString() => super.toString();
-}
patch class RtcDataChannel {
static Type get instanceRuntimeType => RtcDataChannelImpl;
@@ -3958,6 +3949,15 @@
get runtimeType => _Request;
toString() => super.toString();
}
+patch class _ResourceProgressEvent {
+ static Type get instanceRuntimeType => _ResourceProgressEventImpl;
+
+}
+class _ResourceProgressEventImpl extends _ResourceProgressEvent implements js_library.JSObjectInterfacesDom {
+ _ResourceProgressEventImpl.internal_() : super.internal_();
+ get runtimeType => _ResourceProgressEvent;
+ toString() => super.toString();
+}
patch class _Response {
static Type get instanceRuntimeType => _ResponseImpl;
diff --git a/sdk/lib/math/point.dart b/sdk/lib/math/point.dart
index 42fcc46..01ce93c 100644
--- a/sdk/lib/math/point.dart
+++ b/sdk/lib/math/point.dart
@@ -55,8 +55,9 @@
* it, passing in a double [factor] on a `Point<int>` _causes_ _a_
* _runtime_ _error_ in checked mode.
*/
- Point<T> operator *(num factor) {
- return new Point<T>(x * factor, y * factor);
+ Point<T> operator *(num/*T|int*/ factor) {
+ return new Point<T>(
+ (x * factor) as dynamic/*=T*/, (y * factor) as dynamic/*=T*/);
}
/**
diff --git a/sdk/lib/math/rectangle.dart b/sdk/lib/math/rectangle.dart
index 1ab292a..6fe2075 100644
--- a/sdk/lib/math/rectangle.dart
+++ b/sdk/lib/math/rectangle.dart
@@ -209,8 +209,8 @@
* point `(left, top)`.
*/
MutableRectangle(this.left, this.top, T width, T height)
- : this._width = (width < 0) ? _clampToZero(width) : width,
- this._height = (height < 0) ? _clampToZero(height) : height;
+ : this._width = (width < 0) ? _clampToZero/*<T>*/(width) : width,
+ this._height = (height < 0) ? _clampToZero/*<T>*/(height) : height;
/**
* Create a mutable rectangle spanned by the points [a] and [b];
@@ -244,7 +244,7 @@
* but will not change [left].
*/
void set width(T width) {
- if (width < 0) width = _clampToZero(width);
+ if (width < 0) width = _clampToZero/*<T>*/(width);
_width = width;
}
@@ -260,7 +260,7 @@
* but will not change [top].
*/
void set height(T height) {
- if (height < 0) height = _clampToZero(height);
+ if (height < 0) height = _clampToZero/*<T>*/(height);
_height = height;
}
}
@@ -270,7 +270,7 @@
*
* Returns `0` if value is int, `0.0` if value is double.
*/
-num _clampToZero(num value) {
+num/*=T*/ _clampToZero/*<T extends num>*/(num/*=T*/ value) {
assert(value < 0);
return -value * 0;
}
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 3ba8dcd..a5f5750 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -225,7 +225,7 @@
/**
* The simple name for this Dart language entity.
*
- * The simple name is in most cases the the identifier name of the entity,
+ * The simple name is in most cases the identifier name of the entity,
* such as 'myMethod' for a method, [:void myMethod() {...}:] or 'mylibrary'
* for a [:library 'mylibrary';:] declaration.
*/
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index d9a0814..69afd94 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -150,20 +150,6 @@
Language/Mixins/Mixin_Application/error_t02: Pass
Language/Mixins/declaring_constructor_t01: Pass
-[ $runtime == vm && $mode == product ]
-LibTest/typed_data/Float32List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Float32x4List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Float64List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Int16List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Int32List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Int64List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Int8List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Uint16List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Uint32List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Uint64List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Uint8ClampedList/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-LibTest/typed_data/Uint8List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
-
[ ($arch == simdbc || $arch == simdbc64) && $mode == debug ]
# TODO(vegorov) These tests are very slow on unoptimized SIMDBC
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Timeout
diff --git a/tests/compiler/dart2js/analyze_test_test.dart b/tests/compiler/dart2js/analyze_test_test.dart
index a38c814..af3eb25 100644
--- a/tests/compiler/dart2js/analyze_test_test.dart
+++ b/tests/compiler/dart2js/analyze_test_test.dart
@@ -58,27 +58,34 @@
main(List<String> arguments) {
List<String> options = <String>[];
- for (String argument in arguments) {
- if (argument == '-v') {
- options.add(Flags.verbose);
- } else if (argument.startsWith('-')) {
- options.add(argument);
- }
- }
List<Uri> uriList = <Uri>[];
- for (String arg in arguments) {
- if (!arg.startsWith('-')) {
- for (String line in new File(arg).readAsLinesSync()) {
- line = line.trim();
- if (line.startsWith('Analyzing uri: ')) {
- int filenameOffset = line.indexOf('tests/compiler/dart2js/');
- if (filenameOffset != -1) {
- uriList.add(Uri.base.resolve(
- nativeToUriPath(line.substring(filenameOffset))));
+ String filter;
+ bool first = true;
+ for (String argument in arguments) {
+ if (argument.startsWith('-')) {
+ options.add(argument == '-v' ? Flags.verbose : argument);
+ } else if (first) {
+ File file = new File(argument);
+ if (file.existsSync()) {
+ // Read test files from [file].
+ for (String line in file.readAsLinesSync()) {
+ line = line.trim();
+ if (line.startsWith('Analyzing uri: ')) {
+ int filenameOffset = line.indexOf('tests/compiler/dart2js/');
+ if (filenameOffset != -1) {
+ uriList.add(Uri.base.resolve(
+ nativeToUriPath(line.substring(filenameOffset))));
+ }
}
}
+ } else {
+ // Use argument as filter on test files.
+ filter = argument;
}
+ } else {
+ throw new ArgumentError("Extra argument $argument in $arguments.");
}
+ first = false;
}
asyncTest(() async {
@@ -88,6 +95,9 @@
for (FileSystemEntity entity in dir.listSync(recursive: true)) {
if (entity is File && entity.path.endsWith('.dart')) {
Uri file = Uri.base.resolve(nativeToUriPath(entity.path));
+ if (filter != null && !'$file'.contains(filter)) {
+ continue;
+ }
if (!SKIP_LIST.any((skip) => file.path.contains(skip))) {
uriList.add(file);
}
diff --git a/tests/compiler/dart2js/bad_output_io_test.dart b/tests/compiler/dart2js/bad_output_io_test.dart
index 6f11981..ebda63f 100644
--- a/tests/compiler/dart2js/bad_output_io_test.dart
+++ b/tests/compiler/dart2js/bad_output_io_test.dart
@@ -56,11 +56,9 @@
int throwOnErrorCount;
}
-testOutputProvider(script, libraryRoot, packageRoot, inputProvider, handler,
- [options, outputProvider, environment, packageConfig,
- findPackages]) {
+testOutputProvider(options, input, diagnostics, output) {
diagnosticHandler = new CollectingFormattingDiagnosticHandler();
- outputProvider("/non/existing/directory/should/fail/file", "js");
+ output.createEventSink("/non/existing/directory/should/fail/file", "js");
}
void main() {
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index 67a04bd..3c7b2d9 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -11,7 +11,6 @@
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
-import 'package:compiler/compiler.dart' as old_api;
import 'package:compiler/compiler_new.dart' as api;
import 'package:compiler/src/common/codegen.dart';
import 'package:compiler/src/compile_time_constants.dart';
@@ -26,7 +25,6 @@
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/library_loader.dart';
import 'package:compiler/src/null_compiler_output.dart';
-import 'package:compiler/src/old_to_new_api.dart';
import 'package:compiler/src/options.dart' show CompilerOptions;
import 'package:compiler/src/resolution/resolution.dart';
import 'package:compiler/src/scanner/scanner_task.dart';
@@ -42,24 +40,12 @@
TestCompiler(api.CompilerInput inputProvider,
api.CompilerOutput outputProvider,
api.CompilerDiagnostics handler,
- Uri libraryRoot,
- Uri packageRoot,
- List<String> options,
- Map<String, dynamic> environment,
- Uri packageConfig,
- api.PackagesDiscoveryProvider findPackages,
+ CompilerOptions options,
String this.testMarker,
String this.testType,
Function this.onTest)
: reporter = new TestDiagnosticReporter(),
- super(inputProvider, outputProvider, handler,
- new CompilerOptions.parse(
- libraryRoot: libraryRoot,
- packageRoot: packageRoot,
- options: options,
- environment: environment,
- packageConfig: packageConfig,
- packagesDiscoveryProvider: findPackages)) {
+ super(inputProvider, outputProvider, handler, options) {
reporter.compiler = this;
reporter.reporter = super.reporter;
test('Compiler');
@@ -186,36 +172,24 @@
}
}
return new Future(() {
- Future<old_api.CompilationResult> compile(
- Uri script,
- Uri libraryRoot,
- Uri packageRoot,
- old_api.CompilerInputProvider inputProvider,
- old_api.DiagnosticHandler handler,
- [List<String> options = const [],
- old_api.CompilerOutputProvider outputProvider,
- Map<String, dynamic> environment = const {},
- Uri packageConfig,
- api.PackagesDiscoveryProvider findPackages]) {
- libraryRoot = Platform.script.resolve('../../../sdk/');
- outputProvider = NullSink.outputProvider;
+ Future<api.CompilationResult> compile(
+ CompilerOptions compilerOptions,
+ api.CompilerInput compilerInput,
+ api.CompilerDiagnostics compilerDiagnostics,
+ api.CompilerOutput compilerOutput) {
+ compilerOutput = const NullCompilerOutput();
// Use this to silence the test when debugging:
// handler = (uri, begin, end, message, kind) {};
Compiler compiler = new TestCompiler(
- new LegacyCompilerInput(inputProvider),
- new LegacyCompilerOutput(outputProvider),
- new LegacyCompilerDiagnostics(handler),
- libraryRoot,
- packageRoot,
- options,
- environment,
- packageConfig,
- findPackages,
+ compilerInput,
+ compilerOutput,
+ compilerDiagnostics,
+ compilerOptions,
marker,
type,
onTest);
- return compiler.run(script).then((bool success) {
- return new old_api.CompilationResult(compiler, isSuccess: success);
+ return compiler.run(compilerOptions.entryPoint).then((bool success) {
+ return new api.CompilationResult(compiler, isSuccess: success);
});
}
@@ -242,6 +216,7 @@
entry.compileFunc = compile;
List<String> args = new List<String>.from(options)
+ ..add("--library-root=${Platform.script.resolve('../../../sdk/')}")
..add("tests/compiler/dart2js/data/exit_code_helper.dart");
Future result = entry.internalMain(args);
return result.catchError((e, s) {
diff --git a/tests/compiler/dart2js/serialization/analysis_test.dart b/tests/compiler/dart2js/serialization/analysis_test.dart
index b1a96b5..1630660 100644
--- a/tests/compiler/dart2js/serialization/analysis_test.dart
+++ b/tests/compiler/dart2js/serialization/analysis_test.dart
@@ -8,8 +8,6 @@
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common/backend_api.dart';
-import 'package:compiler/src/common/names.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/filenames.dart';
import '../memory_compiler.dart';
@@ -40,7 +38,7 @@
options: [Flags.analyzeOnly],
diagnosticHandler: diagnosticCollector,
beforeRun: (Compiler compiler) {
- deserialize(compiler, serializedData);
+ compiler.serialization.deserializeFromText(serializedData);
});
if (test != null) {
Expect.equals(test.expectedErrorCount, diagnosticCollector.errors.length,
diff --git a/tests/compiler/dart2js/serialization/compilation_test.dart b/tests/compiler/dart2js/serialization/compilation_test.dart
index e6601e1..7346b86 100644
--- a/tests/compiler/dart2js/serialization/compilation_test.dart
+++ b/tests/compiler/dart2js/serialization/compilation_test.dart
@@ -6,10 +6,6 @@
import 'dart:async';
import 'package:async_helper/async_helper.dart';
-import 'package:expect/expect.dart';
-import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common/backend_api.dart';
-import 'package:compiler/src/common/names.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/filenames.dart';
import '../memory_compiler.dart';
@@ -20,29 +16,27 @@
main(List<String> args) {
asyncTest(() async {
Arguments arguments = new Arguments.from(args);
- String serializedData = await serializeDartCore(
- arguments: arguments,
- serializeResolvedAst: true);
+ String serializedData = await serializeDartCore(arguments: arguments);
if (arguments.filename != null) {
Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
await compile(serializedData, entryPoint, null);
} else {
Uri entryPoint = Uri.parse('memory:main.dart');
- // TODO(johnniwinther): Handle the remaining tests.
- for (Test test in TESTS.sublist(0, 5)) {
+ arguments.forEachTest(TESTS, (int index, Test test) async {
await compile(serializedData, entryPoint, test,
+ index: index,
verbose: arguments.verbose);
- }
+ });
}
});
}
Future compile(String serializedData, Uri entryPoint, Test test,
- {bool verbose: false}) async {
+ {int index, bool verbose: false}) async {
String testDescription =
test != null ? test.sourceFiles[entryPoint.path] : '${entryPoint}';
print('------------------------------------------------------------------');
- print('compile ${testDescription}');
+ print('compile ${index != null ? '$index:' :''}${testDescription}');
print('------------------------------------------------------------------');
OutputCollector outputCollector = new OutputCollector();
await runCompiler(
@@ -51,7 +45,7 @@
options: [],
outputProvider: outputCollector,
beforeRun: (Compiler compiler) {
- deserialize(compiler, serializedData, deserializeResolvedAst: true);
+ compiler.serialization.deserializeFromText(serializedData);
});
if (verbose) {
print(outputCollector.getOutput('', 'js'));
diff --git a/tests/compiler/dart2js/serialization/equivalence_test.dart b/tests/compiler/dart2js/serialization/equivalence_test.dart
index 32a538a..fb1ace8 100644
--- a/tests/compiler/dart2js/serialization/equivalence_test.dart
+++ b/tests/compiler/dart2js/serialization/equivalence_test.dart
@@ -8,10 +8,7 @@
import '../memory_compiler.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common.dart';
import 'package:compiler/src/constants/constructors.dart';
-import 'package:compiler/src/constants/expressions.dart';
-import 'package:compiler/src/dart_types.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/diagnostics/invariant.dart';
import 'package:compiler/src/elements/elements.dart';
@@ -245,6 +242,12 @@
element1.accept(this, element2);
check(element1, element2, 'isSynthesized',
element1.isSynthesized, element2.isSynthesized);
+ check(element1, element2, 'isLocal',
+ element1.isLocal, element2.isLocal);
+ check(element1, element2, 'isFinal',
+ element1.isFinal, element2.isFinal);
+ check(element1, element2, 'isConst',
+ element1.isConst, element2.isConst);
}
@override
@@ -438,10 +441,6 @@
checkTypes(
element1, element2, 'type',
element1.type, element2.type);
- check(element1, element2, 'isConst',
- element1.isConst, element2.isConst);
- check(element1, element2, 'isFinal',
- element1.isFinal, element2.isFinal);
checkConstants(
element1, element2, 'constant',
element1.constant, element2.constant);
@@ -553,8 +552,6 @@
checkTypes(
element1, element2, 'type',
element1.type, element2.type);
- check(element1, element2, 'isConst',
- element1.isConst, element2.isConst);
check(element1, element2, 'isExternal',
element1.isExternal, element2.isExternal);
if (element1.isConst && !element1.isExternal) {
@@ -646,9 +643,6 @@
check(
element1, element2, 'isNamed',
element1.isNamed, element2.isNamed);
- check(
- element1, element2, 'isFinal',
- element1.isFinal, element2.isFinal);
check(element1, element2, 'name', element1.name, element2.name);
if (element1.isOptional) {
checkConstants(
diff --git a/tests/compiler/dart2js/serialization/helper.dart b/tests/compiler/dart2js/serialization/helper.dart
index 095915b..1ce8c2b 100644
--- a/tests/compiler/dart2js/serialization/helper.dart
+++ b/tests/compiler/dart2js/serialization/helper.dart
@@ -8,30 +8,16 @@
import 'dart:io';
import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common.dart';
-import 'package:compiler/src/common/backend_api.dart';
import 'package:compiler/src/common/names.dart';
-import 'package:compiler/src/common/resolution.dart';
import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/elements/elements.dart';
-import 'package:compiler/src/io/source_file.dart';
-import 'package:compiler/src/scanner/scanner.dart';
-import 'package:compiler/src/script.dart';
-import 'package:compiler/src/serialization/impact_serialization.dart';
-import 'package:compiler/src/serialization/json_serializer.dart';
-import 'package:compiler/src/serialization/modelz.dart';
-import 'package:compiler/src/serialization/resolved_ast_serialization.dart';
-import 'package:compiler/src/serialization/serialization.dart';
-import 'package:compiler/src/serialization/task.dart';
-import 'package:compiler/src/tokens/token.dart';
-import 'package:compiler/src/universe/call_structure.dart';
-import 'package:compiler/src/universe/world_impact.dart';
-import 'package:compiler/src/universe/use.dart';
import '../memory_compiler.dart';
+import 'test_data.dart';
class Arguments {
final String filename;
+ final int start;
+ final int end;
final bool loadSerializedData;
final bool saveSerializedData;
final String serializedDataFileName;
@@ -39,6 +25,8 @@
const Arguments({
this.filename,
+ this.start,
+ this.end,
this.loadSerializedData: false,
this.saveSerializedData: false,
this.serializedDataFileName: 'out.data',
@@ -46,9 +34,18 @@
factory Arguments.from(List<String> arguments) {
String filename;
+ int start;
+ int end;
for (String arg in arguments) {
if (!arg.startsWith('-')) {
- filename = arg;
+ int index = int.parse(arg);
+ if (index == null) {
+ filename = arg;
+ } else if (start == null) {
+ start = index;
+ } else {
+ end = index;
+ }
}
}
bool verbose = arguments.contains('-v');
@@ -56,16 +53,26 @@
bool saveSerializedData = arguments.contains('-s');
return new Arguments(
filename: filename,
+ start: start,
+ end: end,
verbose: verbose,
loadSerializedData: loadSerializedData,
saveSerializedData: saveSerializedData);
}
+
+ Future forEachTest(List<Test> tests, Future f(int index, Test test)) async {
+ int first = start ?? 0;
+ int last = end ?? tests.length - 1;
+ for (int index = first; index <= last; index++) {
+ Test test = TESTS[index];
+ await f(index, test);
+ }
+ }
}
Future<String> serializeDartCore(
- {Arguments arguments: const Arguments(),
- bool serializeResolvedAst: false}) async {
+ {Arguments arguments: const Arguments()}) async {
print('------------------------------------------------------------------');
print('serialize dart:core');
print('------------------------------------------------------------------');
@@ -82,11 +89,10 @@
options: [Flags.analyzeAll]);
compiler.serialization.supportSerialization = true;
await compiler.run(Uris.dart_core);
- serializedData = serialize(
- compiler,
- compiler.libraryLoader.libraries,
- serializeResolvedAst: serializeResolvedAst)
- .toText(const JsonSerializationEncoder());
+ BufferedEventSink sink = new BufferedEventSink();
+ compiler.serialization.serializeToSink(
+ sink, compiler.libraryLoader.libraries);
+ serializedData = sink.text;
if (arguments.saveSerializedData) {
File file = new File(arguments.serializedDataFileName);
print('Saving data to $file');
@@ -95,287 +101,3 @@
}
return serializedData;
}
-
-Serializer serialize(
- Compiler compiler,
- Iterable<LibraryElement> libraries,
- {bool serializeResolvedAst: false}) {
- assert(compiler.serialization.supportSerialization);
-
- Serializer serializer = new Serializer();
- SerializerPlugin backendSerializer =
- compiler.backend.serialization.serializer;
- serializer.plugins.add(backendSerializer);
- serializer.plugins.add(new ResolutionImpactSerializer(
- compiler.resolution, backendSerializer));
- if (serializeResolvedAst) {
- serializer.plugins.add(new ResolvedAstSerializerPlugin(
- compiler.resolution, backendSerializer));
- }
-
- for (LibraryElement library in libraries) {
- serializer.serialize(library);
- }
- return serializer;
-}
-
-void deserialize(Compiler compiler,
- String serializedData,
- {bool deserializeResolvedAst: false}) {
- Deserializer deserializer = new Deserializer.fromText(
- new DeserializationContext(),
- serializedData,
- const JsonSerializationDecoder());
- deserializer.plugins.add(compiler.backend.serialization.deserializer);
- compiler.serialization.deserializer =
- new _DeserializerSystem(
- compiler,
- deserializer,
- compiler.backend.impactTransformer,
- deserializeResolvedAst: deserializeResolvedAst);
-}
-
-
-const String WORLD_IMPACT_TAG = 'worldImpact';
-
-class ResolutionImpactSerializer extends SerializerPlugin {
- final Resolution resolution;
- final SerializerPlugin nativeDataSerializer;
-
- ResolutionImpactSerializer(this.resolution, this.nativeDataSerializer);
-
- @override
- void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
- if (resolution.hasBeenResolved(element)) {
- ResolutionImpact impact = resolution.getResolutionImpact(element);
- ObjectEncoder encoder = createEncoder(WORLD_IMPACT_TAG);
- new ImpactSerializer(element, encoder, nativeDataSerializer)
- .serialize(impact);
- }
- }
-}
-
-class ResolutionImpactDeserializer extends DeserializerPlugin {
- Map<Element, ResolutionImpact> impactMap = <Element, ResolutionImpact>{};
- final DeserializerPlugin nativeDataDeserializer;
-
- ResolutionImpactDeserializer(this.nativeDataDeserializer);
-
- @override
- void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
- ObjectDecoder decoder = getDecoder(WORLD_IMPACT_TAG);
- if (decoder != null) {
- impactMap[element] =
- ImpactDeserializer.deserializeImpact(
- element, decoder, nativeDataDeserializer);
- }
- }
-}
-
-class _DeserializerSystem extends DeserializerSystem {
- final Compiler _compiler;
- final Deserializer _deserializer;
- final List<LibraryElement> deserializedLibraries = <LibraryElement>[];
- final ResolutionImpactDeserializer _resolutionImpactDeserializer;
- final ResolvedAstDeserializerPlugin _resolvedAstDeserializer;
- final ImpactTransformer _impactTransformer;
- final bool deserializeResolvedAst;
-
- factory _DeserializerSystem(
- Compiler compiler,
- Deserializer deserializer,
- ImpactTransformer impactTransformer,
- {bool deserializeResolvedAst: false}) {
- List<DeserializerPlugin> plugins = <DeserializerPlugin>[];
- DeserializerPlugin backendDeserializer =
- compiler.backend.serialization.deserializer;
- deserializer.plugins.add(backendDeserializer);
- ResolutionImpactDeserializer resolutionImpactDeserializer =
- new ResolutionImpactDeserializer(backendDeserializer);
- deserializer.plugins.add(resolutionImpactDeserializer);
- ResolvedAstDeserializerPlugin resolvedAstDeserializer;
- if (deserializeResolvedAst) {
- resolvedAstDeserializer = new ResolvedAstDeserializerPlugin(
- compiler.parsingContext, backendDeserializer);
- deserializer.plugins.add(resolvedAstDeserializer);
- }
- return new _DeserializerSystem._(
- compiler,
- deserializer,
- impactTransformer,
- resolutionImpactDeserializer,
- resolvedAstDeserializer,
- deserializeResolvedAst: deserializeResolvedAst);
- }
-
- _DeserializerSystem._(
- this._compiler,
- this._deserializer,
- this._impactTransformer,
- this._resolutionImpactDeserializer,
- this._resolvedAstDeserializer,
- {this.deserializeResolvedAst: false});
-
-
- @override
- Future<LibraryElement> readLibrary(Uri resolvedUri) {
- LibraryElement library = _deserializer.lookupLibrary(resolvedUri);
- if (library != null) {
- deserializedLibraries.add(library);
- if (deserializeResolvedAst) {
- return Future.forEach(library.compilationUnits,
- (CompilationUnitElement compilationUnit) {
- ScriptZ script = compilationUnit.script;
- return _compiler.readScript(script.readableUri)
- .then((Script newScript) {
- script.file = newScript.file;
- _resolvedAstDeserializer.sourceFiles[script.resourceUri] =
- newScript.file;
- });
- }).then((_) => library);
- }
- }
- return new Future<LibraryElement>.value(library);
- }
-
- @override
- bool hasResolvedAst(ExecutableElement element) {
- if (_resolvedAstDeserializer != null) {
- return _resolvedAstDeserializer.hasResolvedAst(element);
- }
- return false;
- }
-
- @override
- ResolvedAst getResolvedAst(ExecutableElement element) {
- if (_resolvedAstDeserializer != null) {
- return _resolvedAstDeserializer.getResolvedAst(element);
- }
- return null;
- }
-
- @override
- bool hasResolutionImpact(Element element) {
- if (element.isConstructor &&
- element.enclosingClass.isUnnamedMixinApplication) {
- return true;
- }
- return _resolutionImpactDeserializer.impactMap.containsKey(element);
- }
-
- @override
- ResolutionImpact getResolutionImpact(Element element) {
- if (element.isConstructor &&
- element.enclosingClass.isUnnamedMixinApplication) {
- ClassElement superclass = element.enclosingClass.superclass;
- ConstructorElement superclassConstructor =
- superclass.lookupConstructor(element.name);
- assert(invariant(element, superclassConstructor != null,
- message: "Superclass constructor '${element.name}' called from "
- "${element} not found in ${superclass}."));
- // TODO(johnniwinther): Compute callStructure. Currently not used.
- CallStructure callStructure;
- return _resolutionImpactDeserializer.impactMap.putIfAbsent(element, () {
- return new DeserializedResolutionImpact(
- staticUses: <StaticUse>[new StaticUse.superConstructorInvoke(
- superclassConstructor, callStructure)]);
- });
- }
- return _resolutionImpactDeserializer.impactMap[element];
- }
-
- @override
- WorldImpact computeWorldImpact(Element element) {
- ResolutionImpact resolutionImpact = getResolutionImpact(element);
- assert(invariant(element, resolutionImpact != null,
- message: 'No impact found for $element (${element.library})'));
- return _impactTransformer.transformResolutionImpact(resolutionImpact);
- }
-
- @override
- bool isDeserialized(Element element) {
- return deserializedLibraries.contains(element.library);
- }
-}
-
-const String RESOLVED_AST_TAG = 'resolvedAst';
-
-class ResolvedAstSerializerPlugin extends SerializerPlugin {
- final Resolution resolution;
- final SerializerPlugin nativeDataSerializer;
-
- ResolvedAstSerializerPlugin(this.resolution, this.nativeDataSerializer);
-
- @override
- void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
- assert(invariant(element, element.isDeclaration,
- message: "Element $element must be the declaration"));
- if (element is MemberElement) {
- assert(invariant(element, resolution.hasResolvedAst(element),
- message: "Element $element must have a resolved ast"));
- ResolvedAst resolvedAst = resolution.getResolvedAst(element);
- ObjectEncoder objectEncoder = createEncoder(RESOLVED_AST_TAG);
- new ResolvedAstSerializer(
- objectEncoder,
- resolvedAst,
- nativeDataSerializer).serialize();
- }
- }
-}
-
-class ResolvedAstDeserializerPlugin extends DeserializerPlugin {
- final ParsingContext parsingContext;
- final DeserializerPlugin nativeDataDeserializer;
- final Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{};
-
- Map<ExecutableElement, ResolvedAst> _resolvedAstMap =
- <ExecutableElement, ResolvedAst>{};
- Map<MemberElement, ObjectDecoder> _decoderMap =
- <MemberElement, ObjectDecoder>{};
- Map<Uri, Token> beginTokenMap = <Uri, Token>{};
-
- ResolvedAstDeserializerPlugin(
- this.parsingContext, this.nativeDataDeserializer);
-
- bool hasResolvedAst(ExecutableElement element) {
- return _resolvedAstMap.containsKey(element) ||
- _decoderMap.containsKey(element.memberContext);
- }
-
- ResolvedAst getResolvedAst(ExecutableElement element) {
- ResolvedAst resolvedAst = _resolvedAstMap[element];
- if (resolvedAst == null) {
- ObjectDecoder decoder = _decoderMap[element.memberContext];
- if (decoder != null) {
- ResolvedAstDeserializer.deserialize(
- element.memberContext, decoder, parsingContext, findToken,
- nativeDataDeserializer,
- _resolvedAstMap);
- _decoderMap.remove(element);
- resolvedAst = _resolvedAstMap[element];
- }
- }
- return resolvedAst;
- }
-
- Token findToken(Uri uri, int offset) {
- Token beginToken = beginTokenMap.putIfAbsent(uri, () {
- SourceFile sourceFile = sourceFiles[uri];
- if (sourceFile == null) {
- throw 'No source file found for $uri in:\n '
- '${sourceFiles.keys.join('\n ')}';
- }
- return new Scanner(sourceFile).tokenize();
- });
- return ResolvedAstDeserializer.findTokenInStream(beginToken, offset);
- }
-
- @override
- void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
- ObjectDecoder decoder = getDecoder(RESOLVED_AST_TAG);
- if (decoder != null) {
- _decoderMap[element] = decoder;
- }
- }
-}
-
diff --git a/tests/compiler/dart2js/serialization/impact_test.dart b/tests/compiler/dart2js/serialization/impact_test.dart
index ea1d113..5b062fe 100644
--- a/tests/compiler/dart2js/serialization/impact_test.dart
+++ b/tests/compiler/dart2js/serialization/impact_test.dart
@@ -7,11 +7,8 @@
import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common/resolution.dart';
import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/filenames.dart';
-import 'package:compiler/src/serialization/equivalence.dart';
import '../memory_compiler.dart';
import 'helper.dart';
import 'test_helper.dart';
@@ -48,7 +45,7 @@
memorySourceFiles: sourceFiles,
options: [Flags.analyzeAll]);
compilerDeserialized.resolution.retainCachesForTesting = true;
- deserialize(compilerDeserialized, serializedData);
+ compilerDeserialized.serialization.deserializeFromText(serializedData);
await compilerDeserialized.run(entryPoint);
checkAllImpacts(compilerNormal, compilerDeserialized, verbose: verbose);
diff --git a/tests/compiler/dart2js/serialization/library_test.dart b/tests/compiler/dart2js/serialization/library_test.dart
index 81d90cf..c8cfd4c 100644
--- a/tests/compiler/dart2js/serialization/library_test.dart
+++ b/tests/compiler/dart2js/serialization/library_test.dart
@@ -9,15 +9,9 @@
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/common/names.dart';
-import 'package:compiler/src/constants/constructors.dart';
-import 'package:compiler/src/constants/expressions.dart';
-import 'package:compiler/src/dart_types.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/diagnostics/invariant.dart';
import 'package:compiler/src/elements/elements.dart';
-import 'package:compiler/src/elements/visitor.dart';
-import 'package:compiler/src/ordered_typeset.dart';
-import 'package:compiler/src/serialization/element_serialization.dart';
import 'package:compiler/src/serialization/json_serializer.dart';
import 'package:compiler/src/serialization/serialization.dart';
diff --git a/tests/compiler/dart2js/serialization/model_test.dart b/tests/compiler/dart2js/serialization/model_test.dart
index 0229b02..a8704ae 100644
--- a/tests/compiler/dart2js/serialization/model_test.dart
+++ b/tests/compiler/dart2js/serialization/model_test.dart
@@ -8,23 +8,14 @@
import 'dart:io';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
+import 'package:compiler/src/closure.dart';
import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common/backend_api.dart';
-import 'package:compiler/src/common/names.dart';
-import 'package:compiler/src/common/resolution.dart';
import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/dart_types.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/filenames.dart';
-import 'package:compiler/src/serialization/element_serialization.dart';
-import 'package:compiler/src/serialization/impact_serialization.dart';
-import 'package:compiler/src/serialization/json_serializer.dart';
-import 'package:compiler/src/serialization/serialization.dart';
import 'package:compiler/src/serialization/equivalence.dart';
-import 'package:compiler/src/serialization/task.dart';
-import 'package:compiler/src/universe/world_impact.dart';
+import 'package:compiler/src/tree/nodes.dart';
import 'package:compiler/src/universe/class_set.dart';
-import 'package:compiler/src/universe/use.dart';
import '../memory_compiler.dart';
import 'helper.dart';
import 'test_data.dart';
@@ -36,23 +27,23 @@
String serializedData = await serializeDartCore(arguments: arguments);
if (arguments.filename != null) {
Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
- await check(serializedData, entryPoint);
+ await checkModels(serializedData, entryPoint);
} else {
Uri entryPoint = Uri.parse('memory:main.dart');
- for (Test test in TESTS) {
+ arguments.forEachTest(TESTS, (int index, Test test) async {
print('==============================================================');
print(test.sourceFiles);
- await check(
+ await checkModels(
serializedData,
entryPoint,
sourceFiles: test.sourceFiles,
verbose: arguments.verbose);
- }
+ });
}
});
}
-Future check(
+Future checkModels(
String serializedData,
Uri entryPoint,
{Map<String, String> sourceFiles: const <String, String>{},
@@ -66,7 +57,9 @@
options: [Flags.analyzeOnly]);
compilerNormal.resolution.retainCachesForTesting = true;
await compilerNormal.run(entryPoint);
+ compilerNormal.phase = Compiler.PHASE_DONE_RESOLVING;
compilerNormal.world.populate();
+ compilerNormal.backend.onResolutionComplete();
print('------------------------------------------------------------------');
print('compile deserialized');
@@ -75,9 +68,11 @@
memorySourceFiles: sourceFiles,
options: [Flags.analyzeOnly]);
compilerDeserialized.resolution.retainCachesForTesting = true;
- deserialize(compilerDeserialized, serializedData);
+ compilerDeserialized.serialization.deserializeFromText(serializedData);
await compilerDeserialized.run(entryPoint);
+ compilerDeserialized.phase = Compiler.PHASE_DONE_RESOLVING;
compilerDeserialized.world.populate();
+ compilerDeserialized.backend.onResolutionComplete();
checkAllImpacts(
compilerNormal, compilerDeserialized,
@@ -109,64 +104,144 @@
compilerDeserialized.enqueuer.resolution.processedElements,
"Processed element mismatch",
areElementsEquivalent,
+ onSameElement: (a, b) {
+ checkElements(
+ compilerNormal, compilerDeserialized, a, b, verbose: verbose);
+ },
verbose: verbose);
checkClassHierarchyNodes(
- compilerNormal.world.getClassHierarchyNode(
- compilerNormal.coreClasses.objectClass),
- compilerDeserialized.world.getClassHierarchyNode(
- compilerDeserialized.coreClasses.objectClass),
- verbose: verbose);
+ compilerNormal,
+ compilerDeserialized,
+ compilerNormal.world.getClassHierarchyNode(
+ compilerNormal.coreClasses.objectClass),
+ compilerDeserialized.world.getClassHierarchyNode(
+ compilerDeserialized.coreClasses.objectClass),
+ verbose: verbose);
+}
+
+void checkElements(
+ Compiler compiler1, Compiler compiler2,
+ Element element1, Element element2,
+ {bool verbose: false}) {
+ if (element1.isFunction ||
+ element1.isConstructor ||
+ (element1.isField && element1.isInstanceMember)) {
+ AstElement astElement1 = element1;
+ AstElement astElement2 = element2;
+ ClosureClassMap closureData1 =
+ compiler1.closureToClassMapper.computeClosureToClassMapping(
+ astElement1.resolvedAst);
+ ClosureClassMap closureData2 =
+ compiler2.closureToClassMapper.computeClosureToClassMapping(
+ astElement2.resolvedAst);
+
+ checkElementIdentities(closureData1, closureData2,
+ '$element1.closureElement',
+ closureData1.closureElement, closureData2.closureElement);
+ checkElementIdentities(closureData1, closureData2,
+ '$element1.closureClassElement',
+ closureData1.closureClassElement, closureData2.closureClassElement);
+ checkElementIdentities(closureData1, closureData2,
+ '$element1.callElement',
+ closureData1.callElement, closureData2.callElement);
+ check(closureData1, closureData2,
+ '$element1.thisLocal',
+ closureData1.thisLocal, closureData2.thisLocal,
+ areLocalsEquivalent);
+ checkMaps(
+ closureData1.freeVariableMap,
+ closureData2.freeVariableMap,
+ "$element1.freeVariableMap",
+ areLocalsEquivalent,
+ areCapturedVariablesEquivalent,
+ verbose: verbose);
+ checkMaps(
+ closureData1.capturingScopes,
+ closureData2.capturingScopes,
+ "$element1.capturingScopes",
+ areNodesEquivalent,
+ areClosureScopesEquivalent,
+ verbose: verbose,
+ keyToString: nodeToString);
+ checkSets(
+ closureData1.variablesUsedInTryOrGenerator,
+ closureData2.variablesUsedInTryOrGenerator,
+ "$element1.variablesUsedInTryOrGenerator",
+ areLocalsEquivalent,
+ verbose: verbose);
+ }
+}
+
+void checkMixinUses(
+ Compiler compiler1, Compiler compiler2,
+ ClassElement class1, ClassElement class2,
+ {bool verbose: false}) {
+
+ checkSets(
+ compiler1.world.mixinUsesOf(class1),
+ compiler2.world.mixinUsesOf(class2),
+ "Mixin uses of $class1 vs $class2",
+ areElementsEquivalent,
+ verbose: verbose);
+
}
void checkClassHierarchyNodes(
- ClassHierarchyNode a, ClassHierarchyNode b,
+ Compiler compiler1,
+ Compiler compiler2,
+ ClassHierarchyNode node1, ClassHierarchyNode node2,
{bool verbose: false}) {
if (verbose) {
- print('Checking $a vs $b');
+ print('Checking $node1 vs $node2');
}
Expect.isTrue(
- areElementsEquivalent(a.cls, b.cls),
- "Element identity mismatch for ${a.cls} vs ${b.cls}.");
+ areElementsEquivalent(node1.cls, node2.cls),
+ "Element identity mismatch for ${node1.cls} vs ${node2.cls}.");
Expect.equals(
- a.isDirectlyInstantiated,
- b.isDirectlyInstantiated,
- "Value mismatch for 'isDirectlyInstantiated' for ${a.cls} vs ${b.cls}.");
+ node1.isDirectlyInstantiated,
+ node2.isDirectlyInstantiated,
+ "Value mismatch for 'isDirectlyInstantiated' "
+ "for ${node1.cls} vs ${node2.cls}.");
Expect.equals(
- a.isIndirectlyInstantiated,
- b.isIndirectlyInstantiated,
+ node1.isIndirectlyInstantiated,
+ node2.isIndirectlyInstantiated,
"Value mismatch for 'isIndirectlyInstantiated' "
- "for ${a.cls} vs ${b.cls}.");
+ "for ${node1.cls} vs ${node2.cls}.");
// TODO(johnniwinther): Enforce a canonical and stable order on direct
// subclasses.
- for (ClassHierarchyNode child in a.directSubclasses) {
+ for (ClassHierarchyNode child in node1.directSubclasses) {
bool found = false;
- for (ClassHierarchyNode other in b.directSubclasses) {
+ for (ClassHierarchyNode other in node2.directSubclasses) {
if (areElementsEquivalent(child.cls, other.cls)) {
- checkClassHierarchyNodes(child, other,
- verbose: verbose);
+ checkClassHierarchyNodes(compiler1, compiler2,
+ child, other, verbose: verbose);
found = true;
break;
}
}
if (!found) {
- Expect.isFalse(
- child.isInstantiated, 'Missing subclass ${child.cls} of ${a.cls}');
+ Expect.isFalse(child.isInstantiated,
+ 'Missing subclass ${child.cls} of ${node1.cls}');
}
}
+ checkMixinUses(compiler1, compiler2, node1.cls, node2.cls, verbose: verbose);
}
void checkSets(
Iterable set1,
Iterable set2,
String messagePrefix,
- bool areEquivalent(a, b),
+ bool sameElement(a, b),
{bool failOnUnfound: true,
- bool verbose: false}) {
+ bool verbose: false,
+ void onSameElement(a, b)}) {
List common = [];
List unfound = [];
Set remaining = computeSetDifference(
- set1, set2, common, unfound, areEquivalent);
+ set1, set2, common, unfound,
+ sameElement: sameElement,
+ checkElements: onSameElement);
StringBuffer sb = new StringBuffer();
sb.write("$messagePrefix:");
if (verbose) {
@@ -190,3 +265,136 @@
print(message);
}
}
+
+String defaultToString(obj) => '$obj';
+
+void checkMaps(
+ Map map1,
+ Map map2,
+ String messagePrefix,
+ bool sameKey(a, b),
+ bool sameValue(a, b),
+ {bool failOnUnfound: true,
+ bool failOnMismatch: true,
+ bool verbose: false,
+ String keyToString(key): defaultToString,
+ String valueToString(key): defaultToString}) {
+ List common = [];
+ List unfound = [];
+ List<List> mismatch = <List>[];
+ Set remaining = computeSetDifference(
+ map1.keys, map2.keys, common, unfound,
+ sameElement: sameKey,
+ checkElements: (k1, k2) {
+ var v1 = map1[k1];
+ var v2 = map2[k2];
+ if (!sameValue(v1, v2)) {
+ mismatch.add([k1, k2]);
+ }
+ });
+ StringBuffer sb = new StringBuffer();
+ sb.write("$messagePrefix:");
+ if (verbose) {
+ sb.write("\n Common: \n");
+ for (List pair in common) {
+ var k1 = pair[0];
+ var k2 = pair[1];
+ var v1 = map1[k1];
+ var v2 = map2[k2];
+ sb.write(" key1 =${keyToString(k1)}\n");
+ sb.write(" key2 =${keyToString(k2)}\n");
+ sb.write(" value1=${valueToString(v1)}\n");
+ sb.write(" value2=${valueToString(v2)}\n");
+ }
+ }
+ if (unfound.isNotEmpty || verbose) {
+ sb.write("\n Unfound: \n");
+ for (var k1 in unfound) {
+ var v1 = map1[k1];
+ sb.write(" key1 =${keyToString(k1)}\n");
+ sb.write(" value1=${valueToString(v1)}\n");
+ }
+ }
+ if (remaining.isNotEmpty || verbose) {
+ sb.write("\n Extra: \n");
+ for (var k2 in remaining) {
+ var v2 = map2[k2];
+ sb.write(" key2 =${keyToString(k2)}\n");
+ sb.write(" value2=${valueToString(v2)}\n");
+ }
+ }
+ if (mismatch.isNotEmpty || verbose) {
+ sb.write("\n Mismatch: \n");
+ for (List pair in mismatch) {
+ var k1 = pair[0];
+ var k2 = pair[1];
+ var v1 = map1[k1];
+ var v2 = map2[k2];
+ sb.write(" key1 =${keyToString(k1)}\n");
+ sb.write(" key2 =${keyToString(k2)}\n");
+ sb.write(" value1=${valueToString(v1)}\n");
+ sb.write(" value2=${valueToString(v2)}\n");
+ }
+ }
+ String message = sb.toString();
+ if (unfound.isNotEmpty || mismatch.isNotEmpty || remaining.isNotEmpty) {
+ if ((unfound.isNotEmpty && failOnUnfound) ||
+ (mismatch.isNotEmpty && failOnMismatch) ||
+ remaining.isNotEmpty) {
+ Expect.fail(message);
+ } else {
+ print(message);
+ }
+ } else if (verbose) {
+ print(message);
+ }
+}
+
+bool areLocalsEquivalent(Local a, Local b) {
+ if (a == b) return true;
+ if (a == null || b == null) return false;
+
+ if (a is Element) {
+ return b is Element && areElementsEquivalent(a as Element, b as Element);
+ } else {
+ return a.runtimeType == b.runtimeType &&
+ areElementsEquivalent(a.executableContext, b.executableContext);
+ }
+}
+
+bool areCapturedVariablesEquivalent(CapturedVariable a, CapturedVariable b) {
+ if (a == b) return true;
+ if (a == null || b == null) return false;
+ if (a is ClosureFieldElement && b is ClosureFieldElement) {
+ return areElementsEquivalent(a.closureClass, b.closureClass) &&
+ areLocalsEquivalent(a.local, b.local);
+ } else if (a is BoxFieldElement && b is BoxFieldElement) {
+ return areElementsEquivalent(a.variableElement, b.variableElement) &&
+ areLocalsEquivalent(a.box, b.box);
+ }
+ return false;
+}
+
+bool areClosureScopesEquivalent(ClosureScope a, ClosureScope b) {
+ if (a == b) return true;
+ if (a == null || b == null) return false;
+ if (!areLocalsEquivalent(a.boxElement, b.boxElement)) {
+ return false;
+ }
+ checkMaps(a.capturedVariables, b.capturedVariables,
+ 'ClosureScope.capturedVariables',
+ areLocalsEquivalent,
+ areElementsEquivalent);
+ checkSets(a.boxedLoopVariables, b.boxedLoopVariables,
+ 'ClosureScope.boxedLoopVariables',
+ areElementsEquivalent);
+ return true;
+}
+
+String nodeToString(Node node) {
+ String text = '$node';
+ if (text.length > 40) {
+ return '(${node.runtimeType}) ${text.substring(0, 37)}...';
+ }
+ return '(${node.runtimeType}) $text';
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/serialization/resolved_ast_test.dart b/tests/compiler/dart2js/serialization/resolved_ast_test.dart
index 0ca8672..b9bae80 100644
--- a/tests/compiler/dart2js/serialization/resolved_ast_test.dart
+++ b/tests/compiler/dart2js/serialization/resolved_ast_test.dart
@@ -6,10 +6,7 @@
import 'dart:async';
import 'package:async_helper/async_helper.dart';
-import 'package:expect/expect.dart';
import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/common/backend_api.dart';
-import 'package:compiler/src/common/names.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/filenames.dart';
@@ -23,8 +20,7 @@
main(List<String> args) {
Arguments arguments = new Arguments.from(args);
asyncTest(() async {
- String serializedData = await serializeDartCore(
- arguments: arguments, serializeResolvedAst: true);
+ String serializedData = await serializeDartCore(arguments: arguments);
if (arguments.filename != null) {
Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
await check(serializedData, entryPoint);
@@ -53,8 +49,7 @@
memorySourceFiles: sourceFiles,
options: [Flags.analyzeAll]);
compilerDeserialized.resolution.retainCachesForTesting = true;
- deserialize(
- compilerDeserialized, serializedData, deserializeResolvedAst: true);
+ compilerDeserialized.serialization.deserializeFromText(serializedData);
await compilerDeserialized.run(entryPoint);
checkAllResolvedAsts(compilerNormal, compilerDeserialized, verbose: true);
@@ -80,9 +75,11 @@
void checkResolvedAsts(Compiler compiler1, Element member1,
Compiler compiler2, Element member2,
{bool verbose: false}) {
+ if (!compiler2.serialization.isDeserialized(member2)) {
+ return;
+ }
ResolvedAst resolvedAst1 = compiler1.resolution.getResolvedAst(member1);
- ResolvedAst resolvedAst2 =
- compiler2.serialization.deserializer.getResolvedAst(member2);
+ ResolvedAst resolvedAst2 = compiler2.serialization.getResolvedAst(member2);
if (resolvedAst1 == null || resolvedAst2 == null) return;
diff --git a/tests/compiler/dart2js/serialization/test_data.dart b/tests/compiler/dart2js/serialization/test_data.dart
index 3056735..0606a48 100644
--- a/tests/compiler/dart2js/serialization/test_data.dart
+++ b/tests/compiler/dart2js/serialization/test_data.dart
@@ -201,6 +201,22 @@
}'''
}),
+ const Test(const {
+ 'main.dart': '''
+class A {
+ A();
+}
+main() => new A();
+ ''',
+ }),
+
+ const Test(const {
+ 'main.dart': '''
+class C {
+ const C();
+}
+main() => const C();'''
+ }),
];
class Test {
diff --git a/tests/compiler/dart2js/serialization/test_helper.dart b/tests/compiler/dart2js/serialization/test_helper.dart
index d753b53..496d0e3 100644
--- a/tests/compiler/dart2js/serialization/test_helper.dart
+++ b/tests/compiler/dart2js/serialization/test_helper.dart
@@ -4,23 +4,12 @@
library dart2js.serialization_test_helper;
-import 'dart:io';
-import '../memory_compiler.dart';
-import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/common/resolution.dart';
-import 'package:compiler/src/commandline_options.dart';
-import 'package:compiler/src/constants/constructors.dart';
import 'package:compiler/src/constants/expressions.dart';
import 'package:compiler/src/dart_types.dart';
import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/diagnostics/invariant.dart';
import 'package:compiler/src/elements/elements.dart';
-import 'package:compiler/src/elements/visitor.dart';
-import 'package:compiler/src/ordered_typeset.dart';
-import 'package:compiler/src/serialization/element_serialization.dart';
import 'package:compiler/src/serialization/equivalence.dart';
-import 'package:compiler/src/serialization/json_serializer.dart';
-import 'package:compiler/src/serialization/serialization.dart';
import 'package:compiler/src/tree/nodes.dart';
/// Strategy for checking equivalence.
@@ -163,7 +152,8 @@
Iterable set2,
List common,
List unfound,
- [bool sameElement(a, b) = equality]) {
+ {bool sameElement(a, b): equality,
+ void checkElements(a, b)}) {
// TODO(johnniwinther): Avoid the quadratic cost here. Some ideas:
// - convert each set to a list and sort it first, then compare by walking
// both lists in parallel
@@ -175,6 +165,9 @@
bool found = false;
for (var element2 in remaining) {
if (sameElement(element1, element2)) {
+ if (checkElements != null) {
+ checkElements(element1, element2);
+ }
found = true;
remaining.remove(element2);
break;
@@ -199,11 +192,13 @@
String property,
Iterable set1,
Iterable set2,
- bool sameElement(a, b)) {
+ bool sameElement(a, b),
+ {void onSameElement(a, b)}) {
List common = [];
List unfound = [];
Set remaining =
- computeSetDifference(set1, set2, common, unfound, sameElement);
+ computeSetDifference(set1, set2, common, unfound,
+ sameElement: sameElement, checkElements: onSameElement);
if (unfound.isNotEmpty || remaining.isNotEmpty) {
String message =
"Set mismatch for `$property` on $object1 vs $object2: \n"
diff --git a/tests/compiler/dart2js/source_map_d2js_validity_test.dart b/tests/compiler/dart2js/source_map_d2js_validity_test.dart
index 062a35a..3829144 100644
--- a/tests/compiler/dart2js/source_map_d2js_validity_test.dart
+++ b/tests/compiler/dart2js/source_map_d2js_validity_test.dart
@@ -8,7 +8,7 @@
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/dart2js.dart' as entry;
import 'package:compiler/src/apiimpl.dart';
-import 'package:compiler/compiler.dart';
+import 'package:compiler/compiler_new.dart';
import 'source_map_validator_helper.dart';
diff --git a/tests/compiler/dart2js/source_map_deferred_d2js_validity_test.dart b/tests/compiler/dart2js/source_map_deferred_d2js_validity_test.dart
index 36a4878..0afe96e 100644
--- a/tests/compiler/dart2js/source_map_deferred_d2js_validity_test.dart
+++ b/tests/compiler/dart2js/source_map_deferred_d2js_validity_test.dart
@@ -8,7 +8,7 @@
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/dart2js.dart' as entry;
import 'package:compiler/src/apiimpl.dart';
-import 'package:compiler/compiler.dart';
+import 'package:compiler/compiler_new.dart';
import 'source_map_validator_helper.dart';
diff --git a/tests/corelib/apply5_test.dart b/tests/corelib/apply5_test.dart
new file mode 100644
index 0000000..5435f10
--- /dev/null
+++ b/tests/corelib/apply5_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, 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";
+
+// Testing that, when compiled to JS, Function.apply works correctly for
+// functions with that will be invoked directly vs using .apply().
+
+class A {
+ foo([a = 10, b = 20, c = 30, d = 40, e = 50]) => "$a $b $c $d $e";
+}
+
+main() {
+ var a = new A();
+ var clos = a.foo;
+ Expect.equals(Function.apply(clos, []), "10 20 30 40 50");
+ Expect.equals(Function.apply(clos, [11]), "11 20 30 40 50");
+ Expect.equals(Function.apply(clos, [11, 21]), "11 21 30 40 50");
+ Expect.equals(Function.apply(clos, [11, 21, 31]), "11 21 31 40 50");
+ Expect.equals(Function.apply(clos, [11, 21, 31, 41]), "11 21 31 41 50");
+ Expect.equals(Function.apply(clos, [11, 21, 31, 41, 51]), "11 21 31 41 51");
+}
diff --git a/tests/corelib/iterable_generate_test.dart b/tests/corelib/iterable_generate_test.dart
index 851f14d..170dba9 100644
--- a/tests/corelib/iterable_generate_test.dart
+++ b/tests/corelib/iterable_generate_test.dart
@@ -42,4 +42,32 @@
if (checkedMode) {
Expect.throws(() => new Iterable<String>.generate(5));
}
+
+ // Omitted generator function means `(int x) => x`, and the type parameters
+ // must then be compatible with `int`.
+ // Check that we catch invalid type parameters.
+
+ // Valid types:
+ Iterable<int> iter1 = new Iterable<int>.generate(5);
+ Expect.equals(2, iter1.elementAt(2));
+ Iterable<num> iter2 = new Iterable<num>.generate(5);
+ Expect.equals(2, iter2.elementAt(2));
+ Iterable<Object> iter3 = new Iterable<Object>.generate(5);
+ Expect.equals(2, iter3.elementAt(2));
+ Iterable<dynamic> iter4 = new Iterable<dynamic>.generate(5);
+ Expect.equals(2, iter4.elementAt(2));
+
+ // Invalid types:
+ Expect.throws(() => new Iterable<String>.generate(5));
+ Expect.throws(() => new Iterable<Null>.generate(5));
+ Expect.throws(() => new Iterable<bool>.generate(5));
+
+ // Regression: https://github.com/dart-lang/sdk/issues/26358
+ var count = 0;
+ var iter = new Iterable.generate(5, (v) { count++; return v; });
+ Expect.equals(0, count);
+ Expect.equals(2, iter.elementAt(2)); // Doesn't compute the earlier values.
+ Expect.equals(1, count);
+ Expect.equals(2, iter.skip(2).first); // Doesn't compute the skipped values.
+ Expect.equals(2, count);
}
diff --git a/tests/corelib/set_test.dart b/tests/corelib/set_test.dart
index 20a136a..55e7250 100644
--- a/tests/corelib/set_test.dart
+++ b/tests/corelib/set_test.dart
@@ -523,5 +523,5 @@
testASetFrom((x) => new Set<A>.from(x));
testASetFrom((x) => new HashSet<A>.from(x));
testASetFrom((x) => new LinkedHashSet<A>.from(x));
- testASetFrom((x) => new SplayTreeSet<A>.from(x));
+ testASetFrom((x) => new SplayTreeSet<A>.from(x, identityCompare));
}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 157f638..59748da 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -4,9 +4,9 @@
[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
browser/*: SkipByDesign # Browser specific tests
-isolate_stress_test: Fail # Issue 12588: This should be able to pass when we have wrapper-less tests.
+isolate_stress_test: Skip # Issue 12588: Uses dart:html. This should be able to pass when we have wrapper-less tests.
-[ $runtime != vm ]
+[ $runtime != vm || $mode == product ]
checked_test: Skip # Unsupported.
[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == mips && $mode == debug ]
@@ -176,10 +176,11 @@
spawn_uri_vm_test: Skip # Isolate.spawnUri
issue_21398_parent_isolate_test: Skip # Isolate.spawnUri
error_at_spawnuri_test: Skip # Isolate.spawnUri
+spawn_uri_missing_from_isolate_test: Skip # Isolate.spawnUri
+spawn_uri_missing_test: Skip # Isolate.spawnUri
-[ $runtime == dart_product ]
-spawn_uri_missing_from_isolate_test: Skip # SpawnUri in product mode
-spawn_uri_missing_test: Skip # SpawnUri in product mode
+[ $mode == product ]
+issue_24243_parent_isolate_test: Skip # Requires checked mode
[ $compiler == dart2js && $cps_ir && $checked ]
*: Skip # `assert` not implemented
diff --git a/tests/language/generic_functions_test.dart b/tests/language/generic_functions_test.dart
index e3f6caf..c9628a6 100644
--- a/tests/language/generic_functions_test.dart
+++ b/tests/language/generic_functions_test.dart
@@ -1,6 +1,8 @@
// Copyright (c) 2016, 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.
+//
+// DartOptions=--generic-method-syntax
/// Dart test verifying that the parser can handle type parameterization of
/// function declarations and function invocations. Variant of code from
diff --git a/tests/language/generic_local_functions_test.dart b/tests/language/generic_local_functions_test.dart
index 6a350d4..21bd7a7 100644
--- a/tests/language/generic_local_functions_test.dart
+++ b/tests/language/generic_local_functions_test.dart
@@ -1,6 +1,8 @@
// Copyright (c) 2016, 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.
+//
+// DartOptions=--generic-method-syntax
/// Dart test verifying that the parser can handle type parameterization of
/// local function declarations, and declarations of function parameters.
diff --git a/tests/language/generic_methods_test.dart b/tests/language/generic_methods_test.dart
index 9151fc3..fba394a 100644
--- a/tests/language/generic_methods_test.dart
+++ b/tests/language/generic_methods_test.dart
@@ -1,6 +1,8 @@
// Copyright (c) 2016, 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.
+//
+// DartOptions=--generic-method-syntax
/// Dart test verifying that the parser can handle type parameterization of
/// method declarations and method invocations. Slightly adjusted version of
diff --git a/tests/language/generic_sends_test.dart b/tests/language/generic_sends_test.dart
index 57befee..332439c7 100644
--- a/tests/language/generic_sends_test.dart
+++ b/tests/language/generic_sends_test.dart
@@ -1,6 +1,8 @@
// Copyright (c) 2016, 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.
+//
+// DartOptions=--generic-method-syntax
/// Dart test verifying that the parser can handle certain cases where
/// grammar ambiguity is resolved in favor of generic sends, not
diff --git a/tests/language/language.status b/tests/language/language.status
index 5eacbfa..4b75506 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -49,7 +49,6 @@
generic_functions_test: CompiletimeError # Issue 25869
generic_local_functions_test: CompiletimeError # Issue 25869
generic_sends_test: CompiletimeError # Issue 25869
-generic_method_type_usage_test: CompiletimeError # Tests --generic-method-syntax, plus issue 25869
[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
@@ -58,7 +57,7 @@
vm/debug_break_enabled_vm_test/01: Crash, OK # Expected to hit breakpoint.
try_catch_optimized1_test: Skip # Srdjan investigating
-[ ($compiler == none || $compiler == precompiler) && $checked ]
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $checked ]
type_variable_bounds4_test/01: Fail # Issue 14006
[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && (($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) || $runtime == drt || $runtime == dartium) ]
@@ -95,7 +94,6 @@
generic_functions_test: RuntimeError # Issue 25869
generic_local_functions_test: RuntimeError # Issue 25869
generic_sends_test: RuntimeError # Issue 25869
-generic_method_type_usage_test: CompiletimeError # Tests --generic-method-syntax, plus issue 25869
config_import_test: Skip # Issue 26250
[ $compiler == none && $runtime == dartium && $system == linux && $arch != x64 ]
@@ -158,17 +156,30 @@
super_getter_setter_test: SkipByDesign
vm/reflect_core_vm_test: SkipByDesign
-[ ($noopt || $compiler == precompiler || $compiler == dart2app) ]
+[ $noopt || $compiler == precompiler || $compiler == dart2app || $mode == product ]
# Deferred loading happens eagerly
regress_23408_test: Skip
deferred_inheritance_constraints_test: Skip
deferred_global_test: Skip
deferred_load_constants_test: Skip
tearoff_basic_test: Skip
+deferred_static_seperate_test: Skip
+deferred_constraints_type_annotation_test/new_before_load: Skip
+regress_22443_test: Skip
+[ $compiler == precompiler || $compiler == dart2app ]
+ct_const2_test: Skip # Incompatible flag: --compile_all
+hello_dart_test: Skip # Incompatible flag: --compile_all
+
+[ $compiler == precompiler ]
+implicit_closure_test: Skip # Incompatible flag: --use_slow_path
+deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
+
+[ $noopt || $compiler == precompiler || $compiler == dart2app ]
vm/type_vm_test: RuntimeError # Expects line and column numbers
-vm/type_cast_vm_test: RuntimeError # Line number mismatch.
+vm/type_cast_vm_test: RuntimeError # Expects line and column numbers
+[ $mode == product ]
issue13474_test: SkipByDesign # Requires checked mode.
assertion_test: SkipByDesign # Requires checked mode.
named_parameters_type_test/01: SkipByDesign # Requires checked mode.
@@ -181,21 +192,9 @@
generic_test: SkipByDesign # Requires checked mode.
map_literal4_test: SkipByDesign # Requires checked mode.
-[ $runtime == dart_precompiled ]
-ct_const2_test: Skip # Incompatible flag: --compile_all
-hello_dart_test: Skip # Incompatible flag: --compile_all
-implicit_closure_test: Skip # Incompatible flag: --use_slow_path
-deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
-
-[ $runtime == dart_product ]
-# Deferred loading happens eagerly (not sure why this works on precompiled code).
-deferred_static_seperate_test: Skip
-deferred_constraints_type_annotation_test/new_before_load: Skip
-regress_22443_test: Skip
-
-[ $runtime == vm && $mode == product ]
vm/type_vm_test: Fail,OK # Expects exact type name.
+
[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $browser ]
# The following tests are supposed to fail.
library_env_test/has_io_support: RuntimeError, OK
@@ -206,7 +205,7 @@
library_env_test/has_html_support: RuntimeError, OK
library_env_test/has_no_io_support: RuntimeError, OK
-[ $compiler == none && $noopt == false && $mode != product ]
+[ ($compiler == none || $compiler == dart2app) && $noopt == false && $mode != product ]
# The following tests are supposed to fail.
library_env_test/has_no_mirror_support: RuntimeError, OK
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 9cc27c9..2035434 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -506,4 +506,3 @@
generic_local_functions_test: CompileTimeError # Issue 25868
generic_methods_test: CompileTimeError # Issue 25868
generic_sends_test: CompileTimeError # Issue 25868
-generic_method_type_usage_test: CompiletimeError # Tests --generic-method-syntax, plus issue 25868
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 025d91a..25902c1 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -35,13 +35,6 @@
accessor_conflict_import_prefixed_test: RuntimeError # Issue 25626
accessor_conflict_import_test: RuntimeError # Issue 25626
-# Experimental feature: Syntactic support for generic methods.
-generic_functions_test: CompileTimeError # Issue 25835
-generic_local_functions_test: CompileTimeError # Issue 25835
-generic_methods_test: CompileTimeError # Issue 25835
-generic_sends_test: CompileTimeError # Issue 25835
-generic_method_type_usage_test: CompiletimeError # Tests --generic-method-syntax, plus issue 25835
-
[ $compiler == dart2js && $runtime == jsshell ]
await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
async_star_test: RuntimeError # Jsshell does not provide non-zero timers, Issue 7728
@@ -52,6 +45,12 @@
[ $compiler == dart2js && $browser ]
config_import_test: Fail # Test flag is not passed to the compiler.
+# Experimental feature: Syntactic support for generic methods.
+generic_functions_test: CompileTimeError # DartOptions not passed to compiler.
+generic_local_functions_test: CompileTimeError # DartOptions not passed to compiler.
+generic_methods_test: CompileTimeError # DartOptions not passed to compiler.
+generic_sends_test: CompileTimeError # DartOptions not passed to compiler.
+
[ $compiler == dart2js ]
invocation_mirror_empty_arguments_test: Fail # Issue 24331
nan_identical_test: Fail # Issue 11551
@@ -133,6 +132,9 @@
malbounded_type_test_test/04: Fail # Issue 14121
malbounded_type_test2_test: Fail # Issue 14121
default_factory2_test/01: Fail # Issue 14121
+generic_functions_test: Crash # Issue 26436
+generic_local_functions_test: Crash # Issue 26436
+generic_methods_test: Crash # Issue 26436
[ $compiler == dart2js && $unchecked ]
type_checks_in_factory_method_test: RuntimeError # Issue 12746
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index e8387bf..52185f2 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -994,6 +994,29 @@
cs[0].completeError("BAD");
}
+void testFutureResult() {
+ asyncStart();
+ () async {
+ var f = new UglyFuture(5);
+ // Sanity check that our future is as mis-behaved as we think.
+ f.then((v) { Expect.isTrue(v is Future); });
+
+ var v = await f;
+ // The static type of await is Flatten(static-type-of-expression), so it
+ // suggests that it flattens. In practice it currently doesn't.
+ // The specification doesn't say anything special, so v should be the
+ // completion value of the UglyFuture future which is a future.
+ Expect.isTrue(v is Future);
+
+ // This used to hit an assert in checked mode.
+ // The CL adding this test changed the behavior to actually flatten the
+ // the future returned by the then-callback.
+ var w = new Future.value(42).then((_) => f);
+ Expect.equals(42, await w);
+ asyncEnd();
+ }();
+}
+
main() {
asyncStart();
@@ -1062,10 +1085,12 @@
testAnyIgnoreIncomplete();
testAnyIgnoreError();
+ testFutureResult();
+
asyncEnd();
}
-/// A Future that isn't recognizable as a _Future.
+/// A well-behaved Future that isn't recognizable as a _Future.
class CustomFuture<T> implements Future<T> {
Future _realFuture;
CustomFuture(this._realFuture);
@@ -1081,6 +1106,7 @@
int get hashCode => _realFuture.hashCode;
}
+/// A bad future that throws on every method.
class BadFuture<T> implements Future<T> {
Future then(action(T result), {Function onError}) {
throw "then GOTCHA!";
@@ -1098,3 +1124,25 @@
throw "timeout GOTCHA!";
}
}
+
+// An evil future that completes with another future.
+class UglyFuture implements Future<dynamic> {
+ final _result;
+ UglyFuture(int badness) :
+ _result = (badness == 0) ? 42 : new UglyFuture(badness - 1);
+ Future then(action(value), {onError(error, StackTrace stack)}) {
+ var c = new Completer();
+ c.complete(new Future.microtask(() => action(_result)));
+ return c.future;
+ }
+ Future catchError(onError, {test}) => this; // Never an error.
+ Future whenComplete(action()) {
+ return new Future.microtask(action).then((_) => this);
+ }
+ Stream asStream() {
+ return (new StreamController()..add(_result)..close()).stream;
+ }
+ Future timeout(Duration duration, {onTimeout()}) {
+ return this;
+ }
+}
diff --git a/tests/lib/convert/chunked_conversion1_test.dart b/tests/lib/convert/chunked_conversion1_test.dart
index 3c84b3e..0bbe44b 100644
--- a/tests/lib/convert/chunked_conversion1_test.dart
+++ b/tests/lib/convert/chunked_conversion1_test.dart
@@ -54,8 +54,7 @@
specialB(o) => add(o);
}
-class IntBoolConverter1 extends
- ChunkedConverter<List<int>, List<bool>, int, bool> {
+class IntBoolConverter1 extends Converter<List<int>, List<bool>> {
List<bool> convert(List<int> input) => input.map((x) => x > 0).toList();
startChunkedConversion(sink) {
@@ -64,8 +63,7 @@
}
}
-class BoolIntConverter1 extends
- ChunkedConverter<List<bool>, List<int>, bool, int> {
+class BoolIntConverter1 extends Converter<List<bool>, List<int>> {
List<int> convert(List<bool> input) => input.map((x) => x ? 1 : 0).toList();
startChunkedConversion(sink) {
@@ -106,7 +104,7 @@
close() => outSink.close();
}
-class IdentityConverter extends ChunkedConverter {
+class IdentityConverter extends Converter {
convert(x) => x;
startChunkedConversion(sink) {
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index ec94cf6..d6abe8f 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -314,6 +314,9 @@
developer/metrics_num_test: Skip # Because of a int / double type test.
developer/timeline_test: Skip # Not supported
+[ $mode == product ]
+developer/timeline_test: Skip # Not supported
+
[ $arch == simarm64 ]
convert/utf85_test: Skip # Pass, Slow Issue 20111.
diff --git a/tests/standalone/io/https_bad_certificate_test.dart b/tests/standalone/io/https_bad_certificate_test.dart
index 7dc5aa2..cafacfb 100644
--- a/tests/standalone/io/https_bad_certificate_test.dart
+++ b/tests/standalone/io/https_bad_certificate_test.dart
@@ -71,7 +71,8 @@
} catch (error) {
Expect.notEquals(result, 'pass');
if (result == 'fail') {
- Expect.isTrue(error is HandshakeException);
+ Expect.isTrue(error is HandshakeException ||
+ (callbackReturns is! bool && error is TypeError));
} else if (result == 'throw') {
Expect.isTrue(error is CustomException);
} else {
diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart
index 0c907ba..27d896f 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_test.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart
@@ -7,7 +7,7 @@
* already up to date" feature does work as it should.
* Therefore this test ensures that compilations are only skipped if the last
* modified date of the output of a dart2js compilation is newer than
- * - the the dart application to compile (including it's dependencies)
+ * - the dart application to compile (including it's dependencies)
* - the dart2js snapshot
* Furtheremore it ensure that a compilations is not skipped if any of the
* necessary files could not be found (dart2js snapshots, previous dart2js
diff --git a/tests/standalone/io/stdin_sync_test.dart b/tests/standalone/io/stdin_sync_test.dart
index 97c4b58..470f34b 100644
--- a/tests/standalone/io/stdin_sync_test.dart
+++ b/tests/standalone/io/stdin_sync_test.dart
@@ -12,7 +12,7 @@
void test(String line, List<String> expected) {
var script = Platform.script.resolve("stdin_sync_script.dart").toFilePath();
Process.start(Platform.executable,
- ["--checked", script]..addAll(
+ [script]..addAll(
expected.map(JSON.encode))).then((process) {
process.stdin.write(line);
process.stdin.close();
diff --git a/tests/standalone/io/stdio_nonblocking_test.dart b/tests/standalone/io/stdio_nonblocking_test.dart
index 05f5fde..69220e9 100644
--- a/tests/standalone/io/stdio_nonblocking_test.dart
+++ b/tests/standalone/io/stdio_nonblocking_test.dart
@@ -11,7 +11,7 @@
var script =
Platform.script.resolve("stdio_nonblocking_script.dart").toFilePath();
Process.run(Platform.executable,
- ['--checked', script],
+ [script],
stdoutEncoding: ASCII,
stderrEncoding: ASCII).then((result) {
print(result.stdout);
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 30a1101..b163964 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -115,6 +115,7 @@
[ ($runtime == vm || $runtime == dart_product) && ($arch == arm || $arch == arm64) ]
io/file_stream_test: Skip # Issue 26109
io/file_typed_data_test: Skip # Issue 26109
+io/file_input_stream_test: Skip # Issue 26109
[ $compiler == dart2js && $jscl ]
assert_test: RuntimeError, OK # Assumes unspecified fields on the AssertionError.
@@ -216,14 +217,13 @@
full_coverage_test: Skip # Platform.executable
regress_26031_test: Skip # Platform.resolvedExecutable
-[ $runtime == dart_precompiled ]
-io/compile_all_test: Crash # Incompatible flag --compile_all
+[ $compiler == precompiler || $compiler == dart2app ]
+io/compile_all_test: Skip # Incompatible flag --compile_all
[ $runtime == dart_product ]
io/stdout_bad_argument_test: Skip # Test exits and so can't generate snapshot.
[ $runtime == dart_precompiled || $runtime == dart_product ]
-debugger/*: Skip
full_coverage_test: Skip # Platform.executable
http_launch_test: Skip # Platform.executable
io/addlatexhash_test: Skip # Platform.executable
@@ -253,14 +253,17 @@
io/file_lock_test: Skip # Platform.executable
io/code_collection_test: Skip # Platform.executable
io/file_lock_test: Skip # Platform.executable
-io/code_collection_test: Skip # Platform.executable
io/raw_socket_cross_process_test: Skip # Platform.executable
io/test_extension_test: Skip # Platform.executable
io/named_pipe_script_test: Skip # Platform.executable
io/regress_7679_test: Skip # Platform.executable
io/process_*: Skip # Most use Platform.executable
+
+[ $runtime == dart_precompiled || $runtime == dart_product || $mode == product ]
+debugger/*: Skip
assert_test: SkipByDesign # Requires checked mode.
no_assert_test: SkipByDesign # Requires checked mode.
+io/code_collection_test: Skip # Incompatible flags
# Code coverage is not supported in product mode.
[ $mode == product ]
diff --git a/tests/try/web/test_case.dart b/tests/try/web/test_case.dart
index 5cb3846..56e1157 100644
--- a/tests/try/web/test_case.dart
+++ b/tests/try/web/test_case.dart
@@ -33,7 +33,7 @@
* 3. Repeat step 2 until there are no more tests.
*
* The purpose of this test is to simulate edits (during setup), and then let
- * the the mutation observer to process the mutations followed by validation.
+ * the mutation observer to process the mutations followed by validation.
*/
void runTests(List<TestCase> tests) {
Completer completer = new Completer();
diff --git a/tools/VERSION b/tools/VERSION
index ea11638..16386c7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 17
PATCH 0
-PRERELEASE 3
+PRERELEASE 4
PRERELEASE_PATCH 0
diff --git a/tools/dom/dom.json b/tools/dom/dom.json
index 3437c02..6514306 100644
--- a/tools/dom/dom.json
+++ b/tools/dom/dom.json
@@ -433,10 +433,34 @@
"PLAYING_STATE": {},
"SCHEDULED_STATE": {},
"UNSCHEDULED_STATE": {},
+ "addEventListener": {
+ "support_level": "untriaged"
+ },
"buffer": {},
+ "channelCount": {
+ "support_level": "untriaged"
+ },
+ "channelCountMode": {
+ "support_level": "untriaged"
+ },
+ "channelInterpretation": {
+ "support_level": "untriaged"
+ },
+ "connect": {
+ "support_level": "untriaged"
+ },
+ "context": {
+ "support_level": "untriaged"
+ },
"detune": {
"support_level": "untriaged"
},
+ "disconnect": {
+ "support_level": "untriaged"
+ },
+ "dispatchEvent": {
+ "support_level": "untriaged"
+ },
"gain": {},
"loop": {},
"loopEnd": {},
@@ -444,11 +468,20 @@
"noteGrainOn": {},
"noteOff": {},
"noteOn": {},
+ "numberOfInputs": {
+ "support_level": "untriaged"
+ },
+ "numberOfOutputs": {
+ "support_level": "untriaged"
+ },
"onended": {
"support_level": "untriaged"
},
"playbackRate": {},
"playbackState": {},
+ "removeEventListener": {
+ "support_level": "untriaged"
+ },
"start": {},
"stop": {}
},
@@ -1589,6 +1622,9 @@
"MIN_RADIUS": {
"support_level": "untriaged"
},
+ "id": {
+ "support_level": "untriaged"
+ },
"latitude": {
"support_level": "untriaged"
},
@@ -1858,6 +1894,12 @@
"timeStamp": {
"support_level": "experimental"
},
+ "timeline": {
+ "support_level": "untriaged"
+ },
+ "timelineEnd": {
+ "support_level": "untriaged"
+ },
"trace": {},
"warn": {}
},
@@ -2873,10 +2915,43 @@
"DirectoryEntry": {
"comment": "http://www.w3.org/TR/file-system-api/#the-directoryentry-interface",
"members": {
+ "copyTo": {
+ "support_level": "untriaged"
+ },
"createReader": {},
+ "filesystem": {
+ "support_level": "untriaged"
+ },
+ "fullPath": {
+ "support_level": "untriaged"
+ },
"getDirectory": {},
"getFile": {},
- "removeRecursively": {}
+ "getMetadata": {
+ "support_level": "untriaged"
+ },
+ "getParent": {
+ "support_level": "untriaged"
+ },
+ "isDirectory": {
+ "support_level": "untriaged"
+ },
+ "isFile": {
+ "support_level": "untriaged"
+ },
+ "moveTo": {
+ "support_level": "untriaged"
+ },
+ "name": {
+ "support_level": "untriaged"
+ },
+ "remove": {
+ "support_level": "untriaged"
+ },
+ "removeRecursively": {},
+ "toURL": {
+ "support_level": "untriaged"
+ }
},
"support_level": "experimental"
},
@@ -4312,8 +4387,41 @@
"FileEntry": {
"comment": "http://www.w3.org/TR/file-system-api/#the-fileentry-interface",
"members": {
+ "copyTo": {
+ "support_level": "untriaged"
+ },
"createWriter": {},
- "file": {}
+ "file": {},
+ "filesystem": {
+ "support_level": "untriaged"
+ },
+ "fullPath": {
+ "support_level": "untriaged"
+ },
+ "getMetadata": {
+ "support_level": "untriaged"
+ },
+ "getParent": {
+ "support_level": "untriaged"
+ },
+ "isDirectory": {
+ "support_level": "untriaged"
+ },
+ "isFile": {
+ "support_level": "untriaged"
+ },
+ "moveTo": {
+ "support_level": "untriaged"
+ },
+ "name": {
+ "support_level": "untriaged"
+ },
+ "remove": {
+ "support_level": "untriaged"
+ },
+ "toURL": {
+ "support_level": "untriaged"
+ }
},
"support_level": "experimental"
},
@@ -8054,8 +8162,41 @@
"MediaElementAudioSourceNode": {
"comment": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#MediaElementAudioSourceNode",
"members": {
+ "addEventListener": {
+ "support_level": "untriaged"
+ },
+ "channelCount": {
+ "support_level": "untriaged"
+ },
+ "channelCountMode": {
+ "support_level": "untriaged"
+ },
+ "channelInterpretation": {
+ "support_level": "untriaged"
+ },
+ "connect": {
+ "support_level": "untriaged"
+ },
+ "context": {
+ "support_level": "untriaged"
+ },
+ "disconnect": {
+ "support_level": "untriaged"
+ },
+ "dispatchEvent": {
+ "support_level": "untriaged"
+ },
"mediaElement": {
"support_level": "nonstandard"
+ },
+ "numberOfInputs": {
+ "support_level": "untriaged"
+ },
+ "numberOfOutputs": {
+ "support_level": "untriaged"
+ },
+ "removeEventListener": {
+ "support_level": "untriaged"
}
},
"support_level": "experimental"
@@ -8346,7 +8487,40 @@
"MediaStreamAudioSourceNode": {
"comment": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#MediaStreamAudioSourceNode",
"members": {
- "mediaStream": {}
+ "addEventListener": {
+ "support_level": "untriaged"
+ },
+ "channelCount": {
+ "support_level": "untriaged"
+ },
+ "channelCountMode": {
+ "support_level": "untriaged"
+ },
+ "channelInterpretation": {
+ "support_level": "untriaged"
+ },
+ "connect": {
+ "support_level": "untriaged"
+ },
+ "context": {
+ "support_level": "untriaged"
+ },
+ "disconnect": {
+ "support_level": "untriaged"
+ },
+ "dispatchEvent": {
+ "support_level": "untriaged"
+ },
+ "mediaStream": {},
+ "numberOfInputs": {
+ "support_level": "untriaged"
+ },
+ "numberOfOutputs": {
+ "support_level": "untriaged"
+ },
+ "removeEventListener": {
+ "support_level": "untriaged"
+ }
},
"support_level": "experimental"
},
@@ -9215,8 +9389,101 @@
"comment": "https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#OfflineAudioContext-section",
"members": {
"OfflineAudioContext": {},
+ "addEventListener": {
+ "support_level": "untriaged"
+ },
+ "close": {
+ "support_level": "untriaged"
+ },
+ "createAnalyser": {
+ "support_level": "untriaged"
+ },
+ "createBiquadFilter": {
+ "support_level": "untriaged"
+ },
+ "createBuffer": {
+ "support_level": "untriaged"
+ },
+ "createBufferSource": {
+ "support_level": "untriaged"
+ },
+ "createChannelMerger": {
+ "support_level": "untriaged"
+ },
+ "createChannelSplitter": {
+ "support_level": "untriaged"
+ },
+ "createConvolver": {
+ "support_level": "untriaged"
+ },
+ "createDelay": {
+ "support_level": "untriaged"
+ },
+ "createDynamicsCompressor": {
+ "support_level": "untriaged"
+ },
+ "createGain": {
+ "support_level": "untriaged"
+ },
+ "createMediaElementSource": {
+ "support_level": "untriaged"
+ },
+ "createMediaStreamDestination": {
+ "support_level": "untriaged"
+ },
+ "createMediaStreamSource": {
+ "support_level": "untriaged"
+ },
+ "createOscillator": {
+ "support_level": "untriaged"
+ },
+ "createPanner": {
+ "support_level": "untriaged"
+ },
+ "createPeriodicWave": {
+ "support_level": "untriaged"
+ },
+ "createScriptProcessor": {
+ "support_level": "untriaged"
+ },
+ "createStereoPanner": {
+ "support_level": "untriaged"
+ },
+ "createWaveShaper": {
+ "support_level": "untriaged"
+ },
+ "currentTime": {
+ "support_level": "untriaged"
+ },
+ "decodeAudioData": {
+ "support_level": "untriaged"
+ },
+ "destination": {
+ "support_level": "untriaged"
+ },
+ "dispatchEvent": {
+ "support_level": "untriaged"
+ },
+ "listener": {
+ "support_level": "untriaged"
+ },
+ "removeEventListener": {
+ "support_level": "untriaged"
+ },
+ "resume": {
+ "support_level": "untriaged"
+ },
+ "sampleRate": {
+ "support_level": "untriaged"
+ },
"startRendering": {
"support_level": "untriaged"
+ },
+ "state": {
+ "support_level": "untriaged"
+ },
+ "suspend": {
+ "support_level": "untriaged"
}
},
"support_level": "experimental"
@@ -9253,14 +9520,47 @@
"support_level": "deprecated"
},
"UNSCHEDULED_STATE": {},
+ "addEventListener": {
+ "support_level": "untriaged"
+ },
+ "channelCount": {
+ "support_level": "untriaged"
+ },
+ "channelCountMode": {
+ "support_level": "untriaged"
+ },
+ "channelInterpretation": {
+ "support_level": "untriaged"
+ },
+ "connect": {
+ "support_level": "untriaged"
+ },
+ "context": {
+ "support_level": "untriaged"
+ },
"detune": {},
+ "disconnect": {
+ "support_level": "untriaged"
+ },
+ "dispatchEvent": {
+ "support_level": "untriaged"
+ },
"frequency": {},
"noteOff": {},
"noteOn": {},
+ "numberOfInputs": {
+ "support_level": "untriaged"
+ },
+ "numberOfOutputs": {
+ "support_level": "untriaged"
+ },
"onended": {
"support_level": "untriaged"
},
"playbackState": {},
+ "removeEventListener": {
+ "support_level": "untriaged"
+ },
"setPeriodicWave": {
"support_level": "untriaged"
},
@@ -10438,6 +10738,15 @@
"Request": {
"members": {
"Request": {},
+ "arrayBuffer": {
+ "support_level": "untriaged"
+ },
+ "blob": {
+ "support_level": "untriaged"
+ },
+ "bodyUsed": {
+ "support_level": "untriaged"
+ },
"clone": {
"support_level": "untriaged"
},
@@ -10450,6 +10759,9 @@
"headers": {
"support_level": "untriaged"
},
+ "json": {
+ "support_level": "untriaged"
+ },
"mode": {
"support_level": "untriaged"
},
@@ -10459,6 +10771,9 @@
"referrer": {
"support_level": "untriaged"
},
+ "text": {
+ "support_level": "untriaged"
+ },
"url": {
"support_level": "untriaged"
}
@@ -20356,7 +20671,77 @@
"support_level": "stable"
},
"WorkerConsole": {
- "members": {},
+ "members": {
+ "assert": {
+ "support_level": "untriaged"
+ },
+ "clear": {
+ "support_level": "untriaged"
+ },
+ "count": {
+ "support_level": "untriaged"
+ },
+ "debug": {
+ "support_level": "untriaged"
+ },
+ "dir": {
+ "support_level": "untriaged"
+ },
+ "dirxml": {
+ "support_level": "untriaged"
+ },
+ "error": {
+ "support_level": "untriaged"
+ },
+ "group": {
+ "support_level": "untriaged"
+ },
+ "groupCollapsed": {
+ "support_level": "untriaged"
+ },
+ "groupEnd": {
+ "support_level": "untriaged"
+ },
+ "info": {
+ "support_level": "untriaged"
+ },
+ "log": {
+ "support_level": "untriaged"
+ },
+ "markTimeline": {
+ "support_level": "untriaged"
+ },
+ "profile": {
+ "support_level": "untriaged"
+ },
+ "profileEnd": {
+ "support_level": "untriaged"
+ },
+ "table": {
+ "support_level": "untriaged"
+ },
+ "time": {
+ "support_level": "untriaged"
+ },
+ "timeEnd": {
+ "support_level": "untriaged"
+ },
+ "timeStamp": {
+ "support_level": "untriaged"
+ },
+ "timeline": {
+ "support_level": "untriaged"
+ },
+ "timelineEnd": {
+ "support_level": "untriaged"
+ },
+ "trace": {
+ "support_level": "untriaged"
+ },
+ "warn": {
+ "support_level": "untriaged"
+ }
+ },
"support_level": "untriaged"
},
"WorkerContext": {
diff --git a/tools/dom/scripts/database.py b/tools/dom/scripts/database.py
index 7329b22..e5f1e6c 100755
--- a/tools/dom/scripts/database.py
+++ b/tools/dom/scripts/database.py
@@ -333,7 +333,7 @@
result = []
if interface.parents:
parent = interface.parents[0]
- if (IsPureInterface(parent.type.id) or
+ if (IsPureInterface(parent.type.id, self) or
(propagate_event_target and parent.type.id == 'EventTarget')):
result = walk(interface.parents, [])
else:
diff --git a/tools/dom/scripts/databasebuilder.py b/tools/dom/scripts/databasebuilder.py
index b0977ad..95dcd42 100755
--- a/tools/dom/scripts/databasebuilder.py
+++ b/tools/dom/scripts/databasebuilder.py
@@ -301,7 +301,7 @@
continue
if sig in res:
op = res[sig]
- # Only report if the the operations that match are either both suppressed
+ # Only report if the operations that match are either both suppressed
# or both not suppressed. Optional args aren't part of type signature
# for this routine. Suppressing a non-optional type and supplementing
# with an optional type appear the same.
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 90f8b34..125d64a 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -14,50 +14,152 @@
from htmlrenamer import custom_html_constructors, html_interface_renames, \
typed_array_renames
-_pure_interfaces = monitored.Set('generator._pure_interfaces', [
- # TODO(sra): DOMStringMap should be a class implementing Map<String,String>.
- 'DOMStringMap',
- 'AbstractWorker',
- 'CanvasPathMethods',
- 'ChildNode',
- 'DocumentAnimation',
- 'DocumentFontFaceSet',
- 'DocumentFullscreen',
- 'DocumentXPathEvaluator',
- 'ElementAnimation',
- 'ElementFullscreen',
- 'EventListener',
- 'GlobalEventHandlers',
- 'ImageBitmapFactories',
- 'MediaQueryListListener',
- 'MouseEventHitRegion',
- 'MutationCallback',
- 'NavigatorCPU',
- 'NavigatorEvents',
- 'NavigatorID',
- 'NavigatorLanguage',
- 'NavigatorOnLine',
- 'ParentNode',
- 'SVGDocument',
- 'SVGExternalResourcesRequired',
- 'SVGFilterPrimitiveStandardAttributes',
- 'SVGFitToViewBox',
- 'SVGTests',
- 'SVGURIReference',
- 'SVGZoomAndPan',
- 'TimeoutHandler',
- 'URLUtils',
- 'URLUtilsReadOnly',
- 'WebGLRenderingContextBase',
- 'WindowBase64',
- 'WindowEventHandlers',
- 'WindowImageBitmapFactories',
- 'WindowPagePopup',
- 'WindowTimers',
+_safe_interfaces = monitored.Set('generator._safe_interfaces', [
+ 'double',
+ 'Float32Array',
+ 'Float64Array',
+ 'Int8Array',
+ 'Int16Array',
+ 'Int32Array',
+ 'Uint8Array',
+ 'Uint8ClampedArray',
+ 'Uint16Array',
+ 'Uint32Array',
+ 'ArrayBufferView',
+ 'ArrayBuffer',
+ 'SourceBuffer', # IDL lies about this class being a pure interface.
+ 'Console', # this one is a bit of a hack as our console implementation
+ # in dart:html is non-standard for legacy reasons.
+ 'AudioContext',
+ 'AudioSourceNode',
+ 'WebGLVertexArrayObjectOES', # Added a polyfill for this.
+ # Types where we can get access to the prototype easily enough.
+ # We might consider in the future treating these are regular interface types.
+ 'StereoPannerNode',
+ 'PannerNode',
+ 'AudioNode',
+ 'FontFaceSet',
+ 'MemoryInfo',
+ 'ConsoleBase',
+ 'Geolocation',
+ 'Animation',
+ 'SourceBufferList',
+ 'GamepadList',
+
+ # The following classes are enabled just to get the build to go.
+ # SpeechRecognitionResultList isn't really allowed but the codegen creates
+ # invalid output otherwise.
+
+ 'SpeechRecognitionResultList',
+ 'SQLResultSetRowList',
])
-def IsPureInterface(interface_name):
- return interface_name in _pure_interfaces
+# These are interfaces that we have to treat as safe for dart2js and dartium
+# but going in dev compiler we should not treat as safe as these classes
+# really aren't guaranteed to have a stable interface name.
+_safe_interfaces_legacy = monitored.Set('generator._safe_interfaces_legacy', [
+ 'ANGLEInstancedArrays',
+ 'Bluetooth',
+ 'Body',
+ 'NonDocumentTypeChildNode',
+ 'CHROMIUMSubscribeUniform',
+ 'CHROMIUMValuebuffer',
+ 'GeofencingRegion',
+ 'Coordinates',
+ 'DOMFileSystem',
+ 'DirectoryEntry',
+ 'DOMFileSystemSync',
+ 'Entry',
+ 'Database',
+ 'DeprecatedStorageInfo',
+ 'DeprecatedStorageQuota',
+ 'DeviceAcceleration',
+ 'DeviceRotationRate',
+ 'DirectoryReader',
+ 'EntrySync',
+ 'DirectoryEntrySync',
+ 'DirectoryReaderSync',
+ 'NonElementParentNode',
+ 'EXTBlendMinMax',
+ 'EXTFragDepth',
+ 'EXTShaderTextureLOD',
+ 'EXTTextureFilterAnisotropic',
+ 'EXTsRGB',
+ 'EffectModel',
+ 'FileEntry',
+ 'FileEntrySync',
+ 'FileWriter',
+ 'FileWriterSync',
+ 'FontFaceSetLoadEvent',
+ 'Geofencing',
+ 'Geoposition',
+ 'Iterator',
+ 'MediaDeviceInfo',
+ 'MediaStreamTrackEvent',
+ 'Metadata',
+ 'NavigatorStorageUtils',
+ 'StorageQuota',
+ 'NavigatorUserMediaError',
+ 'OESElementIndexUint',
+ 'OESStandardDerivatives',
+ 'OESTextureFloat',
+ 'OESTextureFloatLinear',
+ 'OESTextureHalfFloat',
+ 'OESTextureHalfFloatLinear',
+ 'OESVertexArrayObject',
+ 'PagePopupController',
+ 'PluginPlaceholderElement',
+ 'PositionError',
+ 'RTCDTMFSender',
+ 'RTCDataChannel',
+ 'RTCDataChannelEvent',
+ 'RTCIceCandidateEvent',
+ 'RTCStatsReport',
+ 'RTCStatsResponse',
+ 'ReadableByteStreamReader',
+ 'ReadableStreamReader',
+ 'ResourceProgressEvent',
+ 'SQLError',
+ 'SQLResultSet',
+ 'SQLTransaction',
+ 'SharedArrayBuffer',
+ 'SourceInfo',
+ 'SpeechRecognitionAlternative',
+ 'SpeechRecognitionResult',
+ 'SpeechSynthesis',
+ 'SpeechSynthesisVoice',
+ 'StorageInfo',
+ 'StyleMedia',
+ 'WebGL2RenderingContextBase',
+ 'WebGLCompressedTextureATC',
+ 'WebGLCompressedTextureETC1',
+ 'WebGLCompressedTexturePVRTC',
+ 'WebGLCompressedTextureS3TC',
+ 'WebGLDebugRendererInfo',
+ 'WebGLDebugShaders',
+ 'WebGLDepthTexture',
+ 'WebGLDrawBuffers',
+ 'WebGLLoseContext',
+ 'WorkerConsole',
+ 'WorkerPerformance',
+ 'XPathNSResolver',
+])
+
+# Classes we should just suppress?
+# SpeechGrammarList and friends
+
+def IsPureInterface(interface_name, database):
+ if (interface_name in _safe_interfaces or
+ interface_name in _safe_interfaces_legacy or
+ database.HasInterface(interface_name)):
+ return False
+
+ interface = database.GetInterface(interface_name)
+
+ if 'Constructor' in interface.ext_attrs:
+ return False
+
+ return interface.is_no_interface_object
#
# Classes which have native constructors but which we are suppressing because
@@ -163,7 +265,7 @@
'PannerNode': 'PannerNode,AudioPannerNode,webkitAudioPannerNode',
- 'RTCPeerConnection': 'RTCPeerConnection,mozRTCPeerConnection',
+ 'RTCPeerConnection': 'RTCPeerConnection,webkitRTCPeerConnection,mozRTCPeerConnection',
'RTCIceCandidate': 'RTCIceCandidate,mozRTCIceCandidate',
@@ -929,7 +1031,7 @@
# dart_type.
if self._data.dart_type != None:
return self.dart_type()
- if IsPureInterface(self.idl_type()):
+ if IsPureInterface(self.idl_type(), self._type_registry._database):
return self.idl_type()
return self.interface_name()
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index c66ce5b..8397b8f 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -177,7 +177,7 @@
# Never remove operations that are added as a result of an implements they
# are pure interfaces (mixins to this interface).
- if (IsPureInterface(parent_name)):
+ if (IsPureInterface(parent_name, self._database)):
return
for operation in parent.operations:
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 8b9311b..856da50 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -141,6 +141,8 @@
'WorkerLocation', # Workers
'WorkerNavigator', # Workers
'XMLHttpRequestProgressEvent',
+ # Obsolete event for NaCl.
+ 'ResourceProgressEvent',
]
for interface in _removed_html_interfaces:
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 75e38fd..2208f22 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -554,7 +554,7 @@
base_type_info = None
if self._interface.parents:
supertype = self._interface.parents[0].type.id
- if not IsDartCollectionType(supertype) and not IsPureInterface(supertype):
+ if not IsDartCollectionType(supertype) and not IsPureInterface(supertype, self._database):
base_type_info = self._type_registry.TypeInfo(supertype)
if base_type_info:
@@ -594,7 +594,7 @@
class_modifiers = ''
if (self._renamer.ShouldSuppressInterface(self._interface) or
- IsPureInterface(self._interface.id)):
+ IsPureInterface(self._interface.id, self._database)):
# XMLHttpRequestProgressEvent can't be abstract we need to instantiate
# for JsInterop.
if (not(isinstance(self._backend, Dart2JSBackend)) and
@@ -614,7 +614,7 @@
class_modifiers = 'abstract '
native_spec = ''
- if not IsPureInterface(self._interface.id):
+ if not IsPureInterface(self._interface.id, self._database):
native_spec = self._backend.NativeSpec()
class_name = self._interface_type_info.implementation_name()
@@ -689,7 +689,7 @@
if (implementation_members_emitter and
self._options.templates._conditions['DARTIUM'] and
self._options.dart_js_interop and
- not IsPureInterface(self._interface.id)):
+ not IsPureInterface(self._interface.id, self._database)):
implementation_members_emitter.Emit(js_interop_wrapper)
if isElement and self._interface.id != 'Element':
@@ -760,7 +760,9 @@
def AdditionalImplementedInterfaces(self):
implements = super(Dart2JSBackend, self).AdditionalImplementedInterfaces()
if self._interface_type_info.list_item_type() and self.HasIndexedGetter():
- implements.append('JavaScriptIndexingBehavior')
+ item_type = self._type_registry.TypeInfo(
+ self._interface_type_info.list_item_type()).dart_type()
+ implements.append('JavaScriptIndexingBehavior<%s>' % item_type)
return implements
def NativeSpec(self):
@@ -898,7 +900,7 @@
if self._HasCustomImplementation(attribute.id):
return
- if IsPureInterface(self._interface.id):
+ if IsPureInterface(self._interface.id, self._database):
self._AddInterfaceAttribute(attribute, html_name, read_only)
return
@@ -1068,7 +1070,7 @@
if self._HasCustomImplementation(info.name):
return
- if IsPureInterface(self._interface.id):
+ if IsPureInterface(self._interface.id, self._database):
self._AddInterfaceOperation(info, html_name)
elif info.callback_args:
self._AddFutureifiedOperation(info, html_name)
@@ -1202,6 +1204,7 @@
idl_type, self._interface.id, idl_member_name):
return_type = self.SecureOutputType(idl_type)
native_type = self._NarrowToImplementationType(idl_type)
+
if native_type != return_type:
anns = anns + [
"@Returns('%s')" % native_type,
@@ -1227,7 +1230,7 @@
parent = interface.parents[0]
if IsDartCollectionType(parent.type.id):
return (None, None)
- if IsPureInterface(parent.type.id):
+ if IsPureInterface(parent.type.id, self._database):
return (None, None)
if self._database.HasInterface(parent.type.id):
interfaces_to_search_in = []
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 1f5a030..f6284ab 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -193,7 +193,7 @@
def StartInterface(self, members_emitter):
# Create emitters for c++ implementation.
- if not IsPureInterface(self._interface.id) and \
+ if not IsPureInterface(self._interface.id, self._database) and \
not IsCustomType(self._interface.id):
self._cpp_header_emitter = self._cpp_library_emitter.CreateHeaderEmitter(
self._interface.id,
@@ -951,7 +951,7 @@
full_dart_name = \
self.DeriveQualifiedBlinkName(self._interface.id,
dart_native_name)
- if IsPureInterface(self._interface.id):
+ if IsPureInterface(self._interface.id, self._database):
caller_emitter.Emit(
'\n'
' $METADATA$DART_DECLARATION;\n',
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index 76bed57..474a143 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -76,7 +76,7 @@
* [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener)
*/
ElementStream<T> _forElementList(ElementList e, {bool useCapture: false}) {
- return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+ return new _ElementListEventStreamImpl<T>(e, _eventType, useCapture);
}
/**
@@ -294,9 +294,9 @@
}
}
- Future asFuture([var futureValue]) {
+ Future/*<E>*/ asFuture/*<E>*/([var/*=E*/ futureValue]) {
// We just need a future that will never succeed or fail.
- Completer completer = new Completer();
+ var completer = new Completer/*<E>*/();
return completer.future;
}
}
diff --git a/tools/dom/src/WrappedList.dart b/tools/dom/src/WrappedList.dart
index c06e8dc..2e28c5c 100644
--- a/tools/dom/src/WrappedList.dart
+++ b/tools/dom/src/WrappedList.dart
@@ -16,7 +16,7 @@
// Iterable APIs
- Iterator<E> get iterator => new _WrappedIterator(_list.iterator);
+ Iterator<E> get iterator => new _WrappedIterator<E>(_list.iterator);
int get length => _list.length;
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index ead9d63..a2bd1e8 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -132,12 +132,6 @@
HtmlElement.created() : super.created();
}
-// EntryArray type was removed, so explicitly adding it to allow support for
-// older Chrome versions.
-// Issue #12573.
-@Native("EntryArray")
-abstract class _EntryArray implements List<Entry> {}
-
/**
* Spawn a DOM isolate using the given URI in the same window.
* This isolate is not concurrent. It runs on the browser thread
diff --git a/tools/dom/templates/html/impl/impl_Window.darttemplate b/tools/dom/templates/html/impl/impl_Window.darttemplate
index c9f8279..8abac37 100644
--- a/tools/dom/templates/html/impl/impl_Window.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Window.darttemplate
@@ -339,8 +339,10 @@
const _BeforeUnloadEventStreamProvider(this._eventType);
Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
- var stream = new _EventStream(e, _eventType, useCapture);
$if DART2JS
+ // Specify the generic type for EventStream only in dart2js to avoid
+ // checked mode errors in dartium.
+ var stream = new _EventStream<BeforeUnloadEvent>(e, _eventType, useCapture);
var controller = new StreamController<BeforeUnloadEvent>(sync: true);
stream.listen((event) {
@@ -350,6 +352,7 @@
return controller.stream;
$else
+ var stream = new _EventStream(e, _eventType, useCapture);
return stream;
$endif
}
@@ -359,11 +362,23 @@
}
ElementStream<BeforeUnloadEvent> forElement(Element e, {bool useCapture: false}) {
+$if DART2JS
+ // Specify the generic type for _ElementEventStreamImpl only in dart2js to
+ // avoid checked mode errors in dartium.
+ return new _ElementEventStreamImpl<BeforeUnloadEvent>(e, _eventType, useCapture);
+$else
return new _ElementEventStreamImpl(e, _eventType, useCapture);
+$endif
}
ElementStream<BeforeUnloadEvent> _forElementList(ElementList e,
{bool useCapture: false}) {
+$if DART2JS
+ // Specify the generic type for _ElementEventStreamImpl only in dart2js to
+ // avoid checked mode errors in dartium.
+ return new _ElementListEventStreamImpl<BeforeUnloadEvent>(e, _eventType, useCapture);
+$else
return new _ElementListEventStreamImpl(e, _eventType, useCapture);
+$endif
}
}
diff --git a/tools/get_archive.py b/tools/get_archive.py
index 409d147..7517f54 100755
--- a/tools/get_archive.py
+++ b/tools/get_archive.py
@@ -132,7 +132,7 @@
result, out = Gsutil('ls', permanent_prefix % {'osname' : osname,
'num1': the_revision_num, 'num2': '*', 'bot': bot })
if result == 0:
- # First try to find one with the the second number the same as the
+ # First try to find one with the second number the same as the
# requested number.
latest = out.split()[0]
# Now test that the permissions are correct so you can actually
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 67a739a..822700f 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -299,6 +299,7 @@
return <Command>[
commandBuilder.getAdbPrecompiledCommand(precompiledRunner,
script,
+ arguments,
useBlobs)
];
}
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index d862db5..e9fed49 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -348,10 +348,12 @@
class AdbPrecompilationCommand extends Command {
final String precompiledRunnerFilename;
final String precompiledTestDirectory;
+ final List<String> arguments;
final bool useBlobs;
AdbPrecompilationCommand._(this.precompiledRunnerFilename,
this.precompiledTestDirectory,
+ this.arguments,
this.useBlobs)
: super._("adb_precompilation");
@@ -359,6 +361,7 @@
super._buildHashCode(builder);
builder.add(precompiledRunnerFilename);
builder.add(precompiledTestDirectory);
+ builder.add(arguments);
builder.add(useBlobs);
}
@@ -366,6 +369,7 @@
super._equal(other) &&
precompiledRunnerFilename == other.precompiledRunnerFilename &&
useBlobs == other.useBlobs &&
+ arguments == other.arguments &&
precompiledTestDirectory == other.precompiledTestDirectory;
String toString() => 'Steps to push precompiled runner and precompiled code '
@@ -640,9 +644,10 @@
AdbPrecompilationCommand getAdbPrecompiledCommand(String precompiledRunner,
String testDirectory,
+ List<String> arguments,
bool useBlobs) {
var command = new AdbPrecompilationCommand._(
- precompiledRunner, testDirectory, useBlobs);
+ precompiledRunner, testDirectory, arguments, useBlobs);
return _getUniqueCommand(command);
}
@@ -2415,7 +2420,7 @@
/*
* [CommandExecutor] is responsible for executing commands. It will make sure
- * that the the following two constraints are satisfied
+ * that the following two constraints are satisfied
* - [:numberOfProcessesUsed <= maxProcesses:]
* - [:numberOfBrowserProcessesUsed <= maxBrowserProcesses:]
*
@@ -2518,6 +2523,7 @@
AdbDevice device, AdbPrecompilationCommand command, int timeout) async {
var runner = command.precompiledRunnerFilename;
var testdir = command.precompiledTestDirectory;
+ var arguments = command.arguments;
var devicedir = '/data/local/tmp/precompilation-testing';
var deviceTestDir = '/data/local/tmp/precompilation-testing/test';
@@ -2556,13 +2562,13 @@
steps.add(() => device.runAdbShellCommand(
['$devicedir/dart_precompiled_runtime',
'--run-app-snapshot=$deviceTestDir',
- '--use-blobs', 'ignored.dart'],
+ '--use-blobs']..addAll(arguments),
timeout: timeoutDuration));
} else {
steps.add(() => device.runAdbShellCommand(
['$devicedir/dart_precompiled_runtime',
- '--run-app-snapshot=$deviceTestDir',
- 'ignored.dart'],
+ '--run-app-snapshot=$deviceTestDir'
+ ]..addAll(arguments),
timeout: timeoutDuration));
}
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 58b0937..ca8b8c8 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -1610,7 +1610,7 @@
* // OtherScripts=file1.dart file2.dart
*
* - You can indicate whether a test is treated as a web-only test by
- * using an explicit import to a part of the the dart:html library:
+ * using an explicit import to a part of the dart:html library:
*
* import 'dart:html';
* import 'dart:web_audio';
diff --git a/utils/peg/pegparser.dart b/utils/peg/pegparser.dart
index 8666550..9c58dea 100644
--- a/utils/peg/pegparser.dart
+++ b/utils/peg/pegparser.dart
@@ -371,7 +371,7 @@
}
}
}
- // Delegate the matching logic to the the specialized function.
+ // Delegate the matching logic to the specialized function.
return _match(state, pos);
}