Version 1.21.0-dev.7.0
Merge de8e04d76a8974a5c18f34820b23b381565dec72 into dev
diff --git a/.packages b/.packages
index 3c252bb1..721c67e 100644
--- a/.packages
+++ b/.packages
@@ -72,7 +72,6 @@
pool:third_party/pkg/pool/lib
protobuf:third_party/pkg/protobuf/lib
pub:third_party/pkg/pub/lib
-pub_cache:third_party/pkg/pub_cache/lib
pub_semver:third_party/pkg/pub_semver/lib
quiver:third_party/pkg/quiver/lib
resource:third_party/pkg/resource/lib
diff --git a/.travis.yml b/.travis.yml
index ef84927..2f868f8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -70,7 +70,7 @@
- if [[ -z "$TEST" ]]; then ./tool/presubmit.sh ; fi
- if [[ "$TEST" == coverage ]]; then ./tool/build_sdk.sh && ./tool/coverage.sh ; fi
- if [[ "$TEST" == node ]]; then ./tool/node_test.sh ; fi
- - if [[ "$TEST" == package ]]; then ./tool/build_sdk.sh && ./tool/build_pkgs.sh ; fi
+ - if [[ "$TEST" == package ]]; then ./tool/build_sdk.sh && ./tool/build_pkgs.dart ; fi
env:
- ANALYZER=master
- ANALYZER=master DDC_BROWSERS=Firefox
diff --git a/DEPS b/DEPS
index ef26510..bfad3e5 100644
--- a/DEPS
+++ b/DEPS
@@ -91,7 +91,6 @@
"ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
"pool_tag": "@1.2.4",
"protobuf_tag": "@0.5.3",
- "pub_cache_tag": "@v0.1.0",
"pub_rev": "@3dd04bd17ba269ccdd34502a253041dd96ded3be",
"pub_semver_tag": "@1.3.0",
"quiver_tag": "@0.22.0",
@@ -279,8 +278,6 @@
(Var("github_mirror") % "pub_semver") + Var("pub_semver_tag"),
Var("dart_root") + "/third_party/pkg/pub":
(Var("github_mirror") % "pub") + Var("pub_rev"),
- Var("dart_root") + "/third_party/pkg/pub_cache":
- (Var("github_mirror") % "pub_cache") + Var("pub_cache_tag"),
Var("dart_root") + "/third_party/pkg/quiver":
Var("chromium_git")
+ "/external/github.com/google/quiver-dart.git"
diff --git a/dart.gyp b/dart.gyp
index 1bbf75e..5e1508d 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -42,6 +42,7 @@
'dependencies': [
'runtime/dart-runtime.gyp:dart_precompiled_runtime',
'runtime/dart-runtime.gyp:dart_bootstrap#host',
+ 'runtime/dart-runtime.gyp:process_test',
'runtime/dart-runtime.gyp:generate_patched_sdk#host',
],
},
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index 4e37d5d..dad9113 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -1238,10 +1238,10 @@
\end{grammar}
\LMHash{}
-A {\em constructor parameter list} is a parenthesized, comma-separated list of formal constructor parameters. A {\em formal constructor parameter} is either a formal parameter (\ref{formalParameters}) or an initializing formal. An {\em initializing formal} has the form \code{\THIS{}.$id$}, where $id$ is the name of an instance variable of the immediately enclosing class. It is a compile-time error if \code{id} is not an instance variable of the immediately enclosing class. It is a compile-time error if an initializing formal is used by a function other than a non-redirecting generative constructor.
+A {\em constructor parameter list} is a parenthesized, comma-separated list of formal constructor parameters. A {\em formal constructor parameter} is either a formal parameter (\ref{formalParameters}) or an initializing formal. An {\em initializing formal} has the form \code{\THIS{}.$id$}, where $id$ is the name of an instance variable of the immediately enclosing class. It is a compile-time error if $id$ is not an instance variable of the immediately enclosing class. It is a compile-time error if an initializing formal is used by a function other than a non-redirecting generative constructor.
\LMHash{}
-If an explicit type is attached to the initializing formal, that is its static type. Otherwise, the type of an initializing formal named \code{id} is $T_{id}$, where $T_{id}$ is the type of the field named \code{id} in the immediately enclosing class. It is a static warning if the static type of \code{id} is not assignable to $T_{id}$.
+If an explicit type is attached to the initializing formal, that is its static type. Otherwise, the type of an initializing formal named $id$ is $T_{id}$, where $T_{id}$ is the type of the field named $id$ in the immediately enclosing class. It is a static warning if the static type of $id$ is not assignable to $T_{id}$.
\LMHash{}
Initializing formals constitute an exception to the rule that every formal parameter introduces a local variable into the formal parameter scope (\ref{formalParameters}).
@@ -3154,7 +3154,7 @@
The exception to that would be a type $X$ that extended or implemented \code{Future}. In that case, only one unwrapping takes place. As an example of why this is done, consider
-\cd{\CLASS{} C<T> \IMPLEMENTS{} Future<C<C<T$>>>$ \ldots }
+\cd{\CLASS{} C<T> \IMPLEMENTS{} Future<C<C<T>>> \ldots }
Here, a naive definition of $flatten$ diverges; there is not even a fixed point. A more sophisticated definition of $flatten$ is possible, but the existing rule deals with most realistic examples while remaining relatively simple to understand.
@@ -3713,10 +3713,15 @@
If there exists a lexically visible declaration named $id$, let $f_{id}$ be the innermost such declaration. Then:
\begin{itemize}
\item
+If $id$ is a type literal, then $i$ is interpreted as a function expression invocation (ref{functionExpressionInvociation}) with $(id)$ as the expression $e_f$.
+\commentary{
+The expression $(id)$ where $id$ is a type literal always evaluates to an instance of class \code{Type} which is not a function. This ensures that a runtime error occurs when trying to call a type literal.
+}
+\item
If $f_{id}$ is a prefix object, a compile-time error occurs.
\item
- If $f_{id}$ is a local function, a library function, a library or static getter or a variable then $i$ is interpreted as a function expression invocation (\ref{functionExpressionInvocation}).
- \item
+If $f_{id}$ is a local function, a library function, a library or static getter or a variable then $i$ is interpreted as a function expression invocation (\ref{functionExpressionInvocation}).
+\item
Otherwise, if $f_{id}$ is a static method of the enclosing class $C$, $i$ is equivalent to $C.id(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$.
\item Otherwise, $f_{id}$ is considered equivalent to the ordinary method invocation $\THIS{}.id(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$.
\end{itemize}
@@ -3743,7 +3748,14 @@
$e_f(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$,
-where $e_f$ is an expression. If $e_f$ is an identifier $id$, then $id$ must necessarily denote a local function, a library function, a library or static getter or a variable as described above, or $i$ is not considered a function expression invocation. If $e_f$ is a property extraction expression (\ref{propertyExtraction}), then $i$ is is not a function expression invocation and is instead recognized as an ordinary method invocation (\ref{ordinaryInvocation}).
+where $e_f$ is an expression. If $e_f$ is an identifier $id$, then $id$ must necessarily denote a local function, a library function, a library or static getter or a variable as described above, or $i$ is not considered a function expression invocation.
+If $e_f$ is a type literal, then it is equivalent to the expression $(e_f)$.
+
+\commentary{
+The expression $(e_f)$ where $e_f$ is a type literal always evaluates to an instance of class \code{Type} which is not a function. This ensures that a runtime error occurs when trying to call a type literal.
+}
+
+If $e_f$ is a property extraction expression (\ref{propertyExtraction}), then $i$ is is not a function expression invocation and is instead recognized as an ordinary method invocation (\ref{ordinaryInvocation}).
\commentary{
\code{$a.b(x)$} is parsed as a method invocation of method \code{$b()$} on object \code{$a$}, not as an invocation of getter \code{$b$} on \code{$a$} followed by a function call \code{$(a.b)(x)$}. If a method or getter \code{$b$} exists, the two will be equivalent. However, if \code{$b$} is not defined on \code{$a$}, the resulting invocation of \code{noSuchMethod()} would differ. The \code{Invocation} passed to \code{noSuchMethod()} would describe a call to a method \code{$b$} with argument \code{$x$} in the former case, and a call to a getter \code{$b$} (with no arguments) in the latter.
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 391a76a..7d70974 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -29,6 +29,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/plugin/resolver_provider.dart';
import 'package:analyzer/source/pub_package_map_provider.dart';
@@ -367,10 +368,15 @@
defaultContextOptions.generateImplicitErrors = false;
operationQueue = new ServerOperationQueue();
_analysisPerformanceLogger = new nd.PerformanceLog(io.stdout);
- byteStore = new MemoryCachingByteStore(
- new FileByteStore(
- resourceProvider.getStateLocation('.analysis-driver')),
- 64 * 1024 * 1024);
+ if (resourceProvider is PhysicalResourceProvider) {
+ byteStore = new MemoryCachingByteStore(
+ new FileByteStore(
+ resourceProvider.getStateLocation('.analysis-driver').path,
+ 1024 * 1024 * 1024 /*1 GiB*/),
+ 64 * 1024 * 1024 /*64 MiB*/);
+ } else {
+ byteStore = new MemoryByteStore();
+ }
analysisDriverScheduler =
new nd.AnalysisDriverScheduler(_analysisPerformanceLogger);
analysisDriverScheduler.status.listen(sendStatusNotificationNew);
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index f47e10a..137d374 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.30.0-alpha.0
+* Changed the API for creating BazelWorkspace. It should now be constructed using BazelWorkspace.find(). Note that this might return `null` in the event that the given path is not part of a BazelWorkspace.
+* Added an AST structure to support asserts in constructor initializers (AssertInitializer). AstVisitor classes must now implement visitAssertInitializer().
+
## 0.29.0-alpha.0
* Removed `Element.docRange`.
diff --git a/pkg/analyzer/lib/dart/ast/syntactic_entity.dart b/pkg/analyzer/lib/dart/ast/syntactic_entity.dart
index 5ab6c78..8d6d0dc 100644
--- a/pkg/analyzer/lib/dart/ast/syntactic_entity.dart
+++ b/pkg/analyzer/lib/dart/ast/syntactic_entity.dart
@@ -4,5 +4,4 @@
library analyzer.dart.ast.syntactic_entity;
-export 'package:front_end/src/scanner/syntactic_entity.dart'
- show SyntacticEntity;
+export 'package:front_end/src/base/syntactic_entity.dart' show SyntacticEntity;
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 388e0c8..8a4f9e8 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -13,9 +13,10 @@
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:analyzer/src/generated/source.dart';
+import 'package:front_end/src/base/errors.dart';
import 'package:front_end/src/scanner/errors.dart';
-export 'package:front_end/src/scanner/errors.dart'
+export 'package:front_end/src/base/errors.dart'
show ErrorCode, ErrorSeverity, ErrorType;
const List<ErrorCode> errorCodeValues = const [
diff --git a/pkg/analyzer/lib/source/analysis_options_provider.dart b/pkg/analyzer/lib/source/analysis_options_provider.dart
index cdd912c..808c835 100644
--- a/pkg/analyzer/lib/source/analysis_options_provider.dart
+++ b/pkg/analyzer/lib/source/analysis_options_provider.dart
@@ -8,12 +8,20 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/source/source_resource.dart';
import 'package:analyzer/src/util/yaml.dart';
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';
/// Provide the options found in the analysis options file.
class AnalysisOptionsProvider {
+ /// The source factory used to resolve include declarations
+ /// in analysis options files or `null` if include is not supported.
+ SourceFactory sourceFactory;
+
+ AnalysisOptionsProvider([this.sourceFactory]);
+
/// Provide the options found in either
/// [root]/[AnalysisEngine.ANALYSIS_OPTIONS_FILE] or
/// [root]/[AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE].
@@ -30,15 +38,29 @@
break;
}
}
- String optionsText = _readAnalysisOptionsFile(resource);
- return getOptionsFromString(optionsText);
+ return getOptionsFromFile(resource);
}
/// Provide the options found in [file].
/// Return an empty options map if the file does not exist.
Map<String, YamlNode> getOptionsFromFile(File file) {
- var optionsSource = _readAnalysisOptionsFile(file);
- return getOptionsFromString(optionsSource);
+ return getOptionsFromSource(new FileSource(file));
+ }
+
+ /// Provide the options found in [source].
+ /// Return an empty options map if the file does not exist.
+ Map<String, YamlNode> getOptionsFromSource(Source source) {
+ Map<String, YamlNode> options =
+ getOptionsFromString(_readAnalysisOptions(source));
+ YamlNode node = options.remove('include');
+ if (sourceFactory != null && node is YamlScalar) {
+ var path = node.value;
+ if (path is String) {
+ Source parent = sourceFactory.resolveUri(source, path);
+ options = merge(getOptionsFromSource(parent), options);
+ }
+ }
+ return options;
}
/// Provide the options found in [optionsSource].
@@ -110,13 +132,13 @@
Map<String, YamlNode> defaults, Map<String, YamlNode> overrides) =>
new Merger().merge(defaults, overrides) as Map<String, YamlNode>;
- /// Read the contents of [file] as a string.
- /// Returns null if file does not exist.
- String _readAnalysisOptionsFile(File file) {
+ /// Read the contents of [source] as a string.
+ /// Returns null if source is null or does not exist.
+ String _readAnalysisOptions(Source source) {
try {
- return file.readAsStringSync();
- } on FileSystemException {
- // File can't be read.
+ return source.contents.data;
+ } catch (e) {
+ // Source can't be read.
return null;
}
}
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index d0d9b1e..75875f7 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -336,9 +336,20 @@
if (optionsFile != null) {
List<OptionsProcessor> optionsProcessors =
AnalysisEngine.instance.optionsPlugin.optionsProcessors;
+ // TODO(danrubel) restructure so that we don't recalculate the package map
+ // more than once per path.
+ Packages packages = createPackageMap(path);
+ Map<String, List<Folder>> packageMap = convertPackagesToMap(packages);
+ List<UriResolver> resolvers = <UriResolver>[
+ new ResourceUriResolver(resourceProvider),
+ new PackageMapUriResolver(resourceProvider, packageMap),
+ ];
+ SourceFactory sourceFactory =
+ new SourceFactory(resolvers, packages, resourceProvider);
try {
Map<String, YamlNode> optionMap =
- new AnalysisOptionsProvider().getOptionsFromFile(optionsFile);
+ new AnalysisOptionsProvider(sourceFactory)
+ .getOptionsFromFile(optionsFile);
optionsProcessors.forEach(
(OptionsProcessor p) => p.optionsProcessed(context, optionMap));
applyToAnalysisOptions(options, optionMap);
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index f18e767..543e382 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -342,8 +342,9 @@
}
/**
- * Return the [Future] that completes with a [AnalysisResult] for the file
- * with the given [path].
+ * Return the [Future] that completes with a [AnalysisResult] for the Dart
+ * file with the given [path]. If the file is not a Dart file, the [Future]
+ * completes with `null`.
*
* The [path] must be absolute and normalized.
*
@@ -356,13 +357,16 @@
* transitions to "idle".
*/
Future<AnalysisResult> getResult(String path) {
- var completer = new Completer<AnalysisResult>();
- _requestedFiles
- .putIfAbsent(path, () => <Completer<AnalysisResult>>[])
- .add(completer);
- _statusSupport.transitionToAnalyzing();
- _scheduler._notify(this);
- return completer.future;
+ if (AnalysisEngine.isDartFileName(path)) {
+ var completer = new Completer<AnalysisResult>();
+ _requestedFiles
+ .putIfAbsent(path, () => <Completer<AnalysisResult>>[])
+ .add(completer);
+ _statusSupport.transitionToAnalyzing();
+ _scheduler._notify(this);
+ return completer.future;
+ }
+ return new Future.value();
}
/**
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart b/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
index 49e668f..46f4648 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_byte_store.dart
@@ -2,24 +2,35 @@
// 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:analyzer/file_system/file_system.dart';
+import 'dart:async';
+import 'dart:io';
+import 'dart:isolate';
+
import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:path/path.dart';
/**
- * [ByteStore] that stores values as [File]s.
- *
- * TODO(scheglov) Add some eviction policies.
+ * [ByteStore] that stores values as files.
*/
class FileByteStore implements ByteStore {
- final Folder folder;
+ static bool _cleanUpSendPortShouldBePrepared = true;
+ static SendPort _cleanUpSendPort;
- FileByteStore(this.folder);
+ final String _cachePath;
+ final String _tempName = 'temp_${pid}';
+ final int _maxSizeBytes;
+
+ int _bytesWrittenSinceCleanup = 0;
+ bool _evictionIsolateIsRunning = false;
+
+ FileByteStore(this._cachePath, this._maxSizeBytes) {
+ _requestCacheCleanUp();
+ }
@override
List<int> get(String key) {
try {
- File file = folder.getChildAssumingFile(key);
- return file.readAsBytesSync();
+ return _getFileForKey(key).readAsBytesSync();
} catch (_) {
return null;
}
@@ -28,8 +39,103 @@
@override
void put(String key, List<int> bytes) {
try {
- File file = folder.getChildAssumingFile(key);
- file.writeAsBytesSync(bytes);
+ File tempFile = _getFileForKey(_tempName);
+ tempFile.writeAsBytesSync(bytes);
+ File file = _getFileForKey(key);
+ tempFile.renameSync(file.path);
+ // Update the current size.
+ _bytesWrittenSinceCleanup += bytes.length;
+ if (_bytesWrittenSinceCleanup > _maxSizeBytes ~/ 8) {
+ _requestCacheCleanUp();
+ }
} catch (_) {}
}
+
+ File _getFileForKey(String key) {
+ return new File(join(_cachePath, key));
+ }
+
+ /**
+ * If the cache clean up process has not been requested yet, request it.
+ */
+ Future<Null> _requestCacheCleanUp() async {
+ if (_cleanUpSendPortShouldBePrepared) {
+ _cleanUpSendPortShouldBePrepared = false;
+ ReceivePort response = new ReceivePort();
+ await Isolate.spawn(_cacheCleanUpFunction, response.sendPort);
+ _cleanUpSendPort = await response.first as SendPort;
+ } else {
+ while (_cleanUpSendPort == null) {
+ await new Future.delayed(new Duration(milliseconds: 100), () {});
+ }
+ }
+
+ if (!_evictionIsolateIsRunning) {
+ _evictionIsolateIsRunning = true;
+ try {
+ ReceivePort response = new ReceivePort();
+ _cleanUpSendPort.send([_cachePath, _maxSizeBytes, response.sendPort]);
+ await response.first;
+ } finally {
+ _evictionIsolateIsRunning = false;
+ _bytesWrittenSinceCleanup = 0;
+ }
+ }
+ }
+
+ /**
+ * This function is started in a new isolate, receives cache folder clean up
+ * requests and evicts older files from the folder.
+ */
+ static void _cacheCleanUpFunction(SendPort initialReplyTo) {
+ ReceivePort port = new ReceivePort();
+ initialReplyTo.send(port.sendPort);
+ port.listen((args) async {
+ if (args is List &&
+ args.length == 3 &&
+ args[0] is String &&
+ args[1] is int &&
+ args[2] is SendPort) {
+ String cachePath = args[0] as String;
+ int maxSizeBytes = args[1] as int;
+ await _cleanUpFolder(cachePath, maxSizeBytes);
+ // Let that client know that we're done.
+ SendPort replyTo = args[2] as SendPort;
+ replyTo.send(true);
+ }
+ });
+ }
+
+ static Future<Null> _cleanUpFolder(String cachePath, int maxSizeBytes) async {
+ // Prepare the list of files and their statistics.
+ List<File> files = <File>[];
+ Map<File, FileStat> fileStatMap = {};
+ int currentSizeBytes = 0;
+ List<FileSystemEntity> resources = new Directory(cachePath).listSync();
+ for (FileSystemEntity resource in resources) {
+ if (resource is File) {
+ try {
+ FileStat fileStat = await resource.stat();
+ files.add(resource);
+ fileStatMap[resource] = fileStat;
+ currentSizeBytes += fileStat.size;
+ } catch (_) {}
+ }
+ }
+ files.sort((a, b) {
+ return fileStatMap[a].accessed.millisecondsSinceEpoch -
+ fileStatMap[b].accessed.millisecondsSinceEpoch;
+ });
+
+ // Delete files until the current size is less than the max.
+ for (File file in files) {
+ if (currentSizeBytes < maxSizeBytes) {
+ break;
+ }
+ try {
+ await file.delete();
+ } catch (_) {}
+ currentSizeBytes -= fileStatMap[file].size;
+ }
+ }
}
diff --git a/pkg/analyzer/lib/src/dart/scanner/reader.dart b/pkg/analyzer/lib/src/dart/scanner/reader.dart
index 54f367b..6e111e2 100644
--- a/pkg/analyzer/lib/src/dart/scanner/reader.dart
+++ b/pkg/analyzer/lib/src/dart/scanner/reader.dart
@@ -6,7 +6,8 @@
import 'package:front_end/src/scanner/reader.dart';
-export 'package:front_end/src/scanner/reader.dart' show CharacterReader;
+export 'package:front_end/src/scanner/reader.dart'
+ show CharacterReader, CharSequenceReader, SubSequenceReader;
/**
* A [CharacterReader] that reads a range of characters from another character
@@ -59,92 +60,3 @@
return baseReader.peek();
}
}
-
-/**
- * A [CharacterReader] that reads characters from a character sequence.
- */
-class CharSequenceReader implements CharacterReader {
- /**
- * The sequence from which characters will be read.
- */
- final String _sequence;
-
- /**
- * The number of characters in the string.
- */
- int _stringLength;
-
- /**
- * The index, relative to the string, of the next character to be read.
- */
- int _charOffset;
-
- /**
- * Initialize a newly created reader to read the characters in the given
- * [_sequence].
- */
- CharSequenceReader(this._sequence) {
- this._stringLength = _sequence.length;
- this._charOffset = 0;
- }
-
- @override
- int get offset => _charOffset - 1;
-
- @override
- void set offset(int offset) {
- _charOffset = offset + 1;
- }
-
- @override
- int advance() {
- if (_charOffset >= _stringLength) {
- return -1;
- }
- return _sequence.codeUnitAt(_charOffset++);
- }
-
- @override
- String getString(int start, int endDelta) =>
- _sequence.substring(start, _charOffset + endDelta);
-
- @override
- int peek() {
- if (_charOffset >= _stringLength) {
- return -1;
- }
- return _sequence.codeUnitAt(_charOffset);
- }
-}
-
-/**
- * A [CharacterReader] that reads characters from a character sequence, but adds
- * a delta when reporting the current character offset so that the character
- * sequence can be a subsequence from a larger sequence.
- */
-class SubSequenceReader extends CharSequenceReader {
- /**
- * The offset from the beginning of the file to the beginning of the source
- * being scanned.
- */
- final int _offsetDelta;
-
- /**
- * Initialize a newly created reader to read the characters in the given
- * [sequence]. The [_offsetDelta] is the offset from the beginning of the file
- * to the beginning of the source being scanned
- */
- SubSequenceReader(String sequence, this._offsetDelta) : super(sequence);
-
- @override
- int get offset => _offsetDelta + super.offset;
-
- @override
- void set offset(int offset) {
- super.offset = offset - _offsetDelta;
- }
-
- @override
- String getString(int start, int endDelta) =>
- super.getString(start - _offsetDelta, endDelta);
-}
diff --git a/pkg/analyzer/lib/src/generated/bazel.dart b/pkg/analyzer/lib/src/generated/bazel.dart
index b81a0c8..8d014c7 100644
--- a/pkg/analyzer/lib/src/generated/bazel.dart
+++ b/pkg/analyzer/lib/src/generated/bazel.dart
@@ -143,6 +143,12 @@
static const String _WORKSPACE = 'WORKSPACE';
static const String _READONLY = 'READONLY';
+ /**
+ * Default prefix for "-genfiles" and "-bin" that will be assumed if no build
+ * output symlinks are found.
+ */
+ static const defaultSymlinkPrefix = 'bazel';
+
final ResourceProvider provider;
/**
@@ -197,6 +203,11 @@
return file;
}
}
+ // Writable
+ File writableFile = provider.getFile(absolutePath);
+ if (writableFile.exists) {
+ return writableFile;
+ }
// READONLY
if (readonly != null) {
File file = provider.getFile(context.join(readonly, relative));
@@ -205,7 +216,7 @@
}
}
// Not generated, return the default one.
- return provider.getFile(absolutePath);
+ return writableFile;
} catch (_) {
return null;
}
@@ -281,8 +292,9 @@
/**
* Return the symlink prefix for folders `X-bin` or `X-genfiles` by probing
- * the internal `blaze-genfiles` and `bazel-genfiles`. Return `null` if
- * neither of the folders exists.
+ * the internal `blaze-genfiles` and `bazel-genfiles`. Make a default
+ * assumption according to defaultSymlinkPrefix if neither of the folders
+ * exists.
*/
static String _findSymlinkPrefix(ResourceProvider provider, String root) {
Context context = provider.pathContext;
@@ -292,6 +304,7 @@
if (provider.getFolder(context.join(root, 'bazel-genfiles')).exists) {
return 'bazel';
}
- return null;
+ // Couldn't find it. Make a default assumption.
+ return defaultSymlinkPrefix;
}
}
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index a33beba..6a78ba5 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -29,12 +29,14 @@
import 'package:analyzer/src/task/manager.dart';
import 'package:analyzer/task/dart.dart';
import 'package:analyzer/task/model.dart';
+import 'package:front_end/src/base/timestamped_data.dart';
import 'package:html/dom.dart' show Document;
import 'package:path/path.dart' as pathos;
import 'package:plugin/manager.dart';
import 'package:plugin/plugin.dart';
export 'package:analyzer/error/listener.dart' show RecordingErrorListener;
+export 'package:front_end/src/base/timestamped_data.dart' show TimestampedData;
/**
* Used by [AnalysisOptions] to allow function bodies to be analyzed in some
@@ -2720,24 +2722,3 @@
_changeSet.removedSources.length > 0 ||
_changeSet.removedContainers.length > 0;
}
-
-/**
- * Analysis data for which we have a modification time.
- */
-class TimestampedData<E> {
- /**
- * The modification time of the source from which the data was created.
- */
- final int modificationTime;
-
- /**
- * The data that was created from the source.
- */
- final E data;
-
- /**
- * Initialize a newly created holder to associate the given [data] with the
- * given [modificationTime].
- */
- TimestampedData(this.modificationTime, this.data);
-}
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index d847a7b..b718661 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -665,6 +665,14 @@
} else if (oldParent is FunctionBody && newParent is FunctionBody) {
if (oldParent is BlockFunctionBody &&
newParent is BlockFunctionBody) {
+ if (oldParent.isAsynchronous != newParent.isAsynchronous) {
+ logger.log('Failure: body async mismatch.');
+ return false;
+ }
+ if (oldParent.isGenerator != newParent.isGenerator) {
+ logger.log('Failure: body generator mismatch.');
+ return false;
+ }
oldNode = oldParent;
newNode = newParent;
found = true;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 7a36d85..8208abb 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -424,7 +424,8 @@
void _checkForAbstractSuperMemberReference(
Expression target, SimpleIdentifier name) {
- if (target is SuperExpression) {
+ if (target is SuperExpression &&
+ !_currentLibrary.context.analysisOptions.enableSuperMixins) {
Element element = name.staticElement;
if (element is ExecutableElement && element.isAbstract) {
if (!_enclosingClass.hasNoSuchMethod) {
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 7f95c01..e4ceae7 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -8,17 +8,20 @@
import "dart:math" as math;
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/context/source.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/java_io.dart' show JavaFile;
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource;
-import 'package:analyzer/task/model.dart';
+import 'package:front_end/src/base/source.dart';
+import 'package:front_end/src/base/uri_kind.dart';
import 'package:package_config/packages.dart';
import 'package:path/path.dart' as pathos;
+export 'package:front_end/src/base/source.dart' show Source;
+export 'package:front_end/src/base/uri_kind.dart' show UriKind;
+
/**
* A function that is used to visit [ContentCache] entries.
*/
@@ -411,147 +414,6 @@
}
/**
- * The interface `Source` defines the behavior of objects representing source code that can be
- * analyzed by the analysis engine.
- *
- * Implementations of this interface need to be aware of some assumptions made by the analysis
- * engine concerning sources:
- * * Sources are not required to be unique. That is, there can be multiple instances representing
- * the same source.
- * * Sources are long lived. That is, the engine is allowed to hold on to a source for an extended
- * period of time and that source must continue to report accurate and up-to-date information.
- * Because of these assumptions, most implementations will not maintain any state but will delegate
- * to an authoritative system of record in order to implement this API. For example, a source that
- * represents files on disk would typically query the file system to determine the state of the
- * file.
- *
- * If the instances that implement this API are the system of record, then they will typically be
- * unique. In that case, sources that are created that represent non-existent files must also be
- * retained so that if those files are created at a later date the long-lived sources representing
- * those files will know that they now exist.
- */
-abstract class Source implements AnalysisTarget {
- /**
- * An empty list of sources.
- */
- static const List<Source> EMPTY_LIST = const <Source>[];
-
- /**
- * Get the contents and timestamp of this source.
- *
- * 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.
- *
- * @return the contents and timestamp of the source
- * @throws Exception if the contents of this source could not be accessed
- */
- TimestampedData<String> get contents;
-
- /**
- * Return an encoded representation of this source that can be used to create a source that is
- * equal to this source.
- *
- * @return an encoded representation of this source
- * See [SourceFactory.fromEncoding].
- */
- String get encoding;
-
- /**
- * Return the full (long) version of the name that can be displayed to the user to denote this
- * source. For example, for a source representing a file this would typically be the absolute path
- * of the file.
- *
- * @return a name that can be displayed to the user to denote this source
- */
- String get fullName;
-
- /**
- * Return a hash code for this source.
- *
- * @return a hash code for this source
- * See [Object.hashCode].
- */
- @override
- int get hashCode;
-
- /**
- * Return `true` if this source is in one of the system libraries.
- *
- * @return `true` if this is in a system library
- */
- bool get isInSystemLibrary;
-
- @override
- Source get librarySource => null;
-
- /**
- * Return the modification stamp for this source, or a negative value if the
- * source does not exist. A modification stamp is a non-negative integer with
- * the property that if the contents of the source have not been modified
- * since the last time the modification stamp was accessed then the same value
- * 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 method
- * [AnalysisContext.getModificationStamp] because contexts can have local
- * overrides of the content of a source that the source is not aware of.
- */
- int get modificationStamp;
-
- /**
- * Return a short version of the name that can be displayed to the user to denote this source. For
- * example, for a source representing a file this would typically be the name of the file.
- *
- * @return a name that can be displayed to the user to denote this source
- */
- String get shortName;
-
- @override
- Source get source => this;
-
- /**
- * Return the URI from which this source was originally derived.
- *
- * @return the URI from which this source was originally derived
- */
- Uri get uri;
-
- /**
- * Return the kind of URI from which this source was originally derived. If this source was
- * created from an absolute URI, then the returned kind will reflect the scheme of the absolute
- * URI. If it was created from a relative URI, then the returned kind will be the same as the kind
- * of the source against which the relative URI was resolved.
- *
- * @return the kind of URI from which this source was originally derived
- */
- UriKind get uriKind;
-
- /**
- * Return `true` if the given object is a source that represents the same source code as
- * this source.
- *
- * @param object the object to be compared with this object
- * @return `true` if the given object is a source that represents the same source code as
- * this source
- * See [Object.==].
- */
- @override
- bool operator ==(Object object);
-
- /**
- * Return `true` if this source exists.
- *
- * 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.
- *
- * @return `true` if this source exists
- */
- bool exists();
-}
-
-/**
* The interface `ContentReceiver` defines the behavior of objects that can receive the
* content of a source.
*/
@@ -863,90 +725,6 @@
}
/**
- * The enumeration `UriKind` defines the different kinds of URI's that are known to the
- * analysis engine. These are used to keep track of the kind of URI associated with a given source.
- */
-class UriKind implements Comparable<UriKind> {
- /**
- * A 'dart:' URI.
- */
- static const UriKind DART_URI = const UriKind('DART_URI', 0, 0x64);
-
- /**
- * A 'file:' URI.
- */
- static const UriKind FILE_URI = const UriKind('FILE_URI', 1, 0x66);
-
- /**
- * A 'package:' URI.
- */
- static const UriKind PACKAGE_URI = const UriKind('PACKAGE_URI', 2, 0x70);
-
- static const List<UriKind> values = const [DART_URI, FILE_URI, PACKAGE_URI];
-
- /**
- * The name of this URI kind.
- */
- final String name;
-
- /**
- * The ordinal value of the URI kind.
- */
- final int ordinal;
-
- /**
- * The single character encoding used to identify this kind of URI.
- */
- final int encoding;
-
- /**
- * Initialize a newly created URI kind to have the given encoding.
- */
- const UriKind(this.name, this.ordinal, this.encoding);
-
- @override
- int get hashCode => ordinal;
-
- @override
- int compareTo(UriKind other) => ordinal - other.ordinal;
-
- @override
- String toString() => name;
-
- /**
- * Return the URI kind represented by the given [encoding], or `null` if there
- * is no kind with the given encoding.
- */
- static UriKind fromEncoding(int encoding) {
- while (true) {
- if (encoding == 0x64) {
- return DART_URI;
- } else if (encoding == 0x66) {
- return FILE_URI;
- } else if (encoding == 0x70) {
- return PACKAGE_URI;
- }
- break;
- }
- return null;
- }
-
- /**
- * Return the URI kind corresponding to the given scheme string.
- */
- static UriKind fromScheme(String scheme) {
- if (scheme == PackageMapUriResolver.PACKAGE_SCHEME) {
- return UriKind.PACKAGE_URI;
- } else if (scheme == DartUriResolver.DART_SCHEME) {
- return UriKind.DART_URI;
- } else if (scheme == ResourceUriResolver.FILE_SCHEME) {
- return UriKind.FILE_URI;
- }
- return UriKind.FILE_URI;
- }
-}
-
-/**
* The abstract class `UriResolver` defines the behavior of objects that are used to resolve
* URI's for a source factory. Subclasses of this class are expected to resolve a single scheme of
* absolute URI.
diff --git a/pkg/analyzer/lib/src/generated/utilities_general.dart b/pkg/analyzer/lib/src/generated/utilities_general.dart
index b9dca93..d13ad35 100644
--- a/pkg/analyzer/lib/src/generated/utilities_general.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_general.dart
@@ -7,6 +7,8 @@
import 'dart:collection';
import 'dart:developer' show UserTag;
+export 'package:front_end/src/base/jenkins_smi_hash.dart' show JenkinsSmiHash;
+
/**
* Test if the given [value] is `false` or the string "false" (case-insensitive).
*/
@@ -50,31 +52,6 @@
String toUpperCase(Object value) => value?.toString()?.toUpperCase();
/**
- * Jenkins hash function, optimized for small integers.
- * Borrowed from sdk/lib/math/jenkins_smi_hash.dart.
- */
-class JenkinsSmiHash {
- static int combine(int hash, int value) {
- hash = 0x1fffffff & (hash + value);
- hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
- return hash ^ (hash >> 6);
- }
-
- static int finish(int hash) {
- hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
- hash = hash ^ (hash >> 11);
- return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
- }
-
- static int hash2(a, b) => finish(combine(combine(0, a), b));
-
- static int hash3(a, b, c) => finish(combine(combine(combine(0, a), b), c));
-
- static int hash4(a, b, c, d) =>
- finish(combine(combine(combine(combine(0, a), b), c), d));
-}
-
-/**
* A simple limited queue.
*/
class LimitedQueue<E> extends ListQueue<E> {
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index 2a6f6c5..9d1f6ba 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -14,6 +14,9 @@
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/task/driver.dart';
import 'package:analyzer/src/task/model.dart';
+import 'package:front_end/src/base/analysis_target.dart';
+
+export 'package:front_end/src/base/analysis_target.dart' show AnalysisTarget;
/**
* A function that converts the given [key] and [value] into a [TaskInput].
@@ -68,27 +71,6 @@
}
/**
- * An object with which an analysis result can be associated.
- *
- * Clients may implement this class when creating new kinds of targets.
- * Instances of this type are used in hashed data structures, so subtypes are
- * required to correctly implement [==] and [hashCode].
- */
-abstract class AnalysisTarget {
- /**
- * If this target is associated with a library, return the source of the
- * library's defining compilation unit; otherwise return `null`.
- */
- Source get librarySource;
-
- /**
- * Return the source associated with this target, or `null` if this target is
- * not associated with a source.
- */
- Source get source;
-}
-
-/**
* An object used to compute one or more analysis results associated with a
* single target.
*
diff --git a/pkg/analyzer/test/generated/bazel_test.dart b/pkg/analyzer/test/generated/bazel_test.dart
index cc1a75a..884ffb5 100644
--- a/pkg/analyzer/test/generated/bazel_test.dart
+++ b/pkg/analyzer/test/generated/bazel_test.dart
@@ -570,10 +570,14 @@
}
void test_find_null_symlinkPrefix() {
+ String prefix = BazelWorkspace.defaultSymlinkPrefix;
provider.newFile(_p('/workspace/WORKSPACE'), '');
BazelWorkspace workspace =
BazelWorkspace.find(provider, _p('/workspace/my/module'));
- expect(workspace, isNull);
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.readonly, isNull);
+ expect(workspace.bin, _p('/workspace/$prefix-bin'));
+ expect(workspace.genfiles, _p('/workspace/$prefix-genfiles'));
}
void test_findFile_hasReadonlyFolder() {
@@ -612,6 +616,22 @@
_p('/Users/user/test/READONLY/prime/other/module/test4.dart'));
}
+ void test_findFile_main_overrides_readonly() {
+ provider.newFolder(_p('/Users/user/test/READONLY/prime'));
+ provider.newFolder(_p('/Users/user/test/prime'));
+ provider.newFolder(_p('/Users/user/test/prime/bazel-genfiles'));
+ provider.newFile(_p('/Users/user/test/prime/my/module/test.dart'), '');
+ provider.newFile(
+ _p('/Users/user/test/READONLY/prime/my/module/test.dart'), '');
+ BazelWorkspace workspace =
+ BazelWorkspace.find(provider, _p('/Users/user/test/prime/my/module'));
+ expect(
+ workspace
+ .findFile(_p('/Users/user/test/prime/my/module/test.dart'))
+ .path,
+ _p('/Users/user/test/prime/my/module/test.dart'));
+ }
+
void test_findFile_noReadOnly() {
provider.newFile(_p('/workspace/WORKSPACE'), '');
provider.newFile(_p('/workspace/my/module/test1.dart'), '');
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index eba3450..5bfd2a9 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -1011,6 +1011,55 @@
expectedSuccess: false);
}
+ void test_false_inBody_addAsync() {
+ _resolveUnit(r'''
+class C {
+ test() {}
+}
+''');
+ _updateAndValidate(
+ r'''
+class C {
+ test() async {}
+}
+''',
+ expectedSuccess: false);
+ }
+
+ void test_false_inBody_async_addStar() {
+ _resolveUnit(r'''
+import 'dart:async';
+class C {
+ Stream test() async {}
+}
+''');
+ _updateAndValidate(
+ r'''
+import 'dart:async';
+class C {
+ Stream test() async* {}
+}
+''',
+ expectedSuccess: false);
+ }
+
+ void test_false_inBody_async_removeStar() {
+ _resolveUnit(r'''
+import 'dart:async';
+class C {
+ Stream test() async* {}
+}
+''');
+ _updateAndValidate(
+ r'''
+import 'dart:async';
+class C {
+ Stream test() async {}
+}
+''',
+ expectedSuccess: false);
+ }
+
void test_false_inBody_functionExpression() {
_resolveUnit(r'''
class C extends D {
@@ -1034,6 +1083,36 @@
expectedSuccess: false);
}
+ void test_false_inBody_removeAsync() {
+ _resolveUnit(r'''
+class C {
+ test() async {}
+}
+''');
+ _updateAndValidate(
+ r'''
+class C {
+ test() {}
+}
+''',
+ expectedSuccess: false);
+ }
+
+ void test_false_inBody_sync_addStar() {
+ _resolveUnit(r'''
+class C {
+ test() {}
+}
+''');
+ _updateAndValidate(
+ r'''
+class C {
+ test() sync* {}
+}
+''',
+ expectedSuccess: false);
+ }
+
void test_false_topLevelFunction_name() {
_resolveUnit(r'''
a() {}
diff --git a/pkg/analyzer/test/generated/non_hint_code_test.dart b/pkg/analyzer/test/generated/non_hint_code_test.dart
index eda3e13..2ef678b 100644
--- a/pkg/analyzer/test/generated/non_hint_code_test.dart
+++ b/pkg/analyzer/test/generated/non_hint_code_test.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -19,6 +20,23 @@
@reflectiveTest
class NonHintCodeTest extends ResolverTestCase {
+ void test_() {
+ resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+ Source source = addSource(r'''
+abstract class A {
+ void test();
+}
+class B extends A {
+ void test() {
+ super.test;
+ }
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_deadCode_afterTryCatch() {
Source source = addSource('''
main() {
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index 748bab4..92d6621 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -5,8 +5,6 @@
library analyzer.test.generated.scanner_test;
import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
@@ -18,10 +16,7 @@
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(CharSequenceReaderTest);
- defineReflectiveTests(KeywordStateTest);
- defineReflectiveTests(ScannerTest);
- defineReflectiveTests(TokenTypeTest);
+ defineReflectiveTests(LineInfoTest);
});
}
@@ -82,547 +77,7 @@
}
@reflectiveTest
-class CharSequenceReaderTest {
- void test_advance() {
- CharSequenceReader reader = new CharSequenceReader("x");
- expect(reader.advance(), 0x78);
- expect(reader.advance(), -1);
- expect(reader.advance(), -1);
- }
-
- void test_creation() {
- expect(new CharSequenceReader("x"), isNotNull);
- }
-
- void test_getOffset() {
- CharSequenceReader reader = new CharSequenceReader("x");
- expect(reader.offset, -1);
- reader.advance();
- expect(reader.offset, 0);
- reader.advance();
- expect(reader.offset, 0);
- }
-
- void test_getString() {
- CharSequenceReader reader = new CharSequenceReader("xyzzy");
- reader.offset = 3;
- expect(reader.getString(1, 0), "yzz");
- expect(reader.getString(2, 1), "zzy");
- }
-
- void test_peek() {
- CharSequenceReader reader = new CharSequenceReader("xy");
- expect(reader.peek(), 0x78);
- expect(reader.peek(), 0x78);
- reader.advance();
- expect(reader.peek(), 0x79);
- expect(reader.peek(), 0x79);
- reader.advance();
- expect(reader.peek(), -1);
- expect(reader.peek(), -1);
- }
-
- void test_setOffset() {
- CharSequenceReader reader = new CharSequenceReader("xyz");
- reader.offset = 2;
- expect(reader.offset, 2);
- }
-}
-
-@reflectiveTest
-class KeywordStateTest {
- void test_KeywordState() {
- //
- // Generate the test data to be scanned.
- //
- List<Keyword> keywords = Keyword.values;
- int keywordCount = keywords.length;
- List<String> textToTest = new List<String>(keywordCount * 3);
- for (int i = 0; i < keywordCount; i++) {
- String syntax = keywords[i].syntax;
- textToTest[i] = syntax;
- textToTest[i + keywordCount] = "${syntax}x";
- textToTest[i + keywordCount * 2] = syntax.substring(0, syntax.length - 1);
- }
- //
- // Scan each of the identifiers.
- //
- KeywordState firstState = KeywordState.KEYWORD_STATE;
- for (int i = 0; i < textToTest.length; i++) {
- String text = textToTest[i];
- int index = 0;
- int length = text.length;
- KeywordState state = firstState;
- while (index < length && state != null) {
- state = state.next(text.codeUnitAt(index));
- index++;
- }
- if (i < keywordCount) {
- // keyword
- expect(state, isNotNull);
- expect(state.keyword(), isNotNull);
- expect(state.keyword(), keywords[i]);
- } else if (i < keywordCount * 2) {
- // keyword + "x"
- expect(state, isNull);
- } else {
- // keyword.substring(0, keyword.length() - 1)
- expect(state, isNotNull);
- }
- }
- }
-}
-
-@reflectiveTest
-class ScannerTest {
- void fail_incomplete_string_interpolation() {
- // https://code.google.com/p/dart/issues/detail?id=18073
- _assertErrorAndTokens(
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9, "\"foo \${bar", [
- new StringToken(TokenType.STRING, "\"foo ", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5),
- new StringToken(TokenType.IDENTIFIER, "bar", 7)
- ]);
- }
-
- void test_ampersand() {
- _assertToken(TokenType.AMPERSAND, "&");
- }
-
- void test_ampersand_ampersand() {
- _assertToken(TokenType.AMPERSAND_AMPERSAND, "&&");
- }
-
- void test_ampersand_ampersand_eq() {
- _assertToken(TokenType.AMPERSAND_AMPERSAND_EQ, "&&=",
- lazyAssignmentOperators: true);
- }
-
- void test_ampersand_eq() {
- _assertToken(TokenType.AMPERSAND_EQ, "&=");
- }
-
- void test_at() {
- _assertToken(TokenType.AT, "@");
- }
-
- void test_backping() {
- _assertToken(TokenType.BACKPING, "`");
- }
-
- void test_backslash() {
- _assertToken(TokenType.BACKSLASH, "\\");
- }
-
- void test_bang() {
- _assertToken(TokenType.BANG, "!");
- }
-
- void test_bang_eq() {
- _assertToken(TokenType.BANG_EQ, "!=");
- }
-
- void test_bar() {
- _assertToken(TokenType.BAR, "|");
- }
-
- void test_bar_bar() {
- _assertToken(TokenType.BAR_BAR, "||");
- }
-
- void test_bar_bar_eq() {
- _assertToken(TokenType.BAR_BAR_EQ, "||=", lazyAssignmentOperators: true);
- }
-
- void test_bar_eq() {
- _assertToken(TokenType.BAR_EQ, "|=");
- }
-
- void test_caret() {
- _assertToken(TokenType.CARET, "^");
- }
-
- void test_caret_eq() {
- _assertToken(TokenType.CARET_EQ, "^=");
- }
-
- void test_close_curly_bracket() {
- _assertToken(TokenType.CLOSE_CURLY_BRACKET, "}");
- }
-
- void test_close_paren() {
- _assertToken(TokenType.CLOSE_PAREN, ")");
- }
-
- void test_close_quare_bracket() {
- _assertToken(TokenType.CLOSE_SQUARE_BRACKET, "]");
- }
-
- void test_colon() {
- _assertToken(TokenType.COLON, ":");
- }
-
- void test_comma() {
- _assertToken(TokenType.COMMA, ",");
- }
-
- void test_comment_disabled_multi() {
- Scanner scanner = new Scanner(
- null,
- new CharSequenceReader("/* comment */ "),
- AnalysisErrorListener.NULL_LISTENER);
- scanner.preserveComments = false;
- Token token = scanner.tokenize();
- expect(token, isNotNull);
- expect(token.precedingComments, isNull);
- }
-
- void test_comment_generic_method_type_assign() {
- _assertComment(TokenType.MULTI_LINE_COMMENT, "/*=comment*/");
- _assertComment(TokenType.GENERIC_METHOD_TYPE_ASSIGN, "/*=comment*/",
- genericMethodComments: true);
- }
-
- void test_comment_generic_method_type_list() {
- _assertComment(TokenType.MULTI_LINE_COMMENT, "/*<comment>*/");
- _assertComment(TokenType.GENERIC_METHOD_TYPE_LIST, "/*<comment>*/",
- genericMethodComments: true);
- }
-
- void test_comment_multi() {
- _assertComment(TokenType.MULTI_LINE_COMMENT, "/* comment */");
- }
-
- void test_comment_multi_lineEnds() {
- String code = r'''
-/**
- * aa
- * bbb
- * c
- */''';
- GatheringErrorListener listener = new GatheringErrorListener();
- Scanner scanner = new Scanner(null, new CharSequenceReader(code), listener);
- scanner.tokenize();
- expect(
- scanner.lineStarts,
- equals(<int>[
- code.indexOf('/**'),
- code.indexOf(' * aa'),
- code.indexOf(' * bbb'),
- code.indexOf(' * c'),
- code.indexOf(' */')
- ]));
- }
-
- void test_comment_multi_unterminated() {
- _assertError(ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT, 3, "/* x");
- }
-
- void test_comment_nested() {
- _assertComment(
- TokenType.MULTI_LINE_COMMENT, "/* comment /* within a */ comment */");
- }
-
- void test_comment_single() {
- _assertComment(TokenType.SINGLE_LINE_COMMENT, "// comment");
- }
-
- void test_double_both_E() {
- _assertToken(TokenType.DOUBLE, "0.123E4");
- }
-
- void test_double_both_e() {
- _assertToken(TokenType.DOUBLE, "0.123e4");
- }
-
- void test_double_fraction() {
- _assertToken(TokenType.DOUBLE, ".123");
- }
-
- void test_double_fraction_E() {
- _assertToken(TokenType.DOUBLE, ".123E4");
- }
-
- void test_double_fraction_e() {
- _assertToken(TokenType.DOUBLE, ".123e4");
- }
-
- void test_double_missingDigitInExponent() {
- _assertError(ScannerErrorCode.MISSING_DIGIT, 1, "1e");
- }
-
- void test_double_whole_E() {
- _assertToken(TokenType.DOUBLE, "12E4");
- }
-
- void test_double_whole_e() {
- _assertToken(TokenType.DOUBLE, "12e4");
- }
-
- void test_eq() {
- _assertToken(TokenType.EQ, "=");
- }
-
- void test_eq_eq() {
- _assertToken(TokenType.EQ_EQ, "==");
- }
-
- void test_gt() {
- _assertToken(TokenType.GT, ">");
- }
-
- void test_gt_eq() {
- _assertToken(TokenType.GT_EQ, ">=");
- }
-
- void test_gt_gt() {
- _assertToken(TokenType.GT_GT, ">>");
- }
-
- void test_gt_gt_eq() {
- _assertToken(TokenType.GT_GT_EQ, ">>=");
- }
-
- void test_hash() {
- _assertToken(TokenType.HASH, "#");
- }
-
- void test_hexidecimal() {
- _assertToken(TokenType.HEXADECIMAL, "0x1A2B3C");
- }
-
- void test_hexidecimal_missingDigit() {
- _assertError(ScannerErrorCode.MISSING_HEX_DIGIT, 1, "0x");
- }
-
- void test_identifier() {
- _assertToken(TokenType.IDENTIFIER, "result");
- }
-
- void test_illegalChar_cyrillicLetter_middle() {
- _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 5, "Shche\u0433lov");
- }
-
- void test_illegalChar_cyrillicLetter_start() {
- _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0429");
- }
-
- void test_illegalChar_nbsp() {
- _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u00A0");
- }
-
- void test_illegalChar_notLetter() {
- _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0312");
- }
-
- void test_index() {
- _assertToken(TokenType.INDEX, "[]");
- }
-
- void test_index_eq() {
- _assertToken(TokenType.INDEX_EQ, "[]=");
- }
-
- void test_int() {
- _assertToken(TokenType.INT, "123");
- }
-
- void test_int_initialZero() {
- _assertToken(TokenType.INT, "0123");
- }
-
- void test_keyword_abstract() {
- _assertKeywordToken("abstract");
- }
-
- void test_keyword_as() {
- _assertKeywordToken("as");
- }
-
- void test_keyword_assert() {
- _assertKeywordToken("assert");
- }
-
- void test_keyword_break() {
- _assertKeywordToken("break");
- }
-
- void test_keyword_case() {
- _assertKeywordToken("case");
- }
-
- void test_keyword_catch() {
- _assertKeywordToken("catch");
- }
-
- void test_keyword_class() {
- _assertKeywordToken("class");
- }
-
- void test_keyword_const() {
- _assertKeywordToken("const");
- }
-
- void test_keyword_continue() {
- _assertKeywordToken("continue");
- }
-
- void test_keyword_default() {
- _assertKeywordToken("default");
- }
-
- void test_keyword_deferred() {
- _assertKeywordToken("deferred");
- }
-
- void test_keyword_do() {
- _assertKeywordToken("do");
- }
-
- void test_keyword_dynamic() {
- _assertKeywordToken("dynamic");
- }
-
- void test_keyword_else() {
- _assertKeywordToken("else");
- }
-
- void test_keyword_enum() {
- _assertKeywordToken("enum");
- }
-
- void test_keyword_export() {
- _assertKeywordToken("export");
- }
-
- void test_keyword_extends() {
- _assertKeywordToken("extends");
- }
-
- void test_keyword_factory() {
- _assertKeywordToken("factory");
- }
-
- void test_keyword_false() {
- _assertKeywordToken("false");
- }
-
- void test_keyword_final() {
- _assertKeywordToken("final");
- }
-
- void test_keyword_finally() {
- _assertKeywordToken("finally");
- }
-
- void test_keyword_for() {
- _assertKeywordToken("for");
- }
-
- void test_keyword_get() {
- _assertKeywordToken("get");
- }
-
- void test_keyword_if() {
- _assertKeywordToken("if");
- }
-
- void test_keyword_implements() {
- _assertKeywordToken("implements");
- }
-
- void test_keyword_import() {
- _assertKeywordToken("import");
- }
-
- void test_keyword_in() {
- _assertKeywordToken("in");
- }
-
- void test_keyword_is() {
- _assertKeywordToken("is");
- }
-
- void test_keyword_library() {
- _assertKeywordToken("library");
- }
-
- void test_keyword_new() {
- _assertKeywordToken("new");
- }
-
- void test_keyword_null() {
- _assertKeywordToken("null");
- }
-
- void test_keyword_operator() {
- _assertKeywordToken("operator");
- }
-
- void test_keyword_part() {
- _assertKeywordToken("part");
- }
-
- void test_keyword_rethrow() {
- _assertKeywordToken("rethrow");
- }
-
- void test_keyword_return() {
- _assertKeywordToken("return");
- }
-
- void test_keyword_set() {
- _assertKeywordToken("set");
- }
-
- void test_keyword_static() {
- _assertKeywordToken("static");
- }
-
- void test_keyword_super() {
- _assertKeywordToken("super");
- }
-
- void test_keyword_switch() {
- _assertKeywordToken("switch");
- }
-
- void test_keyword_this() {
- _assertKeywordToken("this");
- }
-
- void test_keyword_throw() {
- _assertKeywordToken("throw");
- }
-
- void test_keyword_true() {
- _assertKeywordToken("true");
- }
-
- void test_keyword_try() {
- _assertKeywordToken("try");
- }
-
- void test_keyword_typedef() {
- _assertKeywordToken("typedef");
- }
-
- void test_keyword_var() {
- _assertKeywordToken("var");
- }
-
- void test_keyword_void() {
- _assertKeywordToken("void");
- }
-
- void test_keyword_while() {
- _assertKeywordToken("while");
- }
-
- void test_keyword_with() {
- _assertKeywordToken("with");
- }
-
+class LineInfoTest extends EngineTestCase {
void test_lineInfo_multilineComment() {
String source = "/*\r *\r */";
_assertLineInfo(source, [
@@ -668,503 +123,6 @@
]);
}
- void test_lt() {
- _assertToken(TokenType.LT, "<");
- }
-
- void test_lt_eq() {
- _assertToken(TokenType.LT_EQ, "<=");
- }
-
- void test_lt_lt() {
- _assertToken(TokenType.LT_LT, "<<");
- }
-
- void test_lt_lt_eq() {
- _assertToken(TokenType.LT_LT_EQ, "<<=");
- }
-
- void test_minus() {
- _assertToken(TokenType.MINUS, "-");
- }
-
- void test_minus_eq() {
- _assertToken(TokenType.MINUS_EQ, "-=");
- }
-
- void test_minus_minus() {
- _assertToken(TokenType.MINUS_MINUS, "--");
- }
-
- void test_open_curly_bracket() {
- _assertToken(TokenType.OPEN_CURLY_BRACKET, "{");
- }
-
- void test_open_paren() {
- _assertToken(TokenType.OPEN_PAREN, "(");
- }
-
- void test_open_square_bracket() {
- _assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
- }
-
- void test_openSquareBracket() {
- _assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
- }
-
- void test_percent() {
- _assertToken(TokenType.PERCENT, "%");
- }
-
- void test_percent_eq() {
- _assertToken(TokenType.PERCENT_EQ, "%=");
- }
-
- void test_period() {
- _assertToken(TokenType.PERIOD, ".");
- }
-
- void test_period_period() {
- _assertToken(TokenType.PERIOD_PERIOD, "..");
- }
-
- void test_period_period_period() {
- _assertToken(TokenType.PERIOD_PERIOD_PERIOD, "...");
- }
-
- void test_periodAfterNumberNotIncluded_identifier() {
- _assertTokens("42.isEven()", [
- new StringToken(TokenType.INT, "42", 0),
- new Token(TokenType.PERIOD, 2),
- new StringToken(TokenType.IDENTIFIER, "isEven", 3),
- new Token(TokenType.OPEN_PAREN, 9),
- new Token(TokenType.CLOSE_PAREN, 10)
- ]);
- }
-
- void test_periodAfterNumberNotIncluded_period() {
- _assertTokens("42..isEven()", [
- new StringToken(TokenType.INT, "42", 0),
- new Token(TokenType.PERIOD_PERIOD, 2),
- new StringToken(TokenType.IDENTIFIER, "isEven", 4),
- new Token(TokenType.OPEN_PAREN, 10),
- new Token(TokenType.CLOSE_PAREN, 11)
- ]);
- }
-
- void test_plus() {
- _assertToken(TokenType.PLUS, "+");
- }
-
- void test_plus_eq() {
- _assertToken(TokenType.PLUS_EQ, "+=");
- }
-
- void test_plus_plus() {
- _assertToken(TokenType.PLUS_PLUS, "++");
- }
-
- void test_question() {
- _assertToken(TokenType.QUESTION, "?");
- }
-
- void test_question_dot() {
- _assertToken(TokenType.QUESTION_PERIOD, "?.");
- }
-
- void test_question_question() {
- _assertToken(TokenType.QUESTION_QUESTION, "??");
- }
-
- void test_question_question_eq() {
- _assertToken(TokenType.QUESTION_QUESTION_EQ, "??=");
- }
-
- void test_scriptTag_withArgs() {
- _assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart -debug");
- }
-
- void test_scriptTag_withoutSpace() {
- _assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart");
- }
-
- void test_scriptTag_withSpace() {
- _assertToken(TokenType.SCRIPT_TAG, "#! /bin/dart");
- }
-
- void test_semicolon() {
- _assertToken(TokenType.SEMICOLON, ";");
- }
-
- void test_setSourceStart() {
- int offsetDelta = 42;
- GatheringErrorListener listener = new GatheringErrorListener();
- Scanner scanner =
- new Scanner(null, new SubSequenceReader("a", offsetDelta), listener);
- scanner.setSourceStart(3, 9);
- scanner.tokenize();
- List<int> lineStarts = scanner.lineStarts;
- expect(lineStarts, isNotNull);
- expect(lineStarts.length, 3);
- expect(lineStarts[2], 33);
- }
-
- void test_slash() {
- _assertToken(TokenType.SLASH, "/");
- }
-
- void test_slash_eq() {
- _assertToken(TokenType.SLASH_EQ, "/=");
- }
-
- void test_star() {
- _assertToken(TokenType.STAR, "*");
- }
-
- void test_star_eq() {
- _assertToken(TokenType.STAR_EQ, "*=");
- }
-
- void test_startAndEnd() {
- Token token = _scan("a");
- Token previous = token.previous;
- expect(previous.next, token);
- expect(previous.previous, previous);
- Token next = token.next;
- expect(next.next, next);
- expect(next.previous, token);
- }
-
- void test_string_multi_double() {
- _assertToken(TokenType.STRING, "\"\"\"line1\nline2\"\"\"");
- }
-
- void test_string_multi_embeddedQuotes() {
- _assertToken(TokenType.STRING, "\"\"\"line1\n\"\"\nline2\"\"\"");
- }
-
- void test_string_multi_embeddedQuotes_escapedChar() {
- _assertToken(TokenType.STRING, "\"\"\"a\"\"\\tb\"\"\"");
- }
-
- void test_string_multi_interpolation_block() {
- _assertTokens("\"Hello \${name}!\"", [
- new StringToken(TokenType.STRING, "\"Hello ", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 7),
- new StringToken(TokenType.IDENTIFIER, "name", 9),
- new Token(TokenType.CLOSE_CURLY_BRACKET, 13),
- new StringToken(TokenType.STRING, "!\"", 14)
- ]);
- }
-
- void test_string_multi_interpolation_identifier() {
- _assertTokens("\"Hello \$name!\"", [
- new StringToken(TokenType.STRING, "\"Hello ", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 7),
- new StringToken(TokenType.IDENTIFIER, "name", 8),
- new StringToken(TokenType.STRING, "!\"", 12)
- ]);
- }
-
- void test_string_multi_single() {
- _assertToken(TokenType.STRING, "'''string'''");
- }
-
- void test_string_multi_slashEnter() {
- _assertToken(TokenType.STRING, "'''\\\n'''");
- }
-
- void test_string_multi_unterminated() {
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8,
- "'''string", [new StringToken(TokenType.STRING, "'''string", 0)]);
- }
-
- void test_string_multi_unterminated_interpolation_block() {
- _assertErrorAndTokens(
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8, "'''\${name", [
- new StringToken(TokenType.STRING, "'''", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 3),
- new StringToken(TokenType.IDENTIFIER, "name", 5),
- new StringToken(TokenType.STRING, "", 9)
- ]);
- }
-
- void test_string_multi_unterminated_interpolation_identifier() {
- _assertErrorAndTokens(
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7, "'''\$name", [
- new StringToken(TokenType.STRING, "'''", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
- new StringToken(TokenType.IDENTIFIER, "name", 4),
- new StringToken(TokenType.STRING, "", 8)
- ]);
- }
-
- void test_string_raw_multi_double() {
- _assertToken(TokenType.STRING, "r\"\"\"line1\nline2\"\"\"");
- }
-
- void test_string_raw_multi_single() {
- _assertToken(TokenType.STRING, "r'''string'''");
- }
-
- void test_string_raw_multi_unterminated() {
- String source = "r'''string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9,
- source, [new StringToken(TokenType.STRING, source, 0)]);
- }
-
- void test_string_raw_simple_double() {
- _assertToken(TokenType.STRING, "r\"string\"");
- }
-
- void test_string_raw_simple_single() {
- _assertToken(TokenType.STRING, "r'string'");
- }
-
- void test_string_raw_simple_unterminated_eof() {
- String source = "r'string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7,
- source, [new StringToken(TokenType.STRING, source, 0)]);
- }
-
- void test_string_raw_simple_unterminated_eol() {
- String source = "r'string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8,
- "$source\n", [new StringToken(TokenType.STRING, source, 0)]);
- }
-
- void test_string_simple_double() {
- _assertToken(TokenType.STRING, "\"string\"");
- }
-
- void test_string_simple_escapedDollar() {
- _assertToken(TokenType.STRING, "'a\\\$b'");
- }
-
- void test_string_simple_interpolation_adjacentIdentifiers() {
- _assertTokens("'\$a\$b'", [
- new StringToken(TokenType.STRING, "'", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
- new StringToken(TokenType.IDENTIFIER, "a", 2),
- new StringToken(TokenType.STRING, "", 3),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
- new StringToken(TokenType.IDENTIFIER, "b", 4),
- new StringToken(TokenType.STRING, "'", 5)
- ]);
- }
-
- void test_string_simple_interpolation_block() {
- _assertTokens("'Hello \${name}!'", [
- new StringToken(TokenType.STRING, "'Hello ", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 7),
- new StringToken(TokenType.IDENTIFIER, "name", 9),
- new Token(TokenType.CLOSE_CURLY_BRACKET, 13),
- new StringToken(TokenType.STRING, "!'", 14)
- ]);
- }
-
- void test_string_simple_interpolation_blockWithNestedMap() {
- _assertTokens("'a \${f({'b' : 'c'})} d'", [
- new StringToken(TokenType.STRING, "'a ", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 3),
- new StringToken(TokenType.IDENTIFIER, "f", 5),
- new Token(TokenType.OPEN_PAREN, 6),
- new Token(TokenType.OPEN_CURLY_BRACKET, 7),
- new StringToken(TokenType.STRING, "'b'", 8),
- new Token(TokenType.COLON, 12),
- new StringToken(TokenType.STRING, "'c'", 14),
- new Token(TokenType.CLOSE_CURLY_BRACKET, 17),
- new Token(TokenType.CLOSE_PAREN, 18),
- new Token(TokenType.CLOSE_CURLY_BRACKET, 19),
- new StringToken(TokenType.STRING, " d'", 20)
- ]);
- }
-
- void test_string_simple_interpolation_firstAndLast() {
- _assertTokens("'\$greeting \$name'", [
- new StringToken(TokenType.STRING, "'", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
- new StringToken(TokenType.IDENTIFIER, "greeting", 2),
- new StringToken(TokenType.STRING, " ", 10),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 11),
- new StringToken(TokenType.IDENTIFIER, "name", 12),
- new StringToken(TokenType.STRING, "'", 16)
- ]);
- }
-
- void test_string_simple_interpolation_identifier() {
- _assertTokens("'Hello \$name!'", [
- new StringToken(TokenType.STRING, "'Hello ", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 7),
- new StringToken(TokenType.IDENTIFIER, "name", 8),
- new StringToken(TokenType.STRING, "!'", 12)
- ]);
- }
-
- void test_string_simple_interpolation_missingIdentifier() {
- _assertTokens("'\$x\$'", [
- new StringToken(TokenType.STRING, "'", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
- new StringToken(TokenType.IDENTIFIER, "x", 2),
- new StringToken(TokenType.STRING, "", 3),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
- new StringToken(TokenType.STRING, "'", 4)
- ]);
- }
-
- void test_string_simple_interpolation_nonIdentifier() {
- _assertTokens("'\$1'", [
- new StringToken(TokenType.STRING, "'", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
- new StringToken(TokenType.STRING, "1'", 2)
- ]);
- }
-
- void test_string_simple_single() {
- _assertToken(TokenType.STRING, "'string'");
- }
-
- void test_string_simple_unterminated_eof() {
- String source = "'string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 6,
- source, [new StringToken(TokenType.STRING, source, 0)]);
- }
-
- void test_string_simple_unterminated_eol() {
- String source = "'string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7,
- "$source\r", [new StringToken(TokenType.STRING, source, 0)]);
- }
-
- void test_string_simple_unterminated_interpolation_block() {
- _assertErrorAndTokens(
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 6, "'\${name", [
- new StringToken(TokenType.STRING, "'", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 1),
- new StringToken(TokenType.IDENTIFIER, "name", 3),
- new StringToken(TokenType.STRING, "", 7)
- ]);
- }
-
- void test_string_simple_unterminated_interpolation_identifier() {
- _assertErrorAndTokens(
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 5, "'\$name", [
- new StringToken(TokenType.STRING, "'", 0),
- new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
- new StringToken(TokenType.IDENTIFIER, "name", 2),
- new StringToken(TokenType.STRING, "", 6)
- ]);
- }
-
- void test_tilde() {
- _assertToken(TokenType.TILDE, "~");
- }
-
- void test_tilde_slash() {
- _assertToken(TokenType.TILDE_SLASH, "~/");
- }
-
- void test_tilde_slash_eq() {
- _assertToken(TokenType.TILDE_SLASH_EQ, "~/=");
- }
-
- void test_unclosedPairInInterpolation() {
- GatheringErrorListener listener = new GatheringErrorListener();
- _scanWithListener("'\${(}'", listener);
- }
-
- void _assertComment(TokenType commentType, String source,
- {bool genericMethodComments: false}) {
- //
- // Test without a trailing end-of-line marker
- //
- Token token = _scan(source, genericMethodComments: genericMethodComments);
- expect(token, isNotNull);
- expect(token.type, TokenType.EOF);
- Token comment = token.precedingComments;
- expect(comment, isNotNull);
- expect(comment.type, commentType);
- expect(comment.offset, 0);
- expect(comment.length, source.length);
- expect(comment.lexeme, source);
- //
- // Test with a trailing end-of-line marker
- //
- token = _scan("$source\n", genericMethodComments: genericMethodComments);
- expect(token, isNotNull);
- expect(token.type, TokenType.EOF);
- comment = token.precedingComments;
- expect(comment, isNotNull);
- expect(comment.type, commentType);
- expect(comment.offset, 0);
- expect(comment.length, source.length);
- expect(comment.lexeme, source);
- }
-
- /**
- * Assert that scanning the given [source] produces an error with the given
- * code.
- *
- * [expectedError] the error that should be produced
- * [expectedOffset] the string offset that should be associated with the error
- * [source] the source to be scanned to produce the error
- */
- void _assertError(
- ScannerErrorCode expectedError, int expectedOffset, String source) {
- GatheringErrorListener listener = new GatheringErrorListener();
- _scanWithListener(source, listener);
- listener.assertErrors([
- new AnalysisError(null, expectedOffset, 1, expectedError,
- [source.codeUnitAt(expectedOffset)])
- ]);
- }
-
- /**
- * Assert that scanning the given [source] produces an error with the given
- * code, and also produces the given tokens.
- *
- * [expectedError] the error that should be produced
- * [expectedOffset] the string offset that should be associated with the error
- * [source] the source to be scanned to produce the error
- * [expectedTokens] the tokens that are expected to be in the source
- */
- void _assertErrorAndTokens(ScannerErrorCode expectedError, int expectedOffset,
- String source, List<Token> expectedTokens) {
- GatheringErrorListener listener = new GatheringErrorListener();
- Token token = _scanWithListener(source, listener);
- listener.assertErrors([
- new AnalysisError(null, expectedOffset, 1, expectedError,
- [source.codeUnitAt(expectedOffset)])
- ]);
- _checkTokens(token, expectedTokens);
- }
-
- /**
- * Assert that when scanned the given [source] contains a single keyword token
- * with the same lexeme as the original source.
- */
- void _assertKeywordToken(String source) {
- Token token = _scan(source);
- expect(token, isNotNull);
- expect(token.type, TokenType.KEYWORD);
- expect(token.offset, 0);
- expect(token.length, source.length);
- expect(token.lexeme, source);
- Object value = token.value();
- expect(value is Keyword, isTrue);
- expect((value as Keyword).syntax, source);
- token = _scan(" $source ");
- expect(token, isNotNull);
- expect(token.type, TokenType.KEYWORD);
- expect(token.offset, 1);
- expect(token.length, source.length);
- expect(token.lexeme, source);
- value = token.value();
- expect(value is Keyword, isTrue);
- expect((value as Keyword).syntax, source);
- expect(token.next.type, TokenType.EOF);
- }
-
void _assertLineInfo(
String source, List<ScannerTest_ExpectedLocation> expectedLocations) {
GatheringErrorListener listener = new GatheringErrorListener();
@@ -1183,99 +141,6 @@
}
}
- /**
- * Assert that the token scanned from the given [source] has the
- * [expectedType].
- */
- Token _assertToken(TokenType expectedType, String source,
- {bool lazyAssignmentOperators: false}) {
- Token originalToken =
- _scan(source, lazyAssignmentOperators: lazyAssignmentOperators);
- expect(originalToken, isNotNull);
- expect(originalToken.type, expectedType);
- expect(originalToken.offset, 0);
- expect(originalToken.length, source.length);
- expect(originalToken.lexeme, source);
- if (expectedType == TokenType.SCRIPT_TAG) {
- // Adding space before the script tag is not allowed, and adding text at
- // the end changes nothing.
- return originalToken;
- } else if (expectedType == TokenType.SINGLE_LINE_COMMENT) {
- // Adding space to an end-of-line comment changes the comment.
- Token tokenWithSpaces =
- _scan(" $source", lazyAssignmentOperators: lazyAssignmentOperators);
- expect(tokenWithSpaces, isNotNull);
- expect(tokenWithSpaces.type, expectedType);
- expect(tokenWithSpaces.offset, 1);
- expect(tokenWithSpaces.length, source.length);
- expect(tokenWithSpaces.lexeme, source);
- return originalToken;
- } else if (expectedType == TokenType.INT ||
- expectedType == TokenType.DOUBLE) {
- Token tokenWithLowerD =
- _scan("${source}d", lazyAssignmentOperators: lazyAssignmentOperators);
- expect(tokenWithLowerD, isNotNull);
- expect(tokenWithLowerD.type, expectedType);
- expect(tokenWithLowerD.offset, 0);
- expect(tokenWithLowerD.length, source.length);
- expect(tokenWithLowerD.lexeme, source);
- Token tokenWithUpperD =
- _scan("${source}D", lazyAssignmentOperators: lazyAssignmentOperators);
- expect(tokenWithUpperD, isNotNull);
- expect(tokenWithUpperD.type, expectedType);
- expect(tokenWithUpperD.offset, 0);
- expect(tokenWithUpperD.length, source.length);
- expect(tokenWithUpperD.lexeme, source);
- }
- Token tokenWithSpaces =
- _scan(" $source ", lazyAssignmentOperators: lazyAssignmentOperators);
- expect(tokenWithSpaces, isNotNull);
- expect(tokenWithSpaces.type, expectedType);
- expect(tokenWithSpaces.offset, 1);
- expect(tokenWithSpaces.length, source.length);
- expect(tokenWithSpaces.lexeme, source);
- expect(originalToken.next.type, TokenType.EOF);
- return originalToken;
- }
-
- /**
- * Assert that when scanned the given [source] contains a sequence of tokens
- * identical to the given list of [expectedTokens].
- */
- void _assertTokens(String source, List<Token> expectedTokens) {
- Token token = _scan(source);
- _checkTokens(token, expectedTokens);
- }
-
- void _checkTokens(Token firstToken, List<Token> expectedTokens) {
- expect(firstToken, isNotNull);
- Token token = firstToken;
- for (int i = 0; i < expectedTokens.length; i++) {
- Token expectedToken = expectedTokens[i];
- expect(token.type, expectedToken.type, reason: "Wrong type for token $i");
- expect(token.offset, expectedToken.offset,
- reason: "Wrong offset for token $i");
- expect(token.length, expectedToken.length,
- reason: "Wrong length for token $i");
- expect(token.lexeme, expectedToken.lexeme,
- reason: "Wrong lexeme for token $i");
- token = token.next;
- expect(token, isNotNull);
- }
- expect(token.type, TokenType.EOF);
- }
-
- Token _scan(String source,
- {bool genericMethodComments: false,
- bool lazyAssignmentOperators: false}) {
- GatheringErrorListener listener = new GatheringErrorListener();
- Token token = _scanWithListener(source, listener,
- genericMethodComments: genericMethodComments,
- lazyAssignmentOperators: lazyAssignmentOperators);
- listener.assertNoErrors();
- return token;
- }
-
Token _scanWithListener(String source, GatheringErrorListener listener,
{bool genericMethodComments: false,
bool lazyAssignmentOperators: false}) {
@@ -1369,71 +234,3 @@
buffer.write("]");
}
}
-
-@reflectiveTest
-class TokenTypeTest extends EngineTestCase {
- void test_isOperator() {
- expect(TokenType.AMPERSAND.isOperator, isTrue);
- expect(TokenType.AMPERSAND_AMPERSAND.isOperator, isTrue);
- expect(TokenType.AMPERSAND_EQ.isOperator, isTrue);
- expect(TokenType.BANG.isOperator, isTrue);
- expect(TokenType.BANG_EQ.isOperator, isTrue);
- expect(TokenType.BAR.isOperator, isTrue);
- expect(TokenType.BAR_BAR.isOperator, isTrue);
- expect(TokenType.BAR_EQ.isOperator, isTrue);
- expect(TokenType.CARET.isOperator, isTrue);
- expect(TokenType.CARET_EQ.isOperator, isTrue);
- expect(TokenType.EQ.isOperator, isTrue);
- expect(TokenType.EQ_EQ.isOperator, isTrue);
- expect(TokenType.GT.isOperator, isTrue);
- expect(TokenType.GT_EQ.isOperator, isTrue);
- expect(TokenType.GT_GT.isOperator, isTrue);
- expect(TokenType.GT_GT_EQ.isOperator, isTrue);
- expect(TokenType.INDEX.isOperator, isTrue);
- expect(TokenType.INDEX_EQ.isOperator, isTrue);
- expect(TokenType.IS.isOperator, isTrue);
- expect(TokenType.LT.isOperator, isTrue);
- expect(TokenType.LT_EQ.isOperator, isTrue);
- expect(TokenType.LT_LT.isOperator, isTrue);
- expect(TokenType.LT_LT_EQ.isOperator, isTrue);
- expect(TokenType.MINUS.isOperator, isTrue);
- expect(TokenType.MINUS_EQ.isOperator, isTrue);
- expect(TokenType.MINUS_MINUS.isOperator, isTrue);
- expect(TokenType.PERCENT.isOperator, isTrue);
- expect(TokenType.PERCENT_EQ.isOperator, isTrue);
- expect(TokenType.PERIOD_PERIOD.isOperator, isTrue);
- expect(TokenType.PLUS.isOperator, isTrue);
- expect(TokenType.PLUS_EQ.isOperator, isTrue);
- expect(TokenType.PLUS_PLUS.isOperator, isTrue);
- expect(TokenType.QUESTION.isOperator, isTrue);
- expect(TokenType.SLASH.isOperator, isTrue);
- expect(TokenType.SLASH_EQ.isOperator, isTrue);
- expect(TokenType.STAR.isOperator, isTrue);
- expect(TokenType.STAR_EQ.isOperator, isTrue);
- expect(TokenType.TILDE.isOperator, isTrue);
- expect(TokenType.TILDE_SLASH.isOperator, isTrue);
- expect(TokenType.TILDE_SLASH_EQ.isOperator, isTrue);
- }
-
- void test_isUserDefinableOperator() {
- expect(TokenType.AMPERSAND.isUserDefinableOperator, isTrue);
- expect(TokenType.BAR.isUserDefinableOperator, isTrue);
- expect(TokenType.CARET.isUserDefinableOperator, isTrue);
- expect(TokenType.EQ_EQ.isUserDefinableOperator, isTrue);
- expect(TokenType.GT.isUserDefinableOperator, isTrue);
- expect(TokenType.GT_EQ.isUserDefinableOperator, isTrue);
- expect(TokenType.GT_GT.isUserDefinableOperator, isTrue);
- expect(TokenType.INDEX.isUserDefinableOperator, isTrue);
- expect(TokenType.INDEX_EQ.isUserDefinableOperator, isTrue);
- expect(TokenType.LT.isUserDefinableOperator, isTrue);
- expect(TokenType.LT_EQ.isUserDefinableOperator, isTrue);
- expect(TokenType.LT_LT.isUserDefinableOperator, isTrue);
- expect(TokenType.MINUS.isUserDefinableOperator, isTrue);
- expect(TokenType.PERCENT.isUserDefinableOperator, isTrue);
- expect(TokenType.PLUS.isUserDefinableOperator, isTrue);
- expect(TokenType.SLASH.isUserDefinableOperator, isTrue);
- expect(TokenType.STAR.isUserDefinableOperator, isTrue);
- expect(TokenType.TILDE.isUserDefinableOperator, isTrue);
- expect(TokenType.TILDE_SLASH.isUserDefinableOperator, isTrue);
- }
-}
diff --git a/pkg/analyzer/test/source/analysis_options_provider_test.dart b/pkg/analyzer/test/source/analysis_options_provider_test.dart
index 5ea408a..8ada91c 100644
--- a/pkg/analyzer/test/source/analysis_options_provider_test.dart
+++ b/pkg/analyzer/test/source/analysis_options_provider_test.dart
@@ -10,6 +10,7 @@
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:analyzer/src/generated/source.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:yaml/yaml.dart';
@@ -115,7 +116,7 @@
TestPathTranslator pathTranslator;
ResourceProvider resourceProvider;
- AnalysisOptionsProvider provider = new AnalysisOptionsProvider();
+ AnalysisOptionsProvider provider;
String get optionsFileName;
@@ -123,6 +124,9 @@
var rawProvider = new MemoryResourceProvider();
resourceProvider = new TestResourceProvider(rawProvider);
pathTranslator = new TestPathTranslator(rawProvider);
+ provider = new AnalysisOptionsProvider(new SourceFactory([
+ new ResourceUriResolver(rawProvider),
+ ]));
}
void test_getOptions_crawlUp_hasInFolder() {
@@ -188,6 +192,44 @@
expect(options, isEmpty);
}
+ void test_getOptions_include() {
+ pathTranslator.newFile(
+ '/foo.include',
+ r'''
+analyzer:
+ ignore:
+ - ignoreme.dart
+ - 'sdk_ext/**'
+''');
+ pathTranslator.newFile(
+ '/$optionsFileName',
+ r'''
+include: foo.include
+''');
+ Map<String, YamlNode> options = _getOptions('/');
+ expect(options, hasLength(1));
+ {
+ YamlMap analyzer = options['analyzer'];
+ expect(analyzer, hasLength(1));
+ {
+ YamlList ignore = analyzer['ignore'];
+ expect(ignore, hasLength(2));
+ expect(ignore[0], 'ignoreme.dart');
+ expect(ignore[1], 'sdk_ext/**');
+ }
+ }
+ }
+
+ void test_getOptions_include_missing() {
+ pathTranslator.newFile(
+ '/$optionsFileName',
+ r'''
+include: /foo.include
+''');
+ Map<String, YamlNode> options = _getOptions('/');
+ expect(options, hasLength(0));
+ }
+
void test_getOptions_invalid() {
pathTranslator.newFile('/$optionsFileName', r''':''');
expect(() {
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index b05daa5..0c47bd0 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -555,6 +555,63 @@
}
}
+ void test_getAnalysisOptions_includes() {
+ AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+ defaultOptions.enableGenericMethods = true;
+ builderOptions.defaultOptions = defaultOptions;
+ AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
+ expected.enableSuperMixins = true;
+ expected.enableGenericMethods = true;
+ resourceProvider.newFile(
+ resourceProvider.convertPath('/mypkgs/somepkg/lib/here.yaml'),
+ '''
+two: {boo: newt}
+''');
+ String path = resourceProvider.convertPath('/some/directory/path');
+ resourceProvider.newFile(
+ pathContext.join(path, '.packages'),
+ '''
+somepkg:../../../mypkgs/somepkg/lib
+''');
+ resourceProvider.newFile(
+ pathContext.join(path, 'bar.yaml'),
+ '''
+include: package:somepkg/here.yaml
+foo: {bar: baz}
+''');
+ String filePath =
+ pathContext.join(path, AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
+ resourceProvider.newFile(
+ filePath,
+ '''
+include: bar.yaml
+analyzer:
+ language:
+ enableSuperMixins : true
+''');
+
+ AnalysisEngine engine = AnalysisEngine.instance;
+ OptionsPlugin plugin = engine.optionsPlugin;
+ plugin.registerExtensionPoints((_) {});
+ try {
+ _TestOptionsProcessor processor = new _TestOptionsProcessor();
+ processor.expectedOptions = <String, Object>{
+ 'analyzer': {
+ 'language': {'enableSuperMixins': true}
+ },
+ 'foo': {'bar': 'baz'},
+ 'two': {'boo': 'newt'},
+ };
+ (plugin.optionsProcessorExtensionPoint as ExtensionPointImpl)
+ .add(processor);
+ AnalysisContext context = engine.createAnalysisContext();
+ AnalysisOptions options = builder.getAnalysisOptions(context, path);
+ _expectEqualOptions(options, expected);
+ } finally {
+ plugin.registerExtensionPoints((_) {});
+ }
+ }
+
void test_getAnalysisOptions_invalid() {
String path = resourceProvider.convertPath('/some/directory/path');
String filePath =
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 3b7d74d..ec693f4 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -602,6 +602,14 @@
}
}
+ test_getResult_notDartFile() async {
+ var path = _p('/test/lib/test.txt');
+ provider.newFile(path, 'foo bar');
+
+ AnalysisResult result = await driver.getResult(path);
+ expect(result, isNull);
+ }
+
test_getResult_sameFile_twoUris() async {
var a = _p('/test/lib/a.dart');
var b = _p('/test/lib/b.dart');
diff --git a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
index 7147906..05c7a76 100644
--- a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
+++ b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
@@ -711,6 +711,43 @@
expect(helper.delta.removedMethods, unorderedEquals([oldElementA]));
}
+ test_classDelta_method_async_addStar() {
+ var helper = new _ClassDeltaHelper('A');
+ _buildOldUnit(r'''
+class A {
+ Stream test() async {}
+}
+''');
+ helper.initOld(oldUnit);
+ _buildNewUnit(r'''
+class A {
+ Stream test() async* {}
+}
+''');
+ helper.initNew(newUnit, unitDelta);
+ // nodes
+ ClassMember oldNodeA = helper.oldMembers[0];
+ ClassMember newNodeA = helper.newMembers[0];
+ expect(newNodeA, isNot(same(oldNodeA)));
+ // elements
+ MethodElement oldElement = oldNodeA.element;
+ MethodElement newElement = newNodeA.element;
+ expect(newElement, isNotNull);
+ expect(newElement.name, 'test');
+ expect(oldElement.isAsynchronous, isTrue);
+ expect(oldElement.isGenerator, isFalse);
+ expect(newElement.isAsynchronous, isTrue);
+ expect(newElement.isGenerator, isTrue);
+ expect(helper.element.methods, [newElement]);
+ // verify delta
+ expect(helper.delta.addedConstructors, isEmpty);
+ expect(helper.delta.removedConstructors, isEmpty);
+ expect(helper.delta.addedAccessors, isEmpty);
+ expect(helper.delta.removedAccessors, isEmpty);
+ expect(helper.delta.addedMethods, unorderedEquals([newElement]));
+ expect(helper.delta.removedMethods, unorderedEquals([oldElement]));
+ }
+
test_classDelta_method_changeName() {
var helper = new _ClassDeltaHelper('A');
_buildOldUnit(r'''
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index f58ef31..b613093 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -33,7 +33,6 @@
import '../universe/world_impact.dart'
show ImpactStrategy, WorldImpact, WorldImpactBuilder;
import 'codegen.dart' show CodegenWorkItem;
-import 'registry.dart' show Registry;
import 'tasks.dart' show CompilerTask;
abstract class Backend extends Target {
@@ -316,9 +315,6 @@
void registerMainHasArguments(Enqueuer enqueuer) {}
- void registerAsyncMarker(
- FunctionElement element, Enqueuer enqueuer, Registry registry) {}
-
/// Returns the location of the patch-file associated with [libraryName]
/// resolved from [plaformConfigUri].
///
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 5214585..285e032 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -21,7 +21,6 @@
import '../universe/world_impact.dart'
show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor;
import '../util/util.dart' show Pair, Setlet;
-import 'registry.dart' show Registry;
import 'work.dart' show WorkItem;
class CodegenImpact extends WorldImpact {
@@ -146,7 +145,7 @@
// TODO(johnniwinther): Split this class into interface and implementation.
// TODO(johnniwinther): Move this implementation to the JS backend.
-class CodegenRegistry extends Registry {
+class CodegenRegistry {
final Compiler compiler;
final Element currentElement;
final _CodegenImpact worldImpact;
diff --git a/pkg/compiler/lib/src/common/registry.dart b/pkg/compiler/lib/src/common/registry.dart
deleted file mode 100644
index 08d6081..0000000
--- a/pkg/compiler/lib/src/common/registry.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.common.registry;
-
-import '../elements/elements.dart' show Element;
-
-// TODO(johnniwinther): Remove this.
-/// Interface for registration of element dependencies.
-abstract class Registry {
- void registerDependency(Element element) {}
-}
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index c2f91fe..ef0e751 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -13,7 +13,6 @@
import 'common/codegen.dart' show CodegenWorkItem;
import 'common/names.dart' show Selectors;
import 'common/names.dart' show Identifiers, Uris;
-import 'common/registry.dart' show Registry;
import 'common/resolution.dart'
show
ParsingContext,
@@ -850,10 +849,10 @@
void processQueue(Enqueuer enqueuer, Element main) {
selfTask.measureSubtask("Compiler.processQueue", () {
- WorldImpactBuilderImpl nativeImpact = new WorldImpactBuilderImpl();
- enqueuer.nativeEnqueuer
- .processNativeClasses(nativeImpact, libraryLoader.libraries);
- enqueuer.applyImpact(impactStrategy, nativeImpact);
+ enqueuer.applyImpact(
+ impactStrategy,
+ enqueuer.nativeEnqueuer
+ .processNativeClasses(libraryLoader.libraries));
if (main != null && !main.isMalformed) {
FunctionElement mainMethod = main;
mainMethod.computeType(resolution);
@@ -2213,7 +2212,7 @@
}
}
-class GlobalDependencyRegistry extends Registry {
+class GlobalDependencyRegistry {
Setlet<Element> _otherDependencies;
GlobalDependencyRegistry();
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index 06b58d9..178ba03 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -237,7 +237,7 @@
/// `true` if this element is the body of a generative constructor.
///
- /// This is a synthetic element kind used only be the JavaScript backend.
+ /// This is a synthetic element kind used only by the JavaScript backend.
bool get isGenerativeConstructorBody;
/// `true` if this element is a factory constructor,
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index 66c3260..bb50941 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -10,7 +10,6 @@
import 'common/backend_api.dart' show Backend;
import 'common/names.dart' show Identifiers;
import 'common/resolution.dart' show Resolution, ResolutionWorkItem;
-import 'common/registry.dart' show Registry;
import 'common/tasks.dart' show CompilerTask;
import 'common/work.dart' show WorkItem;
import 'common.dart';
@@ -85,7 +84,6 @@
void registerStaticUse(StaticUse staticUse);
void registerStaticUseInternal(StaticUse staticUse);
void registerDynamicUse(DynamicUse dynamicUse);
- void registerTypeUse(TypeUse typeUse);
/// Returns [:true:] if this enqueuer is the resolution enqueuer.
bool get isResolutionQueue;
@@ -455,7 +453,7 @@
break;
case StaticUseKind.CONSTRUCTOR_INVOKE:
case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
- registerTypeUse(new TypeUse.instantiation(staticUse.type));
+ _registerTypeUse(new TypeUse.instantiation(staticUse.type));
break;
case StaticUseKind.DIRECT_INVOKE:
invariant(
@@ -467,7 +465,7 @@
}
}
- void registerTypeUse(TypeUse typeUse) {
+ void _registerTypeUse(TypeUse typeUse) {
DartType type = typeUse.type;
switch (typeUse.kind) {
case TypeUseKind.INSTANTIATION:
@@ -743,7 +741,7 @@
}
class _EnqueuerImpactVisitor implements WorldImpactVisitor {
- final Enqueuer enqueuer;
+ final ResolutionEnqueuer enqueuer;
_EnqueuerImpactVisitor(this.enqueuer);
@@ -759,7 +757,7 @@
@override
void visitTypeUse(TypeUse typeUse) {
- enqueuer.registerTypeUse(typeUse);
+ enqueuer._registerTypeUse(typeUse);
}
}
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index 4e96cd6..f6cdace 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -1473,8 +1473,9 @@
isThisExposed = true;
Selector selector = elements.getSelector(node);
TypeMask mask = inTreeData.typeOfSend(node);
- return handleStaticSend(
+ handleStaticSend(
node, selector, mask, element, new ArgumentsTypes<T>([rhsType], null));
+ return rhsType;
}
@override
@@ -1684,13 +1685,13 @@
return handleForeignSend(node, target);
}
Selector selector = elements.getSelector(node);
+ CallStructure callStructure = selector.callStructure;
TypeMask mask = inTreeData.typeOfSend(node);
// In erroneous code the number of arguments in the selector might not
// match the function element.
// TODO(polux): return nonNullEmpty and check it doesn't break anything
- if (!selector.applies(target) ||
- (mask != null &&
- !mask.canHit(target, selector, compiler.closedWorld))) {
+ if (target.isMalformed ||
+ !callStructure.signatureApplies(target.functionSignature)) {
return types.dynamicType;
}
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 56e8e89..3aca346 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -19,7 +19,6 @@
NativeRegistry;
import '../common/codegen.dart' show CodegenImpact, CodegenWorkItem;
import '../common/names.dart' show Identifiers, Selectors, Uris;
-import '../common/registry.dart' show Registry;
import '../common/resolution.dart' show Frontend, Resolution, ResolutionImpact;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
@@ -1928,9 +1927,6 @@
}
}
- /// Called when [:new Symbol(...):] is seen.
- void registerNewSymbol(Registry registry) {}
-
/// Should [element] (a getter) that would normally not be generated due to
/// treeshaking be retained for reflection?
bool shouldRetainGetter(Element element) {
@@ -2384,14 +2380,20 @@
}
if (isTreeShakingDisabled) {
- mirrorsAnalysis.enqueueReflectiveElements(
- enqueuer, recentClasses, compiler.libraryLoader.libraries);
+ enqueuer.applyImpact(
+ compiler.impactStrategy,
+ mirrorsAnalysis.computeImpactForReflectiveElements(recentClasses,
+ enqueuer.processedClasses, compiler.libraryLoader.libraries,
+ forResolution: enqueuer.isResolutionQueue));
} else if (!targetsUsed.isEmpty && enqueuer.isResolutionQueue) {
// Add all static elements (not classes) that have been requested for
// reflection. If there is no mirror-usage these are probably not
// necessary, but the backend relies on them being resolved.
- mirrorsAnalysis.enqueueReflectiveStaticFields(
- enqueuer, _findStaticFieldTargets());
+ enqueuer.applyImpact(
+ compiler.impactStrategy,
+ mirrorsAnalysis.computeImpactForReflectiveStaticFields(
+ _findStaticFieldTargets(),
+ forResolution: enqueuer.isResolutionQueue));
}
if (mustPreserveNames) reporter.log('Preserving names.');
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index c169537..179a65d 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -8,7 +8,6 @@
import '../common/backend_api.dart' show Backend;
import '../common/codegen.dart' show CodegenWorkItem;
-import '../common/registry.dart' show Registry;
import '../common/names.dart' show Identifiers;
import '../common/tasks.dart' show CompilerTask;
import '../common/work.dart' show WorkItem;
diff --git a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
index c6e204d..fec60e3 100644
--- a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
@@ -8,7 +8,6 @@
import 'package:pub_semver/pub_semver.dart';
import '../common.dart';
-import '../common/registry.dart' show Registry;
import '../compiler.dart' show Compiler;
import '../constants/values.dart'
show
diff --git a/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart b/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
index 930dba3..93344f6 100644
--- a/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
@@ -7,9 +7,9 @@
import '../common/resolution.dart';
import '../diagnostics/diagnostic_listener.dart';
import '../elements/elements.dart';
-import '../enqueue.dart';
import '../universe/selector.dart';
import '../universe/use.dart';
+import '../universe/world_impact.dart';
import 'backend.dart';
class MirrorsAnalysis {
@@ -20,26 +20,26 @@
: resolutionHandler = new MirrorsHandler(backend, resolution),
codegenHandler = new MirrorsHandler(backend, resolution);
- /// Enqueue all elements that are matched by the mirrors used
+ /// Compute the impact for elements that are matched by the mirrors used
/// annotation or, in lack thereof, all elements.
- // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly.
- void enqueueReflectiveElements(
- Enqueuer enqueuer,
+ WorldImpact computeImpactForReflectiveElements(
Iterable<ClassElement> recents,
- Iterable<LibraryElement> loadedLibraries) {
- MirrorsHandler handler =
- enqueuer.isResolutionQueue ? resolutionHandler : codegenHandler;
- handler.enqueueReflectiveElements(enqueuer, recents, loadedLibraries);
+ Iterable<ClassElement> processedClasses,
+ Iterable<LibraryElement> loadedLibraries,
+ {bool forResolution}) {
+ MirrorsHandler handler = forResolution ? resolutionHandler : codegenHandler;
+ handler.enqueueReflectiveElements(
+ recents, processedClasses, loadedLibraries);
+ return handler.flush();
}
- /// Enqueue the static fields that have been marked as used by reflective
- /// usage through `MirrorsUsed`.
- // TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly.
- void enqueueReflectiveStaticFields(
- Enqueuer enqueuer, Iterable<Element> elements) {
- MirrorsHandler handler =
- enqueuer.isResolutionQueue ? resolutionHandler : codegenHandler;
- handler.enqueueReflectiveStaticFields(enqueuer, elements);
+ /// Compute the impact for the static fields that have been marked as used by
+ /// reflective usage through `MirrorsUsed`.
+ WorldImpact computeImpactForReflectiveStaticFields(Iterable<Element> elements,
+ {bool forResolution}) {
+ MirrorsHandler handler = forResolution ? resolutionHandler : codegenHandler;
+ handler.enqueueReflectiveStaticFields(elements);
+ return handler.flush();
}
}
@@ -53,10 +53,14 @@
bool hasEnqueuedReflectiveElements = false;
bool hasEnqueuedReflectiveStaticFields = false;
+ StagedWorldImpactBuilder impactBuilder = new StagedWorldImpactBuilder();
+
MirrorsHandler(this._backend, this._resolution);
DiagnosticReporter get _reporter => _resolution.reporter;
+ WorldImpact flush() => impactBuilder.flush();
+
void _logEnqueueReflectiveAction(action, [msg = ""]) {
if (TRACE_MIRROR_ENQUEUING) {
print("MIRROR_ENQUEUE (R): $action $msg");
@@ -80,15 +84,15 @@
///
/// [enclosingWasIncluded] provides a hint whether the enclosing element was
/// needed for reflection.
- void _enqueueReflectiveConstructor(
- Enqueuer enqueuer, ConstructorElement constructor,
+ void _enqueueReflectiveConstructor(ConstructorElement constructor,
{bool enclosingWasIncluded}) {
if (_shouldIncludeElementDueToMirrors(constructor,
includedEnclosing: enclosingWasIncluded)) {
_logEnqueueReflectiveAction(constructor);
ClassElement cls = constructor.declaration.enclosingClass;
- enqueuer.registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType));
- enqueuer
+ impactBuilder
+ .registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType));
+ impactBuilder
.registerStaticUse(new StaticUse.foreignUse(constructor.declaration));
}
}
@@ -97,8 +101,7 @@
///
/// [enclosingWasIncluded] provides a hint whether the enclosing element was
/// needed for reflection.
- void _enqueueReflectiveMember(
- Enqueuer enqueuer, Element element, bool enclosingWasIncluded) {
+ void _enqueueReflectiveMember(Element element, bool enclosingWasIncluded) {
if (_shouldIncludeElementDueToMirrors(element,
includedEnclosing: enclosingWasIncluded)) {
_logEnqueueReflectiveAction(element);
@@ -106,7 +109,7 @@
TypedefElement typedef = element;
typedef.ensureResolved(_resolution);
} else if (Elements.isStaticOrTopLevel(element)) {
- enqueuer
+ impactBuilder
.registerStaticUse(new StaticUse.foreignUse(element.declaration));
} else if (element.isInstanceMember) {
// We need to enqueue all members matching this one in subclasses, as
@@ -114,13 +117,13 @@
// TODO(herhut): Use TypedSelector.subtype for enqueueing
DynamicUse dynamicUse =
new DynamicUse(new Selector.fromElement(element), null);
- enqueuer.registerDynamicUse(dynamicUse);
+ impactBuilder.registerDynamicUse(dynamicUse);
if (element.isField) {
DynamicUse dynamicUse = new DynamicUse(
new Selector.setter(
new Name(element.name, element.library, isSetter: true)),
null);
- enqueuer.registerDynamicUse(dynamicUse);
+ impactBuilder.registerDynamicUse(dynamicUse);
}
}
}
@@ -131,7 +134,7 @@
/// [enclosingWasIncluded] provides a hint whether the enclosing element was
/// needed for reflection.
void _enqueueReflectiveElementsInClass(
- Enqueuer enqueuer, ClassElement cls, Iterable<ClassElement> recents,
+ ClassElement cls, Iterable<ClassElement> recents,
{bool enclosingWasIncluded}) {
if (cls.library.isInternalLibrary || cls.isInjected) return;
bool includeClass = _shouldIncludeElementDueToMirrors(cls,
@@ -140,7 +143,7 @@
_logEnqueueReflectiveAction(cls, "register");
ClassElement declaration = cls.declaration;
declaration.ensureResolved(_resolution);
- enqueuer.registerTypeUse(
+ impactBuilder.registerTypeUse(
new TypeUse.mirrorInstantiation(declaration.rawType));
}
// If the class is never instantiated, we know nothing of it can possibly
@@ -149,11 +152,11 @@
if (recents.contains(cls.declaration)) {
_logEnqueueReflectiveAction(cls, "members");
cls.constructors.forEach((Element element) {
- _enqueueReflectiveConstructor(enqueuer, element,
+ _enqueueReflectiveConstructor(element,
enclosingWasIncluded: includeClass);
});
cls.forEachClassMember((Member member) {
- _enqueueReflectiveMember(enqueuer, member.element, includeClass);
+ _enqueueReflectiveMember(member.element, includeClass);
});
}
}
@@ -165,13 +168,14 @@
/// Although it is in an internal library, we mark it as reflectable. Note
/// that none of its methods are reflectable, unless reflectable by
/// inheritance.
- void _enqueueReflectiveSpecialClasses(Enqueuer enqueuer) {
+ void _enqueueReflectiveSpecialClasses() {
Iterable<ClassElement> classes = _backend.classesRequiredForReflection;
for (ClassElement cls in classes) {
if (_backend.referencedFromMirrorSystem(cls)) {
_logEnqueueReflectiveAction(cls);
cls.ensureResolved(_resolution);
- enqueuer.registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType));
+ impactBuilder
+ .registerTypeUse(new TypeUse.mirrorInstantiation(cls.rawType));
}
}
}
@@ -179,16 +183,16 @@
/// Enqeue all local members of the library [lib] if they are required for
/// reflection.
void _enqueueReflectiveElementsInLibrary(
- Enqueuer enqueuer, LibraryElement lib, Iterable<ClassElement> recents) {
+ LibraryElement lib, Iterable<ClassElement> recents) {
bool includeLibrary =
_shouldIncludeElementDueToMirrors(lib, includedEnclosing: false);
lib.forEachLocalMember((Element member) {
if (member.isInjected) return;
if (member.isClass) {
- _enqueueReflectiveElementsInClass(enqueuer, member, recents,
+ _enqueueReflectiveElementsInClass(member, recents,
enclosingWasIncluded: includeLibrary);
} else {
- _enqueueReflectiveMember(enqueuer, member, includeLibrary);
+ _enqueueReflectiveMember(member, includeLibrary);
}
});
}
@@ -197,8 +201,8 @@
/// annotation or, in lack thereof, all elements.
// TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly.
void enqueueReflectiveElements(
- Enqueuer enqueuer,
Iterable<ClassElement> recents,
+ Iterable<ClassElement> processedClasses,
Iterable<LibraryElement> loadedLibraries) {
if (!hasEnqueuedReflectiveElements) {
_logEnqueueReflectiveAction("!START enqueueAll");
@@ -208,12 +212,12 @@
// as recently seen, as we do not know how many rounds of resolution might
// have run before tree shaking is disabled and thus everything is
// enqueued.
- recents = enqueuer.processedClasses.toSet();
+ recents = processedClasses.toSet();
_reporter.log('Enqueuing everything');
for (LibraryElement lib in loadedLibraries) {
- _enqueueReflectiveElementsInLibrary(enqueuer, lib, recents);
+ _enqueueReflectiveElementsInLibrary(lib, recents);
}
- _enqueueReflectiveSpecialClasses(enqueuer);
+ _enqueueReflectiveSpecialClasses();
hasEnqueuedReflectiveElements = true;
hasEnqueuedReflectiveStaticFields = true;
_logEnqueueReflectiveAction("!DONE enqueueAll");
@@ -221,7 +225,7 @@
// Keep looking at new classes until fixpoint is reached.
_logEnqueueReflectiveAction("!START enqueueRecents");
recents.forEach((ClassElement cls) {
- _enqueueReflectiveElementsInClass(enqueuer, cls, recents,
+ _enqueueReflectiveElementsInClass(cls, recents,
enclosingWasIncluded: _shouldIncludeElementDueToMirrors(cls.library,
includedEnclosing: false));
});
@@ -232,12 +236,11 @@
/// Enqueue the static fields that have been marked as used by reflective
/// usage through `MirrorsUsed`.
// TODO(johnniwinther): Compute [WorldImpact] instead of enqueuing directly.
- void enqueueReflectiveStaticFields(
- Enqueuer enqueuer, Iterable<Element> elements) {
+ void enqueueReflectiveStaticFields(Iterable<Element> elements) {
if (hasEnqueuedReflectiveStaticFields) return;
hasEnqueuedReflectiveStaticFields = true;
for (Element element in elements) {
- _enqueueReflectiveMember(enqueuer, element, true);
+ _enqueueReflectiveMember(element, true);
}
}
}
diff --git a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
index 97c6011..ff8822d 100644
--- a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
+++ b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import '../common.dart';
-import '../common/registry.dart' show Registry;
import '../compiler.dart' show Compiler;
import '../constants/expressions.dart';
import '../constants/values.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/headers.dart b/pkg/compiler/lib/src/js_emitter/headers.dart
index 905cb04..ad9e783 100644
--- a/pkg/compiler/lib/src/js_emitter/headers.dart
+++ b/pkg/compiler/lib/src/js_emitter/headers.dart
@@ -32,4 +32,8 @@
// is loaded. It should load and eval the javascript of `uri`, and call
// successCallback. If it fails to do so, it should call errorCallback with
// an error.
+//
+// defaultPackagesBase:
+// Override the location where `package:` uris are resolved from. By default
+// they are resolved under "packages/" from the current window location.
""";
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 44d3be3..300a650 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -6,7 +6,6 @@
import '../common.dart';
import '../common/backend_api.dart' show ForeignResolver;
-import '../common/registry.dart' show Registry;
import '../common/resolution.dart' show Resolution;
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
@@ -14,7 +13,6 @@
import '../dart_types.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart' show FunctionElementX;
-import '../enqueue.dart' show Enqueuer;
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart';
import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
@@ -22,7 +20,8 @@
import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN;
import '../tree/tree.dart';
import '../universe/use.dart' show StaticUse, TypeUse;
-import '../universe/world_impact.dart' show WorldImpactBuilder;
+import '../universe/world_impact.dart'
+ show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
import 'behavior.dart';
/**
@@ -33,8 +32,8 @@
void onInstantiatedType(InterfaceType type) {}
/// Initial entry point to native enqueuer.
- void processNativeClasses(
- WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) {}
+ WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) =>
+ const WorldImpact();
/// Registers the [nativeBehavior]. Adds the liveness of its instantiated
/// types to the world.
@@ -68,31 +67,19 @@
abstract class NativeEnqueuerBase implements NativeEnqueuer {
static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$');
- /**
- * The set of all native classes. Each native class is in [nativeClasses] and
- * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses].
- */
- final Set<ClassElement> nativeClasses = new Set<ClassElement>();
+ /// The set of all native classes. Each native class is in [nativeClasses]
+ /// and exactly one of [unusedClasses] and [registeredClasses].
+ final Set<ClassElement> _nativeClasses = new Set<ClassElement>();
- final Set<ClassElement> registeredClasses = new Set<ClassElement>();
- final Set<ClassElement> pendingClasses = new Set<ClassElement>();
- final Set<ClassElement> unusedClasses = new Set<ClassElement>();
+ final Set<ClassElement> _registeredClasses = new Set<ClassElement>();
+ final Set<ClassElement> _unusedClasses = new Set<ClassElement>();
final Set<LibraryElement> processedLibraries;
- bool get hasInstantiatedNativeClasses => !registeredClasses.isEmpty;
+ bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty;
final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
- final Map<ClassElement, Set<ClassElement>> nonNativeSubclasses =
- new Map<ClassElement, Set<ClassElement>>();
-
- /**
- * Records matched constraints ([SpecialType] or [DartType]). Once a type
- * constraint has been matched, there is no need to match it again.
- */
- final Set matchedTypeConstraints = new Set();
-
final Compiler compiler;
final bool enableLiveTypeAnalysis;
@@ -113,12 +100,18 @@
CoreTypes get coreTypes => compiler.coreTypes;
void onInstantiatedType(InterfaceType type) {
- if (unusedClasses.remove(type.element)) {
- registeredClasses.add(type.element);
+ if (_unusedClasses.remove(type.element)) {
+ _registeredClasses.add(type.element);
}
}
- void processNativeClasses(
+ WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) {
+ WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
+ _processNativeClasses(impactBuilder, libraries);
+ return impactBuilder;
+ }
+
+ void _processNativeClasses(
WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) {
if (compiler.options.hasIncrementalSupport) {
// Since [Set.add] returns bool if an element was added, this restricts
@@ -132,7 +125,7 @@
}
processSubclassesOfNativeClasses(libraries);
if (!enableLiveTypeAnalysis) {
- _registerTypeUses(impactBuilder, nativeClasses, 'forced');
+ _registerTypeUses(impactBuilder, _nativeClasses, 'forced');
}
}
@@ -146,8 +139,8 @@
}
void processNativeClass(ClassElement classElement) {
- nativeClasses.add(classElement);
- unusedClasses.add(classElement);
+ _nativeClasses.add(classElement);
+ _unusedClasses.add(classElement);
// Resolve class to ensure the class has valid inheritance info.
classElement.ensureResolved(resolution);
}
@@ -190,11 +183,6 @@
ClassElement nativeSuperclass = nativeSuperclassOf(element);
if (nativeSuperclass != null) {
nativeClassesAndSubclasses.add(element);
- if (!backend.isNative(element)) {
- nonNativeSubclasses
- .putIfAbsent(nativeSuperclass, () => new Set<ClassElement>())
- .add(element);
- }
Set<ClassElement> potentialSubclasses = potentialExtends[element.name];
if (potentialSubclasses != null) {
potentialSubclasses.forEach(walkPotentialSubclasses);
@@ -202,10 +190,10 @@
}
}
- nativeClasses.forEach(walkPotentialSubclasses);
+ _nativeClasses.forEach(walkPotentialSubclasses);
- nativeClasses.addAll(nativeClassesAndSubclasses);
- unusedClasses.addAll(nativeClassesAndSubclasses);
+ _nativeClasses.addAll(nativeClassesAndSubclasses);
+ _unusedClasses.addAll(nativeClassesAndSubclasses);
}
/**
@@ -344,7 +332,7 @@
void _registerTypeUses(
WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) {
for (ClassElement cls in classes) {
- if (!unusedClasses.contains(cls)) {
+ if (!_unusedClasses.contains(cls)) {
// No need to add [classElement] to [impactBuilder]: it has already been
// instantiated and we don't track origins of native instantiations
// precisely.
@@ -446,11 +434,9 @@
impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type));
}
- int unusedBefore = unusedClasses.length;
+ int unusedBefore = _unusedClasses.length;
Set<ClassElement> matchingClasses = new Set<ClassElement>();
for (var type in behavior.typesInstantiated) {
- if (matchedTypeConstraints.contains(type)) continue;
- matchedTypeConstraints.add(type);
if (type is SpecialType) {
if (type == SpecialType.JsObject) {
registerInstantiation(compiler.coreTypes.objectType);
@@ -489,12 +475,12 @@
return compiler.types.isSubtype(nativeType, specType);
}));
} else if (type.isDynamic) {
- matchingClasses.addAll(unusedClasses);
+ matchingClasses.addAll(_unusedClasses);
} else {
assert(type is VoidType);
}
}
- if (matchingClasses.isNotEmpty && registeredClasses.isEmpty) {
+ if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
}
_registerTypeUses(impactBuilder, matchingClasses, cause);
@@ -508,7 +494,7 @@
Iterable<ClassElement> _findUnusedClassesMatching(
bool predicate(classElement)) {
- return unusedClasses.where(predicate);
+ return _unusedClasses.where(predicate);
}
Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) {
@@ -564,8 +550,8 @@
}
void logSummary(log(message)) {
- log('Resolved ${registeredClasses.length} native elements used, '
- '${unusedClasses.length} native elements dead.');
+ log('Resolved ${_registeredClasses.length} native elements used, '
+ '${_unusedClasses.length} native elements dead.');
}
/**
@@ -620,19 +606,19 @@
NativeCodegenEnqueuer(Compiler compiler, this.emitter)
: super(compiler, compiler.options.enableNativeLiveTypeAnalysis);
- void processNativeClasses(
+ void _processNativeClasses(
WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) {
- super.processNativeClasses(impactBuilder, libraries);
+ super._processNativeClasses(impactBuilder, libraries);
// HACK HACK - add all the resolved classes.
NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer;
Set<ClassElement> matchingClasses = new Set<ClassElement>();
- for (final classElement in enqueuer.registeredClasses) {
- if (unusedClasses.contains(classElement)) {
+ for (final classElement in enqueuer._registeredClasses) {
+ if (_unusedClasses.contains(classElement)) {
matchingClasses.add(classElement);
}
}
- if (matchingClasses.isNotEmpty && registeredClasses.isEmpty) {
+ if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
}
_registerTypeUses(impactBuilder, matchingClasses, 'was resolved');
@@ -679,7 +665,7 @@
}
void logSummary(log(message)) {
- log('Compiled ${registeredClasses.length} native classes, '
- '${unusedClasses.length} native classes omitted.');
+ log('Compiled ${_registeredClasses.length} native classes, '
+ '${_unusedClasses.length} native classes omitted.');
}
}
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index 51d7e81..ce40fd0 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -7,7 +7,6 @@
import '../common.dart';
import '../common/backend_api.dart'
show Backend, ForeignResolver, NativeRegistry;
-import '../common/registry.dart' show Registry;
import '../common/resolution.dart' show ResolutionImpact, Target;
import '../constants/expressions.dart';
import '../dart_types.dart';
@@ -154,7 +153,7 @@
/// related information in a [TreeElements] mapping and registers calls with
/// [Backend], [World] and [Enqueuer].
// TODO(johnniwinther): Split this into an interface and implementation class.
-class ResolutionRegistry extends Registry {
+class ResolutionRegistry {
final Target target;
final TreeElementMapping mapping;
final ResolutionWorldImpactBuilder impactBuilder;
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index abf9afa..8bb5e0b 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -36,7 +36,7 @@
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
-import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
+import '../universe/use.dart' show DynamicUse, StaticUse;
import '../util/util.dart';
import '../world.dart' show ClosedWorld;
@@ -47,6 +47,7 @@
import 'nodes.dart';
import 'optimize.dart';
import 'ssa_branch_builder.dart';
+import 'type_builder.dart';
import 'types.dart';
class SsaBuilderTask extends CompilerTask {
@@ -188,6 +189,9 @@
/// Handles the building of loops.
LoopHandler<ast.Node> loopHandler;
+ /// Handles type check building.
+ TypeBuilder typeBuilder;
+
// TODO(sigmund): make most args optional
SsaBuilder(
this.target,
@@ -213,6 +217,7 @@
sourceInformationBuilder.buildVariableDeclaration();
localsHandler = new LocalsHandler(this, target, null, compiler);
loopHandler = new SsaLoopHandler(this);
+ typeBuilder = new TypeBuilder(this);
}
BackendHelpers get helpers => backend.helpers;
@@ -223,6 +228,8 @@
CoreClasses get coreClasses => compiler.coreClasses;
+ Element get targetElement => target;
+
/// Reference to resolved elements in [target]'s AST.
TreeElements get elements => resolvedAst.elements;
@@ -244,6 +251,7 @@
/// The returned element is a declaration element.
// TODO(johnniwinther): Check that all usages of sourceElement agree on
// implementation/declaration distinction.
+ @override
Element get sourceElement => sourceElementStack.last;
/// Helper to retrieve global inference results for [element] with special
@@ -257,10 +265,6 @@
inferenceResults.resultOf(
element is ConstructorBodyElementX ? element.constructor : element);
- bool get _checkOrTrustTypes =>
- compiler.options.enableTypeAssertions ||
- compiler.options.trustTypeAnnotations;
-
/// Build the graph for [target].
HGraph build() {
assert(invariant(target, target.isImplementation));
@@ -294,6 +298,13 @@
add(attachPosition(instruction, node));
}
+ HTypeConversion buildFunctionTypeConversion(
+ HInstruction original, DartType type, int kind) {
+ HInstruction reifiedType = buildFunctionType(type);
+ return new HTypeConversion.viaMethodOnType(
+ type, kind, original.instructionType, reifiedType, original);
+ }
+
/**
* Returns a complete argument list for a call of [function].
*/
@@ -309,8 +320,7 @@
// For static calls, [providedArguments] is complete, default arguments
// have been included if necessary, see [makeStaticArgumentList].
if (!isInstanceMember ||
- currentNode == null // In erroneous code, currentNode can be null.
- ||
+ currentNode == null || // In erroneous code, currentNode can be null.
providedArgumentsKnownToBeComplete(currentNode) ||
function.isGenerativeConstructorBody ||
selector.isGetter) {
@@ -751,7 +761,8 @@
// If the method is intercepted, we want the actual receiver
// to be the first parameter.
graph.entry.addBefore(graph.entry.last, parameter);
- HInstruction value = potentiallyCheckOrTrustType(parameter, field.type);
+ HInstruction value =
+ typeBuilder.potentiallyCheckOrTrustType(parameter, field.type);
add(new HFieldSet(field, thisInstruction, value));
return closeFunction();
}
@@ -767,7 +778,7 @@
openFunction(variable, node);
visit(initializer);
HInstruction value = pop();
- value = potentiallyCheckOrTrustType(value, variable.type);
+ value = typeBuilder.potentiallyCheckOrTrustType(value, variable.type);
// In the case of multiple declarations (and some definitions) on the same
// line, the source pointer needs to point to the right initialized
// variable. So find the specific initialized variable we are referring to.
@@ -899,7 +910,8 @@
* Run this builder on the body of the [function] to be inlined.
*/
void visitInlinedFunction(ResolvedAst resolvedAst) {
- potentiallyCheckInlinedParameterTypes(resolvedAst.element.implementation);
+ typeBuilder.potentiallyCheckInlinedParameterTypes(
+ resolvedAst.element.implementation);
if (resolvedAst.element.isGenerativeConstructor) {
buildFactory(resolvedAst);
@@ -932,20 +944,6 @@
}
/**
- * In checked mode, generate type tests for the parameters of the inlined
- * function.
- */
- void potentiallyCheckInlinedParameterTypes(FunctionElement function) {
- if (!_checkOrTrustTypes) return;
-
- FunctionSignature signature = function.functionSignature;
- signature.orderedForEachParameter((ParameterElement parameter) {
- HInstruction argument = localsHandler.readLocal(parameter);
- potentiallyCheckOrTrustType(argument, parameter.type);
- });
- }
-
- /**
* Documentation wanted -- johnniwinther
*
* Invariant: [constructors] must contain only implementation elements.
@@ -980,7 +978,7 @@
TypeVariableType typeVariable = variables.current;
localsHandler.updateLocal(
localsHandler.getTypeVariableAsLocal(typeVariable),
- analyzeTypeArgument(argument));
+ typeBuilder.analyzeTypeArgument(argument, sourceElement));
});
} else {
// If the supertype is a raw type, we need to set to null the
@@ -1282,7 +1280,8 @@
} else {
fields.add(member);
DartType type = localsHandler.substInContext(member.type);
- constructorArguments.add(potentiallyCheckOrTrustType(value, type));
+ constructorArguments
+ .add(typeBuilder.potentiallyCheckOrTrustType(value, type));
}
}, includeSuperAndInjectedMembers: true);
@@ -1480,8 +1479,8 @@
// new A("foo"); // invalid in checked mode.
//
// Only the final target is allowed to check for the argument types.
- newParameter =
- potentiallyCheckOrTrustType(newParameter, parameterElement.type);
+ newParameter = typeBuilder.potentiallyCheckOrTrustType(
+ newParameter, parameterElement.type);
}
localsHandler.directLocals[parameterElement] = newParameter;
});
@@ -1519,112 +1518,12 @@
}
}
- /// Check that [type] is valid in the context of `localsHandler.contextClass`.
- /// This should only be called in assertions.
- bool assertTypeInContext(DartType type, [Spannable spannable]) {
- return invariant(spannable == null ? CURRENT_ELEMENT_SPANNABLE : spannable,
- () {
- ClassElement contextClass = Types.getClassContext(type);
- return contextClass == null || contextClass == localsHandler.contextClass;
- },
- message: "Type '$type' is not valid context of "
- "${localsHandler.contextClass}.");
- }
-
- /// Build a [HTypeConversion] for converting [original] to type [type].
- ///
- /// Invariant: [type] must be valid in the context.
- /// See [LocalsHandler.substInContext].
- HInstruction buildTypeConversion(
- HInstruction original, DartType type, int kind) {
- if (type == null) return original;
- // GENERIC_METHODS: The following statement was added for parsing and
- // ignoring method type variables; must be generalized for full support of
- // generic methods.
- type = type.dynamifyMethodTypeVariableType;
- type = type.unaliased;
- assert(assertTypeInContext(type, original));
- if (type.isInterfaceType && !type.treatAsRaw) {
- TypeMask subtype =
- new TypeMask.subtype(type.element, compiler.closedWorld);
- HInstruction representations = buildTypeArgumentRepresentations(type);
- add(representations);
- return new HTypeConversion.withTypeRepresentation(
- type, kind, subtype, original, representations);
- } else if (type.isTypeVariable) {
- TypeMask subtype = original.instructionType;
- HInstruction typeVariable = addTypeVariableReference(type);
- return new HTypeConversion.withTypeRepresentation(
- type, kind, subtype, original, typeVariable);
- } else if (type.isFunctionType) {
- String name =
- kind == HTypeConversion.CAST_TYPE_CHECK ? '_asCheck' : '_assertCheck';
-
- List<HInstruction> arguments = <HInstruction>[
- buildFunctionType(type),
- original
- ];
- pushInvokeDynamic(
- null,
- new Selector.call(
- new Name(name, helpers.jsHelperLibrary), CallStructure.ONE_ARG),
- null,
- arguments);
-
- return new HTypeConversion(type, kind, original.instructionType, pop());
- } else {
- return original.convertType(compiler, type, kind);
- }
- }
-
- HInstruction _trustType(HInstruction original, DartType type) {
- assert(compiler.options.trustTypeAnnotations);
- assert(type != null);
- type = localsHandler.substInContext(type);
- type = type.unaliased;
- if (type.isDynamic) return original;
- if (!type.isInterfaceType) return original;
- if (type.isObject) return original;
- // The type element is either a class or the void element.
- Element element = type.element;
- TypeMask mask = new TypeMask.subtype(element, compiler.closedWorld);
- return new HTypeKnown.pinned(mask, original);
- }
-
- HInstruction _checkType(HInstruction original, DartType type, int kind) {
- assert(compiler.options.enableTypeAssertions);
- assert(type != null);
- type = localsHandler.substInContext(type);
- HInstruction other = buildTypeConversion(original, type, kind);
- // TODO(johnniwinther): This operation on `registry` may be inconsistent.
- // If it is needed then it seems likely that similar invocations of
- // `buildTypeConversion` in `SsaBuilder.visitAs` should also be followed by
- // a similar operation on `registry`; otherwise, this one might not be
- // needed.
- registry?.registerTypeUse(new TypeUse.isCheck(type));
- return other;
- }
-
- HInstruction potentiallyCheckOrTrustType(HInstruction original, DartType type,
- {int kind: HTypeConversion.CHECKED_MODE_CHECK}) {
- if (type == null) return original;
- HInstruction checkedOrTrusted = original;
- if (compiler.options.trustTypeAnnotations) {
- checkedOrTrusted = _trustType(original, type);
- } else if (compiler.options.enableTypeAssertions) {
- checkedOrTrusted = _checkType(original, type, kind);
- }
- if (checkedOrTrusted == original) return original;
- add(checkedOrTrusted);
- return checkedOrTrusted;
- }
-
void assertIsSubtype(
ast.Node node, DartType subtype, DartType supertype, String message) {
- HInstruction subtypeInstruction =
- analyzeTypeArgument(localsHandler.substInContext(subtype));
- HInstruction supertypeInstruction =
- analyzeTypeArgument(localsHandler.substInContext(supertype));
+ HInstruction subtypeInstruction = typeBuilder.analyzeTypeArgument(
+ localsHandler.substInContext(subtype), sourceElement);
+ HInstruction supertypeInstruction = typeBuilder.analyzeTypeArgument(
+ localsHandler.substInContext(supertype), sourceElement);
HInstruction messageInstruction =
graph.addConstantString(new ast.DartString.literal(message), compiler);
MethodElement element = helpers.assertIsSubtype;
@@ -1650,11 +1549,15 @@
push(attachPosition(instruction, node));
}
+ /// Pops the most recent instruction from the stack and 'boolifies' it.
+ ///
+ /// Boolification is checking if the value is '=== true'.
@override
HInstruction popBoolified() {
HInstruction value = pop();
- if (_checkOrTrustTypes) {
- return potentiallyCheckOrTrustType(value, compiler.coreTypes.boolType,
+ if (typeBuilder.checkOrTrustTypes) {
+ return typeBuilder.potentiallyCheckOrTrustType(
+ value, compiler.coreTypes.boolType,
kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK);
}
HInstruction result = new HBoolify(value, backend.boolType);
@@ -2445,7 +2348,7 @@
pop();
} else {
FieldElement field = element;
- value = potentiallyCheckOrTrustType(value, field.type);
+ value = typeBuilder.potentiallyCheckOrTrustType(value, field.type);
addWithPosition(new HStaticStore(field, value), location);
}
stack.add(value);
@@ -2462,7 +2365,7 @@
value.sourceElement = local;
}
HInstruction checkedOrTrusted =
- potentiallyCheckOrTrustType(value, local.type);
+ typeBuilder.potentiallyCheckOrTrustType(value, local.type);
if (!identical(checkedOrTrusted, value)) {
pop();
stack.add(checkedOrTrusted);
@@ -2484,24 +2387,6 @@
return new HLiteralList(inputs, backend.extendableArrayType);
}
- HInstruction buildTypeArgumentRepresentations(DartType type) {
- assert(!type.isTypeVariable);
- // Compute the representation of the type arguments, including access
- // to the runtime type information for type variables as instructions.
- assert(type.element.isClass);
- InterfaceType interface = type;
- List<HInstruction> inputs = <HInstruction>[];
- for (DartType argument in interface.typeArguments) {
- inputs.add(analyzeTypeArgument(argument));
- }
- HInstruction representation = new HTypeInfoExpression(
- TypeInfoExpressionKind.INSTANCE,
- interface.element.thisType,
- inputs,
- backend.dynamicType);
- return representation;
- }
-
@override
void visitAs(ast.Send node, ast.Node expression, DartType type, _) {
HInstruction expressionInstruction = visitAndPop(expression);
@@ -2514,8 +2399,10 @@
stack.add(expressionInstruction);
}
} else {
- HInstruction converted = buildTypeConversion(expressionInstruction,
- localsHandler.substInContext(type), HTypeConversion.CAST_TYPE_CHECK);
+ HInstruction converted = typeBuilder.buildTypeConversion(
+ expressionInstruction,
+ localsHandler.substInContext(type),
+ HTypeConversion.CAST_TYPE_CHECK);
if (converted != expressionInstruction) add(converted);
stack.add(converted);
}
@@ -2561,7 +2448,8 @@
arguments);
return new HIs.compound(type, expression, pop(), backend.boolType);
} else if (type.isTypeVariable) {
- HInstruction runtimeType = addTypeVariableReference(type);
+ HInstruction runtimeType =
+ typeBuilder.addTypeVariableReference(type, sourceElement);
Element helper = helpers.checkSubtypeOfRuntimeType;
List<HInstruction> inputs = <HInstruction>[expression, runtimeType];
pushInvokeStatic(null, helper, inputs, typeMask: backend.boolType);
@@ -2570,7 +2458,8 @@
} else if (RuntimeTypes.hasTypeArguments(type)) {
ClassElement element = type.element;
Element helper = helpers.checkSubtype;
- HInstruction representations = buildTypeArgumentRepresentations(type);
+ HInstruction representations =
+ typeBuilder.buildTypeArgumentRepresentations(type, sourceElement);
add(representations);
js.Name operator = backend.namer.operatorIs(element);
HInstruction isFieldName = addConstantStringFromName(operator);
@@ -2598,11 +2487,6 @@
}
}
- HInstruction buildFunctionType(FunctionType type) {
- type.accept(new TypeBuilder(compiler.closedWorld), this);
- return pop();
- }
-
void addDynamicSendArgumentsToList(ast.Send node, List<HInstruction> list) {
CallStructure callStructure = elements.getSelector(node).callStructure;
if (callStructure.namedArgumentCount == 0) {
@@ -3389,113 +3273,6 @@
});
}
- /**
- * Generate code to extract the type argument from the object.
- */
- HInstruction readTypeVariable(TypeVariableType variable,
- {SourceInformation sourceInformation}) {
- assert(sourceElement.isInstanceMember);
- assert(variable is! MethodTypeVariableType);
- HInstruction target = localsHandler.readThis();
- push(new HTypeInfoReadVariable(variable, target, backend.dynamicType)
- ..sourceInformation = sourceInformation);
- return pop();
- }
-
- // TODO(karlklose): this is needed to avoid a bug where the resolved type is
- // not stored on a type annotation in the closure translator. Remove when
- // fixed.
- bool hasDirectLocal(Local local) {
- return !localsHandler.isAccessedDirectly(local) ||
- localsHandler.directLocals[local] != null;
- }
-
- /**
- * Helper to create an instruction that gets the value of a type variable.
- */
- HInstruction addTypeVariableReference(TypeVariableType type,
- {SourceInformation sourceInformation}) {
- assert(assertTypeInContext(type));
- if (type is MethodTypeVariableType) {
- return graph.addConstantNull(compiler);
- }
- Element member = sourceElement;
- bool isClosure = member.enclosingElement.isClosure;
- if (isClosure) {
- ClosureClassElement closureClass = member.enclosingElement;
- member = closureClass.methodElement;
- member = member.outermostEnclosingMemberOrTopLevel;
- }
- bool isInConstructorContext =
- member.isConstructor || member.isGenerativeConstructorBody;
- Local typeVariableLocal = localsHandler.getTypeVariableAsLocal(type);
- if (isClosure) {
- if (member.isFactoryConstructor ||
- (isInConstructorContext && hasDirectLocal(typeVariableLocal))) {
- // The type variable is used from a closure in a factory constructor.
- // The value of the type argument is stored as a local on the closure
- // itself.
- return localsHandler.readLocal(typeVariableLocal,
- sourceInformation: sourceInformation);
- } else if (member.isFunction ||
- member.isGetter ||
- member.isSetter ||
- isInConstructorContext) {
- // The type variable is stored on the "enclosing object" and needs to be
- // accessed using the this-reference in the closure.
- return readTypeVariable(type, sourceInformation: sourceInformation);
- } else {
- assert(member.isField);
- // The type variable is stored in a parameter of the method.
- return localsHandler.readLocal(typeVariableLocal);
- }
- } else if (isInConstructorContext ||
- // When [member] is a field, we can be either
- // generating a checked setter or inlining its
- // initializer in a constructor. An initializer is
- // never built standalone, so in that case [target] is not
- // the [member] itself.
- (member.isField && member != target)) {
- // The type variable is stored in a parameter of the method.
- return localsHandler.readLocal(typeVariableLocal,
- sourceInformation: sourceInformation);
- } else if (member.isInstanceMember) {
- // The type variable is stored on the object.
- return readTypeVariable(type, sourceInformation: sourceInformation);
- } else {
- reporter.internalError(
- type.element, 'Unexpected type variable in static context.');
- return null;
- }
- }
-
- HInstruction analyzeTypeArgument(DartType argument,
- {SourceInformation sourceInformation}) {
- assert(assertTypeInContext(argument));
- argument = argument.unaliased;
- if (argument.treatAsDynamic) {
- // Represent [dynamic] as [null].
- return graph.addConstantNull(compiler);
- }
-
- if (argument.isTypeVariable) {
- return addTypeVariableReference(argument,
- sourceInformation: sourceInformation);
- }
-
- List<HInstruction> inputs = <HInstruction>[];
- argument.forEachTypeVariable((variable) {
- if (variable is! MethodTypeVariableType) {
- inputs.add(analyzeTypeArgument(variable));
- }
- });
- HInstruction result = new HTypeInfoExpression(
- TypeInfoExpressionKind.COMPLETE, argument, inputs, backend.dynamicType)
- ..sourceInformation = sourceInformation;
- add(result);
- return result;
- }
-
HInstruction handleListConstructor(
InterfaceType type, ast.Node currentNode, HInstruction newObject) {
if (!backend.classNeedsRti(type.element) || type.treatAsRaw) {
@@ -3504,27 +3281,11 @@
List<HInstruction> inputs = <HInstruction>[];
type = localsHandler.substInContext(type);
type.typeArguments.forEach((DartType argument) {
- inputs.add(analyzeTypeArgument(argument));
+ inputs.add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
});
// TODO(15489): Register at codegen.
registry?.registerInstantiation(type);
- return callSetRuntimeTypeInfoWithTypeArguments(
- type.element, inputs, newObject);
- }
-
- HInstruction callSetRuntimeTypeInfoWithTypeArguments(ClassElement element,
- List<HInstruction> rtiInputs, HInstruction newObject) {
- if (!backend.classNeedsRti(element)) {
- return newObject;
- }
-
- HInstruction typeInfo = new HTypeInfoExpression(
- TypeInfoExpressionKind.INSTANCE,
- element.thisType,
- rtiInputs,
- backend.dynamicType);
- add(typeInfo);
- return callSetRuntimeTypeInfo(typeInfo, newObject);
+ return callSetRuntimeTypeInfoWithTypeArguments(type, inputs, newObject);
}
HInstruction callSetRuntimeTypeInfo(
@@ -3681,12 +3442,8 @@
TypeMask elementType = computeType(constructor);
if (isFixedListConstructorCall) {
if (!inputs[0].isNumber(compiler)) {
- HTypeConversion conversion = new HTypeConversion(
- null,
- HTypeConversion.ARGUMENT_TYPE_CHECK,
- backend.numType,
- inputs[0],
- null);
+ HTypeConversion conversion = new HTypeConversion(null,
+ HTypeConversion.ARGUMENT_TYPE_CHECK, backend.numType, inputs[0]);
add(conversion);
inputs[0] = conversion;
}
@@ -3752,7 +3509,8 @@
// Finally, if we called a redirecting factory constructor, check the type.
if (isRedirected) {
- HInstruction checked = potentiallyCheckOrTrustType(newInstance, type);
+ HInstruction checked =
+ typeBuilder.potentiallyCheckOrTrustType(newInstance, type);
if (checked != newInstance) {
pop();
stack.add(checked);
@@ -3766,8 +3524,8 @@
if (!backend.classNeedsRti(cls)) return;
assert(cls.typeVariables.length == expectedType.typeArguments.length);
expectedType.typeArguments.forEach((DartType argument) {
- inputs.add(
- analyzeTypeArgument(argument, sourceInformation: sourceInformation));
+ inputs.add(typeBuilder.analyzeTypeArgument(argument, sourceElement,
+ sourceInformation: sourceInformation));
});
}
@@ -4039,7 +3797,7 @@
generateTypeError(node, "Method type variables are not reified");
} else {
DartType type = localsHandler.substInContext(typeVariable);
- HInstruction value = analyzeTypeArgument(type,
+ HInstruction value = typeBuilder.analyzeTypeArgument(type, sourceElement,
sourceInformation: sourceInformationBuilder.buildGet(node));
pushInvokeStatic(node, helpers.runtimeTypeToString, [value],
typeMask: backend.stringType);
@@ -5365,7 +5123,7 @@
redirectingConstructor.computeEffectiveTargetType(cls.thisType);
targetType = localsHandler.substInContext(targetType);
targetType.typeArguments.forEach((DartType argument) {
- inputs.add(analyzeTypeArgument(argument));
+ inputs.add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
});
}
pushInvokeStatic(node, targetConstructor.declaration, inputs);
@@ -5415,7 +5173,7 @@
return;
}
} else {
- value = potentiallyCheckOrTrustType(value, returnType);
+ value = typeBuilder.potentiallyCheckOrTrustType(value, returnType);
}
}
@@ -5477,12 +5235,11 @@
}
List<HInstruction> arguments = <HInstruction>[];
for (DartType argument in type.typeArguments) {
- arguments.add(analyzeTypeArgument(argument));
+ arguments.add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
}
// TODO(15489): Register at codegen.
registry?.registerInstantiation(type);
- return callSetRuntimeTypeInfoWithTypeArguments(
- type.element, arguments, object);
+ return callSetRuntimeTypeInfoWithTypeArguments(type, arguments, object);
}
visitLiteralList(ast.LiteralList node) {
@@ -5925,7 +5682,8 @@
if (backend.classNeedsRti(cls)) {
List<HInstruction> typeInputs = <HInstruction>[];
expectedType.typeArguments.forEach((DartType argument) {
- typeInputs.add(analyzeTypeArgument(argument));
+ typeInputs
+ .add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
});
// We lift this common call pattern into a helper function to save space
@@ -7002,94 +6760,3 @@
this.oldElementInferenceResults)
: super(function);
}
-
-class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> {
- final ClosedWorld closedWorld;
-
- TypeBuilder(this.closedWorld);
-
- void visit(DartType type, SsaBuilder builder) => type.accept(this, builder);
-
- void visitVoidType(VoidType type, SsaBuilder builder) {
- ClassElement cls = builder.backend.helpers.VoidRuntimeType;
- builder.push(new HVoidType(type, new TypeMask.exact(cls, closedWorld)));
- }
-
- void visitTypeVariableType(TypeVariableType type, SsaBuilder builder) {
- ClassElement cls = builder.backend.helpers.RuntimeType;
- TypeMask instructionType = new TypeMask.subclass(cls, closedWorld);
- if (!builder.sourceElement.enclosingElement.isClosure &&
- builder.sourceElement.isInstanceMember) {
- HInstruction receiver = builder.localsHandler.readThis();
- builder.push(new HReadTypeVariable(type, receiver, instructionType));
- } else {
- builder.push(new HReadTypeVariable.noReceiver(
- type, builder.addTypeVariableReference(type), instructionType));
- }
- }
-
- void visitFunctionType(FunctionType type, SsaBuilder builder) {
- type.returnType.accept(this, builder);
- HInstruction returnType = builder.pop();
- List<HInstruction> inputs = <HInstruction>[returnType];
-
- for (DartType parameter in type.parameterTypes) {
- parameter.accept(this, builder);
- inputs.add(builder.pop());
- }
-
- for (DartType parameter in type.optionalParameterTypes) {
- parameter.accept(this, builder);
- inputs.add(builder.pop());
- }
-
- List<DartType> namedParameterTypes = type.namedParameterTypes;
- List<String> names = type.namedParameters;
- for (int index = 0; index < names.length; index++) {
- ast.DartString dartString = new ast.DartString.literal(names[index]);
- inputs.add(builder.graph.addConstantString(dartString, builder.compiler));
- namedParameterTypes[index].accept(this, builder);
- inputs.add(builder.pop());
- }
-
- ClassElement cls = builder.backend.helpers.RuntimeFunctionType;
- builder.push(
- new HFunctionType(inputs, type, new TypeMask.exact(cls, closedWorld)));
- }
-
- void visitMalformedType(MalformedType type, SsaBuilder builder) {
- visitDynamicType(const DynamicType(), builder);
- }
-
- void visitStatementType(StatementType type, SsaBuilder builder) {
- throw 'not implemented visitStatementType($type)';
- }
-
- void visitInterfaceType(InterfaceType type, SsaBuilder builder) {
- List<HInstruction> inputs = <HInstruction>[];
- for (DartType typeArgument in type.typeArguments) {
- typeArgument.accept(this, builder);
- inputs.add(builder.pop());
- }
- ClassElement cls;
- if (type.typeArguments.isEmpty) {
- cls = builder.backend.helpers.RuntimeTypePlain;
- } else {
- cls = builder.backend.helpers.RuntimeTypeGeneric;
- }
- builder.push(
- new HInterfaceType(inputs, type, new TypeMask.exact(cls, closedWorld)));
- }
-
- void visitTypedefType(TypedefType type, SsaBuilder builder) {
- DartType unaliased = type.unaliased;
- if (unaliased is TypedefType) throw 'unable to unalias $type';
- unaliased.accept(this, builder);
- }
-
- void visitDynamicType(DynamicType type, SsaBuilder builder) {
- JavaScriptBackend backend = builder.compiler.backend;
- ClassElement cls = backend.helpers.DynamicRuntimeType;
- builder.push(new HDynamicType(type, new TypeMask.exact(cls, closedWorld)));
- }
-}
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 6183f3f..3f407ca 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -16,8 +16,11 @@
import '../kernel/kernel.dart';
import '../resolution/tree_elements.dart';
import '../tree/dartstring.dart';
+import '../tree/nodes.dart' show FunctionExpression, Node;
import '../types/masks.dart';
+import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart';
+import '../universe/use.dart' show TypeUse;
import 'graph_builder.dart';
import 'kernel_ast_adapter.dart';
import 'kernel_string_builder.dart';
@@ -25,6 +28,7 @@
import 'loop_handler.dart';
import 'nodes.dart';
import 'ssa_branch_builder.dart';
+import 'type_builder.dart';
class SsaKernelBuilderTask extends CompilerTask {
final JavaScriptBackend backend;
@@ -62,6 +66,7 @@
SourceInformationBuilder sourceInformationBuilder;
KernelAstAdapter astAdapter;
LoopHandler<ir.Node> loopHandler;
+ TypeBuilder typeBuilder;
KernelSsaBuilder(
this.targetElement,
@@ -72,6 +77,7 @@
Kernel kernel) {
this.compiler = compiler;
this.loopHandler = new KernelLoopHandler(this);
+ typeBuilder = new TypeBuilder(this);
graph.element = targetElement;
// TODO(het): Should sourceInformationBuilder be in GraphBuilder?
this.sourceInformationBuilder =
@@ -118,23 +124,193 @@
closeFunction();
}
+ /// Pops the most recent instruction from the stack and 'boolifies' it.
+ ///
+ /// Boolification is checking if the value is '=== true'.
@override
HInstruction popBoolified() {
HInstruction value = pop();
- // TODO(het): add boolean conversion type check
+ if (typeBuilder.checkOrTrustTypes) {
+ return typeBuilder.potentiallyCheckOrTrustType(
+ value, compiler.coreTypes.boolType,
+ kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK);
+ }
HInstruction result = new HBoolify(value, backend.boolType);
add(result);
return result;
}
+ /// Builds generative constructors.
+ ///
+ /// Generative constructors are built in two stages.
+ ///
+ /// First, the field values for every instance field for every class in the
+ /// class hierarchy are collected. Then, create a function body that sets
+ /// all of the instance fields to the collected values and call the
+ /// constructor bodies for all constructors in the hierarchy.
void buildConstructor(ir.Constructor constructor) {
- // TODO(het): Actually handle this correctly
- HBasicBlock block = graph.addNewBlock();
- open(graph.entry);
- close(new HGoto()).addSuccessor(block);
- open(block);
- closeAndGotoExit(new HGoto());
- graph.finalize();
+ openFunction();
+
+ // Collect field values for the current class.
+ // TODO(het): Does kernel always put field initializers in the constructor
+ // initializer list? If so then this is unnecessary...
+ Map<ir.Field, HInstruction> fieldValues =
+ _collectFieldValues(constructor.enclosingClass);
+
+ _buildInitializers(constructor, fieldValues);
+
+ final constructorArguments = <HInstruction>[];
+ astAdapter.getClass(constructor.enclosingClass).forEachInstanceField(
+ (ClassElement enclosingClass, FieldElement member) {
+ var value = fieldValues[astAdapter.getFieldFromElement(member)];
+ constructorArguments.add(value);
+ }, includeSuperAndInjectedMembers: true);
+
+ // TODO(het): If the class needs runtime type information, add it as a
+ // constructor argument.
+ HInstruction create = new HCreate(
+ astAdapter.getClass(constructor.enclosingClass),
+ constructorArguments,
+ new TypeMask.nonNullExact(
+ astAdapter.getClass(constructor.enclosingClass),
+ compiler.closedWorld),
+ instantiatedTypes: <DartType>[
+ astAdapter.getClass(constructor.enclosingClass).thisType
+ ],
+ hasRtiInput: false);
+
+ add(create);
+
+ // Generate calls to the constructor bodies.
+
+ closeAndGotoExit(new HReturn(create, null));
+ closeFunction();
+ }
+
+ /// Maps the fields of a class to their SSA values.
+ Map<ir.Field, HInstruction> _collectFieldValues(ir.Class clazz) {
+ final fieldValues = <ir.Field, HInstruction>{};
+
+ for (var field in clazz.fields) {
+ if (field.initializer == null) {
+ fieldValues[field] = graph.addConstantNull(compiler);
+ } else {
+ field.initializer.accept(this);
+ fieldValues[field] = pop();
+ }
+ }
+
+ return fieldValues;
+ }
+
+ /// Collects field initializers all the way up the inheritance chain.
+ void _buildInitializers(
+ ir.Constructor constructor, Map<ir.Field, HInstruction> fieldValues) {
+ var foundSuperCall = false;
+ for (var initializer in constructor.initializers) {
+ if (initializer is ir.SuperInitializer) {
+ foundSuperCall = true;
+ var superConstructor = initializer.target;
+ var arguments = _normalizeAndBuildArguments(
+ superConstructor.function, initializer.arguments);
+ _buildInlinedSuperInitializers(
+ superConstructor, arguments, fieldValues);
+ } else if (initializer is ir.FieldInitializer) {
+ initializer.value.accept(this);
+ fieldValues[initializer.field] = pop();
+ }
+ }
+
+ // TODO(het): does kernel always set the super initializer at the end?
+ // If there was no super-call initializer, then call the default constructor
+ // in the superclass.
+ if (!foundSuperCall) {
+ if (constructor.enclosingClass != astAdapter.objectClass) {
+ var superclass = constructor.enclosingClass.superclass;
+ var defaultConstructor = superclass.constructors
+ .firstWhere((c) => c.name == '', orElse: () => null);
+ if (defaultConstructor == null) {
+ compiler.reporter.internalError(
+ NO_LOCATION_SPANNABLE, 'Could not find default constructor.');
+ }
+ _buildInlinedSuperInitializers(
+ defaultConstructor, <HInstruction>[], fieldValues);
+ }
+ }
+ }
+
+ List<HInstruction> _normalizeAndBuildArguments(
+ ir.FunctionNode function, ir.Arguments arguments) {
+ var signature = astAdapter.getFunctionSignature(function);
+ var builtArguments = <HInstruction>[];
+ var positionalIndex = 0;
+ signature.forEachRequiredParameter((_) {
+ arguments.positional[positionalIndex++].accept(this);
+ builtArguments.add(pop());
+ });
+ if (!signature.optionalParametersAreNamed) {
+ signature.forEachOptionalParameter((ParameterElement element) {
+ if (positionalIndex < arguments.positional.length) {
+ arguments.positional[positionalIndex++].accept(this);
+ builtArguments.add(pop());
+ } else {
+ var constantValue =
+ backend.constants.getConstantValue(element.constant);
+ assert(invariant(element, constantValue != null,
+ message: 'No constant computed for $element'));
+ builtArguments.add(graph.addConstant(constantValue, compiler));
+ }
+ });
+ } else {
+ signature.orderedOptionalParameters.forEach((ParameterElement element) {
+ var correspondingNamed = arguments.named.firstWhere(
+ (named) => named.name == element.name,
+ orElse: () => null);
+ if (correspondingNamed != null) {
+ correspondingNamed.value.accept(this);
+ builtArguments.add(pop());
+ } else {
+ var constantValue =
+ backend.constants.getConstantValue(element.constant);
+ assert(invariant(element, constantValue != null,
+ message: 'No constant computed for $element'));
+ builtArguments.add(graph.addConstant(constantValue, compiler));
+ }
+ });
+ }
+
+ return builtArguments;
+ }
+
+ /// Inlines the given super [constructor]'s initializers by collecting it's
+ /// field values and building its constructor initializers. We visit super
+ /// constructors all the way up to the [Object] constructor.
+ void _buildInlinedSuperInitializers(ir.Constructor constructor,
+ List<HInstruction> arguments, Map<ir.Field, HInstruction> fieldValues) {
+ // TODO(het): Handle RTI if class needs it
+ fieldValues.addAll(_collectFieldValues(constructor.enclosingClass));
+
+ var signature = astAdapter.getFunctionSignature(constructor.function);
+ var index = 0;
+ signature.orderedForEachParameter((ParameterElement parameter) {
+ HInstruction argument = arguments[index++];
+ // Because we are inlining the initializer, we must update
+ // what was given as parameter. This will be used in case
+ // there is a parameter check expression in the initializer.
+ parameters[parameter] = argument;
+ localsHandler.updateLocal(parameter, argument);
+ });
+
+ // TODO(het): set the locals handler state as if we were inlining the
+ // constructor.
+ _buildInitializers(constructor, fieldValues);
+ }
+
+ HTypeConversion buildFunctionTypeConversion(
+ HInstruction original, DartType type, int kind) {
+ HInstruction reifiedType = buildFunctionType(type);
+ return new HTypeConversion.viaMethodOnType(
+ type, kind, original.instructionType, reifiedType, original);
}
/// Builds a SSA graph for [procedure].
@@ -147,7 +323,12 @@
void openFunction() {
HBasicBlock block = graph.addNewBlock();
open(graph.entry);
- localsHandler.startFunction(targetElement, resolvedAst.node);
+
+ Node function;
+ if (resolvedAst.kind == ResolvedAstKind.PARSED) {
+ function = resolvedAst.node;
+ }
+ localsHandler.startFunction(targetElement, function);
close(new HGoto()).addSuccessor(block);
open(block);
@@ -158,12 +339,25 @@
graph.finalize();
}
+ /// Pushes a boolean checking [expression] against null.
+ pushCheckNull(HInstruction expression) {
+ push(new HIdentity(
+ expression, graph.addConstantNull(compiler), null, backend.boolType));
+ }
+
@override
void defaultExpression(ir.Expression expression) {
// TODO(het): This is only to get tests working
stack.add(graph.addConstantNull(compiler));
}
+ /// Returns the current source element.
+ ///
+ /// The returned element is a declaration element.
+ // TODO(efortuna): Update this when we implement inlining.
+ @override
+ Element get sourceElement => astAdapter.getElement(target);
+
@override
void visitBlock(ir.Block block) {
assert(!isAborted());
@@ -197,9 +391,10 @@
if (returnStatement.expression == null) {
value = graph.addConstantNull(compiler);
} else {
+ assert(target is ir.Procedure);
returnStatement.expression.accept(this);
- value = pop();
- // TODO(het): Check or trust the type of value
+ value = typeBuilder.potentiallyCheckOrTrustType(pop(),
+ astAdapter.getFunctionReturnType((target as ir.Procedure).function));
}
// TODO(het): Add source information
// TODO(het): Set a return value instead of closing the function when we
@@ -401,6 +596,26 @@
forInStatement, buildInitializer, buildCondition, () {}, buildBody);
}
+ HInstruction callSetRuntimeTypeInfo(
+ HInstruction typeInfo, HInstruction newObject) {
+ // Set the runtime type information on the object.
+ ir.Procedure typeInfoSetterFn = astAdapter.setRuntimeTypeInfo;
+ // TODO(efortuna): Insert source information in this static invocation.
+ _pushStaticInvocation(typeInfoSetterFn, <HInstruction>[newObject, typeInfo],
+ backend.dynamicType);
+
+ // The new object will now be referenced through the
+ // `setRuntimeTypeInfo` call. We therefore set the type of that
+ // instruction to be of the object's type.
+ assert(invariant(CURRENT_ELEMENT_SPANNABLE,
+ stack.last is HInvokeStatic || stack.last == newObject,
+ message: "Unexpected `stack.last`: Found ${stack.last}, "
+ "expected ${newObject} or an HInvokeStatic. "
+ "State: typeInfo=$typeInfo, stack=$stack."));
+ stack.last.instructionType = newObject.instructionType;
+ return pop();
+ }
+
@override
void visitWhileStatement(ir.WhileStatement whileStatement) {
assert(isReachable);
@@ -500,6 +715,21 @@
stack.add(graph.addConstantNull(compiler));
}
+ HInstruction setRtiIfNeeded(HInstruction object, ir.ListLiteral listLiteral) {
+ InterfaceType type = localsHandler
+ .substInContext(elements.getType(astAdapter.getNode(listLiteral)));
+ if (!backend.classNeedsRti(type.element) || type.treatAsRaw) {
+ return object;
+ }
+ List<HInstruction> arguments = <HInstruction>[];
+ for (DartType argument in type.typeArguments) {
+ arguments.add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
+ }
+ // TODO(15489): Register at codegen.
+ registry?.registerInstantiation(type);
+ return callSetRuntimeTypeInfoWithTypeArguments(type, arguments, object);
+ }
+
@override
void visitListLiteral(ir.ListLiteral listLiteral) {
HInstruction listInstruction;
@@ -514,7 +744,7 @@
}
listInstruction = new HLiteralList(elements, backend.extendableArrayType);
add(listInstruction);
- // TODO(het): set runtime type info
+ listInstruction = setRtiIfNeeded(listInstruction, listLiteral);
}
TypeMask type = astAdapter.typeOfNewList(targetElement, listLiteral);
@@ -591,8 +821,10 @@
astAdapter.returnTypeOf(staticTarget));
pop();
} else {
- // TODO(het): check or trust type
- add(new HStaticStore(astAdapter.getMember(staticTarget), value));
+ add(new HStaticStore(
+ astAdapter.getMember(staticTarget),
+ typeBuilder.potentiallyCheckOrTrustType(
+ value, astAdapter.getDartType(staticTarget.setterType))));
}
stack.add(value);
}
@@ -647,8 +879,10 @@
}
stack.add(value);
- // TODO(het): check or trust type
- localsHandler.updateLocal(local, value);
+ localsHandler.updateLocal(
+ local,
+ typeBuilder.potentiallyCheckOrTrustType(
+ value, astAdapter.getDartType(variable.type)));
}
// TODO(het): Also extract type arguments
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 5248f91..c882259 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2825,8 +2825,22 @@
if (helper == null) {
assert(type.isFunctionType);
- use(node.inputs[0]);
+ assert(node.usesMethodOnType);
+
+ String name = node.isCastTypeCheck ? '_asCheck' : '_assertCheck';
+ HInstruction reifiedType = node.inputs[0];
+ HInstruction checkedInput = node.inputs[1];
+ use(reifiedType);
+ js.Expression receiver = pop();
+ use(checkedInput);
+ Selector selector = new Selector.call(
+ new Name(name, helpers.jsHelperLibrary), CallStructure.ONE_ARG);
+ registry.registerDynamicUse(
+ new DynamicUse(selector, reifiedType.instructionType));
+ js.Name methodLiteral = backend.namer.invocationName(selector);
+ push(js.js('#.#(#)', [receiver, methodLiteral, pop()]));
} else {
+ assert(!node.usesMethodOnType);
push(helper.generateCall(this, node));
}
}
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index c3e2bb6..34d156b 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -440,11 +440,18 @@
void visitIs(HIs instruction) {
// In the general case the input might be used multple multiple times, so it
- // must not be set generate at use site. If the code will generate
- // 'instanceof' then we can generate at use site.
+ // must not be set generate at use site.
+
+ // If the code will generate 'instanceof' then we can generate at use site.
if (instruction.useInstanceOf) {
analyzeInputs(instruction, 0);
}
+
+ // Compound and variable checks use a separate instruction to compute the
+ // result.
+ if (instruction.isCompoundCheck || instruction.isVariableCheck) {
+ analyzeInputs(instruction, 0);
+ }
}
// A bounds check method must not have its first input generated at use site,
diff --git a/pkg/compiler/lib/src/ssa/graph_builder.dart b/pkg/compiler/lib/src/ssa/graph_builder.dart
index 22e6c30..e5dce33 100644
--- a/pkg/compiler/lib/src/ssa/graph_builder.dart
+++ b/pkg/compiler/lib/src/ssa/graph_builder.dart
@@ -2,17 +2,25 @@
// 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 '../closure.dart';
+import '../common.dart';
+import '../common/codegen.dart' show CodegenRegistry;
import '../compiler.dart';
+import '../dart_types.dart';
import '../elements/elements.dart';
import '../io/source_information.dart';
import '../js_backend/js_backend.dart';
import '../resolution/tree_elements.dart';
import '../tree/tree.dart' as ast;
import '../types/types.dart';
+import '../universe/call_structure.dart' show CallStructure;
+import '../universe/use.dart' show TypeUse;
+import '../world.dart' show ClosedWorld;
import 'jump_handler.dart';
import 'locals_handler.dart';
import 'nodes.dart';
import 'ssa_branch_builder.dart';
+import 'type_builder.dart';
/// Base class for objects that build up an SSA graph.
///
@@ -32,6 +40,8 @@
/// The tree elements for the element being built into an SSA graph.
TreeElements get elements;
+ CodegenRegistry get registry;
+
/// Used to track the locals while building the graph.
LocalsHandler localsHandler;
@@ -182,4 +192,143 @@
if (expression == null) return null;
return new HSubExpressionBlockInformation(expression);
}
+
+ HInstruction buildFunctionType(FunctionType type) {
+ type.accept(
+ new ReifiedTypeRepresentationBuilder(compiler.closedWorld), this);
+ return pop();
+ }
+
+ HInstruction buildFunctionTypeConversion(
+ HInstruction original, DartType type, int kind);
+
+ /// Returns the current source element.
+ ///
+ /// The returned element is a declaration element.
+ Element get sourceElement;
+
+ // TODO(karlklose): this is needed to avoid a bug where the resolved type is
+ // not stored on a type annotation in the closure translator. Remove when
+ // fixed.
+ bool hasDirectLocal(Local local) {
+ return !localsHandler.isAccessedDirectly(local) ||
+ localsHandler.directLocals[local] != null;
+ }
+
+ HInstruction callSetRuntimeTypeInfoWithTypeArguments(
+ DartType type, List<HInstruction> rtiInputs, HInstruction newObject) {
+ if (!backend.classNeedsRti(type.element)) {
+ return newObject;
+ }
+
+ HInstruction typeInfo = new HTypeInfoExpression(
+ TypeInfoExpressionKind.INSTANCE,
+ (type.element as ClassElement).thisType,
+ rtiInputs,
+ backend.dynamicType);
+ add(typeInfo);
+ return callSetRuntimeTypeInfo(typeInfo, newObject);
+ }
+
+ HInstruction callSetRuntimeTypeInfo(
+ HInstruction typeInfo, HInstruction newObject);
+
+ /// The element for which this SSA builder is being used.
+ Element get targetElement;
+ TypeBuilder get typeBuilder;
+}
+
+class ReifiedTypeRepresentationBuilder
+ implements DartTypeVisitor<dynamic, GraphBuilder> {
+ final ClosedWorld closedWorld;
+
+ ReifiedTypeRepresentationBuilder(this.closedWorld);
+
+ void visit(DartType type, GraphBuilder builder) => type.accept(this, builder);
+
+ void visitVoidType(VoidType type, GraphBuilder builder) {
+ ClassElement cls = builder.backend.helpers.VoidRuntimeType;
+ builder.push(new HVoidType(type, new TypeMask.exact(cls, closedWorld)));
+ }
+
+ void visitTypeVariableType(TypeVariableType type, GraphBuilder builder) {
+ ClassElement cls = builder.backend.helpers.RuntimeType;
+ TypeMask instructionType = new TypeMask.subclass(cls, closedWorld);
+ if (!builder.sourceElement.enclosingElement.isClosure &&
+ builder.sourceElement.isInstanceMember) {
+ HInstruction receiver = builder.localsHandler.readThis();
+ builder.push(new HReadTypeVariable(type, receiver, instructionType));
+ } else {
+ builder.push(new HReadTypeVariable.noReceiver(
+ type,
+ builder.typeBuilder
+ .addTypeVariableReference(type, builder.sourceElement),
+ instructionType));
+ }
+ }
+
+ void visitFunctionType(FunctionType type, GraphBuilder builder) {
+ type.returnType.accept(this, builder);
+ HInstruction returnType = builder.pop();
+ List<HInstruction> inputs = <HInstruction>[returnType];
+
+ for (DartType parameter in type.parameterTypes) {
+ parameter.accept(this, builder);
+ inputs.add(builder.pop());
+ }
+
+ for (DartType parameter in type.optionalParameterTypes) {
+ parameter.accept(this, builder);
+ inputs.add(builder.pop());
+ }
+
+ List<DartType> namedParameterTypes = type.namedParameterTypes;
+ List<String> names = type.namedParameters;
+ for (int index = 0; index < names.length; index++) {
+ ast.DartString dartString = new ast.DartString.literal(names[index]);
+ inputs.add(builder.graph.addConstantString(dartString, builder.compiler));
+ namedParameterTypes[index].accept(this, builder);
+ inputs.add(builder.pop());
+ }
+
+ ClassElement cls = builder.backend.helpers.RuntimeFunctionType;
+ builder.push(
+ new HFunctionType(inputs, type, new TypeMask.exact(cls, closedWorld)));
+ }
+
+ void visitMalformedType(MalformedType type, GraphBuilder builder) {
+ visitDynamicType(const DynamicType(), builder);
+ }
+
+ void visitStatementType(StatementType type, GraphBuilder builder) {
+ throw 'not implemented visitStatementType($type)';
+ }
+
+ void visitInterfaceType(InterfaceType type, GraphBuilder builder) {
+ List<HInstruction> inputs = <HInstruction>[];
+ for (DartType typeArgument in type.typeArguments) {
+ typeArgument.accept(this, builder);
+ inputs.add(builder.pop());
+ }
+ ClassElement cls;
+ if (type.typeArguments.isEmpty) {
+ cls = builder.backend.helpers.RuntimeTypePlain;
+ } else {
+ cls = builder.backend.helpers.RuntimeTypeGeneric;
+ }
+ builder.push(
+ new HInterfaceType(inputs, type, new TypeMask.exact(cls, closedWorld)));
+ }
+
+ void visitTypedefType(TypedefType type, GraphBuilder builder) {
+ DartType unaliased = type.unaliased;
+ if (unaliased is TypedefType) throw 'unable to unalias $type';
+ unaliased.accept(this, builder);
+ }
+
+ void visitDynamicType(DynamicType type, GraphBuilder builder) {
+ JavaScriptBackend backend = builder.compiler.backend;
+ ClassElement cls = backend.helpers.DynamicRuntimeType;
+ builder.push(new HDynamicType(type, new TypeMask.exact(cls, closedWorld)));
+ }
}
diff --git a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
index 1ba818c..4db25e9 100644
--- a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
@@ -127,11 +127,19 @@
return new CallStructure(argumentCount, namedArguments);
}
+ FunctionSignature getFunctionSignature(ir.FunctionNode function) {
+ return getElement(function).asFunctionElement().functionSignature;
+ }
+
Name getName(ir.Name name) {
return new Name(
name.name, name.isPrivate ? getElement(name.library) : null);
}
+ ir.Field getFieldFromElement(FieldElement field) {
+ return kernel.fields[field];
+ }
+
Selector getSelector(ir.Expression node) {
if (node is ir.PropertyGet) return getGetterSelector(node);
if (node is ir.InvocationExpression) return getInvocationSelector(node);
@@ -250,6 +258,8 @@
return _backend.isInterceptedSelector(selector);
}
+ LibraryElement get jsHelperLibrary => _backend.helpers.jsHelperLibrary;
+
JumpTarget getTargetDefinition(ir.Node node) =>
elements.getTargetDefinition(getNode(node));
@@ -282,9 +292,14 @@
ir.Procedure get assertThrow =>
kernel.functions[_backend.helpers.assertThrow];
+ ir.Procedure get setRuntimeTypeInfo =>
+ kernel.functions[_backend.helpers.setRuntimeTypeInfo];
+
TypeMask get assertThrowReturnType => TypeMaskFactory
.inferredReturnTypeForElement(_backend.helpers.assertThrow, _compiler);
+ ir.Class get objectClass => kernel.classes[_compiler.coreClasses.objectClass];
+
DartType getDartType(ir.DartType type) {
return type.accept(_typeConverter);
}
@@ -293,9 +308,13 @@
return types.map(getDartType).toList();
}
+ DartType getFunctionReturnType(ir.FunctionNode node) {
+ return getDartType(node.returnType);
+ }
+
/// Computes the function type corresponding the signature of [node].
FunctionType getFunctionType(ir.FunctionNode node) {
- DartType returnType = getDartType(node.returnType);
+ DartType returnType = getFunctionReturnType(node);
List<DartType> parameterTypes = <DartType>[];
List<DartType> optionalParameterTypes = <DartType>[];
for (ir.VariableDeclaration variable in node.positionalParameters) {
@@ -332,7 +351,6 @@
}
/// Compute the kind of foreign helper function called by [node], if any.
- @override
ForeignKind getForeignKind(ir.StaticInvocation node) {
if (isForeignLibrary(node.target.enclosingLibrary)) {
switch (node.target.name.name) {
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index f2d1af7..712ff29 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -2801,23 +2801,29 @@
}
class HTypeConversion extends HCheck {
- final DartType typeExpression;
- final int kind;
- final Selector receiverTypeCheckSelector;
- final bool contextIsTypeArguments;
- TypeMask checkedType; // Not final because we refine it.
-
+ // Values for [kind].
static const int CHECKED_MODE_CHECK = 0;
static const int ARGUMENT_TYPE_CHECK = 1;
static const int CAST_TYPE_CHECK = 2;
static const int BOOLEAN_CONVERSION_CHECK = 3;
static const int RECEIVER_TYPE_CHECK = 4;
+ final DartType typeExpression;
+ final int kind;
+ // [receiverTypeCheckSelector] is the selector used for a receiver type check
+ // on open-coded operators, e.g. the not-null check on `x` in `x + 1` would be
+ // compiled to the following, for which we need the selector `$add`.
+ //
+ // if (typeof x != "number") x.$add();
+ //
+ final Selector receiverTypeCheckSelector;
+
+ TypeMask checkedType; // Not final because we refine it.
+
HTypeConversion(
this.typeExpression, this.kind, TypeMask type, HInstruction input,
- [this.receiverTypeCheckSelector])
- : contextIsTypeArguments = false,
- checkedType = type,
+ {this.receiverTypeCheckSelector})
+ : checkedType = type,
super(<HInstruction>[input], type) {
assert(!isReceiverTypeCheck || receiverTypeCheckSelector != null);
assert(typeExpression == null || typeExpression.kind != TypeKind.TYPEDEF);
@@ -2826,21 +2832,21 @@
HTypeConversion.withTypeRepresentation(this.typeExpression, this.kind,
TypeMask type, HInstruction input, HInstruction typeRepresentation)
- : contextIsTypeArguments = false,
- checkedType = type,
+ : checkedType = type,
super(<HInstruction>[input, typeRepresentation], type),
receiverTypeCheckSelector = null {
assert(typeExpression.kind != TypeKind.TYPEDEF);
sourceElement = input.sourceElement;
}
- HTypeConversion.withContext(this.typeExpression, this.kind, TypeMask type,
- HInstruction input, HInstruction context,
- {bool this.contextIsTypeArguments})
- : super(<HInstruction>[input, context], type),
- checkedType = type,
+ HTypeConversion.viaMethodOnType(this.typeExpression, this.kind, TypeMask type,
+ HInstruction reifiedType, HInstruction input)
+ : checkedType = type,
+ super(<HInstruction>[reifiedType, input], type),
receiverTypeCheckSelector = null {
- assert(typeExpression.kind != TypeKind.TYPEDEF);
+ // This form is currently used only for function types.
+ assert(typeExpression.isFunctionType);
+ assert(kind == CHECKED_MODE_CHECK || kind == CAST_TYPE_CHECK);
sourceElement = input.sourceElement;
}
@@ -2850,11 +2856,11 @@
HInstruction get typeRepresentation => inputs[1];
- bool get hasContext {
- return typeExpression.isFunctionType && inputs.length > 1;
- }
+ bool get usesMethodOnType =>
+ typeExpression != null && typeExpression.isFunctionType;
- HInstruction get context => inputs[1];
+ HInstruction get checkedInput =>
+ usesMethodOnType ? inputs[1] : super.checkedInput;
HInstruction convertType(Compiler compiler, DartType type, int kind) {
if (typeExpression == type) {
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 507c459..5f11f1d 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -800,11 +800,25 @@
// throw a type error at runtime.
return node;
}
- if (!type.treatAsRaw || type.isTypeVariable) {
+ if (type.isTypeVariable) {
+ return node;
+ }
+ if (!type.treatAsRaw) {
+ HInstruction input = node.checkedInput;
+ // `null` always passes type conversion.
+ if (input.isNull()) return input;
+ // TODO(sra): We can statically check [input] if it is a constructor.
+ // TODO(sra): We can statically check [input] if it is load from a field
+ // of the same ground type, or load from a field of a parameterized type
+ // with the same receiver.
return node;
}
if (type.isFunctionType) {
+ HInstruction input = node.checkedInput;
+ // `null` always passes type conversion.
+ if (input.isNull()) return input;
// TODO(johnniwinther): Optimize function type conversions.
+ // TODO(sra): We can statically check [input] if it is a closure getter.
return node;
}
}
@@ -944,15 +958,18 @@
FieldElement field =
findConcreteFieldForDynamicAccess(receiver, node.selector);
if (field == null || !field.isAssignable) return node;
- // Use [:node.inputs.last:] in case the call follows the
- // interceptor calling convention, but is not a call on an
- // interceptor.
+ // Use `node.inputs.last` in case the call follows the interceptor calling
+ // convention, but is not a call on an interceptor.
HInstruction value = node.inputs.last;
if (compiler.options.enableTypeAssertions) {
DartType type = field.type;
- if (!type.treatAsRaw || type.isTypeVariable) {
+ if (!type.treatAsRaw ||
+ type.isTypeVariable ||
+ type.unaliased.isFunctionType) {
// We cannot generate the correct type representation here, so don't
// inline this access.
+ // TODO(sra): If the input is such that we don't need a type check, we
+ // can skip the test an generate the HFieldSet.
return node;
}
HInstruction other =
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index 1768db1..6c1d543 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -334,9 +334,11 @@
return handleGenericInvoke("InvokeConstructorBody", target, invoke.inputs);
}
- String visitForeignCode(HForeignCode foreign) {
- return handleGenericInvoke(
- "ForeignCode", "${foreign.codeTemplate.ast}", foreign.inputs);
+ String visitForeignCode(HForeignCode node) {
+ var template = node.codeTemplate;
+ String code = '${template.ast}';
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "ForeignCode: $code ($inputs)";
}
String visitLess(HLess node) => handleInvokeBinary(node, 'Less');
@@ -482,11 +484,19 @@
}
String visitTypeConversion(HTypeConversion node) {
- assert(node.inputs.length <= 2);
- String otherInput =
- (node.inputs.length == 2) ? temporaryId(node.inputs[1]) : '';
- return "TypeConversion: ${temporaryId(node.checkedInput)} to "
- "${node.instructionType} $otherInput";
+ String checkedInput = temporaryId(node.checkedInput);
+ String rest;
+ if (node.usesMethodOnType) {
+ assert(node.inputs.length == 2);
+ assert(identical(node.checkedInput, node.inputs.last));
+ rest = " ${temporaryId(node.inputs.first)}";
+ } else if (node.inputs.length == 2) {
+ rest = " ${temporaryId(node.inputs.last)}";
+ } else {
+ assert(node.inputs.length == 1);
+ rest = "";
+ }
+ return "TypeConversion: $checkedInput to ${node.instructionType}$rest";
}
String visitTypeKnown(HTypeKnown node) {
@@ -504,23 +514,29 @@
}
String visitTypeInfoReadRaw(HTypeInfoReadRaw node) {
- return "TypeInfoReadRaw";
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "TypeInfoReadRaw: $inputs";
}
String visitTypeInfoReadVariable(HTypeInfoReadVariable node) {
- return "TypeInfoReadVariable ${node.variable}";
+ return "TypeInfoReadVariable: "
+ "${temporaryId(node.inputs.single)}.${node.variable}";
}
String visitTypeInfoExpression(HTypeInfoExpression node) {
- return "TypeInfoExpression ${node.kindAsString} ${node.dartType}";
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "TypeInfoExpression: ${node.kindAsString} ${node.dartType}"
+ " ($inputs)";
}
String visitReadTypeVariable(HReadTypeVariable node) {
- return "ReadTypeVariable: ${node.dartType} ${node.hasReceiver}";
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "ReadTypeVariable: ${node.dartType} ${node.hasReceiver} $inputs";
}
String visitFunctionType(HFunctionType node) {
- return "FunctionType: ${node.dartType}";
+ var inputs = node.inputs.map(temporaryId).join(', ');
+ return "FunctionType: ${node.dartType} $inputs";
}
String visitVoidType(HVoidType node) {
diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart
new file mode 100644
index 0000000..605678b
--- /dev/null
+++ b/pkg/compiler/lib/src/ssa/type_builder.dart
@@ -0,0 +1,252 @@
+// 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 'graph_builder.dart';
+import 'nodes.dart';
+import '../closure.dart';
+import '../common.dart';
+import '../dart_types.dart';
+import '../types/types.dart';
+import '../elements/elements.dart';
+import '../io/source_information.dart';
+import '../universe/selector.dart' show Selector;
+import '../universe/use.dart' show TypeUse;
+
+/// Functions to insert type checking, coercion, and instruction insertion
+/// depending on the environment for dart code.
+class TypeBuilder {
+ final GraphBuilder builder;
+ TypeBuilder(this.builder);
+
+ /// Create an instruction to simply trust the provided type.
+ HInstruction _trustType(HInstruction original, DartType type) {
+ assert(builder.compiler.options.trustTypeAnnotations);
+ assert(type != null);
+ type = builder.localsHandler.substInContext(type);
+ type = type.unaliased;
+ if (type.isDynamic) return original;
+ if (!type.isInterfaceType) return original;
+ if (type.isObject) return original;
+ // The type element is either a class or the void element.
+ Element element = type.element;
+ TypeMask mask = new TypeMask.subtype(element, builder.compiler.closedWorld);
+ return new HTypeKnown.pinned(mask, original);
+ }
+
+ /// Produces code that checks the runtime type is actually the type specified
+ /// by attempting a type conversion.
+ HInstruction _checkType(HInstruction original, DartType type, int kind) {
+ assert(builder.compiler.options.enableTypeAssertions);
+ assert(type != null);
+ type = builder.localsHandler.substInContext(type);
+ HInstruction other = buildTypeConversion(original, type, kind);
+ // TODO(johnniwinther): This operation on `registry` may be inconsistent.
+ // If it is needed then it seems likely that similar invocations of
+ // `buildTypeConversion` in `SsaBuilder.visitAs` should also be followed by
+ // a similar operation on `registry`; otherwise, this one might not be
+ // needed.
+ builder.registry?.registerTypeUse(new TypeUse.isCheck(type));
+ return other;
+ }
+
+ /// Depending on the context and the mode, wrap the given type in an
+ /// instruction that checks the type is what we expect or automatically
+ /// trusts the written type.
+ HInstruction potentiallyCheckOrTrustType(HInstruction original, DartType type,
+ {int kind: HTypeConversion.CHECKED_MODE_CHECK}) {
+ if (type == null) return original;
+ HInstruction checkedOrTrusted = original;
+ if (builder.compiler.options.trustTypeAnnotations) {
+ checkedOrTrusted = _trustType(original, type);
+ } else if (builder.compiler.options.enableTypeAssertions) {
+ checkedOrTrusted = _checkType(original, type, kind);
+ }
+ if (checkedOrTrusted == original) return original;
+ builder.add(checkedOrTrusted);
+ return checkedOrTrusted;
+ }
+
+ /// Helper to create an instruction that gets the value of a type variable.
+ HInstruction addTypeVariableReference(TypeVariableType type, Element member,
+ {SourceInformation sourceInformation}) {
+ assert(assertTypeInContext(type));
+ if (type is MethodTypeVariableType) {
+ return builder.graph.addConstantNull(builder.compiler);
+ }
+ bool isClosure = member.enclosingElement.isClosure;
+ if (isClosure) {
+ ClosureClassElement closureClass = member.enclosingElement;
+ member = closureClass.methodElement;
+ member = member.outermostEnclosingMemberOrTopLevel;
+ }
+ bool isInConstructorContext =
+ member.isConstructor || member.isGenerativeConstructorBody;
+ Local typeVariableLocal =
+ builder.localsHandler.getTypeVariableAsLocal(type);
+ if (isClosure) {
+ if (member.isFactoryConstructor ||
+ (isInConstructorContext &&
+ builder.hasDirectLocal(typeVariableLocal))) {
+ // The type variable is used from a closure in a factory constructor.
+ // The value of the type argument is stored as a local on the closure
+ // itself.
+ return builder.localsHandler
+ .readLocal(typeVariableLocal, sourceInformation: sourceInformation);
+ } else if (member.isFunction ||
+ member.isGetter ||
+ member.isSetter ||
+ isInConstructorContext) {
+ // The type variable is stored on the "enclosing object" and needs to be
+ // accessed using the this-reference in the closure.
+ return readTypeVariable(type, member,
+ sourceInformation: sourceInformation);
+ } else {
+ assert(member.isField);
+ // The type variable is stored in a parameter of the method.
+ return builder.localsHandler.readLocal(typeVariableLocal);
+ }
+ } else if (isInConstructorContext ||
+ // When [member] is a field, we can be either
+ // generating a checked setter or inlining its
+ // initializer in a constructor. An initializer is
+ // never built standalone, so in that case [target] is not
+ // the [member] itself.
+ (member.isField && member != builder.targetElement)) {
+ // The type variable is stored in a parameter of the method.
+ return builder.localsHandler
+ .readLocal(typeVariableLocal, sourceInformation: sourceInformation);
+ } else if (member.isInstanceMember) {
+ // The type variable is stored on the object.
+ return readTypeVariable(type, member,
+ sourceInformation: sourceInformation);
+ } else {
+ builder.compiler.reporter.internalError(
+ type.element, 'Unexpected type variable in static context.');
+ return null;
+ }
+ }
+
+ /// Generate code to extract the type argument from the object.
+ HInstruction readTypeVariable(TypeVariableType variable, Element member,
+ {SourceInformation sourceInformation}) {
+ assert(member.isInstanceMember);
+ assert(variable is! MethodTypeVariableType);
+ HInstruction target = builder.localsHandler.readThis();
+ builder.push(
+ new HTypeInfoReadVariable(variable, target, builder.backend.dynamicType)
+ ..sourceInformation = sourceInformation);
+ return builder.pop();
+ }
+
+ HInstruction buildTypeArgumentRepresentations(
+ DartType type, Element sourceElement) {
+ assert(!type.isTypeVariable);
+ // Compute the representation of the type arguments, including access
+ // to the runtime type information for type variables as instructions.
+ assert(type.element.isClass);
+ InterfaceType interface = type;
+ List<HInstruction> inputs = <HInstruction>[];
+ for (DartType argument in interface.typeArguments) {
+ inputs.add(analyzeTypeArgument(argument, sourceElement));
+ }
+ HInstruction representation = new HTypeInfoExpression(
+ TypeInfoExpressionKind.INSTANCE,
+ interface.element.thisType,
+ inputs,
+ builder.backend.dynamicType);
+ return representation;
+ }
+
+ /// Check that [type] is valid in the context of `localsHandler.contextClass`.
+ /// This should only be called in assertions.
+ bool assertTypeInContext(DartType type, [Spannable spannable]) {
+ return invariant(spannable == null ? CURRENT_ELEMENT_SPANNABLE : spannable,
+ () {
+ ClassElement contextClass = Types.getClassContext(type);
+ return contextClass == null ||
+ contextClass == builder.localsHandler.contextClass;
+ },
+ message: "Type '$type' is not valid context of "
+ "${builder.localsHandler.contextClass}.");
+ }
+
+ HInstruction analyzeTypeArgument(DartType argument, Element sourceElement,
+ {SourceInformation sourceInformation}) {
+ assert(assertTypeInContext(argument));
+ argument = argument.unaliased;
+ if (argument.treatAsDynamic) {
+ // Represent [dynamic] as [null].
+ return builder.graph.addConstantNull(builder.compiler);
+ }
+
+ if (argument.isTypeVariable) {
+ return addTypeVariableReference(argument, sourceElement,
+ sourceInformation: sourceInformation);
+ }
+
+ List<HInstruction> inputs = <HInstruction>[];
+ argument.forEachTypeVariable((variable) {
+ if (variable is! MethodTypeVariableType) {
+ inputs.add(analyzeTypeArgument(variable, sourceElement));
+ }
+ });
+ HInstruction result = new HTypeInfoExpression(
+ TypeInfoExpressionKind.COMPLETE,
+ argument,
+ inputs,
+ builder.backend.dynamicType)..sourceInformation = sourceInformation;
+ builder.add(result);
+ return result;
+ }
+
+ /// In checked mode, generate type tests for the parameters of the inlined
+ /// function.
+ void potentiallyCheckInlinedParameterTypes(FunctionElement function) {
+ if (!checkOrTrustTypes) return;
+
+ FunctionSignature signature = function.functionSignature;
+ signature.orderedForEachParameter((ParameterElement parameter) {
+ HInstruction argument = builder.localsHandler.readLocal(parameter);
+ potentiallyCheckOrTrustType(argument, parameter.type);
+ });
+ }
+
+ bool get checkOrTrustTypes =>
+ builder.compiler.options.enableTypeAssertions ||
+ builder.compiler.options.trustTypeAnnotations;
+
+ /// Build a [HTypeConversion] for converting [original] to type [type].
+ ///
+ /// Invariant: [type] must be valid in the context.
+ /// See [LocalsHandler.substInContext].
+ HInstruction buildTypeConversion(
+ HInstruction original, DartType type, int kind) {
+ if (type == null) return original;
+ // GENERIC_METHODS: The following statement was added for parsing and
+ // ignoring method type variables; must be generalized for full support of
+ // generic methods.
+ type = type.dynamifyMethodTypeVariableType;
+ type = type.unaliased;
+ assert(assertTypeInContext(type, original));
+ if (type.isInterfaceType && !type.treatAsRaw) {
+ TypeMask subtype =
+ new TypeMask.subtype(type.element, builder.compiler.closedWorld);
+ HInstruction representations =
+ buildTypeArgumentRepresentations(type, builder.sourceElement);
+ builder.add(representations);
+ return new HTypeConversion.withTypeRepresentation(
+ type, kind, subtype, original, representations);
+ } else if (type.isTypeVariable) {
+ TypeMask subtype = original.instructionType;
+ HInstruction typeVariable =
+ addTypeVariableReference(type, builder.sourceElement);
+ return new HTypeConversion.withTypeRepresentation(
+ type, kind, subtype, original, typeVariable);
+ } else if (type.isFunctionType) {
+ return builder.buildFunctionTypeConversion(original, type, kind);
+ } else {
+ return original.convertType(builder.compiler, type, kind);
+ }
+ }
+}
diff --git a/pkg/compiler/lib/src/ssa/types_propagation.dart b/pkg/compiler/lib/src/ssa/types_propagation.dart
index 5a94e8d..63da628 100644
--- a/pkg/compiler/lib/src/ssa/types_propagation.dart
+++ b/pkg/compiler/lib/src/ssa/types_propagation.dart
@@ -233,9 +233,9 @@
Selector selector = (kind == HTypeConversion.RECEIVER_TYPE_CHECK)
? instruction.selector
: null;
- HTypeConversion converted =
- new HTypeConversion(null, kind, type, input, selector)
- ..sourceInformation = instruction.sourceInformation;
+ HTypeConversion converted = new HTypeConversion(null, kind, type, input,
+ receiverTypeCheckSelector: selector)
+ ..sourceInformation = instruction.sourceInformation;
instruction.block.addBefore(instruction, converted);
input.replaceAllUsersDominatedBy(instruction, converted);
}
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart
index 1885e0d..ff36cfe 100644
--- a/pkg/compiler/lib/src/tree/nodes.dart
+++ b/pkg/compiler/lib/src/tree/nodes.dart
@@ -594,7 +594,7 @@
final Node selector;
final NodeList argumentsNode;
- /// Whether this is a conditinal send of the form `a?.b`.
+ /// Whether this is a conditional send of the form `a?.b`.
final bool isConditional;
Link<Node> get arguments => argumentsNode.nodes;
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index c078298..d2831c0 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -251,8 +251,8 @@
typesInferrerInternal ??= new TypeGraphInferrer(compiler, masks);
typesInferrerInternal.analyzeMain(mainElement);
typesInferrerInternal.clear();
- results = new GlobalTypeInferenceResults(
- typesInferrerInternal, compiler, masks, typesInferrerInternal.inferrer.types);
+ results = new GlobalTypeInferenceResults(typesInferrerInternal, compiler,
+ masks, typesInferrerInternal.inferrer.types);
});
}
}
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index 39937fb..bc959c1 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -218,12 +218,12 @@
}
bool appliesUnnamed(Element element) {
- assert(sameNameHack(element));
+ assert(name == element.name);
return appliesUntyped(element);
}
bool appliesUntyped(Element element) {
- assert(sameNameHack(element));
+ assert(name == element.name);
if (Elements.isUnresolved(element)) return false;
if (memberName.isPrivate && memberName.library != element.library) {
// TODO(johnniwinther): Maybe this should be
@@ -247,13 +247,8 @@
return callStructure.signatureApplies(function.functionSignature);
}
- bool sameNameHack(Element element) {
- // TODO(ngeoffray): Remove workaround checks.
- return element.isConstructor || name == element.name;
- }
-
bool applies(Element element) {
- if (!sameNameHack(element)) return false;
+ if (name != element.name) return false;
return appliesUnnamed(element);
}
diff --git a/pkg/dev_compiler/USAGE.md b/pkg/dev_compiler/USAGE.md
index 77c2a69..9a3de65 100644
--- a/pkg/dev_compiler/USAGE.md
+++ b/pkg/dev_compiler/USAGE.md
@@ -73,7 +73,7 @@
## Feedback
-Please file issues in our [GitHub issue tracker](https://github.com/dart-lang/dev_compiler/issues).
+Please file issues in our [GitHub issue tracker](https://github.com/dart-lang/sdk/issues).
You can also view or join our [mailing list](https://groups.google.com/a/dartlang.org/forum/#!forum/dev-compiler).
diff --git a/pkg/dev_compiler/codereview.settings b/pkg/dev_compiler/codereview.settings
index 1c7f5d4..491e3d8 100644
--- a/pkg/dev_compiler/codereview.settings
+++ b/pkg/dev_compiler/codereview.settings
@@ -1,3 +1,3 @@
CODE_REVIEW_SERVER: https://codereview.chromium.org
-VIEW_VC: https://github.com/dart-lang/dev_compiler/commit/
+VIEW_VC: https://github.com/dart-lang/sdk/commit/
CC_LIST: dev-compiler+reviews@dartlang.org
diff --git a/pkg/dev_compiler/lib/js/amd/dart_sdk.js b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
index 8d7c71e..c2cb697 100644
--- a/pkg/dev_compiler/lib/js/amd/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
@@ -36890,7 +36890,7 @@
let args = Array.prototype.map.call(arguments, js._convertToDart);
return js._convertToJS(f(...args));
};
- dart.dsetindex(js._dartProxies, wrapper, f);
+ js._dartProxies.set(wrapper, f);
return wrapper;
};
dart.fn(js._wrapDartFunction, dynamicTodynamic$());
@@ -83133,15 +83133,6 @@
sanitizeNode: dart.definiteFunctionType(dart.void, [html$.Node, html$.Node])
})
});
- html$.Point$ = math.Point$;
- html$.Point = math.Point;
- html$.Rectangle$ = math.Rectangle$;
- html$.Rectangle = math.Rectangle;
- html_common.SupportedBrowser = _metadata.SupportedBrowser;
- html_common.Unstable = _metadata.Unstable;
- html_common.DocsEditable = _metadata.DocsEditable;
- html_common.Experimental = _metadata.Experimental;
- html_common.DomName = _metadata.DomName;
html_common.convertDartToNative_SerializedScriptValue = function(value) {
return html_common.convertDartToNative_PrepareForStructuredClone(value);
};
diff --git a/pkg/dev_compiler/lib/js/common/dart_sdk.js b/pkg/dev_compiler/lib/js/common/dart_sdk.js
index f5370bd..78f09d2 100644
--- a/pkg/dev_compiler/lib/js/common/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/common/dart_sdk.js
@@ -36890,7 +36890,7 @@
let args = Array.prototype.map.call(arguments, js._convertToDart);
return js._convertToJS(f(...args));
};
- dart.dsetindex(js._dartProxies, wrapper, f);
+ js._dartProxies.set(wrapper, f);
return wrapper;
};
dart.fn(js._wrapDartFunction, dynamicTodynamic$());
@@ -83133,15 +83133,6 @@
sanitizeNode: dart.definiteFunctionType(dart.void, [html$.Node, html$.Node])
})
});
- html$.Point$ = math.Point$;
- html$.Point = math.Point;
- html$.Rectangle$ = math.Rectangle$;
- html$.Rectangle = math.Rectangle;
- html_common.SupportedBrowser = _metadata.SupportedBrowser;
- html_common.Unstable = _metadata.Unstable;
- html_common.DocsEditable = _metadata.DocsEditable;
- html_common.Experimental = _metadata.Experimental;
- html_common.DomName = _metadata.DomName;
html_common.convertDartToNative_SerializedScriptValue = function(value) {
return html_common.convertDartToNative_PrepareForStructuredClone(value);
};
diff --git a/pkg/dev_compiler/lib/js/es6/dart_sdk.js b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
index 44083b7..c16638f 100644
--- a/pkg/dev_compiler/lib/js/es6/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
@@ -36888,7 +36888,7 @@
let args = Array.prototype.map.call(arguments, js._convertToDart);
return js._convertToJS(f(...args));
};
- dart.dsetindex(js._dartProxies, wrapper, f);
+ js._dartProxies.set(wrapper, f);
return wrapper;
};
dart.fn(js._wrapDartFunction, dynamicTodynamic());
@@ -83131,15 +83131,6 @@
sanitizeNode: dart.definiteFunctionType(dart.void, [html.Node, html.Node])
})
});
-html.Point$ = math.Point$;
-html.Point = math.Point;
-html.Rectangle$ = math.Rectangle$;
-html.Rectangle = math.Rectangle;
-html_common.SupportedBrowser = _metadata.SupportedBrowser;
-html_common.Unstable = _metadata.Unstable;
-html_common.DocsEditable = _metadata.DocsEditable;
-html_common.Experimental = _metadata.Experimental;
-html_common.DomName = _metadata.DomName;
html_common.convertDartToNative_SerializedScriptValue = function(value) {
return html_common.convertDartToNative_PrepareForStructuredClone(value);
};
diff --git a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
index 4f8489f..2312c34 100644
--- a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
@@ -36891,7 +36891,7 @@
let args = Array.prototype.map.call(arguments, js._convertToDart);
return js._convertToJS(f(...args));
};
- dart.dsetindex(js._dartProxies, wrapper, f);
+ js._dartProxies.set(wrapper, f);
return wrapper;
};
dart.fn(js._wrapDartFunction, dynamicTodynamic$());
@@ -83134,15 +83134,6 @@
sanitizeNode: dart.definiteFunctionType(dart.void, [html$.Node, html$.Node])
})
});
- html$.Point$ = math.Point$;
- html$.Point = math.Point;
- html$.Rectangle$ = math.Rectangle$;
- html$.Rectangle = math.Rectangle;
- html_common.SupportedBrowser = _metadata.SupportedBrowser;
- html_common.Unstable = _metadata.Unstable;
- html_common.DocsEditable = _metadata.DocsEditable;
- html_common.Experimental = _metadata.Experimental;
- html_common.DomName = _metadata.DomName;
html_common.convertDartToNative_SerializedScriptValue = function(value) {
return html_common.convertDartToNative_PrepareForStructuredClone(value);
};
diff --git a/pkg/dev_compiler/lib/sdk/ddc_sdk.sum b/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
index 80408b8..79fff65 100644
--- a/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
+++ b/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
Binary files differ
diff --git a/pkg/dev_compiler/lib/src/analyzer/context.dart b/pkg/dev_compiler/lib/src/analyzer/context.dart
index 209c2fe..5617f7f 100644
--- a/pkg/dev_compiler/lib/src/analyzer/context.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/context.dart
@@ -46,16 +46,21 @@
/// of the unsummarized one.
final String dartSdkSummaryPath;
+ /// Defined variables used by `bool.fromEnvironment` etc.
+ final Map<String, String> declaredVariables;
+
AnalyzerOptions(
{this.summaryPaths: const [],
String dartSdkPath,
this.dartSdkSummaryPath,
this.customUrlMappings: const {},
this.packageRoot: null,
- this.packagePaths: const []})
+ this.packagePaths: const [],
+ this.declaredVariables: const {}})
: dartSdkPath = dartSdkPath ?? getSdkDir().path;
- factory AnalyzerOptions.fromArguments(ArgResults args) {
+ factory AnalyzerOptions.fromArguments(
+ ArgResults args, Map<String, String> declaredVariables) {
var sdkPath = args['dart-sdk'] ?? getSdkDir().path;
var sdkSummaryPath = args['dart-sdk-summary'];
@@ -72,7 +77,8 @@
dartSdkSummaryPath: sdkSummaryPath,
customUrlMappings: _parseUrlMappings(args['url-mapping']),
packageRoot: args['package-root'],
- packagePaths: (args['package-paths'] as String)?.split(',') ?? []);
+ packagePaths: (args['package-paths'] as String)?.split(',') ?? [],
+ declaredVariables: declaredVariables);
}
/// Whether to resolve 'package:' uris using the multi-package resolver.
@@ -186,3 +192,25 @@
: _createFolderBasedDartSdk(sdkPath);
return new DartUriResolver(sdk);
}
+
+List<String> parseDeclaredVariables(
+ List<String> args, Map<String, String> declaredVars) {
+ var count = args.length;
+ var remainingArgs = <String>[];
+ for (int i = 0; i < count; i++) {
+ var arg = args[i];
+ if (arg == '--') {
+ while (i < count) {
+ remainingArgs.add(args[i++]);
+ }
+ } else if (arg.startsWith("-D")) {
+ // The format for defined variables is:
+ // -D<name>=<value>
+ var parts = arg.substring(2).split('=');
+ declaredVars[parts[0]] = parts.length > 1 ? parts[1] : '';
+ } else {
+ remainingArgs.add(arg);
+ }
+ }
+ return remainingArgs;
+}
diff --git a/pkg/dev_compiler/lib/src/compiler/code_generator.dart b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
index 98afa9f..231fcb9 100644
--- a/pkg/dev_compiler/lib/src/compiler/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
@@ -125,7 +125,7 @@
final ClassElement objectClass;
final ClassElement stringClass;
- ConstFieldVisitor _constField;
+ ConstFieldVisitor _constants;
/// The current function body being compiled.
FunctionBody _currentFunction;
@@ -276,7 +276,7 @@
}
_loader = new ElementLoader(nodes);
if (compilationUnits.isNotEmpty) {
- _constField = new ConstFieldVisitor(types,
+ _constants = new ConstFieldVisitor(context,
dummySource: compilationUnits.first.element.source);
}
@@ -517,35 +517,32 @@
// modules we import, so we will never go down this code path for them.
_moduleItems
.add(js.statement('#.# = #;', [libraryName, name.selector, name]));
- } else {
- // top-level fields, getters, setters need to copy the property
- // descriptor.
- _moduleItems.add(_callHelperStatement(
- 'export(#, #, #);', [libraryName, name.receiver, name.selector]));
}
}
- for (var export in exportedNames.definedNames.values) {
- if (export is PropertyAccessorElement) {
- export = (export as PropertyAccessorElement).variable;
- }
+ // We only need to export main as it is the only method party of the
+ // publicly exposed JS API for a library.
+ // TODO(jacobr): add a library level annotation indicating that all
+ // contents of a library need to be exposed to JS.
+ // https://github.com/dart-lang/sdk/issues/26368
- // Don't allow redefining names from this library.
- if (currentNames.containsKey(export.name)) continue;
+ var export = exportedNames.get('main');
- if (export.isSynthetic && export is PropertyInducingElement) {
- _emitDeclaration(export.getter);
- _emitDeclaration(export.setter);
- } else {
- _emitDeclaration(export);
- }
- if (export is ClassElement && export.typeParameters.isNotEmpty) {
- // Export the generic name as well.
- // TODO(jmesserly): revisit generic classes
- emitExport(export, suffix: r'$');
- }
- emitExport(export);
+ if (export == null) return;
+ if (export is PropertyAccessorElement) {
+ export = (export as PropertyAccessorElement).variable;
}
+
+ // Don't allow redefining names from this library.
+ if (currentNames.containsKey(export.name)) return;
+
+ if (export.isSynthetic && export is PropertyInducingElement) {
+ _emitDeclaration(export.getter);
+ _emitDeclaration(export.setter);
+ } else {
+ _emitDeclaration(export);
+ }
+ emitExport(export);
}
@override
@@ -2120,7 +2117,7 @@
for (var declaration in fieldDecls) {
for (var fieldNode in declaration.fields.variables) {
var element = fieldNode.element;
- if (_constField.isFieldInitConstant(fieldNode)) {
+ if (_constants.isFieldInitConstant(fieldNode)) {
unsetFields[element as FieldElement] = fieldNode;
} else {
fields[element as FieldElement] = _visitInitializer(fieldNode);
@@ -3767,7 +3764,7 @@
bool isLoaded = _loader.finishCheckingReferences();
bool eagerInit =
- isLoaded && (field.isConst || _constField.isFieldInitConstant(field));
+ isLoaded && (field.isConst || _constants.isFieldInitConstant(field));
var fieldName = field.name.name;
if (eagerInit &&
@@ -3796,7 +3793,7 @@
bool eagerInit;
JS.Expression jsInit;
- if (field.isConst || _constField.isFieldInitConstant(field)) {
+ if (field.isConst || _constants.isFieldInitConstant(field)) {
// If the field is constant, try and generate it at the top level.
_loader.startTopLevel(element);
jsInit = _visitInitializer(field);
@@ -3961,6 +3958,41 @@
var constructor = node.constructorName;
var name = constructor.name;
var type = constructor.type.type;
+ if (node.isConst &&
+ element?.name == 'fromEnvironment' &&
+ element.library.isDartCore) {
+ var value = node.accept(_constants.constantVisitor);
+
+ if (value == null || value.isNull) {
+ return new JS.LiteralNull();
+ }
+ // Handle unknown value: when the declared variable wasn't found, and no
+ // explicit default value was passed either.
+ // TODO(jmesserly): ideally Analyzer would simply resolve this to the
+ // default value that is specified in the SDK. Instead we implement that
+ // here. `bool.fromEnvironment` defaults to `false`, the others to `null`:
+ // https://api.dartlang.org/stable/1.20.1/dart-core/bool/bool.fromEnvironment.html
+ if (value.isUnknown) {
+ return type == types.boolType
+ ? js.boolean(false)
+ : new JS.LiteralNull();
+ }
+ if (value.type == types.boolType) {
+ var boolValue = value.toBoolValue();
+ return boolValue != null ? js.boolean(boolValue) : new JS.LiteralNull();
+ }
+ if (value.type == types.intType) {
+ var intValue = value.toIntValue();
+ return intValue != null ? js.number(intValue) : new JS.LiteralNull();
+ }
+ if (value.type == types.stringType) {
+ var stringValue = value.toStringValue();
+ return stringValue != null
+ ? js.escapedString(stringValue)
+ : new JS.LiteralNull();
+ }
+ throw new StateError('failed to evaluate $node');
+ }
return _emitInstanceCreationExpression(
element, type, name, node.argumentList, node.isConst);
}
diff --git a/pkg/dev_compiler/lib/src/compiler/command.dart b/pkg/dev_compiler/lib/src/compiler/command.dart
index 7d5e212..221e7d4 100644
--- a/pkg/dev_compiler/lib/src/compiler/command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/command.dart
@@ -10,7 +10,7 @@
import 'package:args/command_runner.dart' show UsageException;
import 'package:path/path.dart' as path;
-import '../analyzer/context.dart' show AnalyzerOptions;
+import '../analyzer/context.dart' show AnalyzerOptions, parseDeclaredVariables;
import 'compiler.dart' show BuildUnit, CompilerOptions, ModuleCompiler;
import 'module_builder.dart';
@@ -41,14 +41,15 @@
int compile(List<String> args, {void printFn(Object obj)}) {
printFn ??= print;
ArgResults argResults;
+ var declaredVars = <String, String>{};
try {
- argResults = _argParser.parse(args);
+ argResults = _argParser.parse(parseDeclaredVariables(args, declaredVars));
} on FormatException catch (error) {
printFn('$error\n\n$_usageMessage');
return 64;
}
try {
- _compile(argResults, printFn);
+ _compile(argResults, declaredVars, printFn);
return 0;
} on UsageException catch (error) {
// Incorrect usage, input file not found, etc.
@@ -90,13 +91,14 @@
return false;
}
-void _compile(ArgResults argResults, void printFn(Object obj)) {
+void _compile(ArgResults argResults, Map<String, String> declaredVars,
+ void printFn(Object obj)) {
if (argResults['help']) {
printFn(_usageMessage);
return;
}
- var compiler =
- new ModuleCompiler(new AnalyzerOptions.fromArguments(argResults));
+ var compiler = new ModuleCompiler(
+ new AnalyzerOptions.fromArguments(argResults, declaredVars));
var compilerOpts = new CompilerOptions.fromArguments(argResults);
var outPaths = argResults['out'] as List<String>;
var moduleFormats = parseModuleFormatOption(argResults);
diff --git a/pkg/dev_compiler/lib/src/compiler/compiler.dart b/pkg/dev_compiler/lib/src/compiler/compiler.dart
index 92cfc59..ea67648 100644
--- a/pkg/dev_compiler/lib/src/compiler/compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/compiler.dart
@@ -94,6 +94,8 @@
context.typeProvider = sdkResolver.dartSdk.context.typeProvider;
context.resultProvider =
new InputPackagesResultProvider(context, summaryData);
+ options.declaredVariables.forEach(context.declaredVariables.define);
+ context.declaredVariables.define('dart.isVM', 'false');
return new ModuleCompiler.withContext(context, summaryData);
}
diff --git a/pkg/dev_compiler/lib/src/compiler/side_effect_analysis.dart b/pkg/dev_compiler/lib/src/compiler/side_effect_analysis.dart
index 5da18ea..499cb86 100644
--- a/pkg/dev_compiler/lib/src/compiler/side_effect_analysis.dart
+++ b/pkg/dev_compiler/lib/src/compiler/side_effect_analysis.dart
@@ -8,7 +8,7 @@
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/error/listener.dart'
show AnalysisErrorListener, ErrorReporter;
-import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/dart/ast/ast.dart';
@@ -105,12 +105,12 @@
}
class ConstFieldVisitor {
- final ConstantVisitor _constantVisitor;
+ final ConstantVisitor constantVisitor;
- ConstFieldVisitor(TypeProvider types, {Source dummySource})
- // TODO(jmesserly): support -D variables on the command line
- : _constantVisitor = new ConstantVisitor(
- new ConstantEvaluationEngine(types, new DeclaredVariables()),
+ ConstFieldVisitor(AnalysisContext context, {Source dummySource})
+ : constantVisitor = new ConstantVisitor(
+ new ConstantEvaluationEngine(
+ context.typeProvider, context.declaredVariables),
new ErrorReporter(
AnalysisErrorListener.NULL_LISTENER, dummySource));
@@ -134,6 +134,6 @@
var initializer = field.initializer;
if (initializer == null) return null;
- return initializer.accept(_constantVisitor);
+ return initializer.accept(constantVisitor);
}
}
diff --git a/pkg/dev_compiler/test/browser/language_tests.js b/pkg/dev_compiler/test/browser/language_tests.js
index 948d48a..af33d47 100644
--- a/pkg/dev_compiler/test/browser/language_tests.js
+++ b/pkg/dev_compiler/test/browser/language_tests.js
@@ -290,7 +290,6 @@
'throwing_lazy_variable_test': skip_fail,
'top_level_non_prefixed_library_test': skip_fail,
'truncdiv_test': fail, // did not throw
- 'type_literal_test': firefox_fail,
'type_variable_nested_test': skip_fail, // unsound is-check
'type_variable_typedef_test': skip_fail, // unsound is-check
@@ -401,7 +400,6 @@
'corelib/regexp': {
'default_arguments_test': fail,
'UC16_test': firefox_fail,
- 'unicodeCaseInsensitive_test': firefox_fail
},
'lib/convert': {
@@ -494,6 +492,7 @@
'native_gc_test': async_unittest,
'notification_test': 'fail', // was sdk#27578, needs triage
'postmessage_structured_test': async_unittest,
+ 'queryall_test': ['slow'], // see sdk #27794
'request_animation_frame_test': async_unittest,
'resource_http_test': async_unittest,
'rtc_test': is.chrome('<=55') ? fail : pass, // was sdk#27578, needs triage
@@ -679,7 +678,6 @@
'typedef_metadata_test': fail,
'typedef_test': fail,
'typevariable_mirror_metadata_test': fail,
- 'unmangled_type_test': firefox_fail,
'unnamed_library_test': fail,
'variable_is_const_test_none_multi': fail,
},
diff --git a/pkg/dev_compiler/test/codegen_test.dart b/pkg/dev_compiler/test/codegen_test.dart
index 5c215e0..80a1a8a 100644
--- a/pkg/dev_compiler/test/codegen_test.dart
+++ b/pkg/dev_compiler/test/codegen_test.dart
@@ -22,7 +22,8 @@
parseDirectives;
import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:args/args.dart' show ArgParser, ArgResults;
-import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions;
+import 'package:dev_compiler/src/analyzer/context.dart'
+ show AnalyzerOptions, parseDeclaredVariables;
import 'package:dev_compiler/src/compiler/compiler.dart'
show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler;
import 'package:dev_compiler/src/compiler/module_builder.dart'
@@ -76,9 +77,8 @@
.where((p) => p.endsWith('.sum'))
.toList();
- var analyzerOptions = new AnalyzerOptions(
- dartSdkSummaryPath: sdkSummaryFile, summaryPaths: summaryPaths);
- var compiler = new ModuleCompiler(analyzerOptions);
+ var sharedCompiler = new ModuleCompiler(new AnalyzerOptions(
+ dartSdkSummaryPath: sdkSummaryFile, summaryPaths: summaryPaths));
var testDirs = [
'language',
@@ -100,9 +100,20 @@
// Our default compiler options. Individual tests can override these.
var defaultOptions = ['--no-source-map', '--no-summarize'];
- var compilerArgParser = new ArgParser();
- CompilerOptions.addArguments(compilerArgParser);
- addModuleFormatOptions(compilerArgParser);
+ var compileArgParser = new ArgParser();
+ CompilerOptions.addArguments(compileArgParser);
+ addModuleFormatOptions(compileArgParser);
+
+ var testFileOptionsMatcher =
+ new RegExp(r'// (compile options: |SharedOptions=)(.*)', multiLine: true);
+
+ // Ignore dart2js options that we don't support in DDC.
+ var ignoreOptions = [
+ '--enable-enum',
+ '--experimental-trust-js-interop-type-annotations',
+ '--trust-type-annotations',
+ '--supermixin'
+ ];
// Compile each test file to JS and put the result in gen/codegen_output.
for (var testFile in testFiles) {
@@ -116,15 +127,17 @@
test('dartdevc $name', () {
// Check if we need to use special compile options.
var contents = new File(testFile).readAsStringSync();
- var match =
- new RegExp(r'// compile options: (.*)').matchAsPrefix(contents);
+ var match = testFileOptionsMatcher.firstMatch(contents);
var args = defaultOptions.toList();
if (match != null) {
- args.addAll(match.group(1).split(' '));
+ var matchedArgs = match.group(2).split(' ');
+ args.addAll(matchedArgs.where((s) => !ignoreOptions.contains(s)));
}
- var argResults = compilerArgParser.parse(args);
+ var declaredVars = <String, String>{};
+ var argResults =
+ compileArgParser.parse(parseDeclaredVariables(args, declaredVars));
var options = new CompilerOptions.fromArguments(argResults);
var moduleFormat = parseModuleFormatOption(argResults).first;
@@ -133,6 +146,14 @@
_collectTransitiveImports(contents, files, from: testFile);
var unit = new BuildUnit(
name, path.dirname(testFile), files.toList(), _moduleForLibrary);
+
+ var compiler = sharedCompiler;
+ if (declaredVars.isNotEmpty) {
+ compiler = new ModuleCompiler(new AnalyzerOptions(
+ dartSdkSummaryPath: sdkSummaryFile,
+ summaryPaths: summaryPaths,
+ declaredVariables: declaredVars));
+ }
var module = compiler.compile(unit, options);
bool notStrong = notYetStrongTests.contains(name);
@@ -155,7 +176,7 @@
if (filePattern.hasMatch('sunflower')) {
test('sunflower', () {
- _buildSunflower(compiler, codegenOutputDir, codegenExpectDir);
+ _buildSunflower(sharedCompiler, codegenOutputDir, codegenExpectDir);
});
}
diff --git a/pkg/dev_compiler/test/not_yet_strong_tests.dart b/pkg/dev_compiler/test/not_yet_strong_tests.dart
index 2b458dd..d6d3976 100644
--- a/pkg/dev_compiler/test/not_yet_strong_tests.dart
+++ b/pkg/dev_compiler/test/not_yet_strong_tests.dart
@@ -2397,27 +2397,12 @@
'language/unresolved_in_factory_negative_test',
'language/unresolved_top_level_method_negative_test',
'language/unresolved_top_level_var_negative_test',
- 'corelib/bool_from_environment_test',
'corelib/file_resource_test',
- 'corelib/from_environment_const_type_test_none_multi',
- 'corelib/from_environment_const_type_test_01_multi',
- 'corelib/from_environment_const_type_test_05_multi',
- 'corelib/from_environment_const_type_test_10_multi',
- 'corelib/from_environment_const_type_test_15_multi',
- 'corelib/from_environment_const_type_undefined_test_none_multi',
- 'corelib/from_environment_const_type_undefined_test_01_multi',
- 'corelib/from_environment_const_type_undefined_test_05_multi',
- 'corelib/from_environment_const_type_undefined_test_10_multi',
- 'corelib/from_environment_const_type_undefined_test_15_multi',
- 'corelib/int_from_environment2_test',
- 'corelib/int_from_environment_test',
'corelib/queue_test',
'corelib/regexp/global_test',
'corelib/regexp/regexp_test',
'corelib/regexp/regress-regexp-codeflush_test',
'corelib/regexp/standalones_test',
- 'corelib/string_from_environment2_test',
- 'corelib/string_from_environment_test',
'corelib/string_from_list_test',
'lib/convert/chunked_conversion_json_encode1_test',
'lib/convert/chunked_conversion_utf84_test',
diff --git a/pkg/dev_compiler/tool/build_pkgs.dart b/pkg/dev_compiler/tool/build_pkgs.dart
new file mode 100755
index 0000000..a6e2b6b
--- /dev/null
+++ b/pkg/dev_compiler/tool/build_pkgs.dart
@@ -0,0 +1,104 @@
+#!/usr/bin/env dart
+import 'dart:io';
+
+import 'package:dev_compiler/src/compiler/command.dart';
+
+/// Compiles the packages that the DDC tests use to JS into:
+///
+/// gen/codegen_output/pkg/...
+///
+/// Assumes the working directory is pkg/dev_compiler.
+///
+/// If no arguments are passed, builds the all of the modules tested on Travis.
+/// If "test" is passed, only builds the modules needed by the tests.
+void main(List<String> arguments) {
+ var test = arguments.length == 1 && arguments[0] == 'test';
+
+ new Directory("gen/codegen_output/pkg").createSync(recursive: true);
+
+ // Build leaf packages. These have no other package dependencies.
+
+ // Under pkg.
+ compileModule('async_helper');
+ compileModule('expect', libs: ['minitest']);
+ compileModule('js', libs: ['js_util']);
+ if (!test) {
+ compileModule('lookup_map');
+ compileModule('meta');
+ compileModule('microlytics', libs: ['html_channels']);
+ compileModule('typed_mock');
+ }
+
+ // Under third_party/pkg.
+ compileModule('collection');
+ compileModule('matcher');
+ compileModule('path');
+ if (!test) {
+ compileModule('args', libs: ['command_runner']);
+ compileModule('charcode');
+ compileModule('fixnum');
+ compileModule('logging');
+ compileModule('markdown');
+ compileModule('mime');
+ compileModule('plugin', libs: ['manager']);
+ compileModule('typed_data');
+ compileModule('usage');
+ compileModule('utf');
+ compileModule('when');
+ }
+
+ // Composite packages with dependencies.
+ compileModule('stack_trace', deps: ['path']);
+ if (!test) {
+ compileModule('async', deps: ['collection']);
+ }
+
+ if (test) {
+ compileModule('unittest',
+ deps: ['matcher', 'path', 'stack_trace'],
+ libs: ['html_config', 'html_individual_config', 'html_enhanced_config'],
+ unsafeForceCompile: true);
+ }
+}
+
+/// Compiles a [module] with a single matching ".dart" library and additional
+/// [libs] and [deps] on other modules.
+void compileModule(String module,
+ {List<String> libs, List<String> deps, bool unsafeForceCompile: false}) {
+ var args = [
+ '--dart-sdk-summary=lib/sdk/ddc_sdk.sum',
+ '-ogen/codegen_output/pkg/$module.js'
+ ];
+
+ // There is always a library that matches the module.
+ args.add('package:$module/$module.dart');
+
+ // Add any additional libraries.
+ if (libs != null) {
+ for (var lib in libs) {
+ args.add('package:$module/$lib.dart');
+ }
+ }
+
+ // Add summaries for any modules this depends on.
+ if (deps != null) {
+ for (var dep in deps) {
+ args.add('-sgen/codegen_output/pkg/$dep.sum');
+ }
+ }
+
+ if (unsafeForceCompile) {
+ args.add('--unsafe-force-compile');
+ }
+
+ // TODO(rnystrom): Hack. DDC has its own forked copy of async_helper that
+ // has a couple of differences from pkg/async_helper. We should unfork them,
+ // but I'm not sure how they'll affect the other non-DDC tests. For now, just
+ // use ours.
+ if (module == 'async_helper') {
+ args.add('--url-mapping=package:async_helper/async_helper.dart,'
+ 'test/codegen/async_helper.dart');
+ }
+
+ compile(args);
+}
diff --git a/pkg/dev_compiler/tool/build_pkgs.sh b/pkg/dev_compiler/tool/build_pkgs.sh
index a26c7ea..87ec3c0 100755
--- a/pkg/dev_compiler/tool/build_pkgs.sh
+++ b/pkg/dev_compiler/tool/build_pkgs.sh
@@ -1,92 +1,5 @@
#!/bin/bash
-set -e # bail on error
-cd $( dirname "${BASH_SOURCE[0]}" )/..
-
-mkdir -p gen/codegen_output/pkg/
-
-SDK=--dart-sdk-summary=lib/sdk/ddc_sdk.sum
-
-# Build leaf packages. These have no other package dependencies.
-
-# Under pkg
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/async_helper.js \
- package:async_helper/async_helper.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/expect.js \
- package:expect/expect.dart \
- package:expect/minitest.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/js.js \
- package:js/js.dart \
- package:js/js_util.dart \
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/lookup_map.js \
- package:lookup_map/lookup_map.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/meta.js \
- package:meta/meta.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/microlytics.js \
- package:microlytics/microlytics.dart \
- package:microlytics/html_channels.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/typed_mock.js \
- package:typed_mock/typed_mock.dart
-
-# Under third_party/pkg
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/args.js \
- package:args/args.dart \
- package:args/command_runner.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/charcode.js \
- package:charcode/charcode.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/collection.js \
- package:collection/collection.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/fixnum.js \
- package:fixnum/fixnum.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/logging.js \
- package:logging/logging.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/markdown.js \
- package:markdown/markdown.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/matcher.js \
- package:matcher/matcher.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/mime.js \
- package:mime/mime.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/path.js \
- package:path/path.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/plugin.js \
- package:plugin/plugin.dart \
- package:plugin/manager.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/typed_data.js \
- package:typed_data/typed_data.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/usage.js \
- package:usage/usage.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/utf.js \
- package:utf/utf.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/when.js \
- package:when/when.dart
-
-# Composite packages with dependencies
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/async.js \
- -s gen/codegen_output/pkg/collection.sum \
- package:async/async.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/stack_trace.js \
- -s gen/codegen_output/pkg/path.sum \
- package:stack_trace/stack_trace.dart
+# TODO: This script is deprecated in favor of the Dart version. For now, forward
+# to it so existing scripts don't break. Eventually, delete this one.
+./tool/build_pkgs.dart
diff --git a/pkg/dev_compiler/tool/build_test_pkgs.sh b/pkg/dev_compiler/tool/build_test_pkgs.sh
index bb63177..1aa3ddf 100755
--- a/pkg/dev_compiler/tool/build_test_pkgs.sh
+++ b/pkg/dev_compiler/tool/build_test_pkgs.sh
@@ -1,42 +1,5 @@
#!/bin/bash
-set -e # bail on error
-cd $( dirname "${BASH_SOURCE[0]}" )/..
-
-mkdir -p gen/codegen_output/pkg/
-
-SDK=--dart-sdk-summary=lib/sdk/ddc_sdk.sum
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/expect.js \
- package:expect/expect.dart \
- package:expect/minitest.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/async_helper.js \
- --url-mapping=package:async_helper/async_helper.dart,test/codegen/async_helper.dart \
- package:async_helper/async_helper.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/collection.js \
- package:collection/collection.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/js.js \
- package:js/js.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/matcher.js \
- package:matcher/matcher.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/path.js \
- package:path/path.dart
-
-./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/stack_trace.js \
- -s gen/codegen_output/pkg/path.sum \
- package:stack_trace/stack_trace.dart
-
-./bin/dartdevc.dart $SDK --unsafe-force-compile \
- -o gen/codegen_output/pkg/unittest.js \
- -s gen/codegen_output/pkg/matcher.sum \
- -s gen/codegen_output/pkg/path.sum \
- -s gen/codegen_output/pkg/stack_trace.sum \
- package:unittest/unittest.dart \
- package:unittest/html_config.dart \
- package:unittest/html_individual_config.dart \
- package:unittest/html_enhanced_config.dart
+# TODO: This script is deprecated in favor of the Dart version. For now, forward
+# to it so existing scripts don't break. Eventually, delete this one.
+./tool/build_pkgs.dart test
diff --git a/pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart b/pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart
index 4e2d6fd..1582f0d 100644
--- a/pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart
+++ b/pkg/dev_compiler/tool/input_sdk/lib/js/dart2js/js_dart2js.dart
@@ -470,7 +470,8 @@
' let args = Array.prototype.map.call(arguments, #);'
' return #(#(...args));'
'}', _convertToDart, _convertToJS, f);
- _dartProxies[wrapper] = f;
+ JS('', '#.set(#, #)', _dartProxies, wrapper, f);
+
return wrapper;
}
diff --git a/pkg/dev_compiler/tool/patch_sdk.dart b/pkg/dev_compiler/tool/patch_sdk.dart
index 3c7e543..00ec5db 100755
--- a/pkg/dev_compiler/tool/patch_sdk.dart
+++ b/pkg/dev_compiler/tool/patch_sdk.dart
@@ -14,8 +14,8 @@
import 'package:path/path.dart' as path;
void main(List<String> argv) {
+ var self = path.relative(path.fromUri(Platform.script));
if (argv.length < 2) {
- var self = path.relative(path.fromUri(Platform.script));
var toolDir = path.relative(path.dirname(path.fromUri(Platform.script)));
var inputExample = path.join(toolDir, 'input_sdk');
@@ -28,6 +28,8 @@
exit(1);
}
+ var selfModifyTime = new File(self).lastModifiedSync().millisecondsSinceEpoch;
+
var input = argv[0];
var sdkLibIn = path.join(input, 'lib');
var patchIn = path.join(input, 'patch');
@@ -71,8 +73,8 @@
var outPaths = <String>[libraryOut];
var libraryContents = libraryFile.readAsStringSync();
- int inputModifyTime =
- libraryFile.lastModifiedSync().millisecondsSinceEpoch;
+ int inputModifyTime = math.max(selfModifyTime,
+ libraryFile.lastModifiedSync().millisecondsSinceEpoch);
var partFiles = <File>[];
for (var part in parseDirectives(libraryContents).directives) {
if (part is PartDirective) {
@@ -263,6 +265,15 @@
int start = patchMeta.endToken.next.offset;
var code = patch.contents.substring(start, patchNode.end);
+ // Const factory constructors can't be legally parsed from the patch file,
+ // so we need to omit the "const" there, but still preserve it.
+ if (node is ConstructorDeclaration &&
+ node.constKeyword != null &&
+ patchNode is ConstructorDeclaration &&
+ patchNode.constKeyword == null) {
+ code = 'const $code';
+ }
+
// For some node like static fields, the node's offset doesn't include
// the external keyword. Also starting from the keyword lets us preserve
// documentation comments.
diff --git a/pkg/dev_compiler/tool/run.js b/pkg/dev_compiler/tool/run.js
index b27a007..7306964 100644
--- a/pkg/dev_compiler/tool/run.js
+++ b/pkg/dev_compiler/tool/run.js
@@ -2,9 +2,23 @@
// 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 is a utility to run and debug an individual DDC compiled test.
+/// Tests can be run with either node or devtool (a Chrome-based utility with
+/// DOM APIs and developer tools support).
+///
+/// Install devtool via:
+/// > npm install -g devtool
+///
+/// Run via:
+/// > devtool tool/run.js -- corelib/apply2_test
+/// or
+/// > node tool/run.js corelib/apply2_test
+///
+/// See TODO below on async / unittest support.
+
var args = process.argv.slice(2);
if (args.length != 1) {
- throw new Error("Usage: node test/run.js <test-module-name>");
+ throw new Error("Usage: devtool tool/run.js <test-module-name>");
}
var test = args[0];
@@ -27,7 +41,13 @@
// TODO(vsm): Factor out test framework code in test/browser/language_tests.js
// and use here. Async tests and unittests won't work without it.
-
+var sdk = requirejs('dart_sdk');
var module = requirejs(test);
-test = test.split('/').slice(-1)[0];
-module[test].main();
+var lib = test.split('/').slice(-1)[0];
+try {
+ module[lib].main();
+ console.log('Test ' + test + ' passed.');
+} catch (e) {
+ console.log('Test ' + test + ' failed:\n' + e.toString());
+ sdk.dart.stackPrint(e);
+}
diff --git a/pkg/dev_compiler/tool/sdk_expected_errors.txt b/pkg/dev_compiler/tool/sdk_expected_errors.txt
index 8e0b1c4..80eacbc 100644
--- a/pkg/dev_compiler/tool/sdk_expected_errors.txt
+++ b/pkg/dev_compiler/tool/sdk_expected_errors.txt
@@ -3,6 +3,12 @@
[error] Invalid override. The type of 'ChunkedConverter.bind' ('(dynamic) → dynamic') isn't a subtype of 'Converter<S, T>.bind' ('(Stream<S>) → Stream<T>'). (dart:convert/chunked_conversion.dart, line 14, col 3)
[error] Invalid override. The type of 'ChunkedConverter.bind' ('(dynamic) → dynamic') isn't a subtype of 'StreamTransformer<S, T>.bind' ('(Stream<S>) → Stream<T>'). (dart:convert/chunked_conversion.dart, line 14, col 3)
[error] Invalid override. The type of 'ChunkedConverter.startChunkedConversion' ('(dynamic) → dynamic') isn't a subtype of 'Converter<S, T>.startChunkedConversion' ('(Sink<T>) → Sink<S>'). (dart:convert/chunked_conversion.dart, line 15, col 3)
+[error] Only redirecting factory constructors can be declared to be 'const'. (dart:core/bool.dart, line 41, col 9)
+[error] Const constructors can't throw exceptions. (dart:core/bool.dart, line 42, col 5)
+[error] Only redirecting factory constructors can be declared to be 'const'. (dart:core/int.dart, line 33, col 9)
+[error] Const constructors can't throw exceptions. (dart:core/int.dart, line 34, col 5)
+[error] Only redirecting factory constructors can be declared to be 'const'. (dart:core/string.dart, line 156, col 9)
+[error] Const constructors can't throw exceptions. (dart:core/string.dart, line 157, col 5)
[error] Invalid override. The type of '_EventStreamSubscription.asFuture' ('([dynamic]) → Future<dynamic>') isn't a subtype of 'StreamSubscription<T>.asFuture' ('<E>([E]) → Future<E>'). (dart:html, line 40152, col 3)
[error] Invalid override. The type of 'JsArray.[]=' ('(Object, E) → void') isn't a subtype of 'JsObject.[]=' ('(Object, dynamic) → dynamic'). (dart:js, line 363, col 3)
[warning] Unsafe implicit cast from 'List<dynamic>' to 'List<String>'. This usually indicates that type information was lost and resulted in 'dynamic' and/or a place that will have a failure at runtime. (dart:_js_helper/regexp_helper.dart, line 140, col 43)
diff --git a/pkg/dev_compiler/tool/test.sh b/pkg/dev_compiler/tool/test.sh
index f32a6ad..f5593bc 100755
--- a/pkg/dev_compiler/tool/test.sh
+++ b/pkg/dev_compiler/tool/test.sh
@@ -27,7 +27,7 @@
rm -r gen/codegen_output || fail
fi
-./tool/build_test_pkgs.sh
+./tool/build_pkgs.dart test
# Make sure we don't run tests in code coverage mode.
# this will cause us to generate files that are not part of the baseline
diff --git a/pkg/front_end/.analysis_options b/pkg/front_end/.analysis_options
index a10d4c5..f0ac32f 100644
--- a/pkg/front_end/.analysis_options
+++ b/pkg/front_end/.analysis_options
@@ -1,2 +1,4 @@
analyzer:
strong-mode: true
+ language:
+ enableSuperMixins: true
diff --git a/pkg/front_end/lib/compilation_error.dart b/pkg/front_end/lib/compilation_error.dart
index a238575..5e30da1 100644
--- a/pkg/front_end/lib/compilation_error.dart
+++ b/pkg/front_end/lib/compilation_error.dart
@@ -18,8 +18,8 @@
/// A text description of how the user can fix the error. May be `null`.
String get correction;
- /// The source location where the error occurred.
- SourceSpan get location;
+ /// The source span where the error occurred.
+ SourceSpan get span;
/// A text description of the compile error.
String get message;
diff --git a/pkg/front_end/lib/src/base/analysis_target.dart b/pkg/front_end/lib/src/base/analysis_target.dart
new file mode 100644
index 0000000..ab50efd
--- /dev/null
+++ b/pkg/front_end/lib/src/base/analysis_target.dart
@@ -0,0 +1,26 @@
+// 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:front_end/src/base/source.dart';
+
+/**
+ * An object with which an analysis result can be associated.
+ *
+ * Clients may implement this class when creating new kinds of targets.
+ * Instances of this type are used in hashed data structures, so subtypes are
+ * required to correctly implement [==] and [hashCode].
+ */
+abstract class AnalysisTarget {
+ /**
+ * If this target is associated with a library, return the source of the
+ * library's defining compilation unit; otherwise return `null`.
+ */
+ Source get librarySource;
+
+ /**
+ * Return the source associated with this target, or `null` if this target is
+ * not associated with a source.
+ */
+ Source get source;
+}
diff --git a/pkg/front_end/lib/src/base/errors.dart b/pkg/front_end/lib/src/base/errors.dart
new file mode 100644
index 0000000..d39953f
--- /dev/null
+++ b/pkg/front_end/lib/src/base/errors.dart
@@ -0,0 +1,282 @@
+// 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.
+
+/**
+ * An error code associated with an [AnalysisError].
+ *
+ * Generally, we want to provide messages that consist of three sentences. From
+ * the user's perspective these sentences should explain:
+ *
+ * 1. what is wrong,
+ * 2. why is it wrong, and
+ * 3. how do I fix it.
+ *
+ * However, we combine the first two in the [message] and the last in the
+ * [correction].
+ *
+ * When composing messages (including correction messages) keep the following
+ * guidelines in mind.
+ *
+ * 1. The message should be a complete sentence starting with an uppercase
+ * letter, and ending with a period.
+ *
+ * 2. Reserved words and embedded identifiers should be in single quotes, so
+ * prefer double quotes for the complete message. For example,
+ * ```
+ * "The class '{0}' can't use 'super'."
+ * ```
+ * Notice that the word 'class' in the preceding message is not quoted as it
+ * refers to the concept 'class', not the reserved word. On the other hand,
+ * 'super' refers to the reserved word. Do not quote 'null' and numeric literals.
+ *
+ * 3. Do not try to compose messages, as it can make translating them hard.
+ *
+ * 4. Try to keep the error messages short, but informative.
+ *
+ * 5. Use simple words and terminology, assume the reader of the message doesn't
+ * have an advanced degree in math, and that English is not the reader's native
+ * language. Do not assume any formal computer science training. For example, do
+ * not use Latin abbreviations (prefer "that is" over "i.e.", and "for example"
+ * over "e.g."). Also avoid phrases such as "if and only if" and "iff"; that
+ * level of precision is unnecessary.
+ *
+ * 6. Prefer contractions when they are in common use, for example, prefer
+ * "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is
+ * off-putting to people new to programming.
+ *
+ * 7. Use common terminology, preferably from the Dart Language Specification.
+ * This increases the user's chance of finding a good explanation on the web.
+ *
+ * 8. Do not try to be cute or funny. It is extremely frustrating to work on a
+ * product that crashes with a "tongue-in-cheek" message, especially if you did
+ * not want to use this product to begin with.
+ *
+ * 9. Do not lie, that is, do not write error messages containing phrases like
+ * "can't happen". If the user ever saw this message, it would be a lie. Prefer
+ * messages like: "Internal error: This function should not be called when 'x'
+ * is null.".
+ *
+ * 10. Prefer to not use the imperative tone. That is, the message should not
+ * sound accusing or like it is ordering the user around. The computer should
+ * describe the problem, not criticize the user for violating the specification.
+ */
+abstract class ErrorCode {
+ /**
+ * The name of the error code.
+ */
+ final String name;
+
+ /**
+ * The template used to create the message to be displayed for this error. The
+ * message should indicate what is wrong and why it is wrong.
+ */
+ final String message;
+
+ /**
+ * The template used to create the correction to be displayed for this error,
+ * or `null` if there is no correction information for this error. The
+ * correction should indicate how the user can fix the error.
+ */
+ final String correction;
+
+ /**
+ * Initialize a newly created error code to have the given [name]. The message
+ * associated with the error will be created from the given [message]
+ * template. The correction associated with the error will be created from the
+ * given [correction] template.
+ */
+ const ErrorCode(this.name, this.message, [this.correction]);
+
+ /**
+ * The severity of the error.
+ */
+ ErrorSeverity get errorSeverity;
+
+ /**
+ * The type of the error.
+ */
+ ErrorType get type;
+
+ /**
+ * The unique name of this error code.
+ */
+ String get uniqueName => "$runtimeType.$name";
+
+ @override
+ String toString() => uniqueName;
+}
+
+/**
+ * The severity of an [ErrorCode].
+ */
+class ErrorSeverity implements Comparable<ErrorSeverity> {
+ /**
+ * The severity representing a non-error. This is never used for any error
+ * code, but is useful for clients.
+ */
+ static const ErrorSeverity NONE = const ErrorSeverity('NONE', 0, " ", "none");
+
+ /**
+ * The severity representing an informational level analysis issue.
+ */
+ static const ErrorSeverity INFO = const ErrorSeverity('INFO', 1, "I", "info");
+
+ /**
+ * The severity representing a warning. Warnings can become errors if the `-Werror` command
+ * line flag is specified.
+ */
+ static const ErrorSeverity WARNING =
+ const ErrorSeverity('WARNING', 2, "W", "warning");
+
+ /**
+ * The severity representing an error.
+ */
+ static const ErrorSeverity ERROR =
+ const ErrorSeverity('ERROR', 3, "E", "error");
+
+ static const List<ErrorSeverity> values = const [NONE, INFO, WARNING, ERROR];
+
+ /**
+ * The name of this error code.
+ */
+ final String name;
+
+ /**
+ * The ordinal value of the error code.
+ */
+ final int ordinal;
+
+ /**
+ * The name of the severity used when producing machine output.
+ */
+ final String machineCode;
+
+ /**
+ * The name of the severity used when producing readable output.
+ */
+ final String displayName;
+
+ /**
+ * Initialize a newly created severity with the given names.
+ */
+ const ErrorSeverity(
+ this.name, this.ordinal, this.machineCode, this.displayName);
+
+ @override
+ int get hashCode => ordinal;
+
+ @override
+ int compareTo(ErrorSeverity other) => ordinal - other.ordinal;
+
+ /**
+ * Return the severity constant that represents the greatest severity.
+ */
+ ErrorSeverity max(ErrorSeverity severity) =>
+ this.ordinal >= severity.ordinal ? this : severity;
+
+ @override
+ String toString() => name;
+}
+
+/**
+ * The type of an [ErrorCode].
+ */
+class ErrorType implements Comparable<ErrorType> {
+ /**
+ * Task (todo) comments in user code.
+ */
+ static const ErrorType TODO = const ErrorType('TODO', 0, ErrorSeverity.INFO);
+
+ /**
+ * Extra analysis run over the code to follow best practices, which are not in
+ * the Dart Language Specification.
+ */
+ static const ErrorType HINT = const ErrorType('HINT', 1, ErrorSeverity.INFO);
+
+ /**
+ * Compile-time errors are errors that preclude execution. A compile time
+ * error must be reported by a Dart compiler before the erroneous code is
+ * executed.
+ */
+ static const ErrorType COMPILE_TIME_ERROR =
+ const ErrorType('COMPILE_TIME_ERROR', 2, ErrorSeverity.ERROR);
+
+ /**
+ * Checked mode compile-time errors are errors that preclude execution in
+ * checked mode.
+ */
+ static const ErrorType CHECKED_MODE_COMPILE_TIME_ERROR = const ErrorType(
+ 'CHECKED_MODE_COMPILE_TIME_ERROR', 3, ErrorSeverity.ERROR);
+
+ /**
+ * Static warnings are those warnings reported by the static checker. They
+ * have no effect on execution. Static warnings must be provided by Dart
+ * compilers used during development.
+ */
+ static const ErrorType STATIC_WARNING =
+ const ErrorType('STATIC_WARNING', 4, ErrorSeverity.WARNING);
+
+ /**
+ * Many, but not all, static warnings relate to types, in which case they are
+ * known as static type warnings.
+ */
+ static const ErrorType STATIC_TYPE_WARNING =
+ const ErrorType('STATIC_TYPE_WARNING', 5, ErrorSeverity.WARNING);
+
+ /**
+ * Syntactic errors are errors produced as a result of input that does not
+ * conform to the grammar.
+ */
+ static const ErrorType SYNTACTIC_ERROR =
+ const ErrorType('SYNTACTIC_ERROR', 6, ErrorSeverity.ERROR);
+
+ /**
+ * Lint warnings describe style and best practice recommendations that can be
+ * used to formalize a project's style guidelines.
+ */
+ static const ErrorType LINT = const ErrorType('LINT', 7, ErrorSeverity.INFO);
+
+ static const List<ErrorType> values = const [
+ TODO,
+ HINT,
+ COMPILE_TIME_ERROR,
+ CHECKED_MODE_COMPILE_TIME_ERROR,
+ STATIC_WARNING,
+ STATIC_TYPE_WARNING,
+ SYNTACTIC_ERROR,
+ LINT
+ ];
+
+ /**
+ * The name of this error type.
+ */
+ final String name;
+
+ /**
+ * The ordinal value of the error type.
+ */
+ final int ordinal;
+
+ /**
+ * The severity of this type of error.
+ */
+ final ErrorSeverity severity;
+
+ /**
+ * Initialize a newly created error type to have the given [name] and
+ * [severity].
+ */
+ const ErrorType(this.name, this.ordinal, this.severity);
+
+ String get displayName => name.toLowerCase().replaceAll('_', ' ');
+
+ @override
+ int get hashCode => ordinal;
+
+ @override
+ int compareTo(ErrorType other) => ordinal - other.ordinal;
+
+ @override
+ String toString() => name;
+}
diff --git a/pkg/front_end/lib/src/base/jenkins_smi_hash.dart b/pkg/front_end/lib/src/base/jenkins_smi_hash.dart
new file mode 100644
index 0000000..8901ba4
--- /dev/null
+++ b/pkg/front_end/lib/src/base/jenkins_smi_hash.dart
@@ -0,0 +1,53 @@
+// 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.
+
+/// Jenkins hash function, optimized for small integers.
+///
+/// Static methods borrowed from sdk/lib/math/jenkins_smi_hash.dart. Non-static
+/// methods are an enhancement for the "front_end" package.
+///
+/// Where performance is critical, use [hash2], [hash3], or [hash4], or the
+/// pattern `finish(combine(combine(...combine(0, a), b)..., z))`, where a..z
+/// are hash codes to be combined.
+///
+/// For ease of use, you may also use this pattern:
+/// `(new JenkinsSmiHash()..add(a)..add(b)....add(z)).hashCode`, where a..z are
+/// the sub-objects whose hashes should be combined. This pattern performs the
+/// same operations as the performance critical variant, but allocates an extra
+/// object.
+class JenkinsSmiHash {
+ /// Accumulates the hash code [value] into the running hash [hash].
+ static int combine(int hash, int value) {
+ hash = 0x1fffffff & (hash + value);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ return hash ^ (hash >> 6);
+ }
+
+ /// Finalizes a running hash produced by [combine].
+ static int finish(int hash) {
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+
+ /// Combines together two hash codes.
+ static int hash2(a, b) => finish(combine(combine(0, a), b));
+
+ /// Combines together three hash codes.
+ static int hash3(a, b, c) => finish(combine(combine(combine(0, a), b), c));
+
+ /// Combines together four hash codes.
+ static int hash4(a, b, c, d) =>
+ finish(combine(combine(combine(combine(0, a), b), c), d));
+
+ int _hash = 0;
+
+ /// Accumulates the object [o] into the hash.
+ void add(Object o) {
+ _hash = combine(_hash, o.hashCode);
+ }
+
+ /// Finalizes the hash and return the resulting hashcode.
+ int get hashCode => finish(_hash);
+}
diff --git a/pkg/front_end/lib/src/base/source.dart b/pkg/front_end/lib/src/base/source.dart
new file mode 100644
index 0000000..0ed4747
--- /dev/null
+++ b/pkg/front_end/lib/src/base/source.dart
@@ -0,0 +1,148 @@
+// 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:front_end/src/base/analysis_target.dart';
+import 'package:front_end/src/base/timestamped_data.dart';
+import 'package:front_end/src/base/uri_kind.dart';
+
+/**
+ * The interface `Source` defines the behavior of objects representing source code that can be
+ * analyzed by the analysis engine.
+ *
+ * Implementations of this interface need to be aware of some assumptions made by the analysis
+ * engine concerning sources:
+ * * Sources are not required to be unique. That is, there can be multiple instances representing
+ * the same source.
+ * * Sources are long lived. That is, the engine is allowed to hold on to a source for an extended
+ * period of time and that source must continue to report accurate and up-to-date information.
+ * Because of these assumptions, most implementations will not maintain any state but will delegate
+ * to an authoritative system of record in order to implement this API. For example, a source that
+ * represents files on disk would typically query the file system to determine the state of the
+ * file.
+ *
+ * If the instances that implement this API are the system of record, then they will typically be
+ * unique. In that case, sources that are created that represent non-existent files must also be
+ * retained so that if those files are created at a later date the long-lived sources representing
+ * those files will know that they now exist.
+ */
+abstract class Source implements AnalysisTarget {
+ /**
+ * An empty list of sources.
+ */
+ static const List<Source> EMPTY_LIST = const <Source>[];
+
+ /**
+ * Get the contents and timestamp of this source.
+ *
+ * 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.
+ *
+ * @return the contents and timestamp of the source
+ * @throws Exception if the contents of this source could not be accessed
+ */
+ TimestampedData<String> get contents;
+
+ /**
+ * Return an encoded representation of this source that can be used to create a source that is
+ * equal to this source.
+ *
+ * @return an encoded representation of this source
+ * See [SourceFactory.fromEncoding].
+ */
+ String get encoding;
+
+ /**
+ * Return the full (long) version of the name that can be displayed to the user to denote this
+ * source. For example, for a source representing a file this would typically be the absolute path
+ * of the file.
+ *
+ * @return a name that can be displayed to the user to denote this source
+ */
+ String get fullName;
+
+ /**
+ * Return a hash code for this source.
+ *
+ * @return a hash code for this source
+ * See [Object.hashCode].
+ */
+ @override
+ int get hashCode;
+
+ /**
+ * Return `true` if this source is in one of the system libraries.
+ *
+ * @return `true` if this is in a system library
+ */
+ bool get isInSystemLibrary;
+
+ @override
+ Source get librarySource => null;
+
+ /**
+ * Return the modification stamp for this source, or a negative value if the
+ * source does not exist. A modification stamp is a non-negative integer with
+ * the property that if the contents of the source have not been modified
+ * since the last time the modification stamp was accessed then the same value
+ * 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 method
+ * [AnalysisContext.getModificationStamp] because contexts can have local
+ * overrides of the content of a source that the source is not aware of.
+ */
+ int get modificationStamp;
+
+ /**
+ * Return a short version of the name that can be displayed to the user to denote this source. For
+ * example, for a source representing a file this would typically be the name of the file.
+ *
+ * @return a name that can be displayed to the user to denote this source
+ */
+ String get shortName;
+
+ @override
+ Source get source => this;
+
+ /**
+ * Return the URI from which this source was originally derived.
+ *
+ * @return the URI from which this source was originally derived
+ */
+ Uri get uri;
+
+ /**
+ * Return the kind of URI from which this source was originally derived. If this source was
+ * created from an absolute URI, then the returned kind will reflect the scheme of the absolute
+ * URI. If it was created from a relative URI, then the returned kind will be the same as the kind
+ * of the source against which the relative URI was resolved.
+ *
+ * @return the kind of URI from which this source was originally derived
+ */
+ UriKind get uriKind;
+
+ /**
+ * Return `true` if the given object is a source that represents the same source code as
+ * this source.
+ *
+ * @param object the object to be compared with this object
+ * @return `true` if the given object is a source that represents the same source code as
+ * this source
+ * See [Object.==].
+ */
+ @override
+ bool operator ==(Object object);
+
+ /**
+ * Return `true` if this source exists.
+ *
+ * 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.
+ *
+ * @return `true` if this source exists
+ */
+ bool exists();
+}
diff --git a/pkg/front_end/lib/src/scanner/syntactic_entity.dart b/pkg/front_end/lib/src/base/syntactic_entity.dart
similarity index 100%
rename from pkg/front_end/lib/src/scanner/syntactic_entity.dart
rename to pkg/front_end/lib/src/base/syntactic_entity.dart
diff --git a/pkg/front_end/lib/src/base/timestamped_data.dart b/pkg/front_end/lib/src/base/timestamped_data.dart
new file mode 100644
index 0000000..4c76dc5
--- /dev/null
+++ b/pkg/front_end/lib/src/base/timestamped_data.dart
@@ -0,0 +1,24 @@
+// 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.
+
+/**
+ * Analysis data for which we have a modification time.
+ */
+class TimestampedData<E> {
+ /**
+ * The modification time of the source from which the data was created.
+ */
+ final int modificationTime;
+
+ /**
+ * The data that was created from the source.
+ */
+ final E data;
+
+ /**
+ * Initialize a newly created holder to associate the given [data] with the
+ * given [modificationTime].
+ */
+ TimestampedData(this.modificationTime, this.data);
+}
diff --git a/pkg/front_end/lib/src/base/uri_kind.dart b/pkg/front_end/lib/src/base/uri_kind.dart
new file mode 100644
index 0000000..0e6d007
--- /dev/null
+++ b/pkg/front_end/lib/src/base/uri_kind.dart
@@ -0,0 +1,87 @@
+// 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.
+
+/**
+ * The enumeration `UriKind` defines the different kinds of URI's that are known to the
+ * analysis engine. These are used to keep track of the kind of URI associated with a given source.
+ */
+class UriKind implements Comparable<UriKind> {
+ /**
+ * A 'dart:' URI.
+ */
+ static const UriKind DART_URI = const UriKind('DART_URI', 0, 0x64);
+
+ /**
+ * A 'file:' URI.
+ */
+ static const UriKind FILE_URI = const UriKind('FILE_URI', 1, 0x66);
+
+ /**
+ * A 'package:' URI.
+ */
+ static const UriKind PACKAGE_URI = const UriKind('PACKAGE_URI', 2, 0x70);
+
+ static const List<UriKind> values = const [DART_URI, FILE_URI, PACKAGE_URI];
+
+ /**
+ * The name of this URI kind.
+ */
+ final String name;
+
+ /**
+ * The ordinal value of the URI kind.
+ */
+ final int ordinal;
+
+ /**
+ * The single character encoding used to identify this kind of URI.
+ */
+ final int encoding;
+
+ /**
+ * Initialize a newly created URI kind to have the given encoding.
+ */
+ const UriKind(this.name, this.ordinal, this.encoding);
+
+ @override
+ int get hashCode => ordinal;
+
+ @override
+ int compareTo(UriKind other) => ordinal - other.ordinal;
+
+ @override
+ String toString() => name;
+
+ /**
+ * Return the URI kind represented by the given [encoding], or `null` if there
+ * is no kind with the given encoding.
+ */
+ static UriKind fromEncoding(int encoding) {
+ while (true) {
+ if (encoding == 0x64) {
+ return DART_URI;
+ } else if (encoding == 0x66) {
+ return FILE_URI;
+ } else if (encoding == 0x70) {
+ return PACKAGE_URI;
+ }
+ break;
+ }
+ return null;
+ }
+
+ /**
+ * Return the URI kind corresponding to the given scheme string.
+ */
+ static UriKind fromScheme(String scheme) {
+ if (scheme == 'package') {
+ return UriKind.PACKAGE_URI;
+ } else if (scheme == 'dart') {
+ return UriKind.DART_URI;
+ } else if (scheme == 'file') {
+ return UriKind.FILE_URI;
+ }
+ return UriKind.FILE_URI;
+ }
+}
diff --git a/pkg/front_end/lib/src/scanner/errors.dart b/pkg/front_end/lib/src/scanner/errors.dart
index e5f66de..bcf0c56 100644
--- a/pkg/front_end/lib/src/scanner/errors.dart
+++ b/pkg/front_end/lib/src/scanner/errors.dart
@@ -2,284 +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.
-/**
- * An error code associated with an [AnalysisError].
- *
- * Generally, we want to provide messages that consist of three sentences. From
- * the user's perspective these sentences should explain:
- *
- * 1. what is wrong,
- * 2. why is it wrong, and
- * 3. how do I fix it.
- *
- * However, we combine the first two in the [message] and the last in the
- * [correction].
- *
- * When composing messages (including correction messages) keep the following
- * guidelines in mind.
- *
- * 1. The message should be a complete sentence starting with an uppercase
- * letter, and ending with a period.
- *
- * 2. Reserved words and embedded identifiers should be in single quotes, so
- * prefer double quotes for the complete message. For example,
- * ```
- * "The class '{0}' can't use 'super'."
- * ```
- * Notice that the word 'class' in the preceding message is not quoted as it
- * refers to the concept 'class', not the reserved word. On the other hand,
- * 'super' refers to the reserved word. Do not quote 'null' and numeric literals.
- *
- * 3. Do not try to compose messages, as it can make translating them hard.
- *
- * 4. Try to keep the error messages short, but informative.
- *
- * 5. Use simple words and terminology, assume the reader of the message doesn't
- * have an advanced degree in math, and that English is not the reader's native
- * language. Do not assume any formal computer science training. For example, do
- * not use Latin abbreviations (prefer "that is" over "i.e.", and "for example"
- * over "e.g."). Also avoid phrases such as "if and only if" and "iff"; that
- * level of precision is unnecessary.
- *
- * 6. Prefer contractions when they are in common use, for example, prefer
- * "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is
- * off-putting to people new to programming.
- *
- * 7. Use common terminology, preferably from the Dart Language Specification.
- * This increases the user's chance of finding a good explanation on the web.
- *
- * 8. Do not try to be cute or funny. It is extremely frustrating to work on a
- * product that crashes with a "tongue-in-cheek" message, especially if you did
- * not want to use this product to begin with.
- *
- * 9. Do not lie, that is, do not write error messages containing phrases like
- * "can't happen". If the user ever saw this message, it would be a lie. Prefer
- * messages like: "Internal error: This function should not be called when 'x'
- * is null.".
- *
- * 10. Prefer to not use the imperative tone. That is, the message should not
- * sound accusing or like it is ordering the user around. The computer should
- * describe the problem, not criticize the user for violating the specification.
- */
-abstract class ErrorCode {
- /**
- * The name of the error code.
- */
- final String name;
-
- /**
- * The template used to create the message to be displayed for this error. The
- * message should indicate what is wrong and why it is wrong.
- */
- final String message;
-
- /**
- * The template used to create the correction to be displayed for this error,
- * or `null` if there is no correction information for this error. The
- * correction should indicate how the user can fix the error.
- */
- final String correction;
-
- /**
- * Initialize a newly created error code to have the given [name]. The message
- * associated with the error will be created from the given [message]
- * template. The correction associated with the error will be created from the
- * given [correction] template.
- */
- const ErrorCode(this.name, this.message, [this.correction]);
-
- /**
- * The severity of the error.
- */
- ErrorSeverity get errorSeverity;
-
- /**
- * The type of the error.
- */
- ErrorType get type;
-
- /**
- * The unique name of this error code.
- */
- String get uniqueName => "$runtimeType.$name";
-
- @override
- String toString() => uniqueName;
-}
-
-/**
- * The severity of an [ErrorCode].
- */
-class ErrorSeverity implements Comparable<ErrorSeverity> {
- /**
- * The severity representing a non-error. This is never used for any error
- * code, but is useful for clients.
- */
- static const ErrorSeverity NONE = const ErrorSeverity('NONE', 0, " ", "none");
-
- /**
- * The severity representing an informational level analysis issue.
- */
- static const ErrorSeverity INFO = const ErrorSeverity('INFO', 1, "I", "info");
-
- /**
- * The severity representing a warning. Warnings can become errors if the `-Werror` command
- * line flag is specified.
- */
- static const ErrorSeverity WARNING =
- const ErrorSeverity('WARNING', 2, "W", "warning");
-
- /**
- * The severity representing an error.
- */
- static const ErrorSeverity ERROR =
- const ErrorSeverity('ERROR', 3, "E", "error");
-
- static const List<ErrorSeverity> values = const [NONE, INFO, WARNING, ERROR];
-
- /**
- * The name of this error code.
- */
- final String name;
-
- /**
- * The ordinal value of the error code.
- */
- final int ordinal;
-
- /**
- * The name of the severity used when producing machine output.
- */
- final String machineCode;
-
- /**
- * The name of the severity used when producing readable output.
- */
- final String displayName;
-
- /**
- * Initialize a newly created severity with the given names.
- */
- const ErrorSeverity(
- this.name, this.ordinal, this.machineCode, this.displayName);
-
- @override
- int get hashCode => ordinal;
-
- @override
- int compareTo(ErrorSeverity other) => ordinal - other.ordinal;
-
- /**
- * Return the severity constant that represents the greatest severity.
- */
- ErrorSeverity max(ErrorSeverity severity) =>
- this.ordinal >= severity.ordinal ? this : severity;
-
- @override
- String toString() => name;
-}
-
-/**
- * The type of an [ErrorCode].
- */
-class ErrorType implements Comparable<ErrorType> {
- /**
- * Task (todo) comments in user code.
- */
- static const ErrorType TODO = const ErrorType('TODO', 0, ErrorSeverity.INFO);
-
- /**
- * Extra analysis run over the code to follow best practices, which are not in
- * the Dart Language Specification.
- */
- static const ErrorType HINT = const ErrorType('HINT', 1, ErrorSeverity.INFO);
-
- /**
- * Compile-time errors are errors that preclude execution. A compile time
- * error must be reported by a Dart compiler before the erroneous code is
- * executed.
- */
- static const ErrorType COMPILE_TIME_ERROR =
- const ErrorType('COMPILE_TIME_ERROR', 2, ErrorSeverity.ERROR);
-
- /**
- * Checked mode compile-time errors are errors that preclude execution in
- * checked mode.
- */
- static const ErrorType CHECKED_MODE_COMPILE_TIME_ERROR = const ErrorType(
- 'CHECKED_MODE_COMPILE_TIME_ERROR', 3, ErrorSeverity.ERROR);
-
- /**
- * Static warnings are those warnings reported by the static checker. They
- * have no effect on execution. Static warnings must be provided by Dart
- * compilers used during development.
- */
- static const ErrorType STATIC_WARNING =
- const ErrorType('STATIC_WARNING', 4, ErrorSeverity.WARNING);
-
- /**
- * Many, but not all, static warnings relate to types, in which case they are
- * known as static type warnings.
- */
- static const ErrorType STATIC_TYPE_WARNING =
- const ErrorType('STATIC_TYPE_WARNING', 5, ErrorSeverity.WARNING);
-
- /**
- * Syntactic errors are errors produced as a result of input that does not
- * conform to the grammar.
- */
- static const ErrorType SYNTACTIC_ERROR =
- const ErrorType('SYNTACTIC_ERROR', 6, ErrorSeverity.ERROR);
-
- /**
- * Lint warnings describe style and best practice recommendations that can be
- * used to formalize a project's style guidelines.
- */
- static const ErrorType LINT = const ErrorType('LINT', 7, ErrorSeverity.INFO);
-
- static const List<ErrorType> values = const [
- TODO,
- HINT,
- COMPILE_TIME_ERROR,
- CHECKED_MODE_COMPILE_TIME_ERROR,
- STATIC_WARNING,
- STATIC_TYPE_WARNING,
- SYNTACTIC_ERROR,
- LINT
- ];
-
- /**
- * The name of this error type.
- */
- final String name;
-
- /**
- * The ordinal value of the error type.
- */
- final int ordinal;
-
- /**
- * The severity of this type of error.
- */
- final ErrorSeverity severity;
-
- /**
- * Initialize a newly created error type to have the given [name] and
- * [severity].
- */
- const ErrorType(this.name, this.ordinal, this.severity);
-
- String get displayName => name.toLowerCase().replaceAll('_', ' ');
-
- @override
- int get hashCode => ordinal;
-
- @override
- int compareTo(ErrorType other) => ordinal - other.ordinal;
-
- @override
- String toString() => name;
-}
+import 'package:front_end/src/base/errors.dart';
/**
* The error codes used for errors detected by the scanner.
diff --git a/pkg/front_end/lib/src/scanner/reader.dart b/pkg/front_end/lib/src/scanner/reader.dart
index ee9d6c0..b079139 100644
--- a/pkg/front_end/lib/src/scanner/reader.dart
+++ b/pkg/front_end/lib/src/scanner/reader.dart
@@ -42,3 +42,92 @@
*/
int peek();
}
+
+/**
+ * A [CharacterReader] that reads characters from a character sequence.
+ */
+class CharSequenceReader implements CharacterReader {
+ /**
+ * The sequence from which characters will be read.
+ */
+ final String _sequence;
+
+ /**
+ * The number of characters in the string.
+ */
+ int _stringLength;
+
+ /**
+ * The index, relative to the string, of the next character to be read.
+ */
+ int _charOffset;
+
+ /**
+ * Initialize a newly created reader to read the characters in the given
+ * [_sequence].
+ */
+ CharSequenceReader(this._sequence) {
+ this._stringLength = _sequence.length;
+ this._charOffset = 0;
+ }
+
+ @override
+ int get offset => _charOffset - 1;
+
+ @override
+ void set offset(int offset) {
+ _charOffset = offset + 1;
+ }
+
+ @override
+ int advance() {
+ if (_charOffset >= _stringLength) {
+ return -1;
+ }
+ return _sequence.codeUnitAt(_charOffset++);
+ }
+
+ @override
+ String getString(int start, int endDelta) =>
+ _sequence.substring(start, _charOffset + endDelta);
+
+ @override
+ int peek() {
+ if (_charOffset >= _stringLength) {
+ return -1;
+ }
+ return _sequence.codeUnitAt(_charOffset);
+ }
+}
+
+/**
+ * A [CharacterReader] that reads characters from a character sequence, but adds
+ * a delta when reporting the current character offset so that the character
+ * sequence can be a subsequence from a larger sequence.
+ */
+class SubSequenceReader extends CharSequenceReader {
+ /**
+ * The offset from the beginning of the file to the beginning of the source
+ * being scanned.
+ */
+ final int _offsetDelta;
+
+ /**
+ * Initialize a newly created reader to read the characters in the given
+ * [sequence]. The [_offsetDelta] is the offset from the beginning of the file
+ * to the beginning of the source being scanned
+ */
+ SubSequenceReader(String sequence, this._offsetDelta) : super(sequence);
+
+ @override
+ int get offset => _offsetDelta + super.offset;
+
+ @override
+ void set offset(int offset) {
+ super.offset = offset - _offsetDelta;
+ }
+
+ @override
+ String getString(int start, int endDelta) =>
+ super.getString(start - _offsetDelta, endDelta);
+}
diff --git a/pkg/front_end/lib/src/scanner/token.dart b/pkg/front_end/lib/src/scanner/token.dart
index 10d4924..95c1005 100644
--- a/pkg/front_end/lib/src/scanner/token.dart
+++ b/pkg/front_end/lib/src/scanner/token.dart
@@ -6,11 +6,10 @@
* Defines the tokens that are produced by the scanner, used by the parser, and
* referenced from the [AST structure](ast.dart).
*/
-
import 'dart:collection';
+import 'package:front_end/src/base/syntactic_entity.dart';
import 'package:front_end/src/scanner/string_utilities.dart';
-import 'package:front_end/src/scanner/syntactic_entity.dart';
/**
* The opening half of a grouping pair of tokens. This is used for curly
diff --git a/pkg/front_end/test/scanner_test.dart b/pkg/front_end/test/scanner_test.dart
new file mode 100644
index 0000000..69e802d
--- /dev/null
+++ b/pkg/front_end/test/scanner_test.dart
@@ -0,0 +1,1298 @@
+// 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:front_end/src/base/errors.dart';
+import 'package:front_end/src/base/jenkins_smi_hash.dart';
+import 'package:front_end/src/scanner/errors.dart';
+import 'package:front_end/src/scanner/reader.dart';
+import 'package:front_end/src/scanner/scanner.dart';
+import 'package:front_end/src/scanner/token.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(CharSequenceReaderTest);
+ defineReflectiveTests(KeywordStateTest);
+ defineReflectiveTests(ScannerTest);
+ defineReflectiveTests(TokenTypeTest);
+ });
+}
+
+@reflectiveTest
+class CharSequenceReaderTest {
+ void test_advance() {
+ CharSequenceReader reader = new CharSequenceReader("x");
+ expect(reader.advance(), 0x78);
+ expect(reader.advance(), -1);
+ expect(reader.advance(), -1);
+ }
+
+ void test_creation() {
+ expect(new CharSequenceReader("x"), isNotNull);
+ }
+
+ void test_getOffset() {
+ CharSequenceReader reader = new CharSequenceReader("x");
+ expect(reader.offset, -1);
+ reader.advance();
+ expect(reader.offset, 0);
+ reader.advance();
+ expect(reader.offset, 0);
+ }
+
+ void test_getString() {
+ CharSequenceReader reader = new CharSequenceReader("xyzzy");
+ reader.offset = 3;
+ expect(reader.getString(1, 0), "yzz");
+ expect(reader.getString(2, 1), "zzy");
+ }
+
+ void test_peek() {
+ CharSequenceReader reader = new CharSequenceReader("xy");
+ expect(reader.peek(), 0x78);
+ expect(reader.peek(), 0x78);
+ reader.advance();
+ expect(reader.peek(), 0x79);
+ expect(reader.peek(), 0x79);
+ reader.advance();
+ expect(reader.peek(), -1);
+ expect(reader.peek(), -1);
+ }
+
+ void test_setOffset() {
+ CharSequenceReader reader = new CharSequenceReader("xyz");
+ reader.offset = 2;
+ expect(reader.offset, 2);
+ }
+}
+
+@reflectiveTest
+class KeywordStateTest {
+ void test_KeywordState() {
+ //
+ // Generate the test data to be scanned.
+ //
+ List<Keyword> keywords = Keyword.values;
+ int keywordCount = keywords.length;
+ List<String> textToTest = new List<String>(keywordCount * 3);
+ for (int i = 0; i < keywordCount; i++) {
+ String syntax = keywords[i].syntax;
+ textToTest[i] = syntax;
+ textToTest[i + keywordCount] = "${syntax}x";
+ textToTest[i + keywordCount * 2] = syntax.substring(0, syntax.length - 1);
+ }
+ //
+ // Scan each of the identifiers.
+ //
+ KeywordState firstState = KeywordState.KEYWORD_STATE;
+ for (int i = 0; i < textToTest.length; i++) {
+ String text = textToTest[i];
+ int index = 0;
+ int length = text.length;
+ KeywordState state = firstState;
+ while (index < length && state != null) {
+ state = state.next(text.codeUnitAt(index));
+ index++;
+ }
+ if (i < keywordCount) {
+ // keyword
+ expect(state, isNotNull);
+ expect(state.keyword(), isNotNull);
+ expect(state.keyword(), keywords[i]);
+ } else if (i < keywordCount * 2) {
+ // keyword + "x"
+ expect(state, isNull);
+ } else {
+ // keyword.substring(0, keyword.length() - 1)
+ expect(state, isNotNull);
+ }
+ }
+ }
+}
+
+@reflectiveTest
+class ScannerTest {
+ void fail_incomplete_string_interpolation() {
+ // https://code.google.com/p/dart/issues/detail?id=18073
+ _assertErrorAndTokens(
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9, "\"foo \${bar", [
+ new StringToken(TokenType.STRING, "\"foo ", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5),
+ new StringToken(TokenType.IDENTIFIER, "bar", 7)
+ ]);
+ }
+
+ void test_ampersand() {
+ _assertToken(TokenType.AMPERSAND, "&");
+ }
+
+ void test_ampersand_ampersand() {
+ _assertToken(TokenType.AMPERSAND_AMPERSAND, "&&");
+ }
+
+ void test_ampersand_ampersand_eq() {
+ _assertToken(TokenType.AMPERSAND_AMPERSAND_EQ, "&&=",
+ lazyAssignmentOperators: true);
+ }
+
+ void test_ampersand_eq() {
+ _assertToken(TokenType.AMPERSAND_EQ, "&=");
+ }
+
+ void test_at() {
+ _assertToken(TokenType.AT, "@");
+ }
+
+ void test_backping() {
+ _assertToken(TokenType.BACKPING, "`");
+ }
+
+ void test_backslash() {
+ _assertToken(TokenType.BACKSLASH, "\\");
+ }
+
+ void test_bang() {
+ _assertToken(TokenType.BANG, "!");
+ }
+
+ void test_bang_eq() {
+ _assertToken(TokenType.BANG_EQ, "!=");
+ }
+
+ void test_bar() {
+ _assertToken(TokenType.BAR, "|");
+ }
+
+ void test_bar_bar() {
+ _assertToken(TokenType.BAR_BAR, "||");
+ }
+
+ void test_bar_bar_eq() {
+ _assertToken(TokenType.BAR_BAR_EQ, "||=", lazyAssignmentOperators: true);
+ }
+
+ void test_bar_eq() {
+ _assertToken(TokenType.BAR_EQ, "|=");
+ }
+
+ void test_caret() {
+ _assertToken(TokenType.CARET, "^");
+ }
+
+ void test_caret_eq() {
+ _assertToken(TokenType.CARET_EQ, "^=");
+ }
+
+ void test_close_curly_bracket() {
+ _assertToken(TokenType.CLOSE_CURLY_BRACKET, "}");
+ }
+
+ void test_close_paren() {
+ _assertToken(TokenType.CLOSE_PAREN, ")");
+ }
+
+ void test_close_quare_bracket() {
+ _assertToken(TokenType.CLOSE_SQUARE_BRACKET, "]");
+ }
+
+ void test_colon() {
+ _assertToken(TokenType.COLON, ":");
+ }
+
+ void test_comma() {
+ _assertToken(TokenType.COMMA, ",");
+ }
+
+ void test_comment_disabled_multi() {
+ Scanner scanner =
+ new _TestScanner(new CharSequenceReader("/* comment */ "));
+ scanner.preserveComments = false;
+ Token token = scanner.tokenize();
+ expect(token, isNotNull);
+ expect(token.precedingComments, isNull);
+ }
+
+ void test_comment_generic_method_type_assign() {
+ _assertComment(TokenType.MULTI_LINE_COMMENT, "/*=comment*/");
+ _assertComment(TokenType.GENERIC_METHOD_TYPE_ASSIGN, "/*=comment*/",
+ genericMethodComments: true);
+ }
+
+ void test_comment_generic_method_type_list() {
+ _assertComment(TokenType.MULTI_LINE_COMMENT, "/*<comment>*/");
+ _assertComment(TokenType.GENERIC_METHOD_TYPE_LIST, "/*<comment>*/",
+ genericMethodComments: true);
+ }
+
+ void test_comment_multi() {
+ _assertComment(TokenType.MULTI_LINE_COMMENT, "/* comment */");
+ }
+
+ void test_comment_multi_lineEnds() {
+ String code = r'''
+/**
+ * aa
+ * bbb
+ * c
+ */''';
+ _ErrorListener listener = new _ErrorListener();
+ Scanner scanner = new _TestScanner(new CharSequenceReader(code), listener);
+ scanner.tokenize();
+ expect(
+ scanner.lineStarts,
+ equals(<int>[
+ code.indexOf('/**'),
+ code.indexOf(' * aa'),
+ code.indexOf(' * bbb'),
+ code.indexOf(' * c'),
+ code.indexOf(' */')
+ ]));
+ }
+
+ void test_comment_multi_unterminated() {
+ _assertError(ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT, 3, "/* x");
+ }
+
+ void test_comment_nested() {
+ _assertComment(
+ TokenType.MULTI_LINE_COMMENT, "/* comment /* within a */ comment */");
+ }
+
+ void test_comment_single() {
+ _assertComment(TokenType.SINGLE_LINE_COMMENT, "// comment");
+ }
+
+ void test_double_both_E() {
+ _assertToken(TokenType.DOUBLE, "0.123E4");
+ }
+
+ void test_double_both_e() {
+ _assertToken(TokenType.DOUBLE, "0.123e4");
+ }
+
+ void test_double_fraction() {
+ _assertToken(TokenType.DOUBLE, ".123");
+ }
+
+ void test_double_fraction_E() {
+ _assertToken(TokenType.DOUBLE, ".123E4");
+ }
+
+ void test_double_fraction_e() {
+ _assertToken(TokenType.DOUBLE, ".123e4");
+ }
+
+ void test_double_missingDigitInExponent() {
+ _assertError(ScannerErrorCode.MISSING_DIGIT, 1, "1e");
+ }
+
+ void test_double_whole_E() {
+ _assertToken(TokenType.DOUBLE, "12E4");
+ }
+
+ void test_double_whole_e() {
+ _assertToken(TokenType.DOUBLE, "12e4");
+ }
+
+ void test_eq() {
+ _assertToken(TokenType.EQ, "=");
+ }
+
+ void test_eq_eq() {
+ _assertToken(TokenType.EQ_EQ, "==");
+ }
+
+ void test_gt() {
+ _assertToken(TokenType.GT, ">");
+ }
+
+ void test_gt_eq() {
+ _assertToken(TokenType.GT_EQ, ">=");
+ }
+
+ void test_gt_gt() {
+ _assertToken(TokenType.GT_GT, ">>");
+ }
+
+ void test_gt_gt_eq() {
+ _assertToken(TokenType.GT_GT_EQ, ">>=");
+ }
+
+ void test_hash() {
+ _assertToken(TokenType.HASH, "#");
+ }
+
+ void test_hexidecimal() {
+ _assertToken(TokenType.HEXADECIMAL, "0x1A2B3C");
+ }
+
+ void test_hexidecimal_missingDigit() {
+ _assertError(ScannerErrorCode.MISSING_HEX_DIGIT, 1, "0x");
+ }
+
+ void test_identifier() {
+ _assertToken(TokenType.IDENTIFIER, "result");
+ }
+
+ void test_illegalChar_cyrillicLetter_middle() {
+ _assertError(
+ ScannerErrorCode.ILLEGAL_CHARACTER, 5, "Shche\u0433lov", [0x433]);
+ }
+
+ void test_illegalChar_cyrillicLetter_start() {
+ _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0429", [0x429]);
+ }
+
+ void test_illegalChar_nbsp() {
+ _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u00A0", [0xa0]);
+ }
+
+ void test_illegalChar_notLetter() {
+ _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0312", [0x312]);
+ }
+
+ void test_index() {
+ _assertToken(TokenType.INDEX, "[]");
+ }
+
+ void test_index_eq() {
+ _assertToken(TokenType.INDEX_EQ, "[]=");
+ }
+
+ void test_int() {
+ _assertToken(TokenType.INT, "123");
+ }
+
+ void test_int_initialZero() {
+ _assertToken(TokenType.INT, "0123");
+ }
+
+ void test_keyword_abstract() {
+ _assertKeywordToken("abstract");
+ }
+
+ void test_keyword_as() {
+ _assertKeywordToken("as");
+ }
+
+ void test_keyword_assert() {
+ _assertKeywordToken("assert");
+ }
+
+ void test_keyword_break() {
+ _assertKeywordToken("break");
+ }
+
+ void test_keyword_case() {
+ _assertKeywordToken("case");
+ }
+
+ void test_keyword_catch() {
+ _assertKeywordToken("catch");
+ }
+
+ void test_keyword_class() {
+ _assertKeywordToken("class");
+ }
+
+ void test_keyword_const() {
+ _assertKeywordToken("const");
+ }
+
+ void test_keyword_continue() {
+ _assertKeywordToken("continue");
+ }
+
+ void test_keyword_default() {
+ _assertKeywordToken("default");
+ }
+
+ void test_keyword_deferred() {
+ _assertKeywordToken("deferred");
+ }
+
+ void test_keyword_do() {
+ _assertKeywordToken("do");
+ }
+
+ void test_keyword_dynamic() {
+ _assertKeywordToken("dynamic");
+ }
+
+ void test_keyword_else() {
+ _assertKeywordToken("else");
+ }
+
+ void test_keyword_enum() {
+ _assertKeywordToken("enum");
+ }
+
+ void test_keyword_export() {
+ _assertKeywordToken("export");
+ }
+
+ void test_keyword_extends() {
+ _assertKeywordToken("extends");
+ }
+
+ void test_keyword_factory() {
+ _assertKeywordToken("factory");
+ }
+
+ void test_keyword_false() {
+ _assertKeywordToken("false");
+ }
+
+ void test_keyword_final() {
+ _assertKeywordToken("final");
+ }
+
+ void test_keyword_finally() {
+ _assertKeywordToken("finally");
+ }
+
+ void test_keyword_for() {
+ _assertKeywordToken("for");
+ }
+
+ void test_keyword_get() {
+ _assertKeywordToken("get");
+ }
+
+ void test_keyword_if() {
+ _assertKeywordToken("if");
+ }
+
+ void test_keyword_implements() {
+ _assertKeywordToken("implements");
+ }
+
+ void test_keyword_import() {
+ _assertKeywordToken("import");
+ }
+
+ void test_keyword_in() {
+ _assertKeywordToken("in");
+ }
+
+ void test_keyword_is() {
+ _assertKeywordToken("is");
+ }
+
+ void test_keyword_library() {
+ _assertKeywordToken("library");
+ }
+
+ void test_keyword_new() {
+ _assertKeywordToken("new");
+ }
+
+ void test_keyword_null() {
+ _assertKeywordToken("null");
+ }
+
+ void test_keyword_operator() {
+ _assertKeywordToken("operator");
+ }
+
+ void test_keyword_part() {
+ _assertKeywordToken("part");
+ }
+
+ void test_keyword_rethrow() {
+ _assertKeywordToken("rethrow");
+ }
+
+ void test_keyword_return() {
+ _assertKeywordToken("return");
+ }
+
+ void test_keyword_set() {
+ _assertKeywordToken("set");
+ }
+
+ void test_keyword_static() {
+ _assertKeywordToken("static");
+ }
+
+ void test_keyword_super() {
+ _assertKeywordToken("super");
+ }
+
+ void test_keyword_switch() {
+ _assertKeywordToken("switch");
+ }
+
+ void test_keyword_this() {
+ _assertKeywordToken("this");
+ }
+
+ void test_keyword_throw() {
+ _assertKeywordToken("throw");
+ }
+
+ void test_keyword_true() {
+ _assertKeywordToken("true");
+ }
+
+ void test_keyword_try() {
+ _assertKeywordToken("try");
+ }
+
+ void test_keyword_typedef() {
+ _assertKeywordToken("typedef");
+ }
+
+ void test_keyword_var() {
+ _assertKeywordToken("var");
+ }
+
+ void test_keyword_void() {
+ _assertKeywordToken("void");
+ }
+
+ void test_keyword_while() {
+ _assertKeywordToken("while");
+ }
+
+ void test_keyword_with() {
+ _assertKeywordToken("with");
+ }
+
+ void test_lt() {
+ _assertToken(TokenType.LT, "<");
+ }
+
+ void test_lt_eq() {
+ _assertToken(TokenType.LT_EQ, "<=");
+ }
+
+ void test_lt_lt() {
+ _assertToken(TokenType.LT_LT, "<<");
+ }
+
+ void test_lt_lt_eq() {
+ _assertToken(TokenType.LT_LT_EQ, "<<=");
+ }
+
+ void test_minus() {
+ _assertToken(TokenType.MINUS, "-");
+ }
+
+ void test_minus_eq() {
+ _assertToken(TokenType.MINUS_EQ, "-=");
+ }
+
+ void test_minus_minus() {
+ _assertToken(TokenType.MINUS_MINUS, "--");
+ }
+
+ void test_open_curly_bracket() {
+ _assertToken(TokenType.OPEN_CURLY_BRACKET, "{");
+ }
+
+ void test_open_paren() {
+ _assertToken(TokenType.OPEN_PAREN, "(");
+ }
+
+ void test_open_square_bracket() {
+ _assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
+ }
+
+ void test_openSquareBracket() {
+ _assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
+ }
+
+ void test_percent() {
+ _assertToken(TokenType.PERCENT, "%");
+ }
+
+ void test_percent_eq() {
+ _assertToken(TokenType.PERCENT_EQ, "%=");
+ }
+
+ void test_period() {
+ _assertToken(TokenType.PERIOD, ".");
+ }
+
+ void test_period_period() {
+ _assertToken(TokenType.PERIOD_PERIOD, "..");
+ }
+
+ void test_period_period_period() {
+ _assertToken(TokenType.PERIOD_PERIOD_PERIOD, "...");
+ }
+
+ void test_periodAfterNumberNotIncluded_identifier() {
+ _assertTokens("42.isEven()", [
+ new StringToken(TokenType.INT, "42", 0),
+ new Token(TokenType.PERIOD, 2),
+ new StringToken(TokenType.IDENTIFIER, "isEven", 3),
+ new Token(TokenType.OPEN_PAREN, 9),
+ new Token(TokenType.CLOSE_PAREN, 10)
+ ]);
+ }
+
+ void test_periodAfterNumberNotIncluded_period() {
+ _assertTokens("42..isEven()", [
+ new StringToken(TokenType.INT, "42", 0),
+ new Token(TokenType.PERIOD_PERIOD, 2),
+ new StringToken(TokenType.IDENTIFIER, "isEven", 4),
+ new Token(TokenType.OPEN_PAREN, 10),
+ new Token(TokenType.CLOSE_PAREN, 11)
+ ]);
+ }
+
+ void test_plus() {
+ _assertToken(TokenType.PLUS, "+");
+ }
+
+ void test_plus_eq() {
+ _assertToken(TokenType.PLUS_EQ, "+=");
+ }
+
+ void test_plus_plus() {
+ _assertToken(TokenType.PLUS_PLUS, "++");
+ }
+
+ void test_question() {
+ _assertToken(TokenType.QUESTION, "?");
+ }
+
+ void test_question_dot() {
+ _assertToken(TokenType.QUESTION_PERIOD, "?.");
+ }
+
+ void test_question_question() {
+ _assertToken(TokenType.QUESTION_QUESTION, "??");
+ }
+
+ void test_question_question_eq() {
+ _assertToken(TokenType.QUESTION_QUESTION_EQ, "??=");
+ }
+
+ void test_scriptTag_withArgs() {
+ _assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart -debug");
+ }
+
+ void test_scriptTag_withoutSpace() {
+ _assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart");
+ }
+
+ void test_scriptTag_withSpace() {
+ _assertToken(TokenType.SCRIPT_TAG, "#! /bin/dart");
+ }
+
+ void test_semicolon() {
+ _assertToken(TokenType.SEMICOLON, ";");
+ }
+
+ void test_setSourceStart() {
+ int offsetDelta = 42;
+ _ErrorListener listener = new _ErrorListener();
+ Scanner scanner =
+ new _TestScanner(new SubSequenceReader("a", offsetDelta), listener);
+ scanner.setSourceStart(3, 9);
+ scanner.tokenize();
+ List<int> lineStarts = scanner.lineStarts;
+ expect(lineStarts, isNotNull);
+ expect(lineStarts.length, 3);
+ expect(lineStarts[2], 33);
+ }
+
+ void test_slash() {
+ _assertToken(TokenType.SLASH, "/");
+ }
+
+ void test_slash_eq() {
+ _assertToken(TokenType.SLASH_EQ, "/=");
+ }
+
+ void test_star() {
+ _assertToken(TokenType.STAR, "*");
+ }
+
+ void test_star_eq() {
+ _assertToken(TokenType.STAR_EQ, "*=");
+ }
+
+ void test_startAndEnd() {
+ Token token = _scan("a");
+ Token previous = token.previous;
+ expect(previous.next, token);
+ expect(previous.previous, previous);
+ Token next = token.next;
+ expect(next.next, next);
+ expect(next.previous, token);
+ }
+
+ void test_string_multi_double() {
+ _assertToken(TokenType.STRING, "\"\"\"line1\nline2\"\"\"");
+ }
+
+ void test_string_multi_embeddedQuotes() {
+ _assertToken(TokenType.STRING, "\"\"\"line1\n\"\"\nline2\"\"\"");
+ }
+
+ void test_string_multi_embeddedQuotes_escapedChar() {
+ _assertToken(TokenType.STRING, "\"\"\"a\"\"\\tb\"\"\"");
+ }
+
+ void test_string_multi_interpolation_block() {
+ _assertTokens("\"Hello \${name}!\"", [
+ new StringToken(TokenType.STRING, "\"Hello ", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 7),
+ new StringToken(TokenType.IDENTIFIER, "name", 9),
+ new Token(TokenType.CLOSE_CURLY_BRACKET, 13),
+ new StringToken(TokenType.STRING, "!\"", 14)
+ ]);
+ }
+
+ void test_string_multi_interpolation_identifier() {
+ _assertTokens("\"Hello \$name!\"", [
+ new StringToken(TokenType.STRING, "\"Hello ", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 7),
+ new StringToken(TokenType.IDENTIFIER, "name", 8),
+ new StringToken(TokenType.STRING, "!\"", 12)
+ ]);
+ }
+
+ void test_string_multi_single() {
+ _assertToken(TokenType.STRING, "'''string'''");
+ }
+
+ void test_string_multi_slashEnter() {
+ _assertToken(TokenType.STRING, "'''\\\n'''");
+ }
+
+ void test_string_multi_unterminated() {
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8,
+ "'''string", [new StringToken(TokenType.STRING, "'''string", 0)]);
+ }
+
+ void test_string_multi_unterminated_interpolation_block() {
+ _assertErrorAndTokens(
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8, "'''\${name", [
+ new StringToken(TokenType.STRING, "'''", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 3),
+ new StringToken(TokenType.IDENTIFIER, "name", 5),
+ new StringToken(TokenType.STRING, "", 9)
+ ]);
+ }
+
+ void test_string_multi_unterminated_interpolation_identifier() {
+ _assertErrorAndTokens(
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7, "'''\$name", [
+ new StringToken(TokenType.STRING, "'''", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
+ new StringToken(TokenType.IDENTIFIER, "name", 4),
+ new StringToken(TokenType.STRING, "", 8)
+ ]);
+ }
+
+ void test_string_raw_multi_double() {
+ _assertToken(TokenType.STRING, "r\"\"\"line1\nline2\"\"\"");
+ }
+
+ void test_string_raw_multi_single() {
+ _assertToken(TokenType.STRING, "r'''string'''");
+ }
+
+ void test_string_raw_multi_unterminated() {
+ String source = "r'''string";
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9,
+ source, [new StringToken(TokenType.STRING, source, 0)]);
+ }
+
+ void test_string_raw_simple_double() {
+ _assertToken(TokenType.STRING, "r\"string\"");
+ }
+
+ void test_string_raw_simple_single() {
+ _assertToken(TokenType.STRING, "r'string'");
+ }
+
+ void test_string_raw_simple_unterminated_eof() {
+ String source = "r'string";
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7,
+ source, [new StringToken(TokenType.STRING, source, 0)]);
+ }
+
+ void test_string_raw_simple_unterminated_eol() {
+ String source = "r'string";
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8,
+ "$source\n", [new StringToken(TokenType.STRING, source, 0)]);
+ }
+
+ void test_string_simple_double() {
+ _assertToken(TokenType.STRING, "\"string\"");
+ }
+
+ void test_string_simple_escapedDollar() {
+ _assertToken(TokenType.STRING, "'a\\\$b'");
+ }
+
+ void test_string_simple_interpolation_adjacentIdentifiers() {
+ _assertTokens("'\$a\$b'", [
+ new StringToken(TokenType.STRING, "'", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
+ new StringToken(TokenType.IDENTIFIER, "a", 2),
+ new StringToken(TokenType.STRING, "", 3),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
+ new StringToken(TokenType.IDENTIFIER, "b", 4),
+ new StringToken(TokenType.STRING, "'", 5)
+ ]);
+ }
+
+ void test_string_simple_interpolation_block() {
+ _assertTokens("'Hello \${name}!'", [
+ new StringToken(TokenType.STRING, "'Hello ", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 7),
+ new StringToken(TokenType.IDENTIFIER, "name", 9),
+ new Token(TokenType.CLOSE_CURLY_BRACKET, 13),
+ new StringToken(TokenType.STRING, "!'", 14)
+ ]);
+ }
+
+ void test_string_simple_interpolation_blockWithNestedMap() {
+ _assertTokens("'a \${f({'b' : 'c'})} d'", [
+ new StringToken(TokenType.STRING, "'a ", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 3),
+ new StringToken(TokenType.IDENTIFIER, "f", 5),
+ new Token(TokenType.OPEN_PAREN, 6),
+ new Token(TokenType.OPEN_CURLY_BRACKET, 7),
+ new StringToken(TokenType.STRING, "'b'", 8),
+ new Token(TokenType.COLON, 12),
+ new StringToken(TokenType.STRING, "'c'", 14),
+ new Token(TokenType.CLOSE_CURLY_BRACKET, 17),
+ new Token(TokenType.CLOSE_PAREN, 18),
+ new Token(TokenType.CLOSE_CURLY_BRACKET, 19),
+ new StringToken(TokenType.STRING, " d'", 20)
+ ]);
+ }
+
+ void test_string_simple_interpolation_firstAndLast() {
+ _assertTokens("'\$greeting \$name'", [
+ new StringToken(TokenType.STRING, "'", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
+ new StringToken(TokenType.IDENTIFIER, "greeting", 2),
+ new StringToken(TokenType.STRING, " ", 10),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 11),
+ new StringToken(TokenType.IDENTIFIER, "name", 12),
+ new StringToken(TokenType.STRING, "'", 16)
+ ]);
+ }
+
+ void test_string_simple_interpolation_identifier() {
+ _assertTokens("'Hello \$name!'", [
+ new StringToken(TokenType.STRING, "'Hello ", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 7),
+ new StringToken(TokenType.IDENTIFIER, "name", 8),
+ new StringToken(TokenType.STRING, "!'", 12)
+ ]);
+ }
+
+ void test_string_simple_interpolation_missingIdentifier() {
+ _assertTokens("'\$x\$'", [
+ new StringToken(TokenType.STRING, "'", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
+ new StringToken(TokenType.IDENTIFIER, "x", 2),
+ new StringToken(TokenType.STRING, "", 3),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
+ new StringToken(TokenType.STRING, "'", 4)
+ ]);
+ }
+
+ void test_string_simple_interpolation_nonIdentifier() {
+ _assertTokens("'\$1'", [
+ new StringToken(TokenType.STRING, "'", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
+ new StringToken(TokenType.STRING, "1'", 2)
+ ]);
+ }
+
+ void test_string_simple_single() {
+ _assertToken(TokenType.STRING, "'string'");
+ }
+
+ void test_string_simple_unterminated_eof() {
+ String source = "'string";
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 6,
+ source, [new StringToken(TokenType.STRING, source, 0)]);
+ }
+
+ void test_string_simple_unterminated_eol() {
+ String source = "'string";
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7,
+ "$source\r", [new StringToken(TokenType.STRING, source, 0)]);
+ }
+
+ void test_string_simple_unterminated_interpolation_block() {
+ _assertErrorAndTokens(
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 6, "'\${name", [
+ new StringToken(TokenType.STRING, "'", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 1),
+ new StringToken(TokenType.IDENTIFIER, "name", 3),
+ new StringToken(TokenType.STRING, "", 7)
+ ]);
+ }
+
+ void test_string_simple_unterminated_interpolation_identifier() {
+ _assertErrorAndTokens(
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 5, "'\$name", [
+ new StringToken(TokenType.STRING, "'", 0),
+ new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
+ new StringToken(TokenType.IDENTIFIER, "name", 2),
+ new StringToken(TokenType.STRING, "", 6)
+ ]);
+ }
+
+ void test_tilde() {
+ _assertToken(TokenType.TILDE, "~");
+ }
+
+ void test_tilde_slash() {
+ _assertToken(TokenType.TILDE_SLASH, "~/");
+ }
+
+ void test_tilde_slash_eq() {
+ _assertToken(TokenType.TILDE_SLASH_EQ, "~/=");
+ }
+
+ void test_unclosedPairInInterpolation() {
+ _ErrorListener listener = new _ErrorListener();
+ _scanWithListener("'\${(}'", listener);
+ }
+
+ void _assertComment(TokenType commentType, String source,
+ {bool genericMethodComments: false}) {
+ //
+ // Test without a trailing end-of-line marker
+ //
+ Token token = _scan(source, genericMethodComments: genericMethodComments);
+ expect(token, isNotNull);
+ expect(token.type, TokenType.EOF);
+ Token comment = token.precedingComments;
+ expect(comment, isNotNull);
+ expect(comment.type, commentType);
+ expect(comment.offset, 0);
+ expect(comment.length, source.length);
+ expect(comment.lexeme, source);
+ //
+ // Test with a trailing end-of-line marker
+ //
+ token = _scan("$source\n", genericMethodComments: genericMethodComments);
+ expect(token, isNotNull);
+ expect(token.type, TokenType.EOF);
+ comment = token.precedingComments;
+ expect(comment, isNotNull);
+ expect(comment.type, commentType);
+ expect(comment.offset, 0);
+ expect(comment.length, source.length);
+ expect(comment.lexeme, source);
+ }
+
+ /**
+ * Assert that scanning the given [source] produces an error with the given
+ * code.
+ *
+ * [expectedError] the error that should be produced
+ * [expectedOffset] the string offset that should be associated with the error
+ * [source] the source to be scanned to produce the error
+ */
+ void _assertError(
+ ScannerErrorCode expectedError, int expectedOffset, String source,
+ [List<Object> arguments]) {
+ _ErrorListener listener = new _ErrorListener();
+ _scanWithListener(source, listener);
+ listener.assertErrors(
+ [new _TestError(expectedOffset, 1, expectedError, arguments)]);
+ }
+
+ /**
+ * Assert that scanning the given [source] produces an error with the given
+ * code, and also produces the given tokens.
+ *
+ * [expectedError] the error that should be produced
+ * [expectedOffset] the string offset that should be associated with the error
+ * [source] the source to be scanned to produce the error
+ * [expectedTokens] the tokens that are expected to be in the source
+ */
+ void _assertErrorAndTokens(ScannerErrorCode expectedError, int expectedOffset,
+ String source, List<Token> expectedTokens) {
+ _ErrorListener listener = new _ErrorListener();
+ Token token = _scanWithListener(source, listener);
+ listener
+ .assertErrors([new _TestError(expectedOffset, 1, expectedError, null)]);
+ _checkTokens(token, expectedTokens);
+ }
+
+ /**
+ * Assert that when scanned the given [source] contains a single keyword token
+ * with the same lexeme as the original source.
+ */
+ void _assertKeywordToken(String source) {
+ Token token = _scan(source);
+ expect(token, isNotNull);
+ expect(token.type, TokenType.KEYWORD);
+ expect(token.offset, 0);
+ expect(token.length, source.length);
+ expect(token.lexeme, source);
+ Object value = token.value();
+ expect(value is Keyword, isTrue);
+ expect((value as Keyword).syntax, source);
+ token = _scan(" $source ");
+ expect(token, isNotNull);
+ expect(token.type, TokenType.KEYWORD);
+ expect(token.offset, 1);
+ expect(token.length, source.length);
+ expect(token.lexeme, source);
+ value = token.value();
+ expect(value is Keyword, isTrue);
+ expect((value as Keyword).syntax, source);
+ expect(token.next.type, TokenType.EOF);
+ }
+
+ /**
+ * Assert that the token scanned from the given [source] has the
+ * [expectedType].
+ */
+ Token _assertToken(TokenType expectedType, String source,
+ {bool lazyAssignmentOperators: false}) {
+ Token originalToken =
+ _scan(source, lazyAssignmentOperators: lazyAssignmentOperators);
+ expect(originalToken, isNotNull);
+ expect(originalToken.type, expectedType);
+ expect(originalToken.offset, 0);
+ expect(originalToken.length, source.length);
+ expect(originalToken.lexeme, source);
+ if (expectedType == TokenType.SCRIPT_TAG) {
+ // Adding space before the script tag is not allowed, and adding text at
+ // the end changes nothing.
+ return originalToken;
+ } else if (expectedType == TokenType.SINGLE_LINE_COMMENT) {
+ // Adding space to an end-of-line comment changes the comment.
+ Token tokenWithSpaces =
+ _scan(" $source", lazyAssignmentOperators: lazyAssignmentOperators);
+ expect(tokenWithSpaces, isNotNull);
+ expect(tokenWithSpaces.type, expectedType);
+ expect(tokenWithSpaces.offset, 1);
+ expect(tokenWithSpaces.length, source.length);
+ expect(tokenWithSpaces.lexeme, source);
+ return originalToken;
+ } else if (expectedType == TokenType.INT ||
+ expectedType == TokenType.DOUBLE) {
+ Token tokenWithLowerD =
+ _scan("${source}d", lazyAssignmentOperators: lazyAssignmentOperators);
+ expect(tokenWithLowerD, isNotNull);
+ expect(tokenWithLowerD.type, expectedType);
+ expect(tokenWithLowerD.offset, 0);
+ expect(tokenWithLowerD.length, source.length);
+ expect(tokenWithLowerD.lexeme, source);
+ Token tokenWithUpperD =
+ _scan("${source}D", lazyAssignmentOperators: lazyAssignmentOperators);
+ expect(tokenWithUpperD, isNotNull);
+ expect(tokenWithUpperD.type, expectedType);
+ expect(tokenWithUpperD.offset, 0);
+ expect(tokenWithUpperD.length, source.length);
+ expect(tokenWithUpperD.lexeme, source);
+ }
+ Token tokenWithSpaces =
+ _scan(" $source ", lazyAssignmentOperators: lazyAssignmentOperators);
+ expect(tokenWithSpaces, isNotNull);
+ expect(tokenWithSpaces.type, expectedType);
+ expect(tokenWithSpaces.offset, 1);
+ expect(tokenWithSpaces.length, source.length);
+ expect(tokenWithSpaces.lexeme, source);
+ expect(originalToken.next.type, TokenType.EOF);
+ return originalToken;
+ }
+
+ /**
+ * Assert that when scanned the given [source] contains a sequence of tokens
+ * identical to the given list of [expectedTokens].
+ */
+ void _assertTokens(String source, List<Token> expectedTokens) {
+ Token token = _scan(source);
+ _checkTokens(token, expectedTokens);
+ }
+
+ void _checkTokens(Token firstToken, List<Token> expectedTokens) {
+ expect(firstToken, isNotNull);
+ Token token = firstToken;
+ for (int i = 0; i < expectedTokens.length; i++) {
+ Token expectedToken = expectedTokens[i];
+ expect(token.type, expectedToken.type, reason: "Wrong type for token $i");
+ expect(token.offset, expectedToken.offset,
+ reason: "Wrong offset for token $i");
+ expect(token.length, expectedToken.length,
+ reason: "Wrong length for token $i");
+ expect(token.lexeme, expectedToken.lexeme,
+ reason: "Wrong lexeme for token $i");
+ token = token.next;
+ expect(token, isNotNull);
+ }
+ expect(token.type, TokenType.EOF);
+ }
+
+ Token _scan(String source,
+ {bool genericMethodComments: false,
+ bool lazyAssignmentOperators: false}) {
+ _ErrorListener listener = new _ErrorListener();
+ Token token = _scanWithListener(source, listener,
+ genericMethodComments: genericMethodComments,
+ lazyAssignmentOperators: lazyAssignmentOperators);
+ listener.assertNoErrors();
+ return token;
+ }
+
+ Token _scanWithListener(String source, _ErrorListener listener,
+ {bool genericMethodComments: false,
+ bool lazyAssignmentOperators: false}) {
+ Scanner scanner =
+ new _TestScanner(new CharSequenceReader(source), listener);
+ scanner.scanGenericMethodComments = genericMethodComments;
+ scanner.scanLazyAssignmentOperators = lazyAssignmentOperators;
+ return scanner.tokenize();
+ }
+}
+
+@reflectiveTest
+class TokenTypeTest {
+ void test_isOperator() {
+ expect(TokenType.AMPERSAND.isOperator, isTrue);
+ expect(TokenType.AMPERSAND_AMPERSAND.isOperator, isTrue);
+ expect(TokenType.AMPERSAND_EQ.isOperator, isTrue);
+ expect(TokenType.BANG.isOperator, isTrue);
+ expect(TokenType.BANG_EQ.isOperator, isTrue);
+ expect(TokenType.BAR.isOperator, isTrue);
+ expect(TokenType.BAR_BAR.isOperator, isTrue);
+ expect(TokenType.BAR_EQ.isOperator, isTrue);
+ expect(TokenType.CARET.isOperator, isTrue);
+ expect(TokenType.CARET_EQ.isOperator, isTrue);
+ expect(TokenType.EQ.isOperator, isTrue);
+ expect(TokenType.EQ_EQ.isOperator, isTrue);
+ expect(TokenType.GT.isOperator, isTrue);
+ expect(TokenType.GT_EQ.isOperator, isTrue);
+ expect(TokenType.GT_GT.isOperator, isTrue);
+ expect(TokenType.GT_GT_EQ.isOperator, isTrue);
+ expect(TokenType.INDEX.isOperator, isTrue);
+ expect(TokenType.INDEX_EQ.isOperator, isTrue);
+ expect(TokenType.IS.isOperator, isTrue);
+ expect(TokenType.LT.isOperator, isTrue);
+ expect(TokenType.LT_EQ.isOperator, isTrue);
+ expect(TokenType.LT_LT.isOperator, isTrue);
+ expect(TokenType.LT_LT_EQ.isOperator, isTrue);
+ expect(TokenType.MINUS.isOperator, isTrue);
+ expect(TokenType.MINUS_EQ.isOperator, isTrue);
+ expect(TokenType.MINUS_MINUS.isOperator, isTrue);
+ expect(TokenType.PERCENT.isOperator, isTrue);
+ expect(TokenType.PERCENT_EQ.isOperator, isTrue);
+ expect(TokenType.PERIOD_PERIOD.isOperator, isTrue);
+ expect(TokenType.PLUS.isOperator, isTrue);
+ expect(TokenType.PLUS_EQ.isOperator, isTrue);
+ expect(TokenType.PLUS_PLUS.isOperator, isTrue);
+ expect(TokenType.QUESTION.isOperator, isTrue);
+ expect(TokenType.SLASH.isOperator, isTrue);
+ expect(TokenType.SLASH_EQ.isOperator, isTrue);
+ expect(TokenType.STAR.isOperator, isTrue);
+ expect(TokenType.STAR_EQ.isOperator, isTrue);
+ expect(TokenType.TILDE.isOperator, isTrue);
+ expect(TokenType.TILDE_SLASH.isOperator, isTrue);
+ expect(TokenType.TILDE_SLASH_EQ.isOperator, isTrue);
+ }
+
+ void test_isUserDefinableOperator() {
+ expect(TokenType.AMPERSAND.isUserDefinableOperator, isTrue);
+ expect(TokenType.BAR.isUserDefinableOperator, isTrue);
+ expect(TokenType.CARET.isUserDefinableOperator, isTrue);
+ expect(TokenType.EQ_EQ.isUserDefinableOperator, isTrue);
+ expect(TokenType.GT.isUserDefinableOperator, isTrue);
+ expect(TokenType.GT_EQ.isUserDefinableOperator, isTrue);
+ expect(TokenType.GT_GT.isUserDefinableOperator, isTrue);
+ expect(TokenType.INDEX.isUserDefinableOperator, isTrue);
+ expect(TokenType.INDEX_EQ.isUserDefinableOperator, isTrue);
+ expect(TokenType.LT.isUserDefinableOperator, isTrue);
+ expect(TokenType.LT_EQ.isUserDefinableOperator, isTrue);
+ expect(TokenType.LT_LT.isUserDefinableOperator, isTrue);
+ expect(TokenType.MINUS.isUserDefinableOperator, isTrue);
+ expect(TokenType.PERCENT.isUserDefinableOperator, isTrue);
+ expect(TokenType.PLUS.isUserDefinableOperator, isTrue);
+ expect(TokenType.SLASH.isUserDefinableOperator, isTrue);
+ expect(TokenType.STAR.isUserDefinableOperator, isTrue);
+ expect(TokenType.TILDE.isUserDefinableOperator, isTrue);
+ expect(TokenType.TILDE_SLASH.isUserDefinableOperator, isTrue);
+ }
+}
+
+class _ErrorListener {
+ final errors = <_TestError>[];
+
+ void assertErrors(List<_TestError> expectedErrors) {
+ expect(errors, unorderedEquals(expectedErrors));
+ }
+
+ void assertNoErrors() {
+ assertErrors([]);
+ }
+}
+
+class _TestError {
+ final int offset;
+ final int length;
+ final ErrorCode errorCode;
+ final List<Object> arguments;
+
+ _TestError(this.offset, this.length, this.errorCode, this.arguments);
+
+ @override
+ get hashCode {
+ var h = new JenkinsSmiHash()..add(offset)..add(length)..add(errorCode);
+ if (arguments != null) {
+ for (Object argument in arguments) {
+ h.add(argument);
+ }
+ }
+ return h.hashCode;
+ }
+
+ @override
+ operator ==(Object other) {
+ if (other is _TestError &&
+ offset == other.offset &&
+ length == other.length &&
+ errorCode == other.errorCode) {
+ if (arguments == null) return other.arguments == null;
+ if (other.arguments == null) return false;
+ if (arguments.length != other.arguments.length) return false;
+ for (int i = 0; i < arguments.length; i++) {
+ if (arguments[i] != other.arguments[i]) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @override
+ toString() {
+ var end = offset + length;
+ var argString = arguments == null ? '' : '(${arguments.join(', ')})';
+ return 'Error($offset..$end, $errorCode$argString)';
+ }
+}
+
+class _TestScanner extends Scanner {
+ final _ErrorListener listener;
+
+ _TestScanner(CharacterReader reader, [this.listener]) : super(reader);
+
+ @override
+ void reportError(
+ ScannerErrorCode errorCode, int offset, List<Object> arguments) {
+ if (listener != null) {
+ listener.errors.add(new _TestError(offset, 1, errorCode, arguments));
+ }
+ }
+}
diff --git a/pkg/front_end/tool/perf.dart b/pkg/front_end/tool/perf.dart
index ec306ca..4d61e9b 100644
--- a/pkg/front_end/tool/perf.dart
+++ b/pkg/front_end/tool/perf.dart
@@ -9,15 +9,12 @@
import 'dart:io' show exit, stderr;
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver;
import 'package:analyzer/file_system/physical_file_system.dart'
show PhysicalResourceProvider;
import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/context/builder.dart';
-import 'package:analyzer/src/dart/scanner/reader.dart';
-import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk;
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -26,6 +23,10 @@
import 'package:kernel/kernel.dart';
import 'package:package_config/discovery.dart';
+import 'package:front_end/src/scanner/reader.dart';
+import 'package:front_end/src/scanner/scanner.dart';
+import 'package:front_end/src/scanner/token.dart';
+
/// Cumulative total number of chars scanned.
int scanTotalChars = 0;
@@ -205,13 +206,23 @@
scanTotalChars += contents.length;
// TODO(sigmund): is there a way to scan from a random-access-file without
// first converting to String?
- var scanner = new Scanner(source, new CharSequenceReader(contents),
- AnalysisErrorListener.NULL_LISTENER)..preserveComments = false;
+ var scanner = new _Scanner(contents);
var token = scanner.tokenize();
scanTimer.stop();
return token;
}
+class _Scanner extends Scanner {
+ _Scanner(String contents) : super(new CharSequenceReader(contents)) {
+ preserveComments = false;
+ }
+
+ @override
+ void reportError(errorCode, int offset, List<Object> arguments) {
+ // ignore errors.
+ }
+}
+
/// Report that metric [name] took [time] micro-seconds to process
/// [scanTotalChars] characters.
void report(String name, int time) {
diff --git a/pkg/pkg.status b/pkg/pkg.status
index ee9fe4a..01ed03e 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -57,6 +57,9 @@
front_end/test/memory_file_system_test: CompileTimeError # Issue 23773
front_end/test/physical_file_system_test: SkipByDesign # Uses dart:io
+[ $compiler == dart2js && $fast_startup ]
+front_end/test/*: SkipByDesign # Tests written with dart:mirrors.
+
[ $compiler == dart2js && $builder_tag != dart2js_analyzer ]
analyzer/test/*: Skip # Issue 26813
analyzer/tool/*: Skip # Issue 26813
@@ -68,6 +71,7 @@
[ $runtime == jsshell ]
async/test/stream_zip_test: RuntimeError, OK # Issue 26103. Timers are not supported.
lookup_map/test/lookup_map_test: RuntimeError, OK # Issue 26103. Timers are not supported.
+front_end/test/*: RuntimeError, OK # Issue 26103. Timers are not supported.
[ $compiler == dart2js && $runtime == drt ]
async/test/stream_zip_test: RuntimeError, Pass # Issue 18548
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index b5116d5..8556ba2 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -247,17 +247,6 @@
]
}
-libdart_library("libdart_nosnapshot_precompiled_runtime") {
- extra_configs = [
- ":dart_no_snapshot_config",
- ":dart_precompiled_runtime_config",
- ]
- extra_deps = [
- "vm:libdart_lib_nosnapshot_precompiled_runtime",
- "vm:libdart_vm_nosnapshot_precompiled_runtime",
- ]
-}
-
libdart_library("libdart_nosnapshot_with_precompiler") {
extra_configs = [
":dart_no_snapshot_config",
diff --git a/runtime/bin/builtin.cc b/runtime/bin/builtin.cc
index 49ebb05..cbc2006 100644
--- a/runtime/bin/builtin.cc
+++ b/runtime/bin/builtin.cc
@@ -110,7 +110,17 @@
void Builtin::SetNativeResolver(BuiltinLibraryId id) {
- UNREACHABLE();
+ ASSERT(static_cast<int>(id) >= 0);
+ ASSERT(static_cast<int>(id) < num_libs_);
+
+ if (builtin_libraries_[id].has_natives_) {
+ Dart_Handle url = DartUtils::NewString(builtin_libraries_[id].url_);
+ Dart_Handle library = Dart_LookupLibrary(url);
+ ASSERT(!Dart_IsError(library));
+ // Setup the native resolver for built in library functions.
+ DART_CHECK_VALID(
+ Dart_SetNativeResolver(library, NativeLookup, NativeSymbol));
+ }
}
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index db8e1fa..cd005db 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -72,8 +72,10 @@
DartUtils::ReadFile(&buffer, kernel_length, script_file);
DartUtils::CloseFile(script_file);
if (*kernel_length > 0 && buffer != NULL) {
- *kernel_file = buffer;
- if (DartUtils::SniffForMagicNumber(&buffer, kernel_length) !=
+ // We need a temporary variable because SniffForMagicNumber modifies the
+ // buffer pointer to skip snapshot magic number.
+ const uint8_t* temp = buffer;
+ if (DartUtils::SniffForMagicNumber(&temp, kernel_length) !=
DartUtils::kKernelMagicNumber) {
free(const_cast<uint8_t*>(buffer));
*kernel_file = NULL;
@@ -83,6 +85,7 @@
// Caller is responsible for freeing the buffer when this function
// returns true.
is_kernel_file = true;
+ *kernel_file = buffer;
}
}
}
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 17acc09..53babb7 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -1266,8 +1266,16 @@
// Now we create an isolate into which we load all the code that needs to
// be in the snapshot.
isolate_data = new IsolateData(NULL, NULL, NULL);
- if (Dart_CreateIsolate(NULL, NULL, NULL, NULL, isolate_data, &error) ==
- NULL) {
+ const uint8_t* kernel = NULL;
+ intptr_t kernel_length = 0;
+ const bool is_kernel_file =
+ TryReadKernel(app_script_name, &kernel, &kernel_length);
+ Dart_Isolate isolate =
+ is_kernel_file
+ ? Dart_CreateIsolateFromKernel(NULL, NULL, kernel, kernel_length,
+ NULL, isolate_data, &error)
+ : Dart_CreateIsolate(NULL, NULL, NULL, NULL, isolate_data, &error);
+ if (isolate == NULL) {
fprintf(stderr, "%s", error);
free(error);
exit(255);
@@ -1284,14 +1292,9 @@
Dart_QualifiedFunctionName* entry_points =
ParseEntryPointsManifestIfPresent();
- intptr_t payload_bytes = 0;
- const uint8_t* payload = NULL;
- const bool is_kernel_file =
- TryReadKernel(app_script_name, &payload, &payload_bytes);
-
if (is_kernel_file) {
- Dart_Handle library = Dart_LoadKernel(payload, payload_bytes);
- free(const_cast<uint8_t*>(payload));
+ Dart_Handle library = Dart_LoadKernel(kernel, kernel_length);
+ free(const_cast<uint8_t*>(kernel));
if (Dart_IsError(library)) FATAL("Failed to load app from Kernel IR");
} else {
// Set up the library tag handler in such a manner that it will use the
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index b481a67..21fde13 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -799,10 +799,26 @@
return NULL;
}
+ // If the script is a Kernel binary, then we will try to bootstrap from the
+ // script.
+ const uint8_t* kernel_file = NULL;
+ intptr_t kernel_length = -1;
+ const bool is_kernel =
+ !run_app_snapshot &&
+ TryReadKernel(script_uri, &kernel_file, &kernel_length);
+
IsolateData* isolate_data =
new IsolateData(script_uri, package_root, packages_config);
- Dart_Isolate isolate = Dart_CreateIsolate(
- script_uri, main, isolate_snapshot_buffer, flags, isolate_data, error);
+ Dart_Isolate isolate =
+ is_kernel ? Dart_CreateIsolateFromKernel(script_uri, main, kernel_file,
+ kernel_length, flags,
+ isolate_data, error)
+ : Dart_CreateIsolate(script_uri, main, isolate_snapshot_buffer,
+ flags, isolate_data, error);
+ if (is_kernel) {
+ free(const_cast<uint8_t*>(kernel_file));
+ }
+
if (isolate == NULL) {
delete isolate_data;
return NULL;
@@ -810,7 +826,20 @@
Dart_EnterScope();
- if (isolate_snapshot_buffer != NULL) {
+ // Set up the library tag handler for this isolate.
+ Dart_Handle result = Dart_SetLibraryTagHandler(Loader::LibraryTagHandler);
+ CHECK_RESULT(result);
+
+ if (is_kernel) {
+ // TODO(27590): We should not read the kernel file again!
+ if (!TryReadKernel(script_uri, &kernel_file, &kernel_length)) {
+ FATAL("Failed to read kernel second time");
+ }
+ Dart_Handle result = Dart_LoadKernel(kernel_file, kernel_length);
+ free(const_cast<uint8_t*>(kernel_file));
+ CHECK_RESULT(result);
+ }
+ if (is_kernel || (isolate_snapshot_buffer != NULL)) {
// Setup the native resolver as the snapshot does not carry it.
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
Builtin::SetNativeResolver(Builtin::kIOLibrary);
@@ -820,10 +849,6 @@
CHECK_RESULT(result);
}
- // Set up the library tag handler for this isolate.
- Dart_Handle result = Dart_SetLibraryTagHandler(Loader::LibraryTagHandler);
- CHECK_RESULT(result);
-
if (Dart_IsServiceIsolate(isolate)) {
// If this is the service isolate, load embedder specific bits and return.
bool skip_library_load = run_app_snapshot;
@@ -872,8 +897,10 @@
Dart_Handle uri =
DartUtils::ResolveScript(Dart_NewStringFromCString(script_uri));
CHECK_RESULT(uri);
- result = Loader::LibraryTagHandler(Dart_kScriptTag, Dart_Null(), uri);
- CHECK_RESULT(result);
+ if (!is_kernel) {
+ result = Loader::LibraryTagHandler(Dart_kScriptTag, Dart_Null(), uri);
+ CHECK_RESULT(result);
+ }
Dart_TimelineEvent("LoadScript", Dart_TimelineGetMicros(),
Dart_GetMainPortId(), Dart_Timeline_Event_Async_End, 0,
@@ -1835,6 +1862,9 @@
if (gen_snapshot_kind == kAppJIT) {
vm_options.AddArgument("--fields_may_be_reset");
+#if !defined(PRODUCT)
+ vm_options.AddArgument("--collect_code=false");
+#endif
}
if ((gen_snapshot_kind == kAppAOT) || is_noopt) {
vm_options.AddArgument("--precompilation");
diff --git a/runtime/bin/platform_patch.dart b/runtime/bin/platform_patch.dart
index 8110ea1..c4b3481 100644
--- a/runtime/bin/platform_patch.dart
+++ b/runtime/bin/platform_patch.dart
@@ -28,7 +28,7 @@
=> VMLibraryHooks.packageConfigString;
// This script singleton is written to by the embedder if applicable.
- @patch static void set _nativeScript(String path) {
+ static void set _nativeScript(String path) {
if (path.startsWith('http:') ||
path.startsWith('https:') ||
path.startsWith('package:') ||
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index 392ae1c..9478180 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -34,7 +34,7 @@
return null;
}
- @patch static int _nativeSocketType(_NativeSocket nativeSocket) {
+ static int _nativeSocketType(_NativeSocket nativeSocket) {
var result = _getSocketType(nativeSocket);
if (result is OSError) {
throw new FileSystemException(
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index da2dd8d..acbcba9 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -155,7 +155,8 @@
bool VmService::LoadForGenPrecompiled() {
Dart_Handle result;
Dart_SetLibraryTagHandler(LibraryTagHandler);
- Dart_Handle library = LoadLibrary(kVMServiceIOLibraryScriptResourceName);
+ Dart_Handle library =
+ LookupOrLoadLibrary(kVMServiceIOLibraryScriptResourceName);
ASSERT(library != Dart_Null());
SHUTDOWN_ON_ERROR(library);
result = Dart_SetNativeResolver(library, VmServiceIONativeResolver, NULL);
@@ -314,10 +315,14 @@
}
-Dart_Handle VmService::LoadLibrary(const char* name) {
+Dart_Handle VmService::LookupOrLoadLibrary(const char* name) {
Dart_Handle uri = Dart_NewStringFromCString(kVMServiceIOLibraryUri);
- Dart_Handle source = GetSource(name);
- return Dart_LoadLibrary(uri, Dart_Null(), source, 0, 0);
+ Dart_Handle library = Dart_LookupLibrary(uri);
+ if (!Dart_IsLibrary(library)) {
+ Dart_Handle source = GetSource(name);
+ library = Dart_LoadLibrary(uri, Dart_Null(), source, 0, 0);
+ }
+ return library;
}
diff --git a/runtime/bin/vmservice_impl.h b/runtime/bin/vmservice_impl.h
index 9f9ce6b..8bdc81e 100644
--- a/runtime/bin/vmservice_impl.h
+++ b/runtime/bin/vmservice_impl.h
@@ -34,7 +34,7 @@
static void SetServerAddress(const char* server_uri_);
static Dart_Handle GetSource(const char* name);
static Dart_Handle LoadScript(const char* name);
- static Dart_Handle LoadLibrary(const char* name);
+ static Dart_Handle LookupOrLoadLibrary(const char* name);
static Dart_Handle LoadSource(Dart_Handle library, const char* name);
static Dart_Handle LoadResources(Dart_Handle library);
static Dart_Handle LoadResource(Dart_Handle library, const char* name);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 652c7913..1a09f7b 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -873,7 +873,7 @@
* \param error DOCUMENT
*
* \return The new isolate is returned. May be NULL if an error
- * occurs duing isolate initialization.
+ * occurs during isolate initialization.
*/
DART_EXPORT Dart_Isolate Dart_CreateIsolate(const char* script_uri,
const char* main,
@@ -885,6 +885,34 @@
* isolate. */
/**
+ * Creates a new isolate from a Dart Kernel file. The new isolate
+ * becomes the current isolate.
+ *
+ * Requires there to be no current isolate.
+ *
+ * \param script_uri The name of the script this isolate will load.
+ * Provided only for advisory purposes to improve debugging messages.
+ * \param main The name of the main entry point this isolate will run.
+ * Provided only for advisory purposes to improve debugging messages.
+ * \param kernel A buffer containing the Dart Kernel binary.
+ * \param kernel_length The length of the Kernel buffer.
+ * \param flags Pointer to VM specific flags or NULL for default flags.
+ * \param callback_data Embedder data. This data will be passed to
+ * the Dart_IsolateCreateCallback when new isolates are spawned from
+ * this parent isolate.
+ * \param error DOCUMENT
+ *
+ * \return The new isolate is returned. May be NULL if an error
+ * occurs during isolate initialization.
+ */
+DART_EXPORT Dart_Isolate Dart_CreateIsolateFromKernel(const char* script_uri,
+ const char* main,
+ const uint8_t* kernel,
+ intptr_t kernel_length,
+ Dart_IsolateFlags* flags,
+ void* callback_data,
+ char** error);
+/**
* Shuts down the current isolate. After this call, the current isolate
* is NULL. Invokes the shutdown callback and any callbacks of remaining
* weak persistent handles.
diff --git a/runtime/lib/class_id.cc b/runtime/lib/class_id.cc
index 2d9f67d..c950b0e 100644
--- a/runtime/lib/class_id.cc
+++ b/runtime/lib/class_id.cc
@@ -13,4 +13,24 @@
return Smi::New(instance.GetClassId());
}
+
+DEFINE_NATIVE_ENTRY(ClassID_byName, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
+
+#define CLASS_LIST_WITH_NULL(V) \
+ V(Null) \
+ CLASS_LIST_NO_OBJECT(V)
+
+#define COMPARE(clazz) \
+ if (name.Equals(#clazz)) return Smi::New(k##clazz##Cid);
+
+ CLASS_LIST_WITH_NULL(COMPARE)
+
+#undef COMPARE
+#undef CLASS_LIST_WITH_NULL
+
+ UNREACHABLE();
+ return Smi::New(-1);
+}
+
} // namespace dart
diff --git a/runtime/lib/class_id.dart b/runtime/lib/class_id.dart
index 045cfa1..8a8d670 100644
--- a/runtime/lib/class_id.dart
+++ b/runtime/lib/class_id.dart
@@ -4,4 +4,14 @@
class ClassID {
static int getID(Object value) native "ClassID_getID";
+
+ static int _lookup(String name) native "ClassID_byName";
+
+ static final int cidArray = _lookup('Array');
+ static final int cidExternalOneByteString = _lookup('ExternalOneByteString');
+ static final int cidGrowableObjectArray = _lookup('GrowableObjectArray');
+ static final int cidImmutableArray = _lookup('ImmutableArray');
+ static final int cidOneByteString = _lookup('OneByteString');
+ static final int cidTwoByteString = _lookup('TwoByteString');
+ static final int cidBigint = _lookup('Bigint');
}
diff --git a/runtime/lib/errors.cc b/runtime/lib/errors.cc
index 390079f..27770a9 100644
--- a/runtime/lib/errors.cc
+++ b/runtime/lib/errors.cc
@@ -117,7 +117,8 @@
AbstractType::CheckedHandle(arguments->NativeArgAt(2));
const String& dst_name = String::CheckedHandle(arguments->NativeArgAt(3));
const String& error_msg = String::CheckedHandle(arguments->NativeArgAt(4));
- const AbstractType& src_type = AbstractType::Handle(src_value.GetType());
+ const AbstractType& src_type =
+ AbstractType::Handle(src_value.GetType(Heap::kNew));
Exceptions::CreateAndThrowTypeError(location, src_type, dst_type, dst_name,
error_msg);
UNREACHABLE();
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index bf04059..2635802 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -103,7 +103,7 @@
static _throwNew(int case_clause_pos) native "FallThroughError_throwNew";
- @patch String toString() {
+ String toString() {
return "'$_url': Switch case fall-through at line $_line.";
}
@@ -273,6 +273,7 @@
}
StringBuffer msg_buf = new StringBuffer("NoSuchMethodError: ");
+ bool is_type_call = false;
switch (level) {
case _InvocationMirror._DYNAMIC: {
if (_receiver == null) {
@@ -286,6 +287,13 @@
if (_receiver is Function) {
msg_buf.writeln("Closure call with mismatched arguments: "
"function '$memberName'");
+ } else if (_receiver is _Type && memberName == "call") {
+ is_type_call = true;
+ String name = _receiver.toString();
+ msg_buf.writeln("Attempted to use type '$name' as a function. "
+ "Since types do not define a method 'call', this is not "
+ "possible. Did you intend to call the $name constructor and "
+ "forget the 'new' operator?");
} else {
msg_buf.writeln("Class '${_receiver.runtimeType}' has no instance "
"$type_str '$memberName'$args_message.");
@@ -324,7 +332,8 @@
}
if (type == _InvocationMirror._METHOD) {
- msg_buf.write("Tried calling: $memberName($arguments)");
+ String m = is_type_call ? "$_receiver" : "$memberName";
+ msg_buf.write("Tried calling: $m($arguments)");
} else if (argumentCount == 0) {
msg_buf.write("Tried calling: $memberName");
} else if (type == _InvocationMirror._SETTER) {
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 48e579b..7a2efe0 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -1370,7 +1370,7 @@
DEFINE_NATIVE_ENTRY(InstanceMirror_computeType, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
- const AbstractType& type = AbstractType::Handle(instance.GetType());
+ const AbstractType& type = AbstractType::Handle(instance.GetType(Heap::kNew));
// The static type of null is specified to be the bottom type, however, the
// runtime type of null is the Null type, which we correctly return here.
return type.Canonicalize();
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 276d0d2..6a7db55 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -123,7 +123,7 @@
} else if (instance.IsDouble()) {
return Type::Double();
}
- return instance.GetType();
+ return instance.GetType(Heap::kNew);
}
@@ -147,8 +147,10 @@
const Class& cls = Class::Handle(left.clazz());
if (cls.IsClosureClass()) {
// TODO(vegorov): provide faster implementation for closure classes.
- const AbstractType& left_type = AbstractType::Handle(left.GetType());
- const AbstractType& right_type = AbstractType::Handle(right.GetType());
+ const AbstractType& left_type =
+ AbstractType::Handle(left.GetType(Heap::kNew));
+ const AbstractType& right_type =
+ AbstractType::Handle(right.GetType(Heap::kNew));
return Bool::Get(left_type.raw() == right_type.raw()).raw();
}
@@ -182,7 +184,7 @@
const char* result_str = is_instance_of ? "true" : "false";
OS::Print("Native Object.instanceOf: result %s\n", result_str);
const AbstractType& instance_type =
- AbstractType::Handle(zone, instance.GetType());
+ AbstractType::Handle(zone, instance.GetType(Heap::kNew));
OS::Print(" instance type: %s\n",
String::Handle(zone, instance_type.Name()).ToCString());
OS::Print(" test type: %s\n",
@@ -318,7 +320,7 @@
const char* result_str = is_instance_of ? "true" : "false";
OS::Print("Object.as: result %s\n", result_str);
const AbstractType& instance_type =
- AbstractType::Handle(zone, instance.GetType());
+ AbstractType::Handle(zone, instance.GetType(Heap::kNew));
OS::Print(" instance type: %s\n",
String::Handle(zone, instance_type.Name()).ToCString());
OS::Print(" cast type: %s\n",
@@ -333,7 +335,7 @@
ASSERT(caller_frame != NULL);
const TokenPosition location = caller_frame->GetTokenPos();
const AbstractType& instance_type =
- AbstractType::Handle(zone, instance.GetType());
+ AbstractType::Handle(zone, instance.GetType(Heap::kNew));
if (!type.IsInstantiated()) {
// Instantiate type before reporting the error.
type = type.InstantiateFrom(instantiator_type_arguments, NULL, NULL, NULL,
diff --git a/runtime/observatory/lib/object_graph.dart b/runtime/observatory/lib/object_graph.dart
index c2b4169..d1c171b 100644
--- a/runtime/observatory/lib/object_graph.dart
+++ b/runtime/observatory/lib/object_graph.dart
@@ -214,14 +214,19 @@
static const int maxUnsignedDataPerByte = byteMask;
}
+// Node indices for the root and sentinel nodes. Note that using 0 as the
+// sentinel means a newly allocated typed array comes initialized with all
+// elements as the sentinel.
+const ROOT = 1;
+const SENTINEL = 0;
+
class ObjectVertex {
- // 0 represents invalid/uninitialized, 1 is the root.
final int _id;
final ObjectGraph _graph;
ObjectVertex._(this._id, this._graph);
- bool get isRoot => _id == 1;
+ bool get isRoot => ROOT == _id;
bool operator ==(other) => _id == other._id && _graph == other._graph;
int get hashCode => _id;
@@ -272,7 +277,7 @@
var parentId = _id;
var domChildren = [];
- for (var childId = 1; childId <= N; childId++) {
+ for (var childId = ROOT; childId <= N; childId++) {
if (doms[childId] == parentId) {
domChildren.add(new ObjectVertex._(childId, _graph));
}
@@ -282,6 +287,81 @@
}
}
+// A node in the dominator tree where siblings with the same class are merged.
+// That is, a set of objects with the same cid whose parent chains in the
+// dominator tree have the same cids at each level. [id_] is the representative
+// object of this set. The other members of the set are found by walking the
+// mergedDomNext links until finding the sentinel node or a node with a
+// different class.
+class MergedObjectVertex {
+ final int _id;
+ final ObjectGraph _graph;
+
+ MergedObjectVertex._(this._id, this._graph);
+
+ bool get isRoot => ROOT == _id;
+
+ bool operator ==(other) => _id == other._id && _graph == other._graph;
+ int get hashCode => _id;
+
+ int get vmCid => _graph._cids[_id];
+
+ int get shallowSize {
+ var cids = _graph._cids;
+ var size = 0;
+ var sibling = _id;
+ while (sibling != SENTINEL &&
+ cids[sibling] == cids[_id]) {
+ size += _graph._shallowSizes[sibling];
+ sibling = _graph._mergedDomNext[sibling];
+ }
+ return size;
+ }
+ int get retainedSize {
+ var cids = _graph._cids;
+ var size = 0;
+ var sibling = _id;
+ while (sibling != SENTINEL &&
+ cids[sibling] == cids[_id]) {
+ size += _graph._retainedSizes[sibling];
+ sibling = _graph._mergedDomNext[sibling];
+ }
+ return size;
+ }
+ int get instanceCount {
+ var cids = _graph._cids;
+ var count = 0;
+ var sibling = _id;
+ while (sibling != SENTINEL &&
+ cids[sibling] == cids[_id]) {
+ count++;
+ sibling = _graph._mergedDomNext[sibling];
+ }
+ return count;
+ }
+
+ List<MergedObjectVertex> dominatorTreeChildren() {
+ var next = _graph._mergedDomNext;
+ var cids = _graph._cids;
+
+ var domChildren = [];
+ var prev = SENTINEL;
+ var child = _graph._mergedDomHead[_id];
+ // Walk the list of children and look for the representative objects, i.e.
+ // the first sibling of each cid.
+ while (child != SENTINEL) {
+ if (prev == SENTINEL ||
+ cids[prev] != cids[child]) {
+ domChildren.add(new MergedObjectVertex._(child, _graph));
+ }
+ prev = child;
+ child = next[child];
+ }
+
+ return domChildren;
+ }
+}
+
class _SuccessorsIterable extends IterableBase<ObjectVertex> {
final ObjectGraph _graph;
final int _id;
@@ -345,7 +425,8 @@
int get vertexCount => _N;
int get edgeCount => _E;
- ObjectVertex get root => new ObjectVertex._(1, this);
+ ObjectVertex get root => new ObjectVertex._(ROOT, this);
+ MergedObjectVertex get mergedRoot => new MergedObjectVertex._(ROOT, this);
Iterable<ObjectVertex> get vertices => new _VerticesIterable(this);
Iterable<ObjectVertex> getMostRetained({int classId, int limit}) {
@@ -381,10 +462,10 @@
controller.add(["Finding depth-first order...", 30.0]);
await new Future(() => _dfs());
- controller.add(["Finding predecessors...", 45.0]);
+ controller.add(["Finding predecessors...", 40.0]);
await new Future(() => _buildPredecessors());
- controller.add(["Finding dominators...", 60.0]);
+ controller.add(["Finding dominators...", 50.0]);
await new Future(() => _buildDominators());
_firstPreds = null;
@@ -393,12 +474,21 @@
_semi = null;
_parent = null;
- controller.add(["Finding retained sizes...", 75.0]);
+ controller.add(["Finding retained sizes...", 60.0]);
await new Future(() => _calculateRetainedSizes());
_vertex = null;
- controller.add(["Loaded", 100.0]);
+ controller.add(["Linking dominator tree children...", 70.0]);
+ await new Future(() => _linkDominatorChildren());
+
+ controller.add(["Sorting dominator tree children...", 80.0]);
+ await new Future(() => _sortDominatorChildren());
+
+ controller.add(["Merging dominator tree siblings...", 90.0]);
+ await new Future(() => _mergeDominatorSiblings());
+
+ controller.add(["Processed", 100.0]);
controller.close();
}());
return controller.stream;
@@ -431,6 +521,8 @@
// Outputs.
Uint32List _doms;
Uint32List _retainedSizes;
+ Uint32List _mergedDomHead;
+ Uint32List _mergedDomNext;
void _remapNodes() {
var N = _N;
@@ -446,7 +538,7 @@
stream.readUnsigned();
_kObjectAlignment = stream.clampedUint32;
- var id = 1;
+ var id = ROOT;
while (stream.pendingBytes > 0) {
stream.readUnsigned(); // addr
addrToId.put(stream.high, stream.mid, stream.low, id);
@@ -466,8 +558,7 @@
}
assert(id == (N + 1));
- var root = addrToId.get(0, 0, 0);
- assert(root == 1);
+ assert(ROOT == addrToId.get(0, 0, 0));
_E = E;
_addrToId = addrToId;
@@ -503,7 +594,8 @@
succs[edge] = childId;
edge++;
} else {
- // Reference into VM isolate's heap.
+ throw new Exception(
+ "Heap snapshot contains an edge but lacks its target node");
}
stream.readUnsigned();
}
@@ -512,8 +604,7 @@
firstSuccs[id] = edge; // Extra entry for cheap boundary detection.
assert(id == N + 1);
- assert(edge <= E); // edge is smaller because E was computed before we knew
- // if references pointed into the VM isolate
+ assert(edge == E);
_E = edge;
_firstSuccs = firstSuccs;
@@ -534,11 +625,10 @@
var dfsNumber = 0;
var stackTop = 0;
- var root = 1;
// Push root.
- stackNodes[0] = root;
- stackCurrentEdgePos[0] = firstSuccs[root];
+ stackNodes[0] = ROOT;
+ stackCurrentEdgePos[0] = firstSuccs[ROOT];
while (stackTop >= 0) {
var v = stackNodes[stackTop];
@@ -571,12 +661,12 @@
}
assert(dfsNumber == N);
- for (var i = 1; i <= N; i++) {
- assert(semi[i] != 0);
+ for (var i = ROOT; i <= N; i++) {
+ assert(semi[i] != SENTINEL);
}
- assert(parent[1] == 0);
- for (var i = 2; i <= N; i++) {
- assert(parent[i] != 0);
+ assert(parent[ROOT] == SENTINEL);
+ for (var i = ROOT + 1; i <= N; i++) {
+ assert(parent[i] != SENTINEL);
}
_vertex = vertex;
@@ -636,7 +726,7 @@
static int _eval(int v, Uint32List ancestor, Uint32List semi,
Uint32List label, Uint32List stackNode, Uint8List stackState) {
- if (ancestor[v] == 0) {
+ if (ancestor[v] == SENTINEL) {
return label[v];
} else {
{
@@ -719,7 +809,6 @@
var firstPreds = _firstPreds;
var preds = _preds;
- var root = 1;
var dom = new Uint32List(N + 1);
var ancestor = new Uint32List(N + 1);
@@ -738,7 +827,7 @@
for (var i = N; i > 1; i--) {
var w = vertex[i];
- assert(w != root);
+ assert(w != ROOT);
// Lengauer & Tarjan Step 2.
var startPred = firstPreds[w];
@@ -771,7 +860,7 @@
}
}
}
- for (var i = 1; i <= N; i++) {
+ for (var i = ROOT; i <= N; i++) {
assert(buckets[i] == null);
}
// Lengauer & Tarjan Step 4.
@@ -794,7 +883,7 @@
var doms = _doms;
// Sum shallow sizes.
- for (var i = 1; i < N; i++) {
+ for (var i = ROOT; i < N; i++) {
size += shallowSizes[i];
}
@@ -805,11 +894,172 @@
// size, skipping root.
for (var i = N; i > 1; i--) {
var v = vertex[i];
- assert(v != 1);
+ assert(v != ROOT);
retainedSizes[doms[i]] += retainedSizes[i];
}
_retainedSizes = retainedSizes;
_size = size;
}
+
+ // Build linked lists of the children for each node in the dominator tree.
+ void _linkDominatorChildren() {
+ var N = _N;
+ var doms = _doms;
+ var head = new Uint32List(N + 1);
+ var next = new Uint32List(N + 1);
+
+ for (var child = ROOT; child <= N; child++) {
+ var parent = doms[child];
+ next[child] = head[parent];
+ head[parent] = child;
+ }
+
+ _mergedDomHead = head;
+ _mergedDomNext = next;
+ }
+
+ // Merge the given lists according to the given key in ascending order.
+ // Returns the head of the merged list.
+ static int _mergeSorted(int head1, int head2,
+ Uint32List next, Uint16List key) {
+ var head = head1;
+ var beforeInsert = SENTINEL;
+ var afterInsert = head1;
+ var startInsert = head2;
+
+ while (startInsert != SENTINEL) {
+ while ((afterInsert != SENTINEL) &&
+ (key[afterInsert] <= key[startInsert])) {
+ beforeInsert = afterInsert;
+ afterInsert = next[beforeInsert];
+ }
+
+ var endInsert = startInsert;
+ var peek = next[endInsert];
+
+ while ((peek != SENTINEL) && (key[peek] < key[afterInsert])) {
+ endInsert = peek;
+ peek = next[endInsert];
+ }
+ assert(endInsert != SENTINEL);
+
+ if (beforeInsert == SENTINEL) {
+ head = startInsert;
+ } else {
+ next[beforeInsert] = startInsert;
+ }
+ next[endInsert] = afterInsert;
+
+ startInsert = peek;
+ beforeInsert = endInsert;
+ }
+
+ return head;
+ }
+
+ void _sortDominatorChildren() {
+ var N = _N;
+ var cids = _cids;
+ var head = _mergedDomHead;
+ var next = _mergedDomNext;
+
+ // Returns the new head of the sorted list.
+ int sort(int head) {
+ if (head == SENTINEL) return SENTINEL;
+ if (next[head] == SENTINEL) return head;
+
+ // Find the middle of the list.
+ int head1 = head;
+ int slow = head;
+ int fast = head;
+ while (next[fast] != SENTINEL &&
+ next[next[fast]] != SENTINEL) {
+ slow = next[slow];
+ fast = next[next[fast]];
+ }
+
+ // Split the list in half.
+ int head2 = next[slow];
+ next[slow] = SENTINEL;
+
+ // Recursively sort the sublists and merge.
+ assert(head1 != head2);
+ int newHead1 = sort(head1);
+ int newHead2 = sort(head2);
+ return _mergeSorted(newHead1, newHead2, next, cids);
+ }
+
+ // Sort all list of dominator tree children by cid.
+ for (var parent = ROOT; parent <= N; parent++) {
+ head[parent] = sort(head[parent]);
+ }
+ }
+
+ void _mergeDominatorSiblings() {
+ var N = _N;
+ var cids = _cids;
+ var head = _mergedDomHead;
+ var next = _mergedDomNext;
+ var workStack = new Uint32List(N);
+ var workStackTop = 0;
+
+ mergeChildrenAndSort(var parent1, var end) {
+ assert(parent1 != SENTINEL);
+ if (next[parent1] == end) return;
+
+ // Find the middle of the list.
+ int cid = cids[parent1];
+ int slow = parent1;
+ int fast = parent1;
+ while (next[fast] != end &&
+ next[next[fast]] != end) {
+ slow = next[slow];
+ fast = next[next[fast]];
+ }
+
+ int parent2 = next[slow];
+
+ assert(parent2 != SENTINEL);
+ assert(parent1 != parent2);
+ assert(cids[parent1] == cids[parent2]);
+
+ // Recursively sort the sublists.
+ mergeChildrenAndSort(parent1, parent2);
+ mergeChildrenAndSort(parent2, end);
+
+ // Merge sorted sublists.
+ head[parent1] = _mergeSorted(head[parent1], head[parent2], next, cids);
+
+ // Children moved to parent1.
+ head[parent2] = SENTINEL;
+ }
+
+ // Push root.
+ workStack[workStackTop++] = ROOT;
+
+ while (workStackTop > 0) {
+ var parent = workStack[--workStackTop];
+
+ var prev = SENTINEL;
+ var child = head[parent];
+ while (child != SENTINEL) {
+ // Push child.
+ workStack[workStackTop++] = child;
+
+ // Find next sibling with a different cid.
+ var after = child;
+ while (after != SENTINEL &&
+ cids[after] == cids[child]) {
+ after = next[after];
+ }
+
+ // From all the siblings between child and after, take their children,
+ // merge them and given to child.
+ mergeChildrenAndSort(child, after);
+
+ child = after;
+ }
+ }
+ }
}
diff --git a/runtime/observatory/lib/repositories.dart b/runtime/observatory/lib/repositories.dart
index 03e6cc6..a4b73ff 100644
--- a/runtime/observatory/lib/repositories.dart
+++ b/runtime/observatory/lib/repositories.dart
@@ -13,7 +13,6 @@
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart' as S;
import 'package:observatory/service_common.dart' as SC;
-import 'package:observatory/utils.dart';
part 'src/repositories/allocation_profile.dart';
part 'src/repositories/breakpoint.dart';
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.dart b/runtime/observatory/lib/src/elements/heap_snapshot.dart
index 2fd6e78..7389daa 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart
@@ -24,7 +24,7 @@
import 'package:observatory/src/elements/nav/vm_menu.dart';
import 'package:observatory/utils.dart';
-enum HeapSnapshotTreeMode { dominatorTree, groupByClass }
+enum HeapSnapshotTreeMode { dominatorTree, mergedDominatorTree, groupByClass }
class HeapSnapshotElement extends HtmlElement implements Renderable {
static const tag =
@@ -266,6 +266,23 @@
_tree
]);
break;
+ case HeapSnapshotTreeMode.mergedDominatorTree:
+ _tree = new VirtualTreeElement(
+ _createMergedDominator, _updateMergedDominator,
+ _getChildrenMergedDominator,
+ items: _getChildrenMergedDominator(_snapshot.mergedDominatorTree),
+ queue: _r.queue);
+ _tree.expand(_snapshot.mergedDominatorTree);
+ final text = 'A heap dominator tree, where siblings with the same class'
+ ' have been merged into a single node.';
+ report.addAll([
+ new DivElement()
+ ..classes = ['content-centered-big', 'explanation']
+ ..text = text
+ ..title = text,
+ _tree
+ ]);
+ break;
case HeapSnapshotTreeMode.groupByClass:
final items = _snapshot.classReferences.toList();
items.sort((a, b) => b.shallowSize - a.shallowSize);
@@ -299,6 +316,24 @@
];
}
+ static Element _createMergedDominator(toggle) {
+ return new DivElement()
+ ..classes = ['tree-item']
+ ..children = [
+ new SpanElement()
+ ..classes = ['size']
+ ..title = 'retained size',
+ new SpanElement()..classes = ['lines'],
+ new ButtonElement()
+ ..classes = ['expander']
+ ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
+ new SpanElement()
+ ..classes = ['percentage']
+ ..title = 'percentage of heap being retained',
+ new SpanElement()..classes = ['name']
+ ];
+ }
+
static Element _createGroup(toggle) {
return new DivElement()
..classes = ['tree-item']
@@ -327,6 +362,13 @@
.where((child) => child.retainedSize >= kMinRetainedSize)
.take(kMaxChildren);
}
+ static _getChildrenMergedDominator(M.HeapSnapshotMergedDominatorNode node) {
+ final list = node.children.toList();
+ list.sort((a, b) => b.retainedSize - a.retainedSize);
+ return list
+ .where((child) => child.retainedSize >= kMinRetainedSize)
+ .take(kMaxChildren);
+ }
static _getChildrenGroup(item) {
if (item is M.HeapSnapshotClassReferences) {
@@ -361,6 +403,31 @@
});
}
+ void _updateMergedDominator(
+ HtmlElement element, M.HeapSnapshotMergedDominatorNode node, int depth) {
+ element.children[0].text = Utils.formatSize(node.retainedSize);
+ _updateLines(element.children[1].children, depth);
+ if (_getChildrenMergedDominator(node).isNotEmpty) {
+ element.children[2].text = _tree.isExpanded(node) ? 'â–¼' : 'â–º';
+ } else {
+ element.children[2].text = '';
+ }
+ element.children[3].text =
+ Utils.formatPercentNormalized(node.retainedSize * 1.0 / _snapshot.size);
+ final wrapper = new SpanElement()
+ ..classes = ['name']
+ ..text = 'Loading...';
+ element.children[4] = wrapper;
+ node.klass.then((klass) {
+ wrapper
+ ..text = ''
+ ..children = [
+ new SpanElement()..text = '${node.instanceCount} instances of ',
+ anyRef(_isolate, klass, _instances, queue: _r.queue)
+ ];
+ });
+ }
+
void _updateGroup(HtmlElement element, item, int depth) {
_updateLines(element.children[1].children, depth);
if (item is M.HeapSnapshotClassReferences) {
@@ -424,6 +491,8 @@
switch (mode) {
case HeapSnapshotTreeMode.dominatorTree:
return 'Dominator tree';
+ case HeapSnapshotTreeMode.mergedDominatorTree:
+ return 'Dominator tree (merged siblings by class)';
case HeapSnapshotTreeMode.groupByClass:
return 'Group by class';
}
diff --git a/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart b/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
index 5345d8c..2d7abcd 100644
--- a/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
@@ -11,6 +11,7 @@
int get references => graph.edgeCount;
int get size => graph.size;
HeapSnapshotDominatorNode dominatorTree;
+ HeapSnapshotMergedDominatorNode mergedDominatorTree;
List<MergedVertex> classReferences;
static Future sleep([Duration duration = const Duration(microseconds: 0)]) {
@@ -36,6 +37,8 @@
});
await stream.last;
dominatorTree = new HeapSnapshotDominatorNode(isolate, graph.root);
+ mergedDominatorTree =
+ new HeapSnapshotMergedDominatorNode(isolate, graph.mergedRoot);
classReferences = await buildMergedVertices(isolate, graph, signal);
progress.close();
}());
@@ -151,6 +154,36 @@
v = vertex;
}
+class HeapSnapshotMergedDominatorNode
+ implements M.HeapSnapshotMergedDominatorNode {
+ final MergedObjectVertex v;
+ final S.Isolate isolate;
+
+ Future<S.HeapObject> get klass {
+ return new Future.value(isolate.getClassByCid(v.vmCid));
+ }
+
+ Iterable<HeapSnapshotMergedDominatorNode> _children;
+ Iterable<HeapSnapshotMergedDominatorNode> get children {
+ if (_children != null) {
+ return _children;
+ } else {
+ return _children =
+ new List.unmodifiable(v.dominatorTreeChildren().map((v) {
+ return new HeapSnapshotMergedDominatorNode(isolate, v);
+ }));
+ }
+ }
+
+ int get instanceCount => v.instanceCount;
+ int get retainedSize => v.retainedSize;
+ int get shallowSize => v.shallowSize;
+
+ HeapSnapshotMergedDominatorNode(S.Isolate isolate, MergedObjectVertex vertex)
+ : isolate = isolate,
+ v = vertex;
+}
+
class MergedEdge {
final MergedVertex sourceVertex;
final MergedVertex targetVertex;
diff --git a/runtime/observatory/lib/src/models/objects/heap_snapshot.dart b/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
index 19392f9..ff4cefe 100644
--- a/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
@@ -10,6 +10,7 @@
int get references;
int get size;
HeapSnapshotDominatorNode get dominatorTree;
+ HeapSnapshotMergedDominatorNode get mergedDominatorTree;
Iterable<HeapSnapshotClassReferences> get classReferences;
}
@@ -20,6 +21,14 @@
Iterable<HeapSnapshotDominatorNode> get children;
}
+abstract class HeapSnapshotMergedDominatorNode {
+ int get instanceCount;
+ int get shallowSize;
+ int get retainedSize;
+ Future<ObjectRef> get klass;
+ Iterable<HeapSnapshotMergedDominatorNode> get children;
+}
+
abstract class HeapSnapshotClassReferences {
ClassRef get clazz;
int get instances;
diff --git a/runtime/observatory/tests/observatory_ui/observatory_ui.status b/runtime/observatory/tests/observatory_ui/observatory_ui.status
index 1b96aa6..a5665d5 100644
--- a/runtime/observatory/tests/observatory_ui/observatory_ui.status
+++ b/runtime/observatory/tests/observatory_ui/observatory_ui.status
@@ -14,6 +14,7 @@
allocation_profile: Skip
cpu_profile_table: Skip
persistent_handles_page: Skip
+vm_connect/element_test: Skip # See issue 27714
[ $runtime == ff || $runtime == chrome ]
-vm_connect/element_test: Skip # Times out
\ No newline at end of file
+vm_connect/element_test: Skip # Times out
diff --git a/runtime/observatory/tests/service/issue_27238_test.dart b/runtime/observatory/tests/service/issue_27238_test.dart
index 07cf335..77302ae 100644
--- a/runtime/observatory/tests/service/issue_27238_test.dart
+++ b/runtime/observatory/tests/service/issue_27238_test.dart
@@ -3,17 +3,16 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--error_on_bad_type --error_on_bad_override --verbose_debug
-import 'package:observatory/service_io.dart';
import 'service_test_common.dart';
import 'dart:async';
import 'test_helper.dart';
import 'dart:developer';
-const int LINE_A = 20;
-const int LINE_B = 23;
-const int LINE_C = 24;
-const int LINE_D = 26;
-const int LINE_E = 27;
+const int LINE_A = 19;
+const int LINE_B = 22;
+const int LINE_C = 23;
+const int LINE_D = 25;
+const int LINE_E = 26;
testMain() async {
debugger();
diff --git a/runtime/observatory/tests/service/issue_27287_test.dart b/runtime/observatory/tests/service/issue_27287_test.dart
index 58633b33..85d3e97 100644
--- a/runtime/observatory/tests/service/issue_27287_test.dart
+++ b/runtime/observatory/tests/service/issue_27287_test.dart
@@ -3,14 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--error_on_bad_type --error_on_bad_override --verbose_debug
-import 'package:observatory/service_io.dart';
import 'service_test_common.dart';
-import 'dart:async';
import 'test_helper.dart';
import 'dart:developer';
-const int LINE_A = 19;
-const int LINE_B = 20;
+const int LINE_A = 17;
+const int LINE_B = 18;
var libVariable;
diff --git a/runtime/observatory/tests/service/reload_sources_test.dart b/runtime/observatory/tests/service/reload_sources_test.dart
index 4c8b4d9..64f5eac 100644
--- a/runtime/observatory/tests/service/reload_sources_test.dart
+++ b/runtime/observatory/tests/service/reload_sources_test.dart
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--error_on_bad_type --error_on_bad_override
-import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
import 'test_helper.dart';
import 'dart:developer';
import 'service_test_common.dart';
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 8cdaef3..638f447 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -20,7 +20,6 @@
debugger_location_second_test: Pass, Slow
debugger_location_test: Pass, Slow
-
# Disable on simulators.
[ $arch == simarm || $arch == simmips || $arch == simarm64 ]
*: SkipSlow
@@ -43,13 +42,18 @@
[ $runtime == vm ]
developer_extension_test: Pass, Fail # Issue 27225
-# Service protocol is not supported in product mode.
-[ $mode == product ]
-*: SkipByDesign
-
-# Service protocol is not supported when running a full application snapshot.
[ $runtime == dart_app ]
-*: SkipByDesign
+address_mapper_test: CompileTimeError # Issue 27806
+capture_stdio_test: CompileTimeError # Issue 27806
+debugger_location_second_test: RuntimeError # Issue 27806
+dev_fs_spawn_test: RuntimeError # Issue 27806
+developer_extension_test: RuntimeError # Issue 27806
+evaluate_activation_test/instance: RuntimeError # Issue 27806
+evaluate_activation_test/scope: RuntimeError # Issue 27806
+get_object_rpc_test: RuntimeError # Issue 27806
+get_source_report_test: RuntimeError # Issue 27806
+set_name_rpc_test: RuntimeError # Issue 27806
+vm_restart_test: CompileTimeError # Issue 27806
[ $compiler == dart2analyzer ]
evaluate_activation_in_method_class_test: CompileTimeError # Issue 24478
@@ -66,3 +70,7 @@
[ $system == windows ]
dev_fs_weird_char_test: Skip # Windows disallows question mark in paths
dev_fs_http_put_weird_char_test: Skip # Windows disallows carriage returns in paths
+
+# Service protocol is not supported in product mode.
+[ $mode == product ]
+*: SkipByDesign
diff --git a/runtime/observatory/tests/service/step_test.dart b/runtime/observatory/tests/service/step_test.dart
new file mode 100644
index 0000000..47009dc
--- /dev/null
+++ b/runtime/observatory/tests/service/step_test.dart
@@ -0,0 +1,38 @@
+import 'dart:async';
+import 'test_helper.dart';
+import 'service_test_common.dart';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+const int LINE_A = 10;
+
+code() {
+ var x = {}; // LINE_A
+}
+
+Future<Isolate> stepThroughProgram(Isolate isolate) async {
+ Completer completer = new Completer();
+ int pauseEventsSeen = 0;
+
+ await subscribeToStream(isolate.vm, VM.kDebugStream,
+ (ServiceEvent event) async {
+ if (event.kind == ServiceEvent.kPauseBreakpoint) {
+ // We are paused: Step further.
+ pauseEventsSeen++;
+ isolate.stepInto();
+ } else if (event.kind == ServiceEvent.kPauseExit) {
+ // We are at the exit: The test is done.
+ expect(pauseEventsSeen > 20, true,
+ reason: "Saw only $pauseEventsSeen pause events.");
+ await cancelStreamSubscription(VM.kDebugStream);
+ completer.complete();
+ }
+ });
+ isolate.resume();
+ return completer.future;
+}
+
+var tests = [hasPausedAtStart, setBreakpointAtLine(LINE_A), stepThroughProgram];
+
+main(args) => runIsolateTestsSynchronous(args, tests,
+ testeeConcurrent: code, pause_on_start: true, pause_on_exit: true);
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 7ff1030..61d2bac 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -8,7 +8,6 @@
cc/IsolateReload_PendingConstructorCall_ConcreteToAbstract: Fail, Crash
cc/IsolateReload_PendingStaticCall_DefinedToNSM: Fail, Crash
cc/IsolateReload_PendingStaticCall_NSMToDefined: Fail, Crash
-cc/IsolateReload_EnumDelete: Skip # Issue 27802
# These tests are expected to crash on all platforms.
cc/ArrayNew_Overflow_Crash: Crash, Timeout
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index e0eab68..8e47ef7 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -102,22 +102,6 @@
include_dirs = [ ".." ]
}
-static_library("libdart_vm_nosnapshot_precompiled_runtime") {
- configs += [
- "..:dart_config",
- "..:dart_maybe_product_config",
- "..:dart_precompiled_runtime_config",
- "..:dart_no_snapshot_config",
- ]
- public_configs = [ ":libdart_vm_config" ]
- set_sources_assignment_filter([
- "*_test.cc",
- "*_test.h",
- ])
- sources = vm_sources_list
- include_dirs = [ ".." ]
-}
-
static_library("libdart_vm_nosnapshot_with_precompiler") {
configs += [
"..:dart_config",
@@ -239,16 +223,6 @@
sources = all_libsources + [ "bootstrap.cc" ] + liboutputs
include_dirs = [ ".." ]
}
- static_library("libdart_lib_nosnapshot_precompiled_runtime") {
- configs += [
- "..:dart_config",
- "..:dart_maybe_product_config",
- "..:dart_precompiled_runtime_config",
- ]
- deps = libdeps
- sources = all_libsources + [ "bootstrap.cc" ] + liboutputs
- include_dirs = [ ".." ]
- }
static_library("libdart_lib_nosnapshot_with_precompiler") {
configs += [
"..:dart_config",
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 168471c..0013157 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -291,6 +291,18 @@
call->set_ic_data(&ic_data);
if (has_unique_no_such_method_) {
call->set_has_unique_selector(true);
+ // Add redefinition of the receiver to prevent code motion across
+ // this call.
+ RedefinitionInstr* redefinition =
+ new (Z) RedefinitionInstr(new (Z) Value(call->ArgumentAt(0)));
+ redefinition->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
+ redefinition->InsertAfter(call);
+ // Replace all uses of the receiver dominated by this call.
+ FlowGraph::RenameDominatedUses(call->ArgumentAt(0), redefinition,
+ redefinition);
+ if (!redefinition->HasUses()) {
+ redefinition->RemoveFromGraph();
+ }
}
return true;
}
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index d242edab..5b4c20f 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -10,6 +10,10 @@
#include "vm/class_finalizer.h"
#include "vm/compiler.h"
#include "vm/dart_api_impl.h"
+#if !defined(DART_PRECOMPILED_RUNTIME)
+#include "vm/kernel.h"
+#include "vm/kernel_reader.h"
+#endif
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/symbols.h"
@@ -244,6 +248,24 @@
}
+static void Finish(Thread* thread, bool from_kernel) {
+ Bootstrap::SetupNativeResolver();
+ if (!ClassFinalizer::ProcessPendingClasses(from_kernel)) {
+ FATAL("Error in class finalization during bootstrapping.");
+ }
+
+ // Eagerly compile the _Closure class as it is the class of all closure
+ // instances. This allows us to just finalize function types without going
+ // through the hoops of trying to compile their scope class.
+ ObjectStore* object_store = thread->isolate()->object_store();
+ Class& cls = Class::Handle(thread->zone(), object_store->closure_class());
+ Compiler::CompileClass(cls);
+ // Eagerly compile Bool class, bool constants are used from within compiler.
+ cls = object_store->bool_class();
+ Compiler::CompileClass(cls);
+}
+
+
static RawError* BootstrapFromSource(Thread* thread) {
Isolate* isolate = thread->isolate();
Zone* zone = thread->zone();
@@ -285,19 +307,8 @@
}
if (error.IsNull()) {
- Bootstrap::SetupNativeResolver();
- ClassFinalizer::ProcessPendingClasses();
-
- // Eagerly compile the _Closure class as it is the class of all closure
- // instances. This allows us to just finalize function types
- // without going through the hoops of trying to compile their scope class.
- Class& cls = Class::Handle(zone, isolate->object_store()->closure_class());
- Compiler::CompileClass(cls);
- // Eagerly compile Bool class, bool constants are used from within compiler.
- cls = isolate->object_store()->bool_class();
- Compiler::CompileClass(cls);
+ Finish(thread, /*from_kernel=*/false);
}
-
// Restore the library tag handler for the isolate.
isolate->set_library_tag_handler(saved_tag_handler);
@@ -305,7 +316,65 @@
}
-RawError* Bootstrap::DoBootstrapping() {
+#if !defined(DART_PRECOMPILED_RUNTIME)
+static RawError* BootstrapFromKernel(Thread* thread,
+ const uint8_t* buffer,
+ intptr_t buffer_size) {
+ Zone* zone = thread->zone();
+ kernel::Program* program =
+ ReadPrecompiledKernelFromBuffer(buffer, buffer_size);
+ if (program == NULL) {
+ const String& message =
+ String::Handle(zone, String::New("Failed to read Kernel file"));
+ return ApiError::New(message);
+ }
+
+ Isolate* isolate = thread->isolate();
+ // Mark the already-pending classes. This mark bit will be used to avoid
+ // adding classes to the list more than once.
+ GrowableObjectArray& pending_classes = GrowableObjectArray::Handle(
+ zone, isolate->object_store()->pending_classes());
+ dart::Class& pending = dart::Class::Handle(zone);
+ for (intptr_t i = 0; i < pending_classes.Length(); ++i) {
+ pending ^= pending_classes.At(i);
+ pending.set_is_marked_for_parsing();
+ }
+
+ Library& library = Library::Handle(zone);
+ String& dart_name = String::Handle(zone);
+ String& kernel_name = String::Handle(zone);
+ kernel::KernelReader reader(NULL, -1, true);
+ for (intptr_t i = 0; i < kBootstrapLibraryCount; ++i) {
+ ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
+ library = isolate->object_store()->bootstrap_library(id);
+ dart_name = library.url();
+ for (intptr_t j = 0; j < program->libraries().length(); ++j) {
+ kernel::Library* kernel_library = program->libraries()[j];
+ kernel::String* uri = kernel_library->import_uri();
+ kernel_name = Symbols::FromUTF8(thread, uri->buffer(), uri->size());
+ if (kernel_name.Equals(dart_name)) {
+ reader.ReadLibrary(kernel_library);
+ library.SetLoaded();
+ break;
+ }
+ }
+ }
+
+ Finish(thread, /*from_kernel=*/true);
+ return Error::null();
+}
+#else
+static RawError* BootstrapFromKernel(Thread* thread,
+ const uint8_t* buffer,
+ intptr_t buffer_size) {
+ UNREACHABLE();
+ return Error::null();
+}
+#endif
+
+
+RawError* Bootstrap::DoBootstrapping(const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_length) {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
Zone* zone = thread->zone();
@@ -328,7 +397,9 @@
}
}
- return BootstrapFromSource(thread);
+ return (kernel_buffer == NULL)
+ ? BootstrapFromSource(thread)
+ : BootstrapFromKernel(thread, kernel_buffer, kernel_buffer_length);
}
} // namespace dart
diff --git a/runtime/vm/bootstrap.h b/runtime/vm/bootstrap.h
index 0c2d912..77fb556 100644
--- a/runtime/vm/bootstrap.h
+++ b/runtime/vm/bootstrap.h
@@ -15,7 +15,15 @@
class Bootstrap : public AllStatic {
public:
- static RawError* DoBootstrapping();
+ // Compile the bootstrap libraries, either from sources or a Kernel binary.
+ // If kernel_buffer is NULL, compile from sources or source paths linked into
+ // the VM. If it is non-NULL it represents a buffer holding a Kernel binary.
+ // The caller of this function is responsible for managing the kernel
+ // buffer's memory, and is welcome to deallocate it after this function
+ // returns.
+ static RawError* DoBootstrapping(const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_length);
+
static void SetupNativeResolver();
static bool IsBootstapResolver(Dart_NativeEntryResolver resolver);
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 559f44a..7ae1810 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -346,6 +346,7 @@
V(UserTag_makeCurrent, 1) \
V(Profiler_getCurrentTag, 0) \
V(ClassID_getID, 1) \
+ V(ClassID_byName, 1) \
V(VMService_SendIsolateServiceMessage, 2) \
V(VMService_SendRootServiceMessage, 1) \
V(VMService_SendObjectRootServiceMessage, 1) \
diff --git a/runtime/vm/bootstrap_nocore.cc b/runtime/vm/bootstrap_nocore.cc
index 64db0eb..d804b24 100644
--- a/runtime/vm/bootstrap_nocore.cc
+++ b/runtime/vm/bootstrap_nocore.cc
@@ -6,15 +6,136 @@
#include "include/dart_api.h"
+#if !defined(DART_PRECOMPILED_RUNTIME)
+#include "vm/class_finalizer.h"
+#include "vm/compiler.h"
+#include "vm/kernel_reader.h"
+#endif
#include "vm/object.h"
+#if !defined(DART_PRECOMPILED_RUNTIME)
+#include "vm/object_store.h"
+#endif
namespace dart {
+#if !defined(DART_PRECOMPILED_RUNTIME)
+#define MAKE_PROPERTIES(CamelName, name) \
+ {ObjectStore::k##CamelName, "dart:" #name},
-RawError* Bootstrap::DoBootstrapping() {
- UNREACHABLE();
+
+struct BootstrapLibProps {
+ ObjectStore::BootstrapLibraryId index;
+ const char* uri;
+};
+
+
+static BootstrapLibProps bootstrap_libraries[] = {
+ FOR_EACH_BOOTSTRAP_LIBRARY(MAKE_PROPERTIES)};
+
+
+#undef MAKE_PROPERTIES
+
+
+static const intptr_t bootstrap_library_count = ARRAY_SIZE(bootstrap_libraries);
+
+
+void Finish(Thread* thread, bool from_kernel) {
+ Bootstrap::SetupNativeResolver();
+ ClassFinalizer::ProcessPendingClasses(from_kernel);
+
+ // Eagerly compile the _Closure class as it is the class of all closure
+ // instances. This allows us to just finalize function types without going
+ // through the hoops of trying to compile their scope class.
+ ObjectStore* object_store = thread->isolate()->object_store();
+ Class& cls = Class::Handle(thread->zone(), object_store->closure_class());
+ Compiler::CompileClass(cls);
+ // Eagerly compile Bool class, bool constants are used from within compiler.
+ cls = object_store->bool_class();
+ Compiler::CompileClass(cls);
+}
+
+
+RawError* BootstrapFromKernel(Thread* thread,
+ const uint8_t* buffer,
+ intptr_t buffer_length) {
+ Zone* zone = thread->zone();
+ kernel::Program* program =
+ ReadPrecompiledKernelFromBuffer(buffer, buffer_length);
+ if (program == NULL) {
+ const String& message =
+ String::Handle(zone, String::New("Failed to read Kernel file"));
+ return ApiError::New(message);
+ }
+
+ Isolate* isolate = thread->isolate();
+ // Mark the already-pending classes. This mark bit will be used to avoid
+ // adding classes to the list more than once.
+ GrowableObjectArray& pending_classes = GrowableObjectArray::Handle(
+ zone, isolate->object_store()->pending_classes());
+ dart::Class& pending = dart::Class::Handle(zone);
+ for (intptr_t i = 0; i < pending_classes.Length(); ++i) {
+ pending ^= pending_classes.At(i);
+ pending.set_is_marked_for_parsing();
+ }
+
+ Library& library = Library::Handle(zone);
+ String& dart_name = String::Handle(zone);
+ String& kernel_name = String::Handle(zone);
+ kernel::KernelReader reader(NULL, -1, true);
+ for (intptr_t i = 0; i < bootstrap_library_count; ++i) {
+ ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
+ library = isolate->object_store()->bootstrap_library(id);
+ dart_name = library.url();
+ for (intptr_t j = 0; j < program->libraries().length(); ++j) {
+ kernel::Library* kernel_library = program->libraries()[j];
+ kernel::String* uri = kernel_library->import_uri();
+ kernel_name = Symbols::FromUTF8(thread, uri->buffer(), uri->size());
+ if (kernel_name.Equals(dart_name)) {
+ reader.ReadLibrary(kernel_library);
+ library.SetLoaded();
+ break;
+ }
+ }
+ }
+
+ Finish(thread, /*from_kernel=*/true);
return Error::null();
}
+RawError* Bootstrap::DoBootstrapping(const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_length) {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ Zone* zone = thread->zone();
+ String& uri = String::Handle(zone);
+ Library& lib = Library::Handle(zone);
+
+ HANDLESCOPE(thread);
+
+ // Ensure there are library objects for all the bootstrap libraries.
+ for (intptr_t i = 0; i < bootstrap_library_count; ++i) {
+ ObjectStore::BootstrapLibraryId id = bootstrap_libraries[i].index;
+ uri = Symbols::New(thread, bootstrap_libraries[i].uri);
+ lib = isolate->object_store()->bootstrap_library(id);
+ ASSERT(lib.raw() == Library::LookupLibrary(thread, uri));
+ if (lib.IsNull()) {
+ lib = Library::NewLibraryHelper(uri, false);
+ lib.SetLoadRequested();
+ lib.Register(thread);
+ isolate->object_store()->set_bootstrap_library(id, lib);
+ }
+ }
+
+ ASSERT(kernel_buffer != NULL);
+ return BootstrapFromKernel(thread, kernel_buffer, kernel_buffer_length);
+}
+#else
+RawError* Bootstrap::DoBootstrapping(const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_length) {
+ UNREACHABLE();
+ return Error::null();
+}
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
+
} // namespace dart
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 98d74ff..c8683ee 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -118,7 +118,7 @@
// Processing ObjectStore::pending_classes_ occurs:
// a) when bootstrap process completes (VerifyBootstrapClasses).
// b) after the user classes are loaded (dart_api).
-bool ClassFinalizer::ProcessPendingClasses() {
+bool ClassFinalizer::ProcessPendingClasses(bool from_kernel) {
Thread* thread = Thread::Current();
NOT_IN_PRODUCT(TimelineDurationScope tds(thread, Timeline::GetIsolateStream(),
"ProcessPendingClasses"));
@@ -150,6 +150,12 @@
for (intptr_t i = 0; i < class_array.Length(); i++) {
cls ^= class_array.At(i);
FinalizeTypesInClass(cls);
+ // Classes compiled from Dart sources are finalized more lazily, classes
+ // compiled from Kernel binaries can be finalized now (and should be,
+ // since we will not revisit them).
+ if (from_kernel) {
+ FinalizeClass(cls);
+ }
}
if (FLAG_print_classes) {
for (intptr_t i = 0; i < class_array.Length(); i++) {
@@ -188,7 +194,7 @@
}
-#if defined(DART_NO_SNAPSHOT)
+#if !defined(DART_PRECOMPILED_RUNTIME)
void ClassFinalizer::VerifyBootstrapClasses() {
if (FLAG_trace_class_finalization) {
OS::Print("VerifyBootstrapClasses START.\n");
@@ -254,7 +260,7 @@
}
Isolate::Current()->heap()->Verify();
}
-#endif // defined(DART_NO_SNAPSHOT).
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
static bool IsLoaded(const Type& type) {
@@ -263,9 +269,15 @@
}
const UnresolvedClass& unresolved_class =
UnresolvedClass::Handle(type.unresolved_class());
- const LibraryPrefix& prefix =
- LibraryPrefix::Handle(unresolved_class.library_prefix());
- return prefix.IsNull() || prefix.is_loaded();
+ const Object& prefix =
+ Object::Handle(unresolved_class.library_or_library_prefix());
+ if (prefix.IsNull()) {
+ return true;
+ } else if (prefix.IsLibraryPrefix()) {
+ return LibraryPrefix::Cast(prefix).is_loaded();
+ } else {
+ return true;
+ }
}
@@ -276,15 +288,19 @@
const String& class_name = String::Handle(unresolved_class.ident());
Library& lib = Library::Handle();
Class& resolved_class = Class::Handle();
- if (unresolved_class.library_prefix() == LibraryPrefix::null()) {
+ if (unresolved_class.library_or_library_prefix() == Object::null()) {
lib = cls.library();
ASSERT(!lib.IsNull());
resolved_class = lib.LookupClass(class_name);
} else {
- LibraryPrefix& lib_prefix = LibraryPrefix::Handle();
- lib_prefix = unresolved_class.library_prefix();
- ASSERT(!lib_prefix.IsNull());
- resolved_class = lib_prefix.LookupClass(class_name);
+ const Object& prefix =
+ Object::Handle(unresolved_class.library_or_library_prefix());
+
+ if (prefix.IsLibraryPrefix()) {
+ resolved_class = LibraryPrefix::Cast(prefix).LookupClass(class_name);
+ } else {
+ resolved_class = Library::Cast(prefix).LookupClass(class_name);
+ }
}
return resolved_class.raw();
}
@@ -1422,7 +1438,7 @@
&error))) {
if (Isolate::Current()->error_on_bad_type()) {
const AbstractType& const_value_type =
- AbstractType::Handle(zone, const_value.GetType());
+ AbstractType::Handle(zone, const_value.GetType(Heap::kNew));
const String& const_value_type_name =
String::Handle(zone, const_value_type.UserVisibleName());
const String& type_name =
@@ -2189,12 +2205,25 @@
const GrowableObjectArray& cloned_funcs =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
- CreateForwardingConstructors(cls, mixin_cls, cloned_funcs);
-
Array& functions = Array::Handle(zone);
Function& func = Function::Handle(zone);
+
// The parser creates the mixin application class with no functions.
- ASSERT((functions = cls.functions(), functions.Length() == 0));
+ // But the Kernel frontend will generate mixin classes with only
+ // constructors inside them, which forward to the base class constructors.
+ //
+ // => We generate the constructors if they are not already there.
+ functions = cls.functions();
+ if (functions.Length() == 0) {
+ CreateForwardingConstructors(cls, mixin_cls, cloned_funcs);
+ } else {
+ for (intptr_t i = 0; i < functions.Length(); i++) {
+ func ^= functions.At(i);
+ ASSERT(func.kernel_function() != 0);
+ cloned_funcs.Add(func);
+ }
+ }
+
// Now clone the functions from the mixin class.
functions = mixin_cls.functions();
const intptr_t num_functions = functions.Length();
@@ -2384,8 +2413,20 @@
// if the class is being refinalized because a patch is being applied
// after the class has been finalized then it is ok for the class to have
// functions.
- ASSERT((Array::Handle(cls.functions()).Length() == 0) ||
- cls.is_refinalize_after_patch());
+ //
+ // TODO(kmillikin): This ASSERT will fail when bootstrapping from Kernel
+ // because classes are first created, methods are added, and then classes
+ // are finalized. It is not easy to finalize classes earlier because not
+ // all bootstrap classes have been created yet. It would be possible to
+ // create all classes, delay adding methods, finalize the classes, and then
+ // reprocess all classes to add methods, but that seems unnecessary.
+ // Marking the bootstrap classes as is_refinalize_after_patch seems cute but
+ // it causes other things to fail by violating their assumptions. Reenable
+ // this ASSERT if it's important, remove it if it's just a sanity check and
+ // not required for correctness.
+ //
+ // ASSERT((Array::Handle(cls.functions()).Length() == 0) ||
+ // cls.is_refinalize_after_patch());
}
}
@@ -2478,17 +2519,31 @@
ASSERT(Instance::Handle(zone, values_field.StaticValue()).IsArray());
Array& values_list =
Array::Handle(zone, Array::RawCast(values_field.StaticValue()));
-
- const Array& fields = Array::Handle(zone, enum_cls.fields());
- Field& field = Field::Handle(zone);
- Instance& ordinal_value = Instance::Handle(zone);
- Instance& enum_value = Instance::Handle(zone);
-
const String& enum_name = String::Handle(enum_cls.ScrubbedName());
const String& name_prefix =
String::Handle(String::Concat(enum_name, Symbols::Dot()));
+ Field& field = Field::Handle(zone);
+ Instance& ordinal_value = Instance::Handle(zone);
+ Instance& enum_value = Instance::Handle(zone);
+
String& enum_ident = String::Handle();
+
+ enum_ident =
+ Symbols::FromConcat(thread, Symbols::_DeletedEnumPrefix(), enum_name);
+ enum_value = Instance::New(enum_cls, Heap::kOld);
+ enum_value.SetField(index_field, Smi::Handle(zone, Smi::New(-1)));
+ enum_value.SetField(name_field, enum_ident);
+ const char* error_msg = NULL;
+ enum_value = enum_value.CheckAndCanonicalize(thread, &error_msg);
+ ASSERT(!enum_value.IsNull());
+ ASSERT(enum_value.IsCanonical());
+ field = enum_cls.LookupStaticField(Symbols::_DeletedEnumSentinel());
+ ASSERT(!field.IsNull());
+ field.SetStaticValue(enum_value, true);
+ field.RecordStore(enum_value);
+
+ const Array& fields = Array::Handle(zone, enum_cls.fields());
for (intptr_t i = 0; i < fields.Length(); i++) {
field = Field::RawCast(fields.At(i));
if (!field.is_static()) continue;
@@ -2509,7 +2564,6 @@
enum_value = Instance::New(enum_cls, Heap::kOld);
enum_value.SetField(index_field, ordinal_value);
enum_value.SetField(name_field, enum_ident);
- const char* error_msg = "";
enum_value = enum_value.CheckAndCanonicalize(thread, &error_msg);
ASSERT(!enum_value.IsNull());
ASSERT(enum_value.IsCanonical());
@@ -2520,7 +2574,6 @@
values_list.SetAt(ord, enum_value);
}
values_list.MakeImmutable();
- const char* error_msg = NULL;
values_list ^= values_list.CheckAndCanonicalize(thread, &error_msg);
ASSERT(!values_list.IsNull());
}
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index 5bcfc6b..f30f7a5 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -70,7 +70,7 @@
// failed. The function returns true if the processing was successful.
// If processing fails, an error message is set in the sticky error field
// in the object store.
- static bool ProcessPendingClasses();
+ static bool ProcessPendingClasses(bool from_kernel = false);
// Finalize the types appearing in the declaration of class 'cls', i.e. its
// type parameters and their upper bounds, its super type and interfaces.
@@ -81,11 +81,11 @@
// Finalize the class including its fields and functions.
static void FinalizeClass(const Class& cls);
-#if defined(DART_NO_SNAPSHOT)
+#if !defined(DART_PRECOMPILED_RUNTIME)
// Verify that the classes have been properly prefinalized. This is
// needed during bootstrapping where the classes have been preloaded.
static void VerifyBootstrapClasses();
-#endif // defined(DART_NO_SNAPSHOT).
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
// Resolve the class of the type, but not the type's type arguments.
// May promote the type to function type by setting its signature field.
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 396e6ad..d8ae134 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -5307,21 +5307,29 @@
WriteIsolateFullSnapshot(num_base_objects);
+ if (FLAG_print_snapshot_sizes) {
+ OS::Print("VMIsolate(CodeSize): %" Pd "\n", VmIsolateSnapshotSize());
+ OS::Print("Isolate(CodeSize): %" Pd "\n", IsolateSnapshotSize());
+ }
+ intptr_t total_size = VmIsolateSnapshotSize() + IsolateSnapshotSize();
+
if (Snapshot::IncludesCode(kind_)) {
instructions_writer_->Write(
*vm_isolate_snapshot_buffer_, vm_isolate_snapshot_size_,
*isolate_snapshot_buffer_, isolate_snapshot_size_);
- OS::Print("VMIsolate(CodeSize): %" Pd "\n", VmIsolateSnapshotSize());
- OS::Print("Isolate(CodeSize): %" Pd "\n", IsolateSnapshotSize());
- OS::Print("ReadOnlyData(CodeSize): %" Pd "\n",
- instructions_writer_->data_size());
- OS::Print("Instructions(CodeSize): %" Pd "\n",
- instructions_writer_->text_size());
- intptr_t total = VmIsolateSnapshotSize() + IsolateSnapshotSize() +
- instructions_writer_->data_size() +
- instructions_writer_->text_size();
- OS::Print("Total(CodeSize): %" Pd "\n", total);
+ if (FLAG_print_snapshot_sizes) {
+ OS::Print("ReadOnlyData(CodeSize): %" Pd "\n",
+ instructions_writer_->data_size());
+ OS::Print("Instructions(CodeSize): %" Pd "\n",
+ instructions_writer_->text_size());
+ }
+ total_size +=
+ instructions_writer_->data_size() + instructions_writer_->text_size();
+ }
+
+ if (FLAG_print_snapshot_sizes) {
+ OS::Print("Total(CodeSize): %" Pd "\n", total_size);
}
}
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index ef90b54..4a35895 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -338,7 +338,8 @@
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
- const AbstractType& instance_type = AbstractType::Handle(instance.GetType());
+ const AbstractType& instance_type =
+ AbstractType::Handle(instance.GetType(Heap::kNew));
ASSERT(instance_type.IsInstantiated());
if (type.IsInstantiated()) {
OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n", message,
@@ -551,7 +552,7 @@
// Throw a dynamic type error.
const TokenPosition location = GetCallerLocation();
const AbstractType& src_type =
- AbstractType::Handle(zone, src_instance.GetType());
+ AbstractType::Handle(zone, src_instance.GetType(Heap::kNew));
if (!dst_type.IsInstantiated()) {
// Instantiate dst_type before reporting the error.
dst_type = dst_type.InstantiateFrom(instantiator_type_arguments, NULL,
@@ -603,7 +604,7 @@
ASSERT(!src_instance.IsBool());
const Type& bool_interface = Type::Handle(Type::BoolType());
const AbstractType& src_type =
- AbstractType::Handle(zone, src_instance.GetType());
+ AbstractType::Handle(zone, src_instance.GetType(Heap::kNew));
const String& no_bound_error = String::Handle(zone);
Exceptions::CreateAndThrowTypeError(location, src_type, bool_interface,
Symbols::BooleanExpression(),
@@ -624,7 +625,7 @@
const AbstractType& dst_type =
AbstractType::CheckedHandle(zone, arguments.ArgAt(2));
const AbstractType& src_type =
- AbstractType::Handle(zone, src_value.GetType());
+ AbstractType::Handle(zone, src_value.GetType(Heap::kNew));
Exceptions::CreateAndThrowTypeError(location, src_type, dst_type, dst_name,
String::Handle(zone));
UNREACHABLE();
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index c2b7e76..16f2e18 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -167,7 +167,9 @@
// Check for ARMv5TE, ARMv6, ARMv7, or aarch64.
// It can be in either the Processor or Model information fields.
if (CpuInfo::FieldContains(kCpuInfoProcessor, "aarch64") ||
- CpuInfo::FieldContains(kCpuInfoModel, "aarch64")) {
+ CpuInfo::FieldContains(kCpuInfoModel, "aarch64") ||
+ CpuInfo::FieldContains(kCpuInfoArchitecture, "8") ||
+ CpuInfo::FieldContains(kCpuInfoArchitecture, "AArch64")) {
// pretend that this arm64 cpu is really an ARMv7
arm_version_ = ARMv7;
is_arm64 = true;
diff --git a/runtime/vm/cpuinfo.h b/runtime/vm/cpuinfo.h
index 6e8da6d..89e2432 100644
--- a/runtime/vm/cpuinfo.h
+++ b/runtime/vm/cpuinfo.h
@@ -16,7 +16,8 @@
kCpuInfoModel = 1,
kCpuInfoHardware = 2,
kCpuInfoFeatures = 3,
- kCpuInfoMax = 4,
+ kCpuInfoArchitecture = 4,
+ kCpuInfoMax = 5,
};
// For Intel architectures, the method to use to get CPU information.
diff --git a/runtime/vm/cpuinfo_android.cc b/runtime/vm/cpuinfo_android.cc
index 1e4229c..077de16 100644
--- a/runtime/vm/cpuinfo_android.cc
+++ b/runtime/vm/cpuinfo_android.cc
@@ -25,16 +25,19 @@
fields_[kCpuInfoModel] = "model name";
fields_[kCpuInfoHardware] = "model name";
fields_[kCpuInfoFeatures] = "flags";
+ fields_[kCpuInfoArchitecture] = "CPU architecture";
#elif defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
fields_[kCpuInfoProcessor] = "Processor";
fields_[kCpuInfoModel] = "model name";
fields_[kCpuInfoHardware] = "Hardware";
fields_[kCpuInfoFeatures] = "Features";
+ fields_[kCpuInfoArchitecture] = "CPU architecture";
#elif defined(HOST_ARCH_MIPS)
fields_[kCpuInfoProcessor] = "system type";
fields_[kCpuInfoModel] = "cpu model";
fields_[kCpuInfoHardware] = "cpu model";
fields_[kCpuInfoFeatures] = "ASEs implemented";
+ fields_[kCpuInfoArchitecture] = "CPU architecture";
#else
#error Unrecognized target architecture
#endif
diff --git a/runtime/vm/cpuinfo_fuchsia.cc b/runtime/vm/cpuinfo_fuchsia.cc
index 899223e..a46f842 100644
--- a/runtime/vm/cpuinfo_fuchsia.cc
+++ b/runtime/vm/cpuinfo_fuchsia.cc
@@ -27,6 +27,7 @@
fields_[kCpuInfoModel] = "Hardware";
fields_[kCpuInfoHardware] = "Hardware";
fields_[kCpuInfoFeatures] = "Features";
+ fields_[kCpuInfoArchitecture] = "CPU architecture";
#endif
}
diff --git a/runtime/vm/cpuinfo_linux.cc b/runtime/vm/cpuinfo_linux.cc
index 8d76233..6f47be0 100644
--- a/runtime/vm/cpuinfo_linux.cc
+++ b/runtime/vm/cpuinfo_linux.cc
@@ -26,6 +26,7 @@
fields_[kCpuInfoModel] = "model name";
fields_[kCpuInfoHardware] = "model name";
fields_[kCpuInfoFeatures] = "flags";
+ fields_[kCpuInfoArchitecture] = "CPU architecture";
method_ = kCpuInfoCpuId;
CpuId::InitOnce();
#elif defined(HOST_ARCH_ARM)
@@ -33,6 +34,7 @@
fields_[kCpuInfoModel] = "model name";
fields_[kCpuInfoHardware] = "Hardware";
fields_[kCpuInfoFeatures] = "Features";
+ fields_[kCpuInfoArchitecture] = "CPU architecture";
method_ = kCpuInfoSystem;
ProcCpuInfo::InitOnce();
#elif defined(HOST_ARCH_ARM64)
@@ -40,6 +42,7 @@
fields_[kCpuInfoModel] = "CPU implementer";
fields_[kCpuInfoHardware] = "CPU implementer";
fields_[kCpuInfoFeatures] = "Features";
+ fields_[kCpuInfoArchitecture] = "CPU architecture";
method_ = kCpuInfoSystem;
ProcCpuInfo::InitOnce();
#elif defined(HOST_ARCH_MIPS)
@@ -47,6 +50,7 @@
fields_[kCpuInfoModel] = "cpu model";
fields_[kCpuInfoHardware] = "cpu model";
fields_[kCpuInfoFeatures] = "ASEs implemented";
+ fields_[kCpuInfoArchitecture] = "CPU architecture";
method_ = kCpuInfoSystem;
ProcCpuInfo::InitOnce();
#else
diff --git a/runtime/vm/cpuinfo_macos.cc b/runtime/vm/cpuinfo_macos.cc
index 64e46f3..f878a5b 100644
--- a/runtime/vm/cpuinfo_macos.cc
+++ b/runtime/vm/cpuinfo_macos.cc
@@ -25,6 +25,7 @@
fields_[kCpuInfoModel] = "machdep.cpu.brand_string";
fields_[kCpuInfoHardware] = "machdep.cpu.brand_string";
fields_[kCpuInfoFeatures] = "machdep.cpu.features";
+ fields_[kCpuInfoArchitecture] = NULL;
}
diff --git a/runtime/vm/cpuinfo_win.cc b/runtime/vm/cpuinfo_win.cc
index 1570af7..6f18a35 100644
--- a/runtime/vm/cpuinfo_win.cc
+++ b/runtime/vm/cpuinfo_win.cc
@@ -29,6 +29,7 @@
fields_[kCpuInfoModel] = "Hardware";
fields_[kCpuInfoHardware] = "Hardware";
fields_[kCpuInfoFeatures] = "Features";
+ fields_[kCpuInfoArchitecture] = NULL;
}
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index bf490bf..a3d3da6 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -491,7 +491,10 @@
}
-RawError* Dart::InitializeIsolate(const uint8_t* snapshot_buffer, void* data) {
+RawError* Dart::InitializeIsolate(const uint8_t* snapshot_buffer,
+ intptr_t snapshot_length,
+ bool from_kernel,
+ void* data) {
// Initialize the new isolate.
Thread* T = Thread::Current();
Isolate* I = T->isolate();
@@ -508,11 +511,18 @@
ObjectStore::Init(I);
}
- const Error& error = Error::Handle(Object::Init(I));
+ Error& error = Error::Handle(T->zone());
+ if (from_kernel) {
+ ASSERT(snapshot_buffer != NULL);
+ ASSERT(snapshot_length > 0);
+ error = Object::Init(I, snapshot_buffer, snapshot_length);
+ } else {
+ error = Object::Init(I, NULL, -1);
+ }
if (!error.IsNull()) {
return error.raw();
}
- if (snapshot_buffer != NULL) {
+ if ((snapshot_buffer != NULL) && !from_kernel) {
// Read the snapshot and setup the initial state.
NOT_IN_PRODUCT(TimelineDurationScope tds(T, Timeline::GetIsolateStream(),
"IsolateSnapshotReader"));
@@ -553,7 +563,7 @@
MegamorphicCacheTable::PrintSizes(I);
}
} else {
- if (snapshot_kind_ != Snapshot::kNone) {
+ if ((snapshot_kind_ != Snapshot::kNone) && !from_kernel) {
const String& message =
String::Handle(String::New("Missing isolate snapshot"));
return ApiError::New(message);
@@ -581,7 +591,7 @@
Code::Handle(I->object_store()->megamorphic_miss_code());
I->set_ic_miss_code(miss_code);
- if (snapshot_buffer == NULL) {
+ if ((snapshot_buffer == NULL) || from_kernel) {
const Error& error = Error::Handle(I->object_store()->PreallocateObjects());
if (!error.IsNull()) {
return error.raw();
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index df31995..3480fad 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -37,7 +37,15 @@
static Isolate* CreateIsolate(const char* name_prefix,
const Dart_IsolateFlags& api_flags);
- static RawError* InitializeIsolate(const uint8_t* snapshot, void* data);
+
+ // Initialize an isolate, either from a snapshot, from a Kernel binary, or
+ // from SDK library sources. If the snapshot_buffer is non-NULL,
+ // initialize from a snapshot or a Kernel binary depending on the value of
+ // from_kernel. Otherwise, initialize from sources.
+ static RawError* InitializeIsolate(const uint8_t* snapshot_buffer,
+ intptr_t snapshot_length,
+ bool from_kernel,
+ void* data);
static void RunShutdownCallback();
static void ShutdownIsolate(Isolate* isolate);
static void ShutdownIsolate();
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 0992611..e5cf6ae 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1236,12 +1236,15 @@
}
-DART_EXPORT Dart_Isolate Dart_CreateIsolate(const char* script_uri,
- const char* main,
- const uint8_t* snapshot,
- Dart_IsolateFlags* flags,
- void* callback_data,
- char** error) {
+static Dart_Isolate CreateIsolate(const char* script_uri,
+ const char* main,
+ const uint8_t* snapshot_buffer,
+ intptr_t snapshot_length,
+ bool from_kernel,
+ Dart_IsolateFlags* flags,
+ void* callback_data,
+ char** error) {
+ ASSERT(!from_kernel || (snapshot_buffer != NULL));
CHECK_NO_ISOLATE(Isolate::Current());
char* isolate_name = BuildIsolateName(script_uri, main);
@@ -1265,11 +1268,12 @@
// bootstrap library files which call out to a tag handler that may create
// Api Handles when an error is encountered.
Dart_EnterScope();
- const Error& error_obj =
- Error::Handle(Z, Dart::InitializeIsolate(snapshot, callback_data));
+ const Error& error_obj = Error::Handle(
+ Z, Dart::InitializeIsolate(snapshot_buffer, snapshot_length,
+ from_kernel, callback_data));
if (error_obj.IsNull()) {
#if defined(DART_NO_SNAPSHOT) && !defined(PRODUCT)
- if (FLAG_check_function_fingerprints) {
+ if (FLAG_check_function_fingerprints && !from_kernel) {
Library::CheckFunctionFingerprints();
}
#endif // defined(DART_NO_SNAPSHOT) && !defined(PRODUCT).
@@ -1292,6 +1296,30 @@
}
+DART_EXPORT Dart_Isolate Dart_CreateIsolate(const char* script_uri,
+ const char* main,
+ const uint8_t* snapshot_buffer,
+ Dart_IsolateFlags* flags,
+ void* callback_data,
+ char** error) {
+ return CreateIsolate(script_uri, main, snapshot_buffer, -1, false, flags,
+ callback_data, error);
+}
+
+
+DART_EXPORT Dart_Isolate
+Dart_CreateIsolateFromKernel(const char* script_uri,
+ const char* main,
+ const uint8_t* kernel_file,
+ intptr_t kernel_length,
+ Dart_IsolateFlags* flags,
+ void* callback_data,
+ char** error) {
+ return CreateIsolate(script_uri, main, kernel_file, kernel_length, true,
+ flags, callback_data, error);
+}
+
+
DART_EXPORT void Dart_ShutdownIsolate() {
Thread* T = Thread::Current();
Isolate* I = T->isolate();
@@ -2108,7 +2136,7 @@
RETURN_TYPE_ERROR(Z, instance, Instance);
}
const AbstractType& type =
- AbstractType::Handle(Instance::Cast(obj).GetType());
+ AbstractType::Handle(Instance::Cast(obj).GetType(Heap::kNew));
return Api::NewHandle(T, type.Canonicalize());
}
@@ -4046,7 +4074,8 @@
// Construct name of the constructor to invoke.
const String& constructor_name = Api::UnwrapStringHandle(Z, name);
- const AbstractType& type_obj = AbstractType::Handle(Z, instance.GetType());
+ const AbstractType& type_obj =
+ AbstractType::Handle(Z, instance.GetType(Heap::kNew));
const Class& cls = Class::Handle(Z, type_obj.type_class());
const String& class_name = String::Handle(Z, cls.Name());
const Array& strings = Array::Handle(Z, Array::New(3));
@@ -5327,7 +5356,7 @@
DARTSCOPE(Thread::Current());
StackZone zone(T);
-#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER)
+#if defined(DART_PRECOMPILED_RUNTIME)
return Api::NewError("%s: Can't load Kernel files from precompiled runtime.",
CURRENT_FUNC);
#else
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index f0c5532..beb0155 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -606,7 +606,7 @@
DART_EXPORT Dart_Handle Dart_GetObjClass(Dart_Handle object_in) {
DARTSCOPE(Thread::Current());
UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
- return Api::NewHandle(T, obj.GetType());
+ return Api::NewHandle(T, obj.GetType(Heap::kNew));
}
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 94c0425..7c1a288 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -122,6 +122,8 @@
"Polymorphic calls with deoptimization / megamorphic call") \
P(precompiled_mode, bool, false, "Precompilation compiler mode") \
C(precompiled_runtime, true, false, bool, false, "Precompiled runtime mode") \
+ R(print_snapshot_sizes, false, bool, false, \
+ "Print sizes of generated snapshots.") \
R(print_ssa_liveranges, false, bool, false, \
"Print live ranges after allocation.") \
C(print_stop_message, false, false, bool, false, "Print stop message.") \
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index bcc18fb..b8e84b5 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -2056,6 +2056,46 @@
}
+// Returns true if use is dominated by the given instruction.
+// Note: uses that occur at instruction itself are not dominated by it.
+static bool IsDominatedUse(Instruction* dom, Value* use) {
+ BlockEntryInstr* dom_block = dom->GetBlock();
+
+ Instruction* instr = use->instruction();
+
+ PhiInstr* phi = instr->AsPhi();
+ if (phi != NULL) {
+ return dom_block->Dominates(phi->block()->PredecessorAt(use->use_index()));
+ }
+
+ BlockEntryInstr* use_block = instr->GetBlock();
+ if (use_block == dom_block) {
+ // Fast path for the case of block entry.
+ if (dom_block == dom) return true;
+
+ for (Instruction* curr = dom->next(); curr != NULL; curr = curr->next()) {
+ if (curr == instr) return true;
+ }
+
+ return false;
+ }
+
+ return dom_block->Dominates(use_block);
+}
+
+
+void FlowGraph::RenameDominatedUses(Definition* def,
+ Instruction* dom,
+ Definition* other) {
+ for (Value::Iterator it(def->input_use_list()); !it.Done(); it.Advance()) {
+ Value* use = it.Current();
+ if (IsDominatedUse(dom, use)) {
+ use->BindTo(other);
+ }
+ }
+}
+
+
static bool IsPositiveOrZeroSmiConst(Definition* d) {
ConstantInstr* const_instr = d->AsConstant();
if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index 8a1b5c6..544dfac 100644
--- a/runtime/vm/flow_graph.h
+++ b/runtime/vm/flow_graph.h
@@ -285,6 +285,12 @@
// Merge instructions (only per basic-block).
void TryOptimizePatterns();
+ // Replaces uses that are dominated by dom of 'def' with 'other'.
+ // Note: uses that occur at instruction dom itself are not dominated by it.
+ static void RenameDominatedUses(Definition* def,
+ Instruction* dom,
+ Definition* other);
+
private:
friend class IfConverter;
friend class BranchSimplifier;
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index dba8c8e..c6b6663 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -84,6 +84,7 @@
FATAL("Precompilation not supported on IA32");
#endif
+#if !defined(DART_PRECOMPILED_RUNTIME)
// Flags affecting compilation only:
// There is no counter feedback in precompilation, so ignore the counter
// when making inlining decisions.
@@ -97,6 +98,7 @@
FLAG_inlining_caller_size_threshold = 1000;
FLAG_inlining_constant_arguments_max_size_threshold = 100;
FLAG_inlining_constant_arguments_min_size_threshold = 30;
+#endif
FLAG_background_compilation = false;
FLAG_fields_may_be_reset = true;
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index fe777cf..afdb4cb 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -346,6 +346,11 @@
RawPcDescriptors::Kind kind,
LocationSummary* locs);
+ void GeneratePatchableCall(TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs);
+
void GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
const StubEntry& stub_entry,
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 738a2bb..a66bc10 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1094,6 +1094,16 @@
}
+void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs) {
+ __ BranchLinkPatchable(stub_entry);
+ AddCurrentDescriptor(kind, Thread::kNoDeoptId, token_pos);
+ RecordSafepoint(locs);
+}
+
+
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
const StubEntry& stub_entry,
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 09ff218..862221e 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1090,6 +1090,16 @@
}
+void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs) {
+ __ BranchLinkPatchable(stub_entry);
+ AddCurrentDescriptor(kind, Thread::kNoDeoptId, token_pos);
+ RecordSafepoint(locs);
+}
+
+
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
const StubEntry& stub_entry,
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 729608f..d2ee67e 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1096,6 +1096,15 @@
}
+void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs) {
+ // No patchable calls on ia32.
+ GenerateCall(token_pos, stub_entry, kind, locs);
+}
+
+
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
const StubEntry& stub_entry,
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index fe38b17..ef95a0e 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1109,6 +1109,16 @@
}
+void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs) {
+ __ BranchLinkPatchable(stub_entry);
+ AddCurrentDescriptor(kind, Thread::kNoDeoptId, token_pos);
+ RecordSafepoint(locs);
+}
+
+
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
const StubEntry& stub_entry,
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 8a8b24f..a4b1288 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1094,6 +1094,16 @@
}
+void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs) {
+ __ CallPatchable(stub_entry);
+ AddCurrentDescriptor(kind, Thread::kNoDeoptId, token_pos);
+ RecordSafepoint(locs);
+}
+
+
void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
TokenPosition token_pos,
const StubEntry& stub_entry,
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 6d2ea72..001535c 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -1,7 +1,7 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-
+#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/flow_graph_inliner.h"
#include "vm/aot_optimizer.h"
@@ -3598,3 +3598,4 @@
} // namespace dart
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
index 28ec325..b19b4e6 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -271,50 +271,6 @@
}
-// Returns true if use is dominated by the given instruction.
-// Note: uses that occur at instruction itself are not dominated by it.
-static bool IsDominatedUse(Instruction* dom, Value* use) {
- BlockEntryInstr* dom_block = dom->GetBlock();
-
- Instruction* instr = use->instruction();
-
- PhiInstr* phi = instr->AsPhi();
- if (phi != NULL) {
- return dom_block->Dominates(phi->block()->PredecessorAt(use->use_index()));
- }
-
- BlockEntryInstr* use_block = instr->GetBlock();
- if (use_block == dom_block) {
- // Fast path for the case of block entry.
- if (dom_block == dom) return true;
-
- for (Instruction* curr = dom->next(); curr != NULL; curr = curr->next()) {
- if (curr == instr) return true;
- }
-
- return false;
- }
-
- return dom_block->Dominates(use_block);
-}
-
-
-void RangeAnalysis::RenameDominatedUses(Definition* def,
- Instruction* dom,
- Definition* other) {
- for (Value::Iterator it(def->input_use_list()); !it.Done(); it.Advance()) {
- Value* use = it.Current();
-
- // Skip dead phis.
- PhiInstr* phi = use->instruction()->AsPhi();
- ASSERT((phi == NULL) || phi->is_alive());
- if (IsDominatedUse(dom, use)) {
- use->BindTo(other);
- }
- }
-}
-
-
// For a comparison operation return an operation for the equivalent flipped
// comparison: a (op) b === b (op') a.
static Token::Kind FlipComparison(Token::Kind op) {
@@ -390,7 +346,7 @@
constraint = new (Z) ConstraintInstr(use->CopyWithType(), constraint_range);
flow_graph_->InsertAfter(after, constraint, NULL, FlowGraph::kValue);
- RenameDominatedUses(defn, constraint, constraint);
+ FlowGraph::RenameDominatedUses(defn, constraint, constraint);
constraints_.Add(constraint);
return constraint;
}
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index bc4a844..9f96d7d 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -804,8 +804,11 @@
}
if (value().IsInstance()) {
+ // Allocate in old-space since this may be invoked from the
+ // background compiler.
return CompileType::Create(
- cid, AbstractType::ZoneHandle(Instance::Cast(value()).GetType()));
+ cid,
+ AbstractType::ZoneHandle(Instance::Cast(value()).GetType(Heap::kOld)));
} else {
// Type info for non-instance objects.
return CompileType::FromCid(cid);
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 8d199c4..395b59a 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -992,8 +992,13 @@
__ LoadImmediate(R1, argc_tag);
ExternalLabel label(entry);
__ LoadNativeEntry(R9, &label, link_lazily() ? kPatchable : kNotPatchable);
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
- locs());
+ if (link_lazily()) {
+ compiler->GeneratePatchableCall(token_pos(), *stub_entry,
+ RawPcDescriptors::kOther, locs());
+ } else {
+ compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+ locs());
+ }
__ Pop(result);
}
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 55ab860..25a220e 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -837,8 +837,13 @@
__ LoadImmediate(R1, argc_tag);
ExternalLabel label(entry);
__ LoadNativeEntry(R5, &label);
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
- locs());
+ if (link_lazily()) {
+ compiler->GeneratePatchableCall(token_pos(), *stub_entry,
+ RawPcDescriptors::kOther, locs());
+ } else {
+ compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+ locs());
+ }
__ Pop(result);
}
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 2e94f65..c90b2c5 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -848,15 +848,17 @@
if (link_lazily()) {
stub_entry = StubCode::CallBootstrapCFunction_entry();
__ movl(ECX, Immediate(NativeEntry::LinkNativeCallEntry()));
+ compiler->GeneratePatchableCall(token_pos(), *stub_entry,
+ RawPcDescriptors::kOther, locs());
} else {
stub_entry = (is_bootstrap_native())
? StubCode::CallBootstrapCFunction_entry()
: StubCode::CallNativeCFunction_entry();
const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
__ movl(ECX, Immediate(label.address()));
+ compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+ locs());
}
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
- locs());
__ popl(result);
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 6a2c623..c5a5af5 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1053,8 +1053,13 @@
__ LoadImmediate(A1, argc_tag);
ExternalLabel label(entry);
__ LoadNativeEntry(T5, &label, kNotPatchable);
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
- locs());
+ if (link_lazily()) {
+ compiler->GeneratePatchableCall(token_pos(), *stub_entry,
+ RawPcDescriptors::kOther, locs());
+ } else {
+ compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+ locs());
+ }
__ Pop(result);
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 9510d28..097df6e 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -815,15 +815,17 @@
stub_entry = StubCode::CallBootstrapCFunction_entry();
ExternalLabel label(NativeEntry::LinkNativeCallEntry());
__ LoadNativeEntry(RBX, &label, kPatchable);
+ compiler->GeneratePatchableCall(token_pos(), *stub_entry,
+ RawPcDescriptors::kOther, locs());
} else {
stub_entry = (is_bootstrap_native())
? StubCode::CallBootstrapCFunction_entry()
: StubCode::CallNativeCFunction_entry();
const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
__ LoadNativeEntry(RBX, &label, kNotPatchable);
+ compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
+ locs());
}
- compiler->GenerateCall(token_pos(), *stub_entry, RawPcDescriptors::kOther,
- locs());
__ popq(result);
}
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index c2a6ae2..1f50387 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -58,7 +58,7 @@
}
-#if defined(DART_NO_SNAPSHOT)
+#if !defined(DART_PRECOMPILED_RUNTIME)
void Intrinsifier::InitializeState() {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
@@ -117,7 +117,7 @@
#undef SETUP_FUNCTION
}
-#endif // defined(DART_NO_SNAPSHOT).
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
// DBC does not use graph intrinsics.
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index c7ff0f8..9242937 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -23,7 +23,7 @@
public:
static bool Intrinsify(const ParsedFunction& parsed_function,
FlowGraphCompiler* compiler);
-#if defined(DART_NO_SNAPSHOT)
+#if !defined(DART_PRECOMPILED_RUNTIME)
static void InitializeState();
#endif
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 949cc77..d79a9da 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -1551,7 +1551,12 @@
random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
ASSERT(!random_A_field.IsNull());
ASSERT(random_A_field.is_const());
- const Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ if (a_value.raw() == Object::sentinel().raw() ||
+ a_value.raw() == Object::transition_sentinel().raw()) {
+ random_A_field.EvaluateInitializer();
+ a_value = random_A_field.StaticValue();
+ }
const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
// 'a_int_value' is a mask.
ASSERT(Utils::IsUint(32, a_int_value));
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 5eba9f6..a78bae6 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -1625,7 +1625,12 @@
random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
ASSERT(!random_A_field.IsNull());
ASSERT(random_A_field.is_const());
- const Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ if (a_value.raw() == Object::sentinel().raw() ||
+ a_value.raw() == Object::transition_sentinel().raw()) {
+ random_A_field.EvaluateInitializer();
+ a_value = random_A_field.StaticValue();
+ }
const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
// Receiver.
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 2e810d9a4..9b5cf1d 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -1666,7 +1666,12 @@
random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
ASSERT(!random_A_field.IsNull());
ASSERT(random_A_field.is_const());
- const Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ if (a_value.raw() == Object::sentinel().raw() ||
+ a_value.raw() == Object::transition_sentinel().raw()) {
+ random_A_field.EvaluateInitializer();
+ a_value = random_A_field.StaticValue();
+ }
const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
// 'a_int_value' is a mask.
ASSERT(Utils::IsUint(32, a_int_value));
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 0fa3e19..54753a2 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -1668,7 +1668,12 @@
random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
ASSERT(!random_A_field.IsNull());
ASSERT(random_A_field.is_const());
- const Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ if (a_value.raw() == Object::sentinel().raw() ||
+ a_value.raw() == Object::transition_sentinel().raw()) {
+ random_A_field.EvaluateInitializer();
+ a_value = random_A_field.StaticValue();
+ }
const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
// 'a_int_value' is a mask.
ASSERT(Utils::IsUint(32, a_int_value));
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index f4f7313..b888804 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -1533,7 +1533,12 @@
random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
ASSERT(!random_A_field.IsNull());
ASSERT(random_A_field.is_const());
- const Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ Instance& a_value = Instance::Handle(random_A_field.StaticValue());
+ if (a_value.raw() == Object::sentinel().raw() ||
+ a_value.raw() == Object::transition_sentinel().raw()) {
+ random_A_field.EvaluateInitializer();
+ a_value = random_A_field.StaticValue();
+ }
const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
// Receiver.
__ movq(RAX, Address(RSP, +1 * kWordSize));
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 4370ab1..9d6569e 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -58,11 +58,12 @@
: from_(Class::Handle(zone, from.raw())),
to_(Class::Handle(zone, to.raw())),
mapping_(zone, 0) {
- ComputeMapping();
before_ = new (zone) ZoneGrowableArray<const Instance*>(zone, 0);
after_ = new (zone) ZoneGrowableArray<const Instance*>(zone, 0);
+ new_fields_ = new (zone) ZoneGrowableArray<const Field*>(zone, 0);
ASSERT(from_.id() == to_.id());
cid_ = from_.id();
+ ComputeMapping();
}
@@ -86,27 +87,50 @@
// Add copying of the instance fields if matching by name.
// Note: currently the type of the fields are ignored.
- const Array& from_fields = Array::Handle(from_.OffsetToFieldMap());
+ const Array& from_fields =
+ Array::Handle(from_.OffsetToFieldMap(true /* original classes */));
const Array& to_fields = Array::Handle(to_.OffsetToFieldMap());
Field& from_field = Field::Handle();
Field& to_field = Field::Handle();
String& from_name = String::Handle();
String& to_name = String::Handle();
- for (intptr_t i = 0; i < from_fields.Length(); i++) {
- if (from_fields.At(i) == Field::null()) continue; // Ignore non-fields.
- from_field = Field::RawCast(from_fields.At(i));
- ASSERT(from_field.is_instance());
- from_name = from_field.name();
- // We now have to find where this field is in the to class.
- for (intptr_t j = 0; j < to_fields.Length(); j++) {
- if (to_fields.At(j) == Field::null()) continue; // Ignore non-fields.
- to_field = Field::RawCast(to_fields.At(j));
- ASSERT(to_field.is_instance());
- to_name = to_field.name();
+
+ // Scan across all the fields in the new class definition.
+ for (intptr_t i = 0; i < to_fields.Length(); i++) {
+ if (to_fields.At(i) == Field::null()) {
+ continue; // Ignore non-fields.
+ }
+
+ // Grab the field's name.
+ to_field = Field::RawCast(to_fields.At(i));
+ ASSERT(to_field.is_instance());
+ to_name = to_field.name();
+
+ // Did this field not exist in the old class definition?
+ bool new_field = true;
+
+ // Find this field in the old class.
+ for (intptr_t j = 0; j < from_fields.Length(); j++) {
+ if (from_fields.At(j) == Field::null()) {
+ continue; // Ignore non-fields.
+ }
+ from_field = Field::RawCast(from_fields.At(j));
+ ASSERT(from_field.is_instance());
+ from_name = from_field.name();
if (from_name.Equals(to_name)) {
// Success
mapping_.Add(from_field.Offset());
mapping_.Add(to_field.Offset());
+ // Field did exist in old class deifnition.
+ new_field = false;
+ }
+ }
+
+ if (new_field) {
+ if (to_field.has_initializer()) {
+ // This is a new field with an initializer.
+ const Field& field = Field::Handle(to_field.raw());
+ new_fields_->Add(&field);
}
}
}
@@ -129,6 +153,48 @@
}
+void InstanceMorpher::RunNewFieldInitializers() const {
+ if ((new_fields_->length() == 0) || (after_->length() == 0)) {
+ return;
+ }
+
+ TIR_Print("Running new field initializers for class: %s\n", to_.ToCString());
+ String& initializing_expression = String::Handle();
+ Function& eval_func = Function::Handle();
+ Object& result = Object::Handle();
+ Class& owning_class = Class::Handle();
+ // For each new field.
+ for (intptr_t i = 0; i < new_fields_->length(); i++) {
+ // Create a function that returns the expression.
+ const Field* field = new_fields_->At(i);
+ owning_class ^= field->Owner();
+ ASSERT(!owning_class.IsNull());
+ // Extract the initializing expression.
+ initializing_expression = field->InitializingExpression();
+ TIR_Print("New `%s` has initializing expression `%s`\n", field->ToCString(),
+ initializing_expression.ToCString());
+ eval_func ^= Function::EvaluateHelper(owning_class, initializing_expression,
+ Array::empty_array(), true);
+ for (intptr_t j = 0; j < after_->length(); j++) {
+ const Instance* instance = after_->At(j);
+ TIR_Print("Initializing instance %" Pd " / %" Pd "\n", j + 1,
+ after_->length());
+ // Run the function and assign the field.
+ result = DartEntry::InvokeFunction(eval_func, Array::empty_array());
+ if (result.IsError()) {
+ // TODO(johnmccutchan): Report this error in the reload response?
+ OS::PrintErr(
+ "RELOAD: Running initializer for new field `%s` resulted in "
+ "an error: %s\n",
+ field->ToCString(), Error::Cast(result).ToErrorCString());
+ continue;
+ }
+ instance->RawSetFieldAtOffset(field->Offset(), result);
+ }
+ }
+}
+
+
void InstanceMorpher::CreateMorphedCopies() const {
for (intptr_t i = 0; i < before()->length(); i++) {
const Instance& copy = Instance::Handle(Morph(*before()->At(i)));
@@ -1141,6 +1207,9 @@
Become::ElementsForwardIdentity(before, after);
}
+ // Run the initializers for new instance fields.
+ RunNewFieldInitializers();
+
if (FLAG_identity_reload) {
if (saved_num_cids_ != I->class_table()->NumCids()) {
TIR_Print("Identity reload failed! B#C=%" Pd " A#C=%" Pd "\n",
@@ -1302,6 +1371,14 @@
}
+void IsolateReloadContext::RunNewFieldInitializers() {
+ // Run new field initializers on all instances.
+ for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
+ instance_morphers_.At(i)->RunNewFieldInitializers();
+ }
+}
+
+
bool IsolateReloadContext::ValidateReload() {
TIMELINE_SCOPE(ValidateReload);
if (reload_aborted()) return false;
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index f2a2df9..e5e5da1 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -58,6 +58,8 @@
// Called on each instance that needs to be morphed.
RawInstance* Morph(const Instance& instance) const;
+ void RunNewFieldInitializers() const;
+
// Adds an object to be morphed.
void AddObject(RawObject* object) const;
@@ -74,6 +76,8 @@
ZoneGrowableArray<const Instance*>* before() const { return before_; }
// Returns the list of morphed objects (matches order in before()).
ZoneGrowableArray<const Instance*>* after() const { return after_; }
+ // Returns the list of new fields.
+ ZoneGrowableArray<const Field*>* new_fields() const { return new_fields_; }
// Returns the cid associated with the from_ and to_ class.
intptr_t cid() const { return cid_; }
@@ -84,6 +88,7 @@
ZoneGrowableArray<intptr_t> mapping_;
ZoneGrowableArray<const Instance*>* before_;
ZoneGrowableArray<const Instance*>* after_;
+ ZoneGrowableArray<const Field*>* new_fields_;
intptr_t cid_;
void ComputeMapping();
@@ -232,6 +237,8 @@
// Transforms the heap based on instance_morphers_.
void MorphInstances();
+ void RunNewFieldInitializers();
+
bool ValidateReload();
void Rollback();
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index 7c7daa6..287eb71 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -2180,7 +2180,8 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
- EXPECT_STREQ("Fruit.Cantalope true 2", SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ("Deleted enum value from Fruit true -1",
+ SimpleInvokeStr(lib, "main"));
}
@@ -3123,6 +3124,297 @@
EXPECT_STREQ("value=0:00:02.000000", SimpleInvokeStr(lib, "main"));
}
+
+TEST_CASE(IsolateReload_RunNewFieldInitializers) {
+ const char* kScript =
+ "class Foo {\n"
+ " int x = 4;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " value = new Foo();\n"
+ " return value.x;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ // Add the field y.
+ const char* kReloadScript =
+ "class Foo {\n"
+ " int x = 4;\n"
+ " int y = 7;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " return value.y;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ // Verify that we ran field initializers on existing instances.
+ EXPECT_EQ(7, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_RunNewFieldInitializersReferenceStaticField) {
+ const char* kScript =
+ "int myInitialValue = 8 * 7;\n"
+ "class Foo {\n"
+ " int x = 4;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " value = new Foo();\n"
+ " return value.x;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ // Add the field y.
+ const char* kReloadScript =
+ "int myInitialValue = 8 * 7;\n"
+ "class Foo {\n"
+ " int x = 4;\n"
+ " int y = myInitialValue;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " return value.y;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ // Verify that we ran field initializers on existing instances.
+ EXPECT_EQ(56, SimpleInvoke(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_RunNewFieldInitializersMutateStaticField) {
+ const char* kScript =
+ "int myInitialValue = 8 * 7;\n"
+ "class Foo {\n"
+ " int x = 4;\n"
+ "}\n"
+ "Foo value;\n"
+ "Foo value1;\n"
+ "main() {\n"
+ " value = new Foo();\n"
+ " value1 = new Foo();\n"
+ " return value.x;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ // Add the field y.
+ const char* kReloadScript =
+ "int myInitialValue = 8 * 7;\n"
+ "class Foo {\n"
+ " int x = 4;\n"
+ " int y = myInitialValue++;\n"
+ "}\n"
+ "Foo value;\n"
+ "Foo value1;\n"
+ "main() {\n"
+ " return myInitialValue;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ // Verify that we ran field initializers on existing instances and that
+ // they affected the value of the field myInitialValue.
+ EXPECT_EQ(58, SimpleInvoke(lib, "main"));
+}
+
+
+// When an initializer expression throws, we leave the field as null.
+TEST_CASE(IsolateReload_RunNewFieldInitializersThrows) {
+ const char* kScript =
+ "class Foo {\n"
+ " int x = 4;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " value = new Foo();\n"
+ " return value.x;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ // Add the field y.
+ const char* kReloadScript =
+ "class Foo {\n"
+ " int x = 4;\n"
+ " int y = throw 'a';\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " return '${value.y == null}';"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ // Verify that we ran field initializers on existing instances.
+ EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
+}
+
+
+// When an initializer expression has a syntax error, we detect it at reload
+// time.
+TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError) {
+ const char* kScript =
+ "class Foo {\n"
+ " int x = 4;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " value = new Foo();\n"
+ " return value.x;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ // Add the field y with a syntax error in the initializing expression.
+ const char* kReloadScript =
+ "class Foo {\n"
+ " int x = 4;\n"
+ " int y = ......;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " return '${value.y == null}';"
+ "}\n";
+
+ // The reload fails because the initializing expression is parsed at
+ // class finalization time.
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(lib, "......");
+}
+
+
+// When an initializer expression has a syntax error, we detect it at reload
+// time.
+TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError2) {
+ const char* kScript =
+ "class Foo {\n"
+ " Foo() { /* default constructor */ }\n"
+ " int x = 4;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " value = new Foo();\n"
+ " return value.x;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ // Add the field y with a syntax error in the initializing expression.
+ const char* kReloadScript =
+ "class Foo {\n"
+ " Foo() { /* default constructor */ }\n"
+ " int x = 4;\n"
+ " int y = ......;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " return '${value.y == null}';"
+ "}\n";
+
+ // The reload fails because the initializing expression is parsed at
+ // class finalization time.
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(lib, "......");
+}
+
+
+// When an initializer expression has a syntax error, we detect it at reload
+// time.
+TEST_CASE(IsolateReload_RunNewFieldInitializersSyntaxError3) {
+ const char* kScript =
+ "class Foo {\n"
+ " Foo() { /* default constructor */ }\n"
+ " int x = 4;\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " value = new Foo();\n"
+ " return value.x;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(4, SimpleInvoke(lib, "main"));
+
+ // Add the field y with a syntax error in the initializing expression.
+ const char* kReloadScript =
+ "class Foo {\n"
+ " Foo() { /* default constructor */ }\n"
+ " int x = 4;\n"
+ " int y = ......\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " return '${value.y == null}';"
+ "}\n";
+
+ // The reload fails because the initializing expression is parsed at
+ // class finalization time.
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(lib, "......");
+}
+
+
+TEST_CASE(IsolateREload_RunNewFieldInitialiazersSuperClass) {
+ const char* kScript =
+ "class Super {\n"
+ " static var foo = 'right';\n"
+ "}\n"
+ "class Foo extends Super {\n"
+ " static var foo = 'wrong';\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " Super.foo;\n"
+ " Foo.foo;\n"
+ " value = new Foo();\n"
+ " return 0;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(0, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Super {\n"
+ " static var foo = 'right';\n"
+ " var newField = foo;\n"
+ "}\n"
+ "class Foo extends Super {\n"
+ " static var foo = 'wrong';\n"
+ "}\n"
+ "Foo value;\n"
+ "main() {\n"
+ " return value.newField;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ // Verify that we ran field initializers on existing instances in the
+ // correct scope.
+ EXPECT_STREQ("right", SimpleInvokeStr(lib, "main"));
+}
+
#endif // !PRODUCT
} // namespace dart
diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc
index d632349..f30e100 100644
--- a/runtime/vm/kernel.cc
+++ b/runtime/vm/kernel.cc
@@ -4,6 +4,7 @@
#include "vm/kernel.h"
+#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
namespace kernel {
@@ -1207,3 +1208,4 @@
} // namespace kernel
} // namespace dart
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index 09e9f70..93b828b 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -5,10 +5,12 @@
#ifndef RUNTIME_VM_KERNEL_H_
#define RUNTIME_VM_KERNEL_H_
+#if !defined(DART_PRECOMPILED_RUNTIME)
#include "platform/assert.h"
#include "vm/allocation.h"
#include "vm/globals.h"
+
#define KERNEL_NODES_DO(M) \
M(Name) \
M(InferredValue) \
@@ -3243,4 +3245,5 @@
} // namespace dart
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
#endif // RUNTIME_VM_KERNEL_H_
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index aaf3333..350690d 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -1,6 +1,7 @@
// 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.
+#if !defined(DART_PRECOMPILED_RUNTIME)
#include <map>
#include <vector>
@@ -2901,3 +2902,4 @@
} // namespace dart
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc
index f9f2277..6c669e4 100644
--- a/runtime/vm/kernel_reader.cc
+++ b/runtime/vm/kernel_reader.cc
@@ -12,6 +12,7 @@
#include "vm/parser.h"
#include "vm/symbols.h"
+#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
namespace kernel {
@@ -81,19 +82,18 @@
dart::Instance* simple_value_;
};
-void BuildingTranslationHelper::SetFinalize(bool finalize) {
- reader_->finalize_ = finalize;
-}
RawLibrary* BuildingTranslationHelper::LookupLibraryByKernelLibrary(
Library* library) {
return reader_->LookupLibrary(library).raw();
}
+
RawClass* BuildingTranslationHelper::LookupClassByKernelClass(Class* klass) {
return reader_->LookupClass(klass).raw();
}
+
Object& KernelReader::ReadProgram() {
ASSERT(!bootstrapping_);
Program* program = ReadPrecompiledKernelFromBuffer(buffer_, buffer_length_);
@@ -113,29 +113,13 @@
ReadLibrary(kernel_library);
}
- // We finalize classes after we've constructed all classes since we
- // currently don't construct them in pre-order of the class hierarchy (and
- // finalization of a class needs all of its superclasses to be finalized).
- dart::String& name = dart::String::Handle(Z);
for (intptr_t i = 0; i < length; i++) {
- Library* kernel_library = program->libraries()[i];
- dart::Library& library = LookupLibrary(kernel_library);
- name = library.url();
+ dart::Library& library = LookupLibrary(program->libraries()[i]);
+ if (!library.Loaded()) library.SetLoaded();
+ }
- // TODO(27590) unskip this library when we fix underlying issue.
- if (name.Equals("dart:vmservice_io")) {
- continue;
- }
-
- if (!library.Loaded()) {
- dart::Class& klass = dart::Class::Handle(Z);
- for (intptr_t i = 0; i < kernel_library->classes().length(); i++) {
- klass = LookupClass(kernel_library->classes()[i]).raw();
- ClassFinalizer::FinalizeTypesInClass(klass);
- ClassFinalizer::FinalizeClass(klass);
- }
- library.SetLoaded();
- }
+ if (!ClassFinalizer::ProcessPendingClasses(/*from_kernel=*/true)) {
+ FATAL("Error in class finalization during bootstrapping.");
}
dart::Library& library = LookupLibrary(kernel_main_library);
@@ -161,6 +145,7 @@
}
}
+
void KernelReader::ReadLibrary(Library* kernel_library) {
dart::Library& library = LookupLibrary(kernel_library);
if (library.Loaded()) return;
@@ -217,13 +202,17 @@
ReadProcedure(library, toplevel_class, kernel_procedure);
}
+ const GrowableObjectArray& classes =
+ GrowableObjectArray::Handle(I->object_store()->pending_classes());
+
// Load all classes.
for (intptr_t i = 0; i < kernel_library->classes().length(); i++) {
Class* kernel_klass = kernel_library->classes()[i];
- ReadClass(library, kernel_klass);
+ classes.Add(ReadClass(library, kernel_klass), Heap::kOld);
}
}
+
void KernelReader::ReadPreliminaryClass(dart::Class* klass,
Class* kernel_klass) {
ASSERT(kernel_klass->IsNormalClass());
@@ -284,7 +273,6 @@
intptr_t interface_count = kernel_klass->implemented_classes().length();
const dart::Array& interfaces =
dart::Array::Handle(Z, dart::Array::New(interface_count));
- dart::Class& interface_class = dart::Class::Handle(Z);
for (intptr_t i = 0; i < interface_count; i++) {
InterfaceType* kernel_interface_type =
kernel_klass->implemented_classes()[i];
@@ -292,33 +280,14 @@
T.TranslateTypeWithoutFinalization(kernel_interface_type);
if (type.IsMalformed()) H.ReportError("Malformed interface type.");
interfaces.SetAt(i, type);
-
- // NOTE: Normally the DartVM keeps a list of pending classes and iterates
- // through them later on using `ClassFinalizer::ProcessPendingClasses()`.
- // This involes calling `ClassFinalizer::ResolveSuperTypeAndInterfaces()`
- // which does a lot of error validation (e.g. cycle checks) which we don't
- // need here. But we do need to do one thing which this resolving phase
- // normally does for us: set the `is_implemented` boolean.
-
- // TODO(27590): Maybe we can do this differently once we have
- // "bootstrapping from kernel"-support.
- interface_class = type.type_class();
- interface_class.set_is_implemented();
}
klass->set_interfaces(interfaces);
if (kernel_klass->is_abstract()) klass->set_is_abstract();
- klass->set_is_cycle_free();
-
- // When bootstrapping we should not finalize types yet because they will be
- // finalized when the object store's pending_classes list is drained by
- // ClassFinalizer::ProcessPendingClasses. Even when not bootstrapping we are
- // careful not to eagerly finalize types that may introduce a circularity
- // (such as type arguments, interface types, field types, etc.).
- if (finalize_) ClassFinalizer::FinalizeTypesInClass(*klass);
}
-void KernelReader::ReadClass(const dart::Library& library,
- Class* kernel_klass) {
+
+dart::Class& KernelReader::ReadClass(const dart::Library& library,
+ Class* kernel_klass) {
// This will trigger a call to [ReadPreliminaryClass] if not already done.
dart::Class& klass = LookupClass(kernel_klass);
@@ -383,8 +352,11 @@
GrowableObjectArray::Handle(Z, I->object_store()->pending_classes())
.Add(klass, Heap::kOld);
}
+
+ return klass;
}
+
void KernelReader::ReadProcedure(const dart::Library& library,
const dart::Class& owner,
Procedure* kernel_procedure,
@@ -524,6 +496,7 @@
}
}
+
void KernelReader::SetupFunctionParameters(TranslationHelper translation_helper,
DartTypeTranslator type_translator,
const dart::Class& klass,
@@ -594,6 +567,7 @@
: return_type);
}
+
void KernelReader::SetupFieldAccessorFunction(const dart::Class& klass,
const dart::Function& function) {
bool is_setter = function.IsImplicitSetterFunction();
@@ -679,6 +653,7 @@
return *handle;
}
+
RawFunction::Kind KernelReader::GetFunctionType(Procedure* kernel_procedure) {
intptr_t lookuptable[] = {
RawFunction::kRegularFunction, // Procedure::kMethod
@@ -696,5 +671,7 @@
}
}
+
} // namespace kernel
} // namespace dart
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/kernel_reader.h b/runtime/vm/kernel_reader.h
index 23dc2e9..6b1db8a 100644
--- a/runtime/vm/kernel_reader.h
+++ b/runtime/vm/kernel_reader.h
@@ -5,6 +5,7 @@
#ifndef RUNTIME_VM_KERNEL_READER_H_
#define RUNTIME_VM_KERNEL_READER_H_
+#if !defined(DART_PRECOMPILED_RUNTIME)
#include <map>
#include "vm/kernel.h"
@@ -25,8 +26,6 @@
: TranslationHelper(thread, zone, isolate), reader_(reader) {}
virtual ~BuildingTranslationHelper() {}
- virtual void SetFinalize(bool finalize);
-
virtual RawLibrary* LookupLibraryByKernelLibrary(Library* library);
virtual RawClass* LookupClassByKernelClass(Class* klass);
@@ -60,9 +59,10 @@
zone_(thread_->zone()),
isolate_(thread_->isolate()),
translation_helper_(this, thread_, zone_, isolate_),
- type_translator_(&translation_helper_, &active_class_, !bootstrapping),
+ type_translator_(&translation_helper_,
+ &active_class_,
+ /*finalize=*/false),
bootstrapping_(bootstrapping),
- finalize_(!bootstrapping),
buffer_(buffer),
buffer_length_(len) {}
@@ -83,7 +83,7 @@
friend class BuildingTranslationHelper;
void ReadPreliminaryClass(dart::Class* klass, Class* kernel_klass);
- void ReadClass(const dart::Library& library, Class* kernel_klass);
+ dart::Class& ReadClass(const dart::Library& library, Class* kernel_klass);
void ReadProcedure(const dart::Library& library,
const dart::Class& owner,
Procedure* procedure,
@@ -110,9 +110,6 @@
bool bootstrapping_;
- // Should created classes be finalized when they are created?
- bool finalize_;
-
const uint8_t* buffer_;
intptr_t buffer_length_;
@@ -123,4 +120,5 @@
} // namespace kernel
} // namespace dart
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
#endif // RUNTIME_VM_KERNEL_READER_H_
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 46750fd..5490abb 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -18,6 +18,7 @@
#include "vm/resolver.h"
#include "vm/stack_frame.h"
+#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
DECLARE_FLAG(bool, support_externalizable_strings);
@@ -645,6 +646,16 @@
for (intptr_t i = 0; i < type_parameters.length(); ++i) {
VisitTypeParameter(type_parameters[i]);
}
+
+ if (node->async_marker() == FunctionNode::kSyncYielding) {
+ LocalScope* scope = parsed_function_->node_sequence()->scope();
+ for (intptr_t i = 0;
+ i < parsed_function_->function().NumOptionalPositionalParameters();
+ i++) {
+ scope->VariableAt(i)->set_is_forced_stack();
+ }
+ }
+
// Do not visit the positional and named parameters, because they've
// already been added to the scope.
if (node->body() != NULL) {
@@ -1109,6 +1120,21 @@
}
+dart::RawUnresolvedClass* TranslationHelper::ToUnresolvedClass(
+ Class* kernel_klass) {
+ dart::RawClass* klass = NULL;
+
+ const dart::String& class_name = DartClassName(kernel_klass);
+ Library* kernel_library = Library::Cast(kernel_klass->parent());
+ dart::Library& library =
+ dart::Library::Handle(Z, LookupLibraryByKernelLibrary(kernel_library));
+
+ ASSERT(klass != Object::null());
+ return dart::UnresolvedClass::New(library, class_name,
+ TokenPosition::kNoSource);
+}
+
+
dart::RawField* TranslationHelper::LookupFieldByKernelField(
Field* kernel_field) {
TreeNode* node = kernel_field->parent();
@@ -1843,7 +1869,9 @@
try_catch_block_(NULL),
next_used_try_index_(0),
catch_block_(NULL),
- type_translator_(&translation_helper_, &active_class_),
+ type_translator_(&translation_helper_,
+ &active_class_,
+ /* finalize= */ true),
constant_evaluator_(this,
zone_,
&translation_helper_,
@@ -3861,10 +3889,8 @@
DartType* node) {
bool saved_finalize = finalize_;
finalize_ = false;
- H.SetFinalize(false);
AbstractType& result = TranslateType(node);
finalize_ = saved_finalize;
- H.SetFinalize(saved_finalize);
return result;
}
@@ -4020,13 +4046,13 @@
const TypeArguments& type_arguments = TranslateTypeArguments(
node->type_arguments().raw_array(), node->type_arguments().length());
- const dart::Class& klass =
- dart::Class::Handle(Z, H.LookupClassByKernelClass(node->klass()));
+ dart::Object& klass =
+ dart::Object::Handle(Z, H.ToUnresolvedClass(node->klass()));
result_ = Type::New(klass, type_arguments, TokenPosition::kNoSource);
- result_.SetIsResolved();
if (finalize_) {
- result_ = ClassFinalizer::FinalizeType(klass, result_,
+ ASSERT(active_class_->klass != NULL);
+ result_ = ClassFinalizer::FinalizeType(*active_class_->klass, result_,
ClassFinalizer::kCanonicalize);
}
}
@@ -5653,9 +5679,6 @@
ASSERT(stack_trace_var->name().raw() ==
Symbols::StackTraceParameter().raw());
- exception_var->set_is_forced_stack();
- stack_trace_var->set_is_forced_stack();
-
TargetEntryInstr* no_error;
TargetEntryInstr* error;
@@ -5745,3 +5768,4 @@
} // namespace kernel
} // namespace dart
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h
index 5001451..5f2539b 100644
--- a/runtime/vm/kernel_to_il.h
+++ b/runtime/vm/kernel_to_il.h
@@ -5,6 +5,8 @@
#ifndef RUNTIME_VM_KERNEL_TO_IL_H_
#define RUNTIME_VM_KERNEL_TO_IL_H_
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
#include "vm/growable_array.h"
#include "vm/hash_map.h"
@@ -202,11 +204,6 @@
Heap::Space allocation_space() { return allocation_space_; }
- // Set whether unfinalized classes should be finalized. The base class
- // implementation used at flow graph construction time looks up classes in the
- // VM's heap, all of which should already be finalized.
- virtual void SetFinalize(bool finalize) {}
-
RawInstance* Canonicalize(const Instance& instance);
const dart::String& DartString(const char* content) {
@@ -241,6 +238,8 @@
virtual RawLibrary* LookupLibraryByKernelLibrary(Library* library);
virtual RawClass* LookupClassByKernelClass(Class* klass);
+ RawUnresolvedClass* ToUnresolvedClass(Class* klass);
+
RawField* LookupFieldByKernelField(Field* field);
RawFunction* LookupStaticMethodByKernelProcedure(Procedure* procedure);
RawFunction* LookupConstructorByKernelConstructor(Constructor* constructor);
@@ -282,7 +281,7 @@
public:
DartTypeTranslator(TranslationHelper* helper,
ActiveClass* active_class,
- bool finalize = true)
+ bool finalize = false)
: translation_helper_(*helper),
active_class_(active_class),
zone_(helper->zone()),
@@ -501,7 +500,9 @@
node_(node),
zone_(Thread::Current()->zone()),
translation_helper_(Thread::Current(), zone_, Isolate::Current()),
- type_translator_(&translation_helper_, &active_class_),
+ type_translator_(&translation_helper_,
+ &active_class_,
+ /*finalize=*/true),
current_function_scope_(NULL),
scope_(NULL),
depth_(0),
@@ -919,5 +920,5 @@
} // namespace kernel
} // namespace dart
-
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
#endif // RUNTIME_VM_KERNEL_TO_IL_H_
diff --git a/runtime/vm/method_recognizer.cc b/runtime/vm/method_recognizer.cc
index f25e4d3..12694a8 100644
--- a/runtime/vm/method_recognizer.cc
+++ b/runtime/vm/method_recognizer.cc
@@ -132,7 +132,7 @@
}
-#if defined(DART_NO_SNAPSHOT)
+#if !defined(DART_PRECOMPILED_RUNTIME)
void MethodRecognizer::InitializeState() {
GrowableArray<Library*> libs(3);
libs.Add(&Library::ZoneHandle(Library::CoreLibrary()));
@@ -182,6 +182,7 @@
#undef SET_IS_POLYMORPHIC_TARGET
#undef SET_FUNCTION_BIT
}
-#endif // defined(DART_NO_SNAPSHOT).
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
+
} // namespace dart
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index ed079f6..580582f 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -518,19 +518,20 @@
static intptr_t ResultCid(const Function& function);
static intptr_t MethodKindToReceiverCid(Kind kind);
static const char* KindToCString(Kind kind);
-#if defined(DART_NO_SNAPSHOT)
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
static void InitializeState();
-#endif // defined(DART_NO_SNAPSHOT).
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
};
-#if defined(DART_NO_SNAPSHOT)
+#if !defined(DART_PRECOMPILED_RUNTIME)
#define CHECK_FINGERPRINT2(f, p0, p1, fp) \
ASSERT(f.CheckSourceFingerprint(#p0 ", " #p1, fp))
#define CHECK_FINGERPRINT3(f, p0, p1, p2, fp) \
ASSERT(f.CheckSourceFingerprint(#p0 ", " #p1 ", " #p2, fp))
-#endif // defined(DART_NO_SNAPSHOT).
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
// clang-format off
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 87d48c8..673ae03 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1119,631 +1119,629 @@
}
-RawError* Object::Init(Isolate* isolate) {
+// Initialize a new isolate from source or from a snapshot.
+//
+// There are three possibilities:
+// 1. Running a Kernel binary. This function will bootstrap from the KERNEL
+// file.
+// 2. There is no snapshot. This function will bootstrap from source.
+// 3. There is a snapshot. The caller should initialize from the snapshot.
+//
+// A non-NULL kernel argument indicates (1). A NULL kernel indicates (2) or
+// (3), depending on whether the VM is compiled with DART_NO_SNAPSHOT defined or
+// not.
+RawError* Object::Init(Isolate* isolate,
+ const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_length) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
ASSERT(isolate == thread->isolate());
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ const bool is_kernel = (kernel_buffer != NULL);
+#endif
NOT_IN_PRODUCT(TimelineDurationScope tds(thread, Timeline::GetIsolateStream(),
- "Object::Init"));
+ "Object::Init");)
#if defined(DART_NO_SNAPSHOT)
- // Object::Init version when we are running in a version of dart that does
- // not have a full snapshot linked in.
- ObjectStore* object_store = isolate->object_store();
+ bool bootstrapping = true;
+#elif defined(DART_PRECOMPILED_RUNTIME)
+ bool bootstrapping = false;
+#else
+ bool bootstrapping = is_kernel;
+#endif
- Class& cls = Class::Handle(zone);
- Type& type = Type::Handle(zone);
- Array& array = Array::Handle(zone);
- Library& lib = Library::Handle(zone);
+ if (bootstrapping) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ // Object::Init version when we are bootstrapping from source or from a
+ // Kernel binary.
+ ObjectStore* object_store = isolate->object_store();
- // All RawArray fields will be initialized to an empty array, therefore
- // initialize array class first.
- cls = Class::New<Array>();
- object_store->set_array_class(cls);
+ Class& cls = Class::Handle(zone);
+ Type& type = Type::Handle(zone);
+ Array& array = Array::Handle(zone);
+ Library& lib = Library::Handle(zone);
- // VM classes that are parameterized (Array, ImmutableArray,
- // GrowableObjectArray, and LinkedHashMap) are also pre-finalized,
- // so CalculateFieldOffsets() is not called, so we need to set the
- // offset of their type_arguments_ field, which is explicitly
- // declared in their respective Raw* classes.
- cls.set_type_arguments_field_offset(Array::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ // All RawArray fields will be initialized to an empty array, therefore
+ // initialize array class first.
+ cls = Class::New<Array>();
+ object_store->set_array_class(cls);
- // Set up the growable object array class (Has to be done after the array
- // class is setup as one of its field is an array object).
- cls = Class::New<GrowableObjectArray>();
- object_store->set_growable_object_array_class(cls);
- cls.set_type_arguments_field_offset(
- GrowableObjectArray::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ // VM classes that are parameterized (Array, ImmutableArray,
+ // GrowableObjectArray, and LinkedHashMap) are also pre-finalized, so
+ // CalculateFieldOffsets() is not called, so we need to set the offset of
+ // their type_arguments_ field, which is explicitly declared in their
+ // respective Raw* classes.
+ cls.set_type_arguments_field_offset(Array::type_arguments_offset());
+ cls.set_num_type_arguments(1);
- // Initialize hash set for canonical_type_.
- const intptr_t kInitialCanonicalTypeSize = 16;
- array =
- HashTables::New<CanonicalTypeSet>(kInitialCanonicalTypeSize, Heap::kOld);
- object_store->set_canonical_types(array);
+ // Set up the growable object array class (Has to be done after the array
+ // class is setup as one of its field is an array object).
+ cls = Class::New<GrowableObjectArray>();
+ object_store->set_growable_object_array_class(cls);
+ cls.set_type_arguments_field_offset(
+ GrowableObjectArray::type_arguments_offset());
+ cls.set_num_type_arguments(1);
- // Initialize hash set for canonical_type_arguments_.
- const intptr_t kInitialCanonicalTypeArgumentsSize = 4;
- array = HashTables::New<CanonicalTypeArgumentsSet>(
- kInitialCanonicalTypeArgumentsSize, Heap::kOld);
- object_store->set_canonical_type_arguments(array);
+ // Initialize hash set for canonical_type_.
+ const intptr_t kInitialCanonicalTypeSize = 16;
+ array = HashTables::New<CanonicalTypeSet>(kInitialCanonicalTypeSize,
+ Heap::kOld);
+ object_store->set_canonical_types(array);
- // Setup type class early in the process.
- const Class& type_cls = Class::Handle(zone, Class::New<Type>());
- const Class& type_ref_cls = Class::Handle(zone, Class::New<TypeRef>());
- const Class& type_parameter_cls =
- Class::Handle(zone, Class::New<TypeParameter>());
- const Class& bounded_type_cls =
- Class::Handle(zone, Class::New<BoundedType>());
- const Class& mixin_app_type_cls =
- Class::Handle(zone, Class::New<MixinAppType>());
- const Class& library_prefix_cls =
- Class::Handle(zone, Class::New<LibraryPrefix>());
+ // Initialize hash set for canonical_type_arguments_.
+ const intptr_t kInitialCanonicalTypeArgumentsSize = 4;
+ array = HashTables::New<CanonicalTypeArgumentsSet>(
+ kInitialCanonicalTypeArgumentsSize, Heap::kOld);
+ object_store->set_canonical_type_arguments(array);
- // Pre-allocate the OneByteString class needed by the symbol table.
- cls = Class::NewStringClass(kOneByteStringCid);
- object_store->set_one_byte_string_class(cls);
+ // Setup type class early in the process.
+ const Class& type_cls = Class::Handle(zone, Class::New<Type>());
+ const Class& type_ref_cls = Class::Handle(zone, Class::New<TypeRef>());
+ const Class& type_parameter_cls =
+ Class::Handle(zone, Class::New<TypeParameter>());
+ const Class& bounded_type_cls =
+ Class::Handle(zone, Class::New<BoundedType>());
+ const Class& mixin_app_type_cls =
+ Class::Handle(zone, Class::New<MixinAppType>());
+ const Class& library_prefix_cls =
+ Class::Handle(zone, Class::New<LibraryPrefix>());
- // Pre-allocate the TwoByteString class needed by the symbol table.
- cls = Class::NewStringClass(kTwoByteStringCid);
- object_store->set_two_byte_string_class(cls);
+ // Pre-allocate the OneByteString class needed by the symbol table.
+ cls = Class::NewStringClass(kOneByteStringCid);
+ object_store->set_one_byte_string_class(cls);
- // Setup the symbol table for the symbols created in the isolate.
- Symbols::SetupSymbolTable(isolate);
+ // Pre-allocate the TwoByteString class needed by the symbol table.
+ cls = Class::NewStringClass(kTwoByteStringCid);
+ object_store->set_two_byte_string_class(cls);
- // Set up the libraries array before initializing the core library.
- const GrowableObjectArray& libraries =
- GrowableObjectArray::Handle(zone, GrowableObjectArray::New(Heap::kOld));
- object_store->set_libraries(libraries);
+ // Setup the symbol table for the symbols created in the isolate.
+ Symbols::SetupSymbolTable(isolate);
- // Pre-register the core library.
- Library::InitCoreLibrary(isolate);
+ // Set up the libraries array before initializing the core library.
+ const GrowableObjectArray& libraries =
+ GrowableObjectArray::Handle(zone, GrowableObjectArray::New(Heap::kOld));
+ object_store->set_libraries(libraries);
- // Basic infrastructure has been setup, initialize the class dictionary.
- const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
- ASSERT(!core_lib.IsNull());
+ // Pre-register the core library.
+ Library::InitCoreLibrary(isolate);
- const GrowableObjectArray& pending_classes =
- GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
- object_store->set_pending_classes(pending_classes);
+ // Basic infrastructure has been setup, initialize the class dictionary.
+ const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
+ ASSERT(!core_lib.IsNull());
- Context& context = Context::Handle(zone, Context::New(0, Heap::kOld));
- object_store->set_empty_context(context);
+ const GrowableObjectArray& pending_classes =
+ GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
+ object_store->set_pending_classes(pending_classes);
- // Now that the symbol table is initialized and that the core dictionary as
- // well as the core implementation dictionary have been setup, preallocate
- // remaining classes and register them by name in the dictionaries.
- String& name = String::Handle(zone);
- cls = object_store->array_class(); // Was allocated above.
- RegisterPrivateClass(cls, Symbols::_List(), core_lib);
- pending_classes.Add(cls);
- // We cannot use NewNonParameterizedType(cls), because Array is parameterized.
- // Warning: class _List has not been patched yet. Its declared number of type
- // parameters is still 0. It will become 1 after patching. The array type
- // allocated below represents the raw type _List and not _List<E> as we
- // could expect. Use with caution.
- type ^= Type::New(Object::Handle(zone, cls.raw()),
- TypeArguments::Handle(zone), TokenPosition::kNoSource);
- type.SetIsFinalized();
- type ^= type.Canonicalize();
- object_store->set_array_type(type);
+ Context& context = Context::Handle(zone, Context::New(0, Heap::kOld));
+ object_store->set_empty_context(context);
- cls = object_store->growable_object_array_class(); // Was allocated above.
- RegisterPrivateClass(cls, Symbols::_GrowableList(), core_lib);
- pending_classes.Add(cls);
+ // Now that the symbol table is initialized and that the core dictionary as
+ // well as the core implementation dictionary have been setup, preallocate
+ // remaining classes and register them by name in the dictionaries.
+ String& name = String::Handle(zone);
+ cls = object_store->array_class(); // Was allocated above.
+ RegisterPrivateClass(cls, Symbols::_List(), core_lib);
+ pending_classes.Add(cls);
+ // We cannot use NewNonParameterizedType(cls), because Array is
+ // parameterized. Warning: class _List has not been patched yet. Its
+ // declared number of type parameters is still 0. It will become 1 after
+ // patching. The array type allocated below represents the raw type _List
+ // and not _List<E> as we could expect. Use with caution.
+ type ^= Type::New(Object::Handle(zone, cls.raw()),
+ TypeArguments::Handle(zone), TokenPosition::kNoSource);
+ type.SetIsFinalized();
+ type ^= type.Canonicalize();
+ object_store->set_array_type(type);
- cls = Class::New<Array>(kImmutableArrayCid);
- object_store->set_immutable_array_class(cls);
- cls.set_type_arguments_field_offset(Array::type_arguments_offset());
- cls.set_num_type_arguments(1);
- ASSERT(object_store->immutable_array_class() != object_store->array_class());
- cls.set_is_prefinalized();
- RegisterPrivateClass(cls, Symbols::_ImmutableList(), core_lib);
- pending_classes.Add(cls);
+ cls = object_store->growable_object_array_class(); // Was allocated above.
+ RegisterPrivateClass(cls, Symbols::_GrowableList(), core_lib);
+ pending_classes.Add(cls);
- cls = object_store->one_byte_string_class(); // Was allocated above.
- RegisterPrivateClass(cls, Symbols::OneByteString(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Array>(kImmutableArrayCid);
+ object_store->set_immutable_array_class(cls);
+ cls.set_type_arguments_field_offset(Array::type_arguments_offset());
+ cls.set_num_type_arguments(1);
+ ASSERT(object_store->immutable_array_class() !=
+ object_store->array_class());
+ cls.set_is_prefinalized();
+ RegisterPrivateClass(cls, Symbols::_ImmutableList(), core_lib);
+ pending_classes.Add(cls);
- cls = object_store->two_byte_string_class(); // Was allocated above.
- RegisterPrivateClass(cls, Symbols::TwoByteString(), core_lib);
- pending_classes.Add(cls);
+ cls = object_store->one_byte_string_class(); // Was allocated above.
+ RegisterPrivateClass(cls, Symbols::OneByteString(), core_lib);
+ pending_classes.Add(cls);
- cls = Class::NewStringClass(kExternalOneByteStringCid);
- object_store->set_external_one_byte_string_class(cls);
- RegisterPrivateClass(cls, Symbols::ExternalOneByteString(), core_lib);
- pending_classes.Add(cls);
+ cls = object_store->two_byte_string_class(); // Was allocated above.
+ RegisterPrivateClass(cls, Symbols::TwoByteString(), core_lib);
+ pending_classes.Add(cls);
- cls = Class::NewStringClass(kExternalTwoByteStringCid);
- object_store->set_external_two_byte_string_class(cls);
- RegisterPrivateClass(cls, Symbols::ExternalTwoByteString(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::NewStringClass(kExternalOneByteStringCid);
+ object_store->set_external_one_byte_string_class(cls);
+ RegisterPrivateClass(cls, Symbols::ExternalOneByteString(), core_lib);
+ pending_classes.Add(cls);
- // Pre-register the isolate library so the native class implementations
- // can be hooked up before compiling it.
- Library& isolate_lib = Library::Handle(
- zone, Library::LookupLibrary(thread, Symbols::DartIsolate()));
- if (isolate_lib.IsNull()) {
- isolate_lib = Library::NewLibraryHelper(Symbols::DartIsolate(), true);
- isolate_lib.SetLoadRequested();
- isolate_lib.Register(thread);
+ cls = Class::NewStringClass(kExternalTwoByteStringCid);
+ object_store->set_external_two_byte_string_class(cls);
+ RegisterPrivateClass(cls, Symbols::ExternalTwoByteString(), core_lib);
+ pending_classes.Add(cls);
+
+ // Pre-register the isolate library so the native class implementations can
+ // be hooked up before compiling it.
+ Library& isolate_lib = Library::Handle(
+ zone, Library::LookupLibrary(thread, Symbols::DartIsolate()));
+ if (isolate_lib.IsNull()) {
+ isolate_lib = Library::NewLibraryHelper(Symbols::DartIsolate(), true);
+ isolate_lib.SetLoadRequested();
+ isolate_lib.Register(thread);
+ }
object_store->set_bootstrap_library(ObjectStore::kIsolate, isolate_lib);
- }
- ASSERT(!isolate_lib.IsNull());
- ASSERT(isolate_lib.raw() == Library::IsolateLibrary());
+ ASSERT(!isolate_lib.IsNull());
+ ASSERT(isolate_lib.raw() == Library::IsolateLibrary());
- cls = Class::New<Capability>();
- RegisterPrivateClass(cls, Symbols::_CapabilityImpl(), isolate_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Capability>();
+ RegisterPrivateClass(cls, Symbols::_CapabilityImpl(), isolate_lib);
+ pending_classes.Add(cls);
- cls = Class::New<ReceivePort>();
- RegisterPrivateClass(cls, Symbols::_RawReceivePortImpl(), isolate_lib);
- pending_classes.Add(cls);
+ cls = Class::New<ReceivePort>();
+ RegisterPrivateClass(cls, Symbols::_RawReceivePortImpl(), isolate_lib);
+ pending_classes.Add(cls);
- cls = Class::New<SendPort>();
- RegisterPrivateClass(cls, Symbols::_SendPortImpl(), isolate_lib);
- pending_classes.Add(cls);
+ cls = Class::New<SendPort>();
+ RegisterPrivateClass(cls, Symbols::_SendPortImpl(), isolate_lib);
+ pending_classes.Add(cls);
- const Class& stacktrace_cls = Class::Handle(zone, Class::New<Stacktrace>());
- RegisterPrivateClass(stacktrace_cls, Symbols::_StackTrace(), core_lib);
- pending_classes.Add(stacktrace_cls);
- // Super type set below, after Object is allocated.
+ const Class& stacktrace_cls = Class::Handle(zone, Class::New<Stacktrace>());
+ RegisterPrivateClass(stacktrace_cls, Symbols::_StackTrace(), core_lib);
+ pending_classes.Add(stacktrace_cls);
+ // Super type set below, after Object is allocated.
- cls = Class::New<RegExp>();
- RegisterPrivateClass(cls, Symbols::_RegExp(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<RegExp>();
+ RegisterPrivateClass(cls, Symbols::_RegExp(), core_lib);
+ pending_classes.Add(cls);
- // Initialize the base interfaces used by the core VM classes.
+ // Initialize the base interfaces used by the core VM classes.
- // Allocate and initialize the pre-allocated classes in the core library.
- // The script and token index of these pre-allocated classes is set up in
- // the parser when the corelib script is compiled (see
- // Parser::ParseClassDefinition).
- cls = Class::New<Instance>(kInstanceCid);
- object_store->set_object_class(cls);
- cls.set_name(Symbols::Object());
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- core_lib.AddClass(cls);
- pending_classes.Add(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_object_type(type);
+ // Allocate and initialize the pre-allocated classes in the core library.
+ // The script and token index of these pre-allocated classes is set up in
+ // the parser when the corelib script is compiled (see
+ // Parser::ParseClassDefinition).
+ cls = Class::New<Instance>(kInstanceCid);
+ object_store->set_object_class(cls);
+ cls.set_name(Symbols::Object());
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ core_lib.AddClass(cls);
+ pending_classes.Add(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_object_type(type);
- cls = Class::New<Bool>();
- object_store->set_bool_class(cls);
- RegisterClass(cls, Symbols::Bool(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Bool>();
+ object_store->set_bool_class(cls);
+ RegisterClass(cls, Symbols::Bool(), core_lib);
+ pending_classes.Add(cls);
- cls = Class::New<Instance>(kNullCid);
- object_store->set_null_class(cls);
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- RegisterClass(cls, Symbols::Null(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Instance>(kNullCid);
+ object_store->set_null_class(cls);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ RegisterClass(cls, Symbols::Null(), core_lib);
+ pending_classes.Add(cls);
- ASSERT(!library_prefix_cls.IsNull());
- RegisterPrivateClass(library_prefix_cls, Symbols::_LibraryPrefix(), core_lib);
- pending_classes.Add(library_prefix_cls);
+ ASSERT(!library_prefix_cls.IsNull());
+ RegisterPrivateClass(library_prefix_cls, Symbols::_LibraryPrefix(),
+ core_lib);
+ pending_classes.Add(library_prefix_cls);
- RegisterPrivateClass(type_cls, Symbols::Type(), core_lib);
- pending_classes.Add(type_cls);
+ RegisterPrivateClass(type_cls, Symbols::Type(), core_lib);
+ pending_classes.Add(type_cls);
- RegisterPrivateClass(type_ref_cls, Symbols::TypeRef(), core_lib);
- pending_classes.Add(type_ref_cls);
+ RegisterPrivateClass(type_ref_cls, Symbols::TypeRef(), core_lib);
+ pending_classes.Add(type_ref_cls);
- RegisterPrivateClass(type_parameter_cls, Symbols::TypeParameter(), core_lib);
- pending_classes.Add(type_parameter_cls);
+ RegisterPrivateClass(type_parameter_cls, Symbols::TypeParameter(),
+ core_lib);
+ pending_classes.Add(type_parameter_cls);
- RegisterPrivateClass(bounded_type_cls, Symbols::BoundedType(), core_lib);
- pending_classes.Add(bounded_type_cls);
+ RegisterPrivateClass(bounded_type_cls, Symbols::BoundedType(), core_lib);
+ pending_classes.Add(bounded_type_cls);
- RegisterPrivateClass(mixin_app_type_cls, Symbols::MixinAppType(), core_lib);
- pending_classes.Add(mixin_app_type_cls);
+ RegisterPrivateClass(mixin_app_type_cls, Symbols::MixinAppType(), core_lib);
+ pending_classes.Add(mixin_app_type_cls);
- cls = Class::New<Integer>();
- object_store->set_integer_implementation_class(cls);
- RegisterPrivateClass(cls, Symbols::IntegerImplementation(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Integer>();
+ object_store->set_integer_implementation_class(cls);
+ RegisterPrivateClass(cls, Symbols::IntegerImplementation(), core_lib);
+ pending_classes.Add(cls);
- cls = Class::New<Smi>();
- object_store->set_smi_class(cls);
- RegisterPrivateClass(cls, Symbols::_Smi(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Smi>();
+ object_store->set_smi_class(cls);
+ RegisterPrivateClass(cls, Symbols::_Smi(), core_lib);
+ pending_classes.Add(cls);
- cls = Class::New<Mint>();
- object_store->set_mint_class(cls);
- RegisterPrivateClass(cls, Symbols::_Mint(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Mint>();
+ object_store->set_mint_class(cls);
+ RegisterPrivateClass(cls, Symbols::_Mint(), core_lib);
+ pending_classes.Add(cls);
- cls = Class::New<Bigint>();
- object_store->set_bigint_class(cls);
- RegisterPrivateClass(cls, Symbols::_Bigint(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Bigint>();
+ object_store->set_bigint_class(cls);
+ RegisterPrivateClass(cls, Symbols::_Bigint(), core_lib);
+ pending_classes.Add(cls);
- cls = Class::New<Double>();
- object_store->set_double_class(cls);
- RegisterPrivateClass(cls, Symbols::_Double(), core_lib);
- pending_classes.Add(cls);
+ cls = Class::New<Double>();
+ object_store->set_double_class(cls);
+ RegisterPrivateClass(cls, Symbols::_Double(), core_lib);
+ pending_classes.Add(cls);
- // Class that represents the Dart class _Closure and C++ class Closure.
- cls = Class::New<Closure>();
- cls.set_type_arguments_field_offset(Closure::type_arguments_offset());
- cls.set_num_type_arguments(0); // Although a closure has type_arguments_.
- cls.set_num_own_type_arguments(0);
- RegisterPrivateClass(cls, Symbols::_Closure(), core_lib);
- pending_classes.Add(cls);
- object_store->set_closure_class(cls);
+ // Class that represents the Dart class _Closure and C++ class Closure.
+ cls = Class::New<Closure>();
+ cls.set_type_arguments_field_offset(Closure::type_arguments_offset());
+ cls.set_num_type_arguments(0); // Although a closure has type_arguments_.
+ cls.set_num_own_type_arguments(0);
+ RegisterPrivateClass(cls, Symbols::_Closure(), core_lib);
+ pending_classes.Add(cls);
+ object_store->set_closure_class(cls);
- cls = Class::New<WeakProperty>();
- object_store->set_weak_property_class(cls);
- RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib);
+ cls = Class::New<WeakProperty>();
+ object_store->set_weak_property_class(cls);
+ RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib);
// Pre-register the mirrors library so we can place the vm class
// MirrorReference there rather than the core library.
#if !defined(PRODUCT)
- lib = Library::LookupLibrary(thread, Symbols::DartMirrors());
- if (lib.IsNull()) {
- lib = Library::NewLibraryHelper(Symbols::DartMirrors(), true);
- lib.SetLoadRequested();
- lib.Register(thread);
+ lib = Library::LookupLibrary(thread, Symbols::DartMirrors());
+ if (lib.IsNull()) {
+ lib = Library::NewLibraryHelper(Symbols::DartMirrors(), true);
+ lib.SetLoadRequested();
+ lib.Register(thread);
+ }
object_store->set_bootstrap_library(ObjectStore::kMirrors, lib);
- }
- ASSERT(!lib.IsNull());
- ASSERT(lib.raw() == Library::MirrorsLibrary());
+ ASSERT(!lib.IsNull());
+ ASSERT(lib.raw() == Library::MirrorsLibrary());
- cls = Class::New<MirrorReference>();
- RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
-#endif // !defined(PRODUCT)
+ cls = Class::New<MirrorReference>();
+ RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
+#endif
- // Pre-register the collection library so we can place the vm class
- // LinkedHashMap there rather than the core library.
- lib = Library::LookupLibrary(thread, Symbols::DartCollection());
- if (lib.IsNull()) {
- lib = Library::NewLibraryHelper(Symbols::DartCollection(), true);
- lib.SetLoadRequested();
- lib.Register(thread);
+ // Pre-register the collection library so we can place the vm class
+ // LinkedHashMap there rather than the core library.
+ lib = Library::LookupLibrary(thread, Symbols::DartCollection());
+ if (lib.IsNull()) {
+ lib = Library::NewLibraryHelper(Symbols::DartCollection(), true);
+ lib.SetLoadRequested();
+ lib.Register(thread);
+ }
+
object_store->set_bootstrap_library(ObjectStore::kCollection, lib);
- }
- ASSERT(!lib.IsNull());
- ASSERT(lib.raw() == Library::CollectionLibrary());
- cls = Class::New<LinkedHashMap>();
- object_store->set_linked_hash_map_class(cls);
- cls.set_type_arguments_field_offset(LinkedHashMap::type_arguments_offset());
- cls.set_num_type_arguments(2);
- cls.set_num_own_type_arguments(2);
- RegisterPrivateClass(cls, Symbols::_LinkedHashMap(), lib);
- pending_classes.Add(cls);
+ ASSERT(!lib.IsNull());
+ ASSERT(lib.raw() == Library::CollectionLibrary());
+ cls = Class::New<LinkedHashMap>();
+ object_store->set_linked_hash_map_class(cls);
+ cls.set_type_arguments_field_offset(LinkedHashMap::type_arguments_offset());
+ cls.set_num_type_arguments(2);
+ cls.set_num_own_type_arguments(0);
+ RegisterPrivateClass(cls, Symbols::_LinkedHashMap(), lib);
+ pending_classes.Add(cls);
- // Pre-register the developer library so we can place the vm class
- // UserTag there rather than the core library.
- lib = Library::LookupLibrary(thread, Symbols::DartDeveloper());
- if (lib.IsNull()) {
- lib = Library::NewLibraryHelper(Symbols::DartDeveloper(), true);
- lib.SetLoadRequested();
- lib.Register(thread);
+ // Pre-register the developer library so we can place the vm class
+ // UserTag there rather than the core library.
+ lib = Library::LookupLibrary(thread, Symbols::DartDeveloper());
+ if (lib.IsNull()) {
+ lib = Library::NewLibraryHelper(Symbols::DartDeveloper(), true);
+ lib.SetLoadRequested();
+ lib.Register(thread);
+ }
object_store->set_bootstrap_library(ObjectStore::kDeveloper, lib);
- }
- ASSERT(!lib.IsNull());
- ASSERT(lib.raw() == Library::DeveloperLibrary());
+ ASSERT(!lib.IsNull());
+ ASSERT(lib.raw() == Library::DeveloperLibrary());
+ cls = Class::New<UserTag>();
+ RegisterPrivateClass(cls, Symbols::_UserTag(), lib);
+ pending_classes.Add(cls);
- lib = Library::LookupLibrary(thread, Symbols::DartDeveloper());
- ASSERT(!lib.IsNull());
- cls = Class::New<UserTag>();
- RegisterPrivateClass(cls, Symbols::_UserTag(), lib);
- pending_classes.Add(cls);
+ // Setup some default native field classes which can be extended for
+ // specifying native fields in dart classes.
+ Library::InitNativeWrappersLibrary(isolate, is_kernel);
+ ASSERT(object_store->native_wrappers_library() != Library::null());
- // Setup some default native field classes which can be extended for
- // specifying native fields in dart classes.
- Library::InitNativeWrappersLibrary(isolate);
- ASSERT(object_store->native_wrappers_library() != Library::null());
-
- // Pre-register the typed_data library so the native class implementations
- // can be hooked up before compiling it.
- lib = Library::LookupLibrary(thread, Symbols::DartTypedData());
- if (lib.IsNull()) {
- lib = Library::NewLibraryHelper(Symbols::DartTypedData(), true);
- lib.SetLoadRequested();
- lib.Register(thread);
+ // Pre-register the typed_data library so the native class implementations
+ // can be hooked up before compiling it.
+ lib = Library::LookupLibrary(thread, Symbols::DartTypedData());
+ if (lib.IsNull()) {
+ lib = Library::NewLibraryHelper(Symbols::DartTypedData(), true);
+ lib.SetLoadRequested();
+ lib.Register(thread);
+ }
object_store->set_bootstrap_library(ObjectStore::kTypedData, lib);
- }
- ASSERT(!lib.IsNull());
- ASSERT(lib.raw() == Library::TypedDataLibrary());
+ ASSERT(!lib.IsNull());
+ ASSERT(lib.raw() == Library::TypedDataLibrary());
#define REGISTER_TYPED_DATA_CLASS(clazz) \
cls = Class::NewTypedDataClass(kTypedData##clazz##ArrayCid); \
RegisterClass(cls, Symbols::clazz##List(), lib);
- DART_CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
+ DART_CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
#undef REGISTER_TYPED_DATA_CLASS
#define REGISTER_TYPED_DATA_VIEW_CLASS(clazz) \
cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid); \
RegisterPrivateClass(cls, Symbols::_##clazz##View(), lib); \
pending_classes.Add(cls);
- CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
- cls = Class::NewTypedDataViewClass(kByteDataViewCid);
- RegisterPrivateClass(cls, Symbols::_ByteDataView(), lib);
- pending_classes.Add(cls);
+ CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
+ cls = Class::NewTypedDataViewClass(kByteDataViewCid);
+ RegisterPrivateClass(cls, Symbols::_ByteDataView(), lib);
+ pending_classes.Add(cls);
#undef REGISTER_TYPED_DATA_VIEW_CLASS
#define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \
cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid); \
RegisterPrivateClass(cls, Symbols::_External##clazz(), lib);
- cls = Class::New<Instance>(kByteBufferCid);
- cls.set_instance_size(0);
- cls.set_next_field_offset(-kWordSize);
- RegisterClass(cls, Symbols::ByteBuffer(), lib);
- pending_classes.Add(cls);
+ cls = Class::New<Instance>(kByteBufferCid);
+ cls.set_instance_size(0);
+ cls.set_next_field_offset(-kWordSize);
+ RegisterClass(cls, Symbols::ByteBuffer(), lib);
+ pending_classes.Add(cls);
- CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
+ CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
#undef REGISTER_EXT_TYPED_DATA_CLASS
- // Register Float32x4 and Int32x4 in the object store.
- cls = Class::New<Float32x4>();
- RegisterClass(cls, Symbols::Float32x4(), lib);
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- pending_classes.Add(cls);
- object_store->set_float32x4_class(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_float32x4_type(type);
+ // Register Float32x4 and Int32x4 in the object store.
+ cls = Class::New<Float32x4>();
+ RegisterClass(cls, Symbols::Float32x4(), lib);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ pending_classes.Add(cls);
+ object_store->set_float32x4_class(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_float32x4_type(type);
- cls = Class::New<Int32x4>();
- RegisterClass(cls, Symbols::Int32x4(), lib);
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- pending_classes.Add(cls);
- object_store->set_int32x4_class(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_int32x4_type(type);
+ cls = Class::New<Int32x4>();
+ RegisterClass(cls, Symbols::Int32x4(), lib);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ pending_classes.Add(cls);
+ object_store->set_int32x4_class(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_int32x4_type(type);
- cls = Class::New<Float64x2>();
- RegisterClass(cls, Symbols::Float64x2(), lib);
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- pending_classes.Add(cls);
- object_store->set_float64x2_class(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_float64x2_type(type);
+ cls = Class::New<Float64x2>();
+ RegisterClass(cls, Symbols::Float64x2(), lib);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ pending_classes.Add(cls);
+ object_store->set_float64x2_class(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_float64x2_type(type);
- // Set the super type of class Stacktrace to Object type so that the
- // 'toString' method is implemented.
- type = object_store->object_type();
- stacktrace_cls.set_super_type(type);
+ // Set the super type of class Stacktrace to Object type so that the
+ // 'toString' method is implemented.
+ type = object_store->object_type();
+ stacktrace_cls.set_super_type(type);
- // Abstract class that represents the Dart class Function.
- cls = Class::New<Instance>(kIllegalCid);
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- RegisterClass(cls, Symbols::Function(), core_lib);
- pending_classes.Add(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_function_type(type);
+ // Abstract class that represents the Dart class Function.
+ cls = Class::New<Instance>(kIllegalCid);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ RegisterClass(cls, Symbols::Function(), core_lib);
+ pending_classes.Add(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_function_type(type);
- cls = Class::New<Number>();
- RegisterClass(cls, Symbols::Number(), core_lib);
- pending_classes.Add(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_number_type(type);
+ cls = Class::New<Number>();
+ RegisterClass(cls, Symbols::Number(), core_lib);
+ pending_classes.Add(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_number_type(type);
- cls = Class::New<Instance>(kIllegalCid);
- RegisterClass(cls, Symbols::Int(), core_lib);
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- pending_classes.Add(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_int_type(type);
+ cls = Class::New<Instance>(kIllegalCid);
+ RegisterClass(cls, Symbols::Int(), core_lib);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ pending_classes.Add(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_int_type(type);
- cls = Class::New<Instance>(kIllegalCid);
- RegisterClass(cls, Symbols::Double(), core_lib);
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- pending_classes.Add(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_double_type(type);
+ cls = Class::New<Instance>(kIllegalCid);
+ RegisterClass(cls, Symbols::Double(), core_lib);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ pending_classes.Add(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_double_type(type);
- name = Symbols::_String().raw();
- cls = Class::New<Instance>(kIllegalCid);
- RegisterClass(cls, name, core_lib);
- cls.set_num_type_arguments(0);
- cls.set_num_own_type_arguments(0);
- cls.set_is_prefinalized();
- pending_classes.Add(cls);
- type = Type::NewNonParameterizedType(cls);
- object_store->set_string_type(type);
+ name = Symbols::_String().raw();
+ cls = Class::New<Instance>(kIllegalCid);
+ RegisterClass(cls, name, core_lib);
+ cls.set_num_type_arguments(0);
+ cls.set_num_own_type_arguments(0);
+ cls.set_is_prefinalized();
+ pending_classes.Add(cls);
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_string_type(type);
- cls = object_store->bool_class();
- type = Type::NewNonParameterizedType(cls);
- object_store->set_bool_type(type);
+ cls = object_store->bool_class();
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_bool_type(type);
- cls = object_store->smi_class();
- type = Type::NewNonParameterizedType(cls);
- object_store->set_smi_type(type);
+ cls = object_store->smi_class();
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_smi_type(type);
- cls = object_store->mint_class();
- type = Type::NewNonParameterizedType(cls);
- object_store->set_mint_type(type);
+ cls = object_store->mint_class();
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_mint_type(type);
- // The classes 'void' and 'dynamic' are phoney classes to make type checking
- // more regular; they live in the VM isolate. The class 'void' is not
- // registered in the class dictionary because its name is a reserved word.
- // The class 'dynamic' is registered in the class dictionary because its name
- // is a built-in identifier (this is wrong).
- // The corresponding types are stored in the object store.
- cls = object_store->null_class();
- type = Type::NewNonParameterizedType(cls);
- object_store->set_null_type(type);
+ // The classes 'void' and 'dynamic' are phony classes to make type checking
+ // more regular; they live in the VM isolate. The class 'void' is not
+ // registered in the class dictionary because its name is a reserved word.
+ // The class 'dynamic' is registered in the class dictionary because its
+ // name is a built-in identifier (this is wrong). The corresponding types
+ // are stored in the object store.
+ cls = object_store->null_class();
+ type = Type::NewNonParameterizedType(cls);
+ object_store->set_null_type(type);
- // Consider removing when/if Null becomes an ordinary class.
- type = object_store->object_type();
- cls.set_super_type(type);
+ // Consider removing when/if Null becomes an ordinary class.
+ type = object_store->object_type();
+ cls.set_super_type(type);
- // Finish the initialization by compiling the bootstrap scripts containing the
- // base interfaces and the implementation of the internal classes.
- const Error& error = Error::Handle(Bootstrap::DoBootstrapping());
- if (!error.IsNull()) {
- return error.raw();
- }
+ // Finish the initialization by compiling the bootstrap scripts containing
+ // the base interfaces and the implementation of the internal classes.
+ const Error& error = Error::Handle(
+ zone, Bootstrap::DoBootstrapping(kernel_buffer, kernel_buffer_length));
+ if (!error.IsNull()) {
+ return error.raw();
+ }
- ClassFinalizer::VerifyBootstrapClasses();
+ ClassFinalizer::VerifyBootstrapClasses();
- // Set up the intrinsic state of all functions (core, math and typed data).
- Intrinsifier::InitializeState();
+ // Set up the intrinsic state of all functions (core, math and typed data).
+ Intrinsifier::InitializeState();
- // Set up recognized state of all functions (core, math and typed data).
- MethodRecognizer::InitializeState();
+ // Set up recognized state of all functions (core, math and typed data).
+ MethodRecognizer::InitializeState();
- // Adds static const fields (class ids) to the class 'ClassID');
- lib = Library::LookupLibrary(thread, Symbols::DartInternal());
- ASSERT(!lib.IsNull());
- cls = lib.LookupClassAllowPrivate(Symbols::ClassID());
- ASSERT(!cls.IsNull());
- Field& field = Field::Handle(zone);
- Smi& value = Smi::Handle(zone);
- String& field_name = String::Handle(zone);
+ isolate->object_store()->InitKnownObjects();
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
+ } else {
+ // Object::Init version when we are running in a version of dart that has a
+ // full snapshot linked in and an isolate is initialized using the full
+ // snapshot.
+ ObjectStore* object_store = isolate->object_store();
-#define CLASS_LIST_WITH_NULL(V) \
- V(Null) \
- CLASS_LIST_NO_OBJECT(V)
+ Class& cls = Class::Handle(zone);
-#define ADD_SET_FIELD(clazz) \
- field_name = Symbols::New(thread, "cid" #clazz); \
- field = \
- Field::New(field_name, true, false, true, false, cls, \
- Type::Handle(Type::IntType()), TokenPosition::kMinSource); \
- value = Smi::New(k##clazz##Cid); \
- field.SetStaticValue(value, true); \
- cls.AddField(field);
+ // Set up empty classes in the object store, these will get initialized
+ // correctly when we read from the snapshot. This is done to allow
+ // bootstrapping of reading classes from the snapshot. Some classes are not
+ // stored in the object store. Yet we still need to create their Class
+ // object so that they get put into the class_table (as a side effect of
+ // Class::New()).
+ cls = Class::New<Instance>(kInstanceCid);
+ object_store->set_object_class(cls);
- CLASS_LIST_WITH_NULL(ADD_SET_FIELD)
-#undef ADD_SET_FIELD
+ cls = Class::New<LibraryPrefix>();
+ cls = Class::New<Type>();
+ cls = Class::New<TypeRef>();
+ cls = Class::New<TypeParameter>();
+ cls = Class::New<BoundedType>();
+ cls = Class::New<MixinAppType>();
- isolate->object_store()->InitKnownObjects();
+ cls = Class::New<Array>();
+ object_store->set_array_class(cls);
- return Error::null();
-#else // defined(DART_NO_SNAPSHOT).
- // Object::Init version when we are running in a version of dart that has
- // a full snapshot linked in and an isolate is initialized using the full
- // snapshot.
- ObjectStore* object_store = isolate->object_store();
+ cls = Class::New<Array>(kImmutableArrayCid);
+ object_store->set_immutable_array_class(cls);
- Class& cls = Class::Handle();
+ cls = Class::New<GrowableObjectArray>();
+ object_store->set_growable_object_array_class(cls);
- // Set up empty classes in the object store, these will get
- // initialized correctly when we read from the snapshot.
- // This is done to allow bootstrapping of reading classes from the snapshot.
- // Some classes are not stored in the object store. Yet we still need to
- // create their Class object so that they get put into the class_table
- // (as a side effect of Class::New()).
+ cls = Class::New<LinkedHashMap>();
+ object_store->set_linked_hash_map_class(cls);
- cls = Class::New<Instance>(kInstanceCid);
- object_store->set_object_class(cls);
+ cls = Class::New<Float32x4>();
+ object_store->set_float32x4_class(cls);
- cls = Class::New<LibraryPrefix>();
- cls = Class::New<Type>();
- cls = Class::New<TypeRef>();
- cls = Class::New<TypeParameter>();
- cls = Class::New<BoundedType>();
- cls = Class::New<MixinAppType>();
+ cls = Class::New<Int32x4>();
+ object_store->set_int32x4_class(cls);
- cls = Class::New<Array>();
- object_store->set_array_class(cls);
-
- cls = Class::New<Array>(kImmutableArrayCid);
- object_store->set_immutable_array_class(cls);
-
- cls = Class::New<GrowableObjectArray>();
- object_store->set_growable_object_array_class(cls);
-
- cls = Class::New<LinkedHashMap>();
- object_store->set_linked_hash_map_class(cls);
-
- cls = Class::New<Float32x4>();
- object_store->set_float32x4_class(cls);
-
- cls = Class::New<Int32x4>();
- object_store->set_int32x4_class(cls);
-
- cls = Class::New<Float64x2>();
- object_store->set_float64x2_class(cls);
+ cls = Class::New<Float64x2>();
+ object_store->set_float64x2_class(cls);
#define REGISTER_TYPED_DATA_CLASS(clazz) \
cls = Class::NewTypedDataClass(kTypedData##clazz##Cid);
- CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
+ CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
#undef REGISTER_TYPED_DATA_CLASS
#define REGISTER_TYPED_DATA_VIEW_CLASS(clazz) \
cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid);
- CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
+ CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
#undef REGISTER_TYPED_DATA_VIEW_CLASS
- cls = Class::NewTypedDataViewClass(kByteDataViewCid);
+ cls = Class::NewTypedDataViewClass(kByteDataViewCid);
#define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \
cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid);
- CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
+ CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
#undef REGISTER_EXT_TYPED_DATA_CLASS
- cls = Class::New<Instance>(kByteBufferCid);
+ cls = Class::New<Instance>(kByteBufferCid);
- cls = Class::New<Integer>();
- object_store->set_integer_implementation_class(cls);
+ cls = Class::New<Integer>();
+ object_store->set_integer_implementation_class(cls);
- cls = Class::New<Smi>();
- object_store->set_smi_class(cls);
+ cls = Class::New<Smi>();
+ object_store->set_smi_class(cls);
- cls = Class::New<Mint>();
- object_store->set_mint_class(cls);
+ cls = Class::New<Mint>();
+ object_store->set_mint_class(cls);
- cls = Class::New<Double>();
- object_store->set_double_class(cls);
+ cls = Class::New<Double>();
+ object_store->set_double_class(cls);
- cls = Class::New<Closure>();
- object_store->set_closure_class(cls);
+ cls = Class::New<Closure>();
+ object_store->set_closure_class(cls);
- cls = Class::New<Bigint>();
- object_store->set_bigint_class(cls);
+ cls = Class::New<Bigint>();
+ object_store->set_bigint_class(cls);
- cls = Class::NewStringClass(kOneByteStringCid);
- object_store->set_one_byte_string_class(cls);
+ cls = Class::NewStringClass(kOneByteStringCid);
+ object_store->set_one_byte_string_class(cls);
- cls = Class::NewStringClass(kTwoByteStringCid);
- object_store->set_two_byte_string_class(cls);
+ cls = Class::NewStringClass(kTwoByteStringCid);
+ object_store->set_two_byte_string_class(cls);
- cls = Class::NewStringClass(kExternalOneByteStringCid);
- object_store->set_external_one_byte_string_class(cls);
+ cls = Class::NewStringClass(kExternalOneByteStringCid);
+ object_store->set_external_one_byte_string_class(cls);
- cls = Class::NewStringClass(kExternalTwoByteStringCid);
- object_store->set_external_two_byte_string_class(cls);
+ cls = Class::NewStringClass(kExternalTwoByteStringCid);
+ object_store->set_external_two_byte_string_class(cls);
- cls = Class::New<Bool>();
- object_store->set_bool_class(cls);
+ cls = Class::New<Bool>();
+ object_store->set_bool_class(cls);
- cls = Class::New<Instance>(kNullCid);
- object_store->set_null_class(cls);
+ cls = Class::New<Instance>(kNullCid);
+ object_store->set_null_class(cls);
- cls = Class::New<Capability>();
- cls = Class::New<ReceivePort>();
- cls = Class::New<SendPort>();
- cls = Class::New<Stacktrace>();
- cls = Class::New<RegExp>();
- cls = Class::New<Number>();
+ cls = Class::New<Capability>();
+ cls = Class::New<ReceivePort>();
+ cls = Class::New<SendPort>();
+ cls = Class::New<Stacktrace>();
+ cls = Class::New<RegExp>();
+ cls = Class::New<Number>();
- cls = Class::New<WeakProperty>();
- object_store->set_weak_property_class(cls);
+ cls = Class::New<WeakProperty>();
+ object_store->set_weak_property_class(cls);
- cls = Class::New<MirrorReference>();
- cls = Class::New<UserTag>();
+ cls = Class::New<MirrorReference>();
+ cls = Class::New<UserTag>();
- const Context& context = Context::Handle(zone, Context::New(0, Heap::kOld));
- object_store->set_empty_context(context);
-
-#endif // defined(DART_NO_SNAPSHOT).
-
+ const Context& context = Context::Handle(zone, Context::New(0, Heap::kOld));
+ object_store->set_empty_context(context);
+ }
return Error::null();
}
@@ -1923,7 +1921,6 @@
RawString* Class::Name() const {
- ASSERT(raw_ptr()->name_ != String::null());
return raw_ptr()->name_;
}
@@ -2043,7 +2040,7 @@
}
-RawArray* Class::OffsetToFieldMap() const {
+RawArray* Class::OffsetToFieldMap(bool original_classes) const {
Array& array = Array::Handle(raw_ptr()->offset_in_words_to_field_);
if (array.IsNull()) {
ASSERT(is_finalized());
@@ -2060,7 +2057,7 @@
array.SetAt(f.Offset() >> kWordSizeLog2, f);
}
}
- cls = cls.SuperClass();
+ cls = cls.SuperClass(original_classes);
}
StorePointer(&raw_ptr()->offset_in_words_to_field_, array.raw());
}
@@ -2433,12 +2430,20 @@
}
-RawClass* Class::SuperClass() const {
+RawClass* Class::SuperClass(bool original_classes) const {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Isolate* isolate = thread->isolate();
if (super_type() == AbstractType::null()) {
return Class::null();
}
- const AbstractType& sup_type = AbstractType::Handle(super_type());
- return sup_type.type_class();
+ const AbstractType& sup_type = AbstractType::Handle(zone, super_type());
+ const intptr_t type_class_id = sup_type.type_class_id();
+ if (original_classes) {
+ return isolate->GetClassForHeapWalkAt(type_class_id);
+ } else {
+ return isolate->class_table()->At(type_class_id);
+ }
}
@@ -2999,10 +3004,10 @@
}
-static RawFunction* EvaluateHelper(const Class& cls,
- const String& expr,
- const Array& param_names,
- bool is_static) {
+RawFunction* Function::EvaluateHelper(const Class& cls,
+ const String& expr,
+ const Array& param_names,
+ bool is_static) {
const String& func_src =
String::Handle(BuildClosureSource(param_names, expr));
Script& script = Script::Handle();
@@ -3037,8 +3042,8 @@
return UnhandledException::New(exception, stacktrace);
}
- const Function& eval_func =
- Function::Handle(EvaluateHelper(*this, expr, param_names, true));
+ const Function& eval_func = Function::Handle(
+ Function::EvaluateHelper(*this, expr, param_names, true));
const Object& result =
Object::Handle(DartEntry::InvokeFunction(eval_func, param_values));
return result.raw();
@@ -4398,11 +4403,11 @@
}
-RawUnresolvedClass* UnresolvedClass::New(const LibraryPrefix& library_prefix,
+RawUnresolvedClass* UnresolvedClass::New(const Object& library_prefix,
const String& ident,
TokenPosition token_pos) {
const UnresolvedClass& type = UnresolvedClass::Handle(UnresolvedClass::New());
- type.set_library_prefix(library_prefix);
+ type.set_library_or_library_prefix(library_prefix);
type.set_ident(ident);
type.set_token_pos(token_pos);
return type.raw();
@@ -4428,19 +4433,24 @@
}
-void UnresolvedClass::set_library_prefix(
- const LibraryPrefix& library_prefix) const {
- StorePointer(&raw_ptr()->library_prefix_, library_prefix.raw());
+void UnresolvedClass::set_library_or_library_prefix(
+ const Object& library_prefix) const {
+ StorePointer(&raw_ptr()->library_or_library_prefix_, library_prefix.raw());
}
RawString* UnresolvedClass::Name() const {
- if (library_prefix() != LibraryPrefix::null()) {
+ if (library_or_library_prefix() != Object::null()) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
- const LibraryPrefix& lib_prefix =
- LibraryPrefix::Handle(zone, library_prefix());
- const String& name = String::Handle(zone, lib_prefix.name()); // Qualifier.
+ const Object& lib_prefix =
+ Object::Handle(zone, library_or_library_prefix());
+ String& name = String::Handle(zone); // Qualifier.
+ if (lib_prefix.IsLibraryPrefix()) {
+ name = LibraryPrefix::Cast(lib_prefix).name();
+ } else {
+ name = Library::Cast(lib_prefix).name();
+ }
GrowableHandlePtrArray<const String> strs(zone, 3);
strs.Add(name);
strs.Add(Symbols::Dot());
@@ -7104,7 +7114,7 @@
bool Function::CheckSourceFingerprint(const char* prefix, int32_t fp) const {
- if (SourceFingerprint() != fp) {
+ if ((kernel_function() == NULL) && (SourceFingerprint() != fp)) {
const bool recalculatingFingerprints = false;
if (recalculatingFingerprints) {
// This output can be copied into a file, then used with sed
@@ -7495,6 +7505,36 @@
}
+RawString* Field::InitializingExpression() const {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ const class Script& scr = Script::Handle(zone, Script());
+ ASSERT(!scr.IsNull());
+ const TokenStream& tkns = TokenStream::Handle(zone, scr.tokens());
+ if (tkns.IsNull()) {
+ ASSERT(Dart::snapshot_kind() == Snapshot::kAppNoJIT);
+ return String::null();
+ }
+ TokenStream::Iterator tkit(zone, tkns, token_pos());
+ ASSERT(Token::IsIdentifier(tkit.CurrentTokenKind()));
+#if defined(DEBUG)
+ const String& literal = String::Handle(zone, tkit.CurrentLiteral());
+ ASSERT(literal.raw() == name());
+#endif
+ tkit.Advance();
+ if (tkit.CurrentTokenKind() != Token::kASSIGN) {
+ return String::null();
+ }
+ tkit.Advance();
+ const TokenPosition start_of_expression = tkit.CurrentPosition();
+ while (tkit.CurrentTokenKind() != Token::kSEMICOLON) {
+ tkit.Advance();
+ }
+ const TokenPosition end_of_expression = tkit.CurrentPosition();
+ return scr.GetSnippet(start_of_expression, end_of_expression);
+}
+
+
RawString* Field::UserVisibleName() const {
if (FLAG_show_internal_names) {
return name();
@@ -8932,6 +8972,17 @@
}
+RawString* Script::GetSnippet(TokenPosition from, TokenPosition to) const {
+ intptr_t from_line;
+ intptr_t from_column;
+ intptr_t to_line;
+ intptr_t to_column;
+ GetTokenLocation(from, &from_line, &from_column);
+ GetTokenLocation(to, &to_line, &to_column);
+ return GetSnippet(from_line, from_column, to_line, to_column);
+}
+
+
RawString* Script::GetSnippet(intptr_t from_line,
intptr_t from_column,
intptr_t to_line,
@@ -10374,7 +10425,7 @@
}
-void Library::InitNativeWrappersLibrary(Isolate* isolate) {
+void Library::InitNativeWrappersLibrary(Isolate* isolate, bool is_kernel) {
static const int kNumNativeWrappersClasses = 4;
COMPILE_ASSERT((kNumNativeWrappersClasses > 0) &&
(kNumNativeWrappersClasses < 10));
@@ -10400,7 +10451,12 @@
cls_name = Symbols::New(thread, name_buffer);
Class::NewNativeWrapper(native_flds_lib, cls_name, fld_cnt);
}
- native_flds_lib.SetLoaded();
+ // NOTE: If we bootstrap from a Kernel IR file we want to generate the
+ // synthetic constructors for the native wrapper classes. We leave this up to
+ // the [KernelReader] who will take care of it later.
+ if (!is_kernel) {
+ native_flds_lib.SetLoaded();
+ }
}
@@ -15176,8 +15232,8 @@
const String& expr,
const Array& param_names,
const Array& param_values) const {
- const Function& eval_func =
- Function::Handle(EvaluateHelper(method_cls, expr, param_names, false));
+ const Function& eval_func = Function::Handle(
+ Function::EvaluateHelper(method_cls, expr, param_names, false));
const Array& args = Array::Handle(Array::New(1 + param_values.Length()));
PassiveObject& param = PassiveObject::Handle();
args.SetAt(0, *this);
@@ -15351,7 +15407,7 @@
#endif // DEBUG
-RawAbstractType* Instance::GetType() const {
+RawAbstractType* Instance::GetType(Heap::Space space) const {
if (IsNull()) {
return Type::NullType();
}
@@ -15371,8 +15427,8 @@
const Class& scope_cls = Class::Handle(type.type_class());
ASSERT(scope_cls.NumTypeArguments() > 0);
TypeArguments& type_arguments = TypeArguments::Handle(GetTypeArguments());
- type = Type::New(scope_cls, type_arguments, TokenPosition::kNoSource,
- Heap::kNew);
+ type =
+ Type::New(scope_cls, type_arguments, TokenPosition::kNoSource, space);
type.set_signature(signature);
type.SetIsFinalized();
type ^= type.Canonicalize();
@@ -15387,7 +15443,7 @@
if (cls.NumTypeArguments() > 0) {
type_arguments = GetTypeArguments();
}
- type = Type::New(cls, type_arguments, TokenPosition::kNoSource);
+ type = Type::New(cls, type_arguments, TokenPosition::kNoSource, space);
type.SetIsFinalized();
type ^= type.Canonicalize();
}
@@ -16890,6 +16946,7 @@
RawAbstractType* Type::CloneUninstantiated(const Class& new_owner,
TrailPtr trail) const {
ASSERT(IsFinalized());
+ ASSERT(IsCanonical());
ASSERT(!IsMalformed());
if (IsInstantiated()) {
return raw();
@@ -16961,6 +17018,7 @@
clone.set_arguments(type_args);
}
clone.SetIsFinalized();
+ clone ^= clone.Canonicalize();
return clone.raw();
}
@@ -17438,9 +17496,12 @@
const char* TypeRef::ToCString() const {
+ AbstractType& ref_type = AbstractType::Handle(type());
+ if (ref_type.IsNull()) {
+ return "TypeRef: null";
+ }
const char* type_cstr =
String::Handle(Class::Handle(type_class()).Name()).ToCString();
- AbstractType& ref_type = AbstractType::Handle(type());
if (ref_type.IsFinalized()) {
const intptr_t hash = ref_type.Hash();
return OS::SCreate(Thread::Current()->zone(),
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index dbf901e..837b833 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -525,8 +525,11 @@
static void InitOnce(Isolate* isolate);
static void FinalizeVMIsolate(Isolate* isolate);
- // Initialize a new isolate either from source or from a snapshot.
- static RawError* Init(Isolate* isolate);
+ // Initialize a new isolate either from a Kernel IR, from source, or from a
+ // snapshot.
+ static RawError* Init(Isolate* isolate,
+ const uint8_t* kernel,
+ intptr_t kernel_length);
static void MakeUnusedSpaceTraversable(const Object& obj,
intptr_t original_size,
@@ -1030,7 +1033,10 @@
}
// Asserts that the class of the super type has been resolved.
- RawClass* SuperClass() const;
+ // |original_classes| only has an effect when reloading. If true and we
+ // are reloading, it will prefer the original classes to the replacement
+ // classes.
+ RawClass* SuperClass(bool original_classes = false) const;
RawType* mixin() const { return raw_ptr()->mixin_; }
void set_mixin(const Type& value) const;
@@ -1119,7 +1125,10 @@
// Returns an array of all instance fields of this class and its superclasses
// indexed by offset in words.
- RawArray* OffsetToFieldMap() const;
+ // |original_classes| only has an effect when reloading. If true and we
+ // are reloading, it will prefer the original classes to the replacement
+ // classes.
+ RawArray* OffsetToFieldMap(bool original_classes = false) const;
// Returns true if non-static fields are defined.
bool HasInstanceFields() const;
@@ -1503,8 +1512,8 @@
// to a class after all classes have been loaded and finalized.
class UnresolvedClass : public Object {
public:
- RawLibraryPrefix* library_prefix() const {
- return raw_ptr()->library_prefix_;
+ RawObject* library_or_library_prefix() const {
+ return raw_ptr()->library_or_library_prefix_;
}
RawString* ident() const { return raw_ptr()->ident_; }
TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
@@ -1515,12 +1524,12 @@
return RoundedAllocationSize(sizeof(RawUnresolvedClass));
}
- static RawUnresolvedClass* New(const LibraryPrefix& library_prefix,
+ static RawUnresolvedClass* New(const Object& library_prefix,
const String& ident,
TokenPosition token_pos);
private:
- void set_library_prefix(const LibraryPrefix& library_prefix) const;
+ void set_library_or_library_prefix(const Object& library_prefix) const;
void set_ident(const String& ident) const;
void set_token_pos(TokenPosition token_pos) const;
@@ -2741,6 +2750,11 @@
return RoundedAllocationSize(sizeof(RawFunction));
}
+ static RawFunction* EvaluateHelper(const Class& cls,
+ const String& expr,
+ const Array& param_names,
+ bool is_static);
+
static RawFunction* New(const String& name,
RawFunction::Kind kind,
bool is_static,
@@ -3130,6 +3144,8 @@
TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
+ RawString* InitializingExpression() const;
+
bool has_initializer() const {
return HasInitializerBit::decode(raw_ptr()->kind_bits_);
}
@@ -3490,6 +3506,7 @@
RawLibrary* FindLibrary() const;
RawString* GetLine(intptr_t line_number,
Heap::Space space = Heap::kNew) const;
+ RawString* GetSnippet(TokenPosition from, TokenPosition to) const;
RawString* GetSnippet(intptr_t from_line,
intptr_t from_column,
intptr_t to_line,
@@ -3766,7 +3783,7 @@
static RawLibrary* GetLibrary(intptr_t index);
static void InitCoreLibrary(Isolate* isolate);
- static void InitNativeWrappersLibrary(Isolate* isolate);
+ static void InitNativeWrappersLibrary(Isolate* isolate, bool is_kernel_file);
static RawLibrary* AsyncLibrary();
static RawLibrary* ConvertLibrary();
@@ -5427,7 +5444,7 @@
StorePointer(FieldAddr(field), value.raw());
}
- RawAbstractType* GetType() const;
+ RawAbstractType* GetType(Heap::Space space) const;
virtual RawTypeArguments* GetTypeArguments() const;
virtual void SetTypeArguments(const TypeArguments& value) const;
@@ -8183,6 +8200,10 @@
}
intptr_t Length() const {
+ // The map may be uninitialized.
+ if (raw_ptr()->used_data_ == Object::null()) return 0;
+ if (raw_ptr()->deleted_keys_ == Object::null()) return 0;
+
intptr_t used = Smi::Value(raw_ptr()->used_data_);
intptr_t deleted = Smi::Value(raw_ptr()->deleted_keys_);
return (used >> 1) - deleted;
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 66bbaca..c80c80c 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -491,13 +491,14 @@
: ObjectPointerVisitor(isolate), stream_(stream), count_(0) {}
virtual void VisitPointers(RawObject** first, RawObject** last) {
for (RawObject** current = first; current <= last; ++current) {
- if (!(*current)->IsHeapObject() || (*current == Object::null())) {
- // Ignore smis and nulls for now.
+ RawObject* object = *current;
+ if (!object->IsHeapObject() || object->IsVMHeapObject()) {
+ // Ignore smis and objects in the VM isolate for now.
// TODO(koda): To track which field each pointer corresponds to,
// we'll need to encode which fields were omitted here.
continue;
}
- WritePtr(*current, stream_);
+ WritePtr(object, stream_);
++count_;
}
}
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index a1318b7..b41ff6c 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -204,18 +204,10 @@
// the ordering is always correct (i.e. enum indicies match slots in values
// array)
// 3) An existing enum value is removed.
-// We leave old enum values that have no mapping to the reloaded class
-// in the heap. This means that if a programmer does the following:
-// enum Foo { A, B }; var x = Foo.A;
-// *reload*
-// enum Foo { B };
-// *reload*
-// enum Foo { A, B }; expect(identical(x, Foo.A));
-// The program will fail because we were not able to pair Foo.A on the second
-// reload.
+// Each enum class has a canonical 'deleted' enum sentinel instance.
+// When an enum value is deleted, we 'become' all references to the 'deleted'
+// sentinel value. The index value is -1.
//
-// Deleted enum values still in the heap continue to function but their
-// index field will not be valid.
void Class::ReplaceEnum(const Class& old_enum) const {
// We only do this for finalized enum classes.
ASSERT(is_enum_class());
@@ -237,6 +229,10 @@
Instance& old_enum_values = Instance::Handle(zone);
// The E.values array.
Instance& enum_values = Instance::Handle(zone);
+ // The E._deleted_enum_sentinel instance.
+ Instance& old_deleted_enum_sentinel = Instance::Handle(zone);
+ // The E._deleted_enum_sentinel instance.
+ Instance& deleted_enum_sentinel = Instance::Handle(zone);
Array& enum_map_storage =
Array::Handle(zone, HashTables::New<UnorderedHashMap<EnumMapTraits> >(4));
ASSERT(!enum_map_storage.IsNull());
@@ -259,6 +255,11 @@
// Non-enum instance.
continue;
}
+ if (enum_ident.Equals(Symbols::_DeletedEnumSentinel())) {
+ old_deleted_enum_sentinel = field.StaticValue();
+ // Non-enum instance.
+ continue;
+ }
old_enum_value = field.StaticValue();
ASSERT(!old_enum_value.IsNull());
VTIR_Print("Element %s being added to mapping\n", enum_ident.ToCString());
@@ -288,6 +289,11 @@
// Non-enum instance.
continue;
}
+ if (enum_ident.Equals(Symbols::_DeletedEnumSentinel())) {
+ deleted_enum_sentinel = field.StaticValue();
+ // Non-enum instance.
+ continue;
+ }
enum_value = field.StaticValue();
ASSERT(!enum_value.IsNull());
old_enum_value ^= enum_map.GetOrNull(enum_ident);
@@ -313,17 +319,29 @@
ASSERT(!enum_values.IsNull());
reload_context->AddEnumBecomeMapping(old_enum_values, enum_values);
- if (enums_deleted && FLAG_trace_reload_verbose) {
+ // Map the old E._deleted_enum_sentinel to the new E._deleted_enum_sentinel.
+ ASSERT(!old_deleted_enum_sentinel.IsNull());
+ ASSERT(!deleted_enum_sentinel.IsNull());
+ reload_context->AddEnumBecomeMapping(old_deleted_enum_sentinel,
+ deleted_enum_sentinel);
+
+ if (enums_deleted) {
+ // Map all deleted enums to the deleted enum senintel value.
// TODO(johnmccutchan): Add this to the reload 'notices' list.
VTIR_Print(
- "The following enum values were deleted and are forever lost in "
- "the heap:\n");
+ "The following enum values were deleted from %s and will become the "
+ "deleted enum sentinel:\n",
+ old_enum.ToCString());
UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw());
UnorderedHashMap<EnumMapTraits>::Iterator it(&enum_map);
while (it.MoveNext()) {
const intptr_t entry = it.Current();
enum_ident = String::RawCast(enum_map.GetKey(entry));
ASSERT(!enum_ident.IsNull());
+ old_enum_value ^= enum_map.GetOrNull(enum_ident);
+ VTIR_Print("Element `%s` was deleted\n", enum_ident.ToCString());
+ reload_context->AddEnumBecomeMapping(old_enum_value,
+ deleted_enum_sentinel);
}
enum_map.Release();
}
@@ -577,7 +595,8 @@
bool Class::RequiresInstanceMorphing(const Class& replacement) const {
// Get the field maps for both classes. These field maps walk the class
// hierarchy.
- const Array& fields = Array::Handle(OffsetToFieldMap());
+ const Array& fields =
+ Array::Handle(OffsetToFieldMap(true /* original classes */));
const Array& replacement_fields =
Array::Handle(replacement.OffsetToFieldMap());
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 86264b9..4bad386 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -4854,6 +4854,7 @@
}
ExpectToken(Token::kRBRACE);
+ const Type& array_type = Type::Handle(Z, Type::ArrayType());
// Add static field 'const List values'.
Field& values_field = Field::ZoneHandle(Z);
values_field =
@@ -4861,10 +4862,19 @@
/* is_static = */ true,
/* is_final = */ true,
/* is_const = */ true,
- /* is_reflectable = */ true, cls,
- Type::Handle(Z, Type::ArrayType()), cls.token_pos());
+ /* is_reflectable = */ true, cls, array_type, cls.token_pos());
enum_members.AddField(values_field);
+ // Add static field 'const _deleted_enum_sentinel'.
+ Field& deleted_enum_sentinel = Field::ZoneHandle(Z);
+ deleted_enum_sentinel = Field::New(Symbols::_DeletedEnumSentinel(),
+ /* is_static = */ true,
+ /* is_final = */ true,
+ /* is_const = */ true,
+ /* is_reflectable = */ false, cls,
+ Object::dynamic_type(), cls.token_pos());
+ enum_members.AddField(deleted_enum_sentinel);
+
// Allocate the immutable array containing the enumeration values.
// The actual enum instance values will be patched in later.
const Array& values_array = Array::Handle(Z, Array::New(i, Heap::kOld));
@@ -11871,7 +11881,7 @@
const String& unresolved_class_name =
String::Handle(Z, unresolved_class.ident());
Class& resolved_type_class = Class::Handle(Z);
- if (unresolved_class.library_prefix() == LibraryPrefix::null()) {
+ if (unresolved_class.library_or_library_prefix() == Object::null()) {
// First check if the type is a function type parameter.
if (!innermost_function().IsNull()) {
// TODO(regis): Shortcut this lookup if no generic functions in scope.
@@ -11921,9 +11931,11 @@
}
} else {
// Resolve class name in the scope of the library prefix.
- const LibraryPrefix& lib_prefix =
- LibraryPrefix::Handle(Z, unresolved_class.library_prefix());
- resolved_type_class = lib_prefix.LookupClass(unresolved_class_name);
+ const Object& prefix =
+ Object::Handle(Z, unresolved_class.library_or_library_prefix());
+ ASSERT(prefix.IsLibraryPrefix());
+ resolved_type_class =
+ LibraryPrefix::Cast(prefix).LookupClass(unresolved_class_name);
}
// At this point, we can only have a parameterized_type.
const Type& parameterized_type = Type::Cast(*type);
@@ -13468,8 +13480,8 @@
// into throwing a type error.
const UnresolvedClass& cls =
UnresolvedClass::Handle(Z, redirect_type.unresolved_class());
- const LibraryPrefix& prefix =
- LibraryPrefix::Handle(Z, cls.library_prefix());
+ const LibraryPrefix& prefix = LibraryPrefix::Cast(
+ Object::Handle(Z, cls.library_or_library_prefix()));
if (!prefix.IsNull() && !prefix.is_loaded() &&
!FLAG_load_deferred_eagerly) {
// If the redirection type is unresolved because it refers to
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 71b64583..50900b4 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -706,10 +706,11 @@
RAW_HEAP_OBJECT_IMPLEMENTATION(UnresolvedClass);
RawObject** from() {
- return reinterpret_cast<RawObject**>(&ptr()->library_prefix_);
+ return reinterpret_cast<RawObject**>(&ptr()->library_or_library_prefix_);
}
- RawLibraryPrefix* library_prefix_; // Library prefix qualifier for the ident.
- RawString* ident_; // Name of the unresolved identifier.
+ RawObject* library_or_library_prefix_; // Library or library prefix qualifier
+ // for the ident.
+ RawString* ident_; // Name of the unresolved identifier.
RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->ident_); }
TokenPosition token_pos_;
};
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 1c05a5c..022199e 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -2454,11 +2454,6 @@
"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,
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index a728610..f15485b 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -55,6 +55,8 @@
V(Close, "close") \
V(Values, "values") \
V(_EnumNames, "_enum_names") \
+ V(_DeletedEnumSentinel, "_deleted_enum_sentinel") \
+ V(_DeletedEnumPrefix, "Deleted enum value from ") \
V(ExprTemp, ":expr_temp") \
V(FinallyRetVal, ":finally_ret_val") \
V(AnonymousClosure, "<anonymous closure>") \
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart b/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
index c181c6d..18da81d 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_helper.dart
@@ -751,6 +751,14 @@
static String thisScript = computeThisScript();
+ /// Returns the base path added to Uri.base to resolve `package:` Uris.
+ ///
+ /// This is used by `Isolate.resolvePackageUri` to load resources. The default
+ /// value is `packages/` but users can override this by using the
+ /// `defaultPackagesBase` hook.
+ static String get packagesBase =>
+ JS('String', r'self.defaultPackagesBase || "packages/"');
+
/// Associates an ID with a native worker object.
static final Expando<int> workerIds = new Expando<int>();
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
index ed72e6c..637943b 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
@@ -31,9 +31,12 @@
throw new UnsupportedError("Isolate.packageConfig");
}
+ static Uri _packageBase = Uri.base.resolve(IsolateNatives.packagesBase);
+
@patch
- static Future<Uri> resolvePackageUri(Uri packageUri) {
- throw new UnsupportedError("Isolate.resolvePackageUri");
+ static Future<Uri> resolvePackageUri(Uri packageUri) async {
+ if (packageUri.scheme != 'package') return packageUri;
+ return _packageBase.resolveUri(packageUri.replace(scheme: ''));
}
@patch
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 2043449..04ed9e6 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -42766,6 +42766,21 @@
convertDartClosureToJS(callback, 4));
}
+/// Checks whether the given [element] correctly extends from the native class
+/// with the given [baseClassName]. This method will throw if the base class
+/// doesn't match, except when the element extends from `template` and it's base
+/// class is `HTMLUnknownElement`. This exclusion is needed to support extension
+/// of template elements (used heavily in Polymer 1.0) on IE11 when using the
+/// webcomponents-lite.js polyfill.
+void _checkExtendsNativeClassOrTemplate(
+ Element element, String extendsTag, String baseClassName) {
+ if (!JS('bool', '(# instanceof window[#])', element, baseClassName) &&
+ !((extendsTag == 'template' &&
+ JS('bool', '(# instanceof window["HTMLUnknownElement"])', element)))) {
+ throw new UnsupportedError('extendsTag does not match base native class');
+ }
+}
+
void _registerCustomElement(context, document, String tag, Type type,
String extendsTagName) {
// Function follows the same pattern as the following JavaScript code for
@@ -42809,10 +42824,8 @@
'native class is not HtmlElement');
}
} else {
- if (!JS('bool', '(#.createElement(#) instanceof window[#])',
- document, extendsTagName, baseClassName)) {
- throw new UnsupportedError('extendsTag does not match base native class');
- }
+ var element = document.createElement(extendsTagName);
+ _checkExtendsNativeClassOrTemplate(element, extendsTagName, baseClassName);
}
var baseConstructor = JS('=Object', '#[#]', context, baseClassName);
@@ -42882,11 +42895,7 @@
_nativeType = HtmlElement;
} else {
var element = document.createElement(extendsTag);
- if (!JS('bool', '(# instanceof window[#])',
- element, baseClassName)) {
- throw new UnsupportedError(
- 'extendsTag does not match base native class');
- }
+ _checkExtendsNativeClassOrTemplate(element, extendsTag, baseClassName);
_nativeType = element.runtimeType;
}
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index 92d5699..8b83fc0 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -11,6 +11,7 @@
external static _localHostname();
external static _executable();
external static _resolvedExecutable();
+
/**
* Retrieve the entries of the process environment.
*
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 7edabe0..a5fdba2 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -2835,10 +2835,8 @@
LayoutTests/fast/canvas/canvas-toDataURL-crash_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/draw-custom-focus-ring_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/drawImage-with-valid-image_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/fillText-shadow_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/getPutImageDataPairTest_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/rgba-parsing_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/text-globalAlpha_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/WebGLContextEvent_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/context-destroyed-crash_t01: Pass, RuntimeError # Issue 26898
@@ -8058,7 +8056,6 @@
LayoutTests/fast/xsl/xslt-string-parameters_t01: RuntimeError # Please triage this failure
LayoutTests/fast/xsl/xslt-transform-to-fragment-crash_t01: RuntimeError # Please triage this failure
LibTest/async/Future/doWhile_A05_t01: Pass, RuntimeError # Sometimes passes on windows 8. Please triage this failure
-LibTest/async/Future/forEach_A04_t02: RuntimeError # Please triage this failure
LibTest/async/Stream/Stream.periodic_A01_t01: Pass, RuntimeError # Please triage this failure
LibTest/async/Stream/timeout_A01_t01: Pass, RuntimeError # Sometimes passes on windows 8. Please triage this failure
LibTest/async/Stream/timeout_A03_t01: Pass, RuntimeError # Sometimes passes on windows 8. Please triage this failure
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index e3a01cf..8b0d135 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -32,17 +32,13 @@
Language/Classes/Setters/name_t13: CompileTimeError
Language/Classes/Setters/name_t14: CompileTimeError
Language/Classes/Setters/name_t15: CompileTimeError
-Language/Classes/definition_t23: CompileTimeError
+Language/Classes/definition_t23: Crash
Language/Enums/declaration_equivalent_t01: RuntimeError
Language/Enums/syntax_t08: MissingCompileTimeError
Language/Enums/syntax_t09: MissingCompileTimeError
-Language/Expressions/Assignment/indexed_expression_super_t01: RuntimeError
-Language/Expressions/Assignment/indexed_expression_super_t02: RuntimeError
-Language/Expressions/Assignment/indexed_expression_super_t04: RuntimeError
-Language/Expressions/Assignment/super_assignment_failed_t01: RuntimeError
-Language/Expressions/Assignment/super_assignment_failed_t02: RuntimeError
-Language/Expressions/Assignment/super_assignment_t06: RuntimeError
-Language/Expressions/Assignment/super_assignment_value_t02: RuntimeError
+Language/Expressions/Await_Expressions/syntax_t01: RuntimeError
+Language/Expressions/Await_Expressions/syntax_t02: RuntimeError
+Language/Expressions/Await_Expressions/syntax_t10: RuntimeError
Language/Expressions/Constants/exception_t01: MissingCompileTimeError
Language/Expressions/Constants/exception_t02: MissingCompileTimeError
Language/Expressions/Constants/string_length_t01: Crash
@@ -53,6 +49,15 @@
Language/Expressions/Function_Invocation/Unqualified_Invocation/instance_context_invocation_t03: MissingCompileTimeError
Language/Expressions/Function_Invocation/Unqualified_Invocation/instance_context_invocation_t04: MissingCompileTimeError
Language/Expressions/Function_Invocation/Unqualified_Invocation/static_method_invocation_t02: RuntimeError
+Language/Expressions/Function_Invocation/async_cleanup_t01: RuntimeError
+Language/Expressions/Function_Invocation/async_cleanup_t02: RuntimeError
+Language/Expressions/Function_Invocation/async_cleanup_t04: Crash
+Language/Expressions/Function_Invocation/async_cleanup_t07: Fail
+Language/Expressions/Function_Invocation/async_cleanup_t08: Fail
+Language/Expressions/Function_Invocation/async_generator_invokation_t05: RuntimeError
+Language/Expressions/Function_Invocation/async_generator_invokation_t06: RuntimeError
+Language/Expressions/Function_Invocation/async_generator_invokation_t09: RuntimeError
+Language/Expressions/Function_Invocation/async_invokation_t05: RuntimeError
Language/Expressions/Identifier_Reference/built_in_identifier_t35: Pass
Language/Expressions/Identifier_Reference/built_in_identifier_t36: Pass
Language/Expressions/Identifier_Reference/built_in_identifier_t37: Pass
@@ -84,11 +89,6 @@
Language/Expressions/Method_Invocation/Ordinary_Invocation/method_lookup_failed_t18: RuntimeError
Language/Expressions/Method_Invocation/Ordinary_Invocation/syntax_t05: MissingCompileTimeError
Language/Expressions/Method_Invocation/Ordinary_Invocation/syntax_t10: MissingCompileTimeError
-Language/Expressions/Method_Invocation/Super_Invocation/evaluation_t05: Crash
-Language/Expressions/Method_Invocation/Super_Invocation/getter_lookup_failed_t01: RuntimeError
-Language/Expressions/Method_Invocation/Super_Invocation/getter_lookup_failed_t02: RuntimeError
-Language/Expressions/Method_Invocation/Super_Invocation/getter_lookup_failed_t03: RuntimeError
-Language/Expressions/Method_Invocation/Super_Invocation/getter_lookup_failed_t04: RuntimeError
Language/Expressions/Method_Invocation/Super_Invocation/syntax_t05: MissingCompileTimeError
Language/Expressions/Object_Identity/string_t01: RuntimeError
Language/Expressions/Property_Extraction/Anonymous_Constructor_Closurization/identical_t01: CompileTimeError
@@ -225,9 +225,6 @@
Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t06: CompileTimeError
Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t07: CompileTimeError
Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/setter_closurization_t08: CompileTimeError
-Language/Expressions/Property_Extraction/Super_Getter_Access_and_Method_Closurization/no_such_method_t01: RuntimeError
-Language/Expressions/Property_Extraction/Super_Getter_Access_and_Method_Closurization/no_such_method_t02: RuntimeError
-Language/Expressions/Spawning_an_Isolate/new_isolate_t01: Crash
Language/Expressions/Strings/adjacent_strings_t02: RuntimeError
Language/Expressions/Type_Test/evaluation_t10: RuntimeError
Language/Functions/External_Functions/not_connected_to_a_body_t01: RuntimeError
@@ -242,15 +239,14 @@
Language/Libraries_and_Scripts/Exports/syntax_t05: MissingCompileTimeError
Language/Libraries_and_Scripts/Exports/syntax_t06: MissingCompileTimeError
Language/Libraries_and_Scripts/Imports/deferred_import_t01: RuntimeError
-Language/Libraries_and_Scripts/Imports/deferred_import_t02: RuntimeError
+Language/Libraries_and_Scripts/Imports/deferred_import_t02: CompileTimeError
+Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t01/01: MissingRuntimeError
Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t02: CompileTimeError
Language/Libraries_and_Scripts/Imports/invalid_uri_t02: Pass
Language/Libraries_and_Scripts/Imports/static_type_t01: RuntimeError
-Language/Libraries_and_Scripts/Parts/compilation_t02: Crash
Language/Libraries_and_Scripts/Parts/syntax_t06: Pass
Language/Libraries_and_Scripts/Scripts/top_level_main_t01: Crash
Language/Libraries_and_Scripts/Scripts/top_level_main_t02: Crash
-Language/Libraries_and_Scripts/Scripts/top_level_main_t05: Crash
Language/Libraries_and_Scripts/definition_syntax_t01: MissingCompileTimeError
Language/Libraries_and_Scripts/definition_syntax_t03: MissingCompileTimeError
Language/Libraries_and_Scripts/definition_syntax_t04: MissingCompileTimeError
@@ -300,26 +296,38 @@
Language/Statements/Rethrow/execution_t04: RuntimeError
Language/Statements/Switch/syntax_t02: Pass
Language/Statements/Try/catch_scope_t01: RuntimeError
+Language/Statements/Yield_and_Yield_Each/Yield/execution_async_t04: Fail
+Language/Statements/Yield_and_Yield_Each/Yield/execution_async_t05: Fail
+Language/Statements/Yield_and_Yield_Each/Yield/execution_async_t06: Fail
+Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_t01: RuntimeError
Language/Types/Interface_Types/subtype_t44: RuntimeError
Language/Types/Static_Types/deferred_type_t01: RuntimeError
Language/Variables/final_or_static_initialization_t01: MissingCompileTimeError
Language/Variables/final_or_static_initialization_t02: MissingCompileTimeError
Language/Variables/final_or_static_initialization_t03: MissingCompileTimeError
+Language/Variables/final_t01/01: MissingRuntimeError
+Language/Variables/final_t02/01: MissingRuntimeError
Language/Variables/final_t04: MissingCompileTimeError
Language/Variables/final_t05: MissingCompileTimeError
Language/Variables/final_t06: MissingCompileTimeError
Language/Variables/final_t07: MissingCompileTimeError
-LibTest/core/Invocation/isAccessor_A01_t01: RuntimeError
-LibTest/core/Invocation/isAccessor_A01_t02: RuntimeError
-LibTest/core/Invocation/isGetter_A01_t01: RuntimeError
-LibTest/core/Invocation/isGetter_A01_t02: RuntimeError
-LibTest/core/Invocation/isMethod_A01_t01: RuntimeError
-LibTest/core/Invocation/isMethod_A01_t02: RuntimeError
-LibTest/core/Invocation/isSetter_A01_t01: RuntimeError
-LibTest/core/Invocation/isSetter_A01_t02: RuntimeError
-LibTest/core/Invocation/memberName_A01_t01: RuntimeError
-LibTest/core/Invocation/namedArguments_A01_t01: RuntimeError
-LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError
+
+# These tests should throw RuntimeError but they Pass instead.
+Language/Libraries_and_Scripts/Imports/static_type_t01/04: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/06: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/01: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/05: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/03: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/07: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/02: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/04: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/06: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/01: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/05: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/03: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/07: Pass
+Language/Libraries_and_Scripts/Imports/static_type_t01/02: Pass
+
# dartk: precompilation failures
[ $compiler == dartkp && $runtime == dart_precompiled ]
@@ -623,4 +631,4 @@
LibTest/core/Invocation/isSetter_A01_t02: Crash
LibTest/core/Invocation/memberName_A01_t01: RuntimeError
LibTest/core/Invocation/namedArguments_A01_t01: Crash
-LibTest/core/Invocation/positionalArguments_A01_t01: Crash
+LibTest/core/Invocation/positionalArguments_A01_t01: Crash
\ No newline at end of file
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 24d95eb..ac487d8a 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -220,9 +220,12 @@
LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Timeout
LibTest/collection/ListMixin/ListMixin_class_A01_t01: Pass, Timeout
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Pass, Timeout
+LibTest/core/List/List_class_A01_t01: Pass, Timeout
LibTest/core/List/List_class_A01_t02: Pass, Timeout
LibTest/core/Map/Map_class_A01_t04: Pass, Timeout
LibTest/core/Uri/Uri_A06_t03: Pass, Timeout
LibTest/core/Uri/encodeQueryComponent_A01_t02: Pass, Timeout
LibTest/isolate/Isolate/spawn_A01_t04: Pass, Timeout
+LibTest/isolate/Isolate/spawnUri_A01_t06: Pass, Fail # Timing dependent
+LibTest/isolate/Isolate/spawnUri_A01_t07: Pass, Fail # Timing dependent
LibTest/isolate/ReceivePort/take_A01_t02: Crash, Fail # Issue 27773
diff --git a/tests/compiler/dart2js/kernel/assert_test.dart b/tests/compiler/dart2js/kernel/assert_test.dart
index 1495ff4..48c8997 100644
--- a/tests/compiler/dart2js/kernel/assert_test.dart
+++ b/tests/compiler/dart2js/kernel/assert_test.dart
@@ -24,9 +24,6 @@
assert(foo(), "foo failed");
}''';
return check(code,
- // disable type inference because kernel doesn't yet support
- // checked mode type checks
- disableTypeInference: false,
extraOptions: const <String>[
Flags.enableCheckedMode,
Flags.enableAssertMessage,
diff --git a/tests/compiler/dart2js/kernel/constructors_test.dart b/tests/compiler/dart2js/kernel/constructors_test.dart
new file mode 100644
index 0000000..1d30c1c
--- /dev/null
+++ b/tests/compiler/dart2js/kernel/constructors_test.dart
@@ -0,0 +1,41 @@
+// 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:compiler/src/compiler.dart' show Compiler;
+import 'package:compiler/src/elements/elements.dart';
+import 'package:test/test.dart';
+
+import 'helper.dart' show check;
+
+main() {
+ test('simple default constructor', () {
+ String code = '''
+class A {
+}
+
+main() {
+ var a = new A();
+ return a;
+}''';
+ return check(code, lookup: defaultConstructorFor('A'));
+ });
+
+ test('simple default constructor with field', () {
+ String code = '''
+class A {
+ int x = 1;
+}
+
+main() {
+ var a = new A();
+ return a;
+}''';
+ return check(code, lookup: defaultConstructorFor('A'));
+ });
+}
+
+defaultConstructorFor(String className) => (Compiler compiler) {
+ ClassElement clazz = compiler.mainApp.find(className);
+ return clazz.lookupDefaultConstructor();
+ };
diff --git a/tests/compiler/dart2js/kernel/helper.dart b/tests/compiler/dart2js/kernel/helper.dart
index d7d4b11..cbb1638b 100644
--- a/tests/compiler/dart2js/kernel/helper.dart
+++ b/tests/compiler/dart2js/kernel/helper.dart
@@ -14,7 +14,7 @@
import '../memory_compiler.dart';
Future<String> compile(String code,
- {String entry: 'main',
+ {dynamic lookup: 'main',
bool useKernel: true,
bool disableTypeInference: true,
List<String> extraOptions: const <String>[]}) async {
@@ -25,29 +25,41 @@
if (useKernel) options.add(Flags.useKernel);
options.addAll(extraOptions);
- if (entry != 'main' && !code.contains('main')) {
- code = "$code\n\nmain() => $entry;";
+ if (lookup is String && lookup != 'main' && !code.contains('main')) {
+ code = "$code\n\nmain() => $lookup;";
}
CompilationResult result = await runCompiler(
memorySourceFiles: {'main.dart': code}, options: options);
expect(result.isSuccess, isTrue);
Compiler compiler = result.compiler;
- Element element = compiler.mainApp.find(entry);
+ Element element;
+ if (lookup is String) {
+ element = compiler.mainApp.find(lookup);
+ } else {
+ element = lookup(compiler);
+ }
js.JavaScriptBackend backend = compiler.backend;
return backend.getGeneratedCode(element);
}
+/// Checks that the given Dart [code] compiles to the same JS in kernel and
+/// normal mode.
+///
+/// The function to check at the end is given by [lookup]. If [lookup] is a
+/// String, then the generated code for a top-level element named [lookup] is
+/// checked. Otherwise, [lookup] is a function that takes a [Compiler] and
+/// returns an [Element], and the returned [Element] is checked.
Future check(String code,
- {String entry: 'main',
+ {dynamic lookup: 'main',
bool disableTypeInference: true,
List<String> extraOptions: const <String>[]}) async {
var original = await compile(code,
- entry: entry,
+ lookup: lookup,
useKernel: false,
disableTypeInference: disableTypeInference,
extraOptions: extraOptions);
var kernel = await compile(code,
- entry: entry,
+ lookup: lookup,
useKernel: true,
disableTypeInference: disableTypeInference,
extraOptions: extraOptions);
diff --git a/tests/compiler/dart2js/kernel/simple_function_test.dart b/tests/compiler/dart2js/kernel/simple_function_test.dart
index 6539134..d58ca33 100644
--- a/tests/compiler/dart2js/kernel/simple_function_test.dart
+++ b/tests/compiler/dart2js/kernel/simple_function_test.dart
@@ -42,6 +42,6 @@
main() {
foo(1);
}''';
- return check(code, entry: 'foo');
+ return check(code, lookup: 'foo');
});
}
diff --git a/tests/compiler/dart2js_extra/inference_super_set_call_test.dart b/tests/compiler/dart2js_extra/inference_super_set_call_test.dart
new file mode 100644
index 0000000..5a56023
--- /dev/null
+++ b/tests/compiler/dart2js_extra/inference_super_set_call_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2013, 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.
+
+// Regression test for dart2js: we incorrectly modeled `super.x = rhs` as a
+// call and not an assignment, so the type of the expression was incorrectly
+// assumed to be the return type of the setter rather than the type of the rhs.
+import 'package:expect/expect.dart';
+
+abstract class A {
+ set x(v) {}
+ set z(v) {}
+ set y(v) { return 'hi';}
+}
+
+class S extends A {
+ var _x; // was bad: inferred as null, than [null | int]
+ var _y = ''; // was bad: inferred as String, rather than [String | int]
+ var _z; // was ok : inferred as [null | int]
+
+ set x(v) {
+ _x = super.x = v;
+ }
+
+ set z(v) {
+ super.z = v;
+ _z = v;
+ }
+
+ set y(v) {
+ _y = super.y = v;
+ }
+
+ get isXNull => _x == null;
+ get isZNull => _z == null;
+}
+
+main() {
+ var s = new S()
+ ..x = 2
+ ..y = 2
+ ..z = 2;
+ Expect.equals(false, s.isXNull); // was incorrectly optimized to 'true'
+ Expect.equals(false, s._y is String); // was incorrectly optimized to 'true'
+ Expect.equals(false, s.isZNull); // prints false
+}
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 24a5cd6..1436f88 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -207,3 +207,7 @@
[ $arch == simdbc || $arch == simdbc64 ]
regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
+
+[ $hot_reload || $hot_reload_rollback ]
+big_integer_parsed_mul_div_vm_test: Pass, Slow # Slow.
+
diff --git a/tests/html/custom/document_register_template_test.dart b/tests/html/custom/document_register_template_test.dart
new file mode 100644
index 0000000..11b0b8d
--- /dev/null
+++ b/tests/html/custom/document_register_template_test.dart
@@ -0,0 +1,24 @@
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'dart:html';
+import '../utils.dart';
+
+main() {
+ useHtmlConfiguration();
+
+ setUp(() => customElementsReady);
+
+ test('can register custom template with webcomponents-lite polyfill', () {
+ document.registerElement('my-element', MyElement, extendsTag: 'template');
+ var e = new Element.tag('template', 'my-element');
+ document.body.append(e);
+ expect(e is TemplateElement, isTrue);
+ expect(e.method(), 'value');
+ });
+}
+
+
+class MyElement extends TemplateElement {
+ MyElement.created() : super.created();
+ method() => 'value';
+}
diff --git a/tests/html/custom/document_register_template_test.html b/tests/html/custom/document_register_template_test.html
new file mode 100644
index 0000000..26f59bf
--- /dev/null
+++ b/tests/html/custom/document_register_template_test.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <title> document_register_basic_test </title>
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents-lite.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <h1> Running document_register_basic_test </h1>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/tests/isolate/browser/package_resolve_browser_hook2_test.dart b/tests/isolate/browser/package_resolve_browser_hook2_test.dart
new file mode 100644
index 0000000..7768338
--- /dev/null
+++ b/tests/isolate/browser/package_resolve_browser_hook2_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:js';
+import 'dart:isolate';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+main() async {
+ useHtmlConfiguration();
+
+ setUp(() {
+ context['defaultPackagesBase'] = 'path1/';
+ });
+
+ test('hook overrides package-uri resolution', () async {
+ var uri = await Isolate.resolvePackageUri(Uri.parse('package:foo/bar.txt'));
+ expect(uri, Uri.base.resolve('path1/foo/bar.txt'));
+ });
+
+ test('hook is read once, on the first use of resolvePackageUri', () async {
+ await Isolate.resolvePackageUri(Uri.parse('package:foo/bar.txt'));
+ context['defaultPackagesBase'] = 'path2/';
+ var uri = await Isolate.resolvePackageUri(Uri.parse('package:foo/bar.txt'));
+ expect(uri, Uri.base.resolve('path1/foo/bar.txt'));
+ });
+}
diff --git a/tests/isolate/browser/package_resolve_browser_hook_test.dart b/tests/isolate/browser/package_resolve_browser_hook_test.dart
new file mode 100644
index 0000000..5c90474
--- /dev/null
+++ b/tests/isolate/browser/package_resolve_browser_hook_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:isolate';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+main() async {
+ useHtmlConfiguration();
+
+ test('defaultPackagesBase hook overrides package-uri resolution', () async {
+ var uri = await Isolate.resolvePackageUri(Uri.parse('package:foo/bar.txt'));
+ expect(uri, Uri.base.resolve('path/set/from/hook/foo/bar.txt'));
+ });
+}
diff --git a/tests/isolate/browser/package_resolve_browser_hook_test.html b/tests/isolate/browser/package_resolve_browser_hook_test.html
new file mode 100644
index 0000000..a3b67b6
--- /dev/null
+++ b/tests/isolate/browser/package_resolve_browser_hook_test.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <title> mirrors_test </title>
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+</head>
+<body>
+ <h1> Running mirrors_test </h1>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ <script>
+ // Dart2js exposes this hook to override the default base path where resource
+ // package uris are resolved from.
+ defaultPackagesBase = 'path/set/from/hook/';
+ </script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/tests/isolate/browser/package_resolve_browser_test.dart b/tests/isolate/browser/package_resolve_browser_test.dart
new file mode 100644
index 0000000..49ced93
--- /dev/null
+++ b/tests/isolate/browser/package_resolve_browser_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:isolate';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+main() {
+ useHtmlConfiguration();
+
+ test('by default package-uri resolve under base/packages/', () async {
+ var uri = await Isolate.resolvePackageUri(Uri.parse('package:foo/bar.txt'));
+ expect(uri, Uri.base.resolve('packages/foo/bar.txt'));
+ });
+}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index ffba137..1c39f36 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -152,7 +152,7 @@
simple_message_test/none: RuntimeError, OK # Uses Isolate.spawn.
start_paused_test: RuntimeError, OK # Uses Isolate.spawn.
message3_test/int32x4: RuntimeError, OK # Uses Isolate.spawn.
-
+browser/package_*: Skip # Issue 25594 (missing implementation in Dartium).
[ $compiler == dart2analyzer ]
browser/typed_data_message_test: StaticWarning
diff --git a/tests/isolate/spawn_uri_child_isolate.dart b/tests/isolate/spawn_uri_child_isolate.dart
index 57f1dde..81f40f9 100644
--- a/tests/isolate/spawn_uri_child_isolate.dart
+++ b/tests/isolate/spawn_uri_child_isolate.dart
@@ -4,9 +4,8 @@
// Child isolate code to be spawned from a URI to this file.
library SpawnUriChildIsolate;
-import 'dart:isolate';
-void main(List<String> args, SendPort replyTo) {
+void main(List<String> args, replyTo) {
var data = args[0];
replyTo.send('re: $data');
}
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 1da0824..5891891 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -270,7 +270,7 @@
[ $compiler == dart2js && ($runtime == chrome || $runtime == ff) && $system == windows ]
string_literals_test: RuntimeError # Issue 27533
-[ $compiler == dart2js && ($runtime == safari || $runtime == safarimobilesim)]
+[ $compiler == dart2js && $runtime == safarimobilesim ]
# Safari codegen bug, fixed on some versions of Safari 7.1 (Version 7.1 (9537.85.10.17.1))
call_through_getter_test: Fail, OK
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index 3571c0c..1346de2 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -17,14 +17,16 @@
accessor_conflict_import_prefixed_test: RuntimeError
accessor_conflict_import_test: RuntimeError
assertion_test: RuntimeError
+async_await_test: Crash
async_break_in_finally_test: RuntimeError
async_control_structures_test: RuntimeError
async_star_cancel_and_throw_in_finally_test: RuntimeError
async_star_cancel_while_paused_test: RuntimeError
-async_star_regression_fisk_test: Crash
+async_star_pause_test: RuntimeError
+async_star_regression_fisk_test: RuntimeError
async_star_stream_take_test: Timeout
async_star_take_reyield_test: Timeout
-async_star_test: Crash
+async_star_test: Timeout
async_throw_in_catch_test/forceAwait: RuntimeError
async_throw_in_catch_test/none: RuntimeError
asyncstar_throw_in_catch_test: Timeout
@@ -46,6 +48,8 @@
compile_time_constant_k_test/03: RuntimeError
compile_time_constant_o_test/01: RuntimeError
compile_time_constant_o_test/02: RuntimeError
+conditional_import_string_test: CompileTimeError
+conditional_import_test: CompileTimeError
config_import_test: RuntimeError
conflicting_type_variable_and_setter_test: CompileTimeError
const_dynamic_type_literal_test/02: RuntimeError
@@ -64,12 +68,13 @@
constructor_duplicate_final_test/02: MissingRuntimeError
constructor_duplicate_final_test/03: MissingCompileTimeError
constructor_named_arguments_test/01: Crash
-cyclic_type2_test: CompileTimeError
+custom_await_stack_trace_test: RuntimeError
+cyclic_type2_test: Crash
cyclic_type_test/00: RuntimeError
cyclic_type_test/01: RuntimeError
-cyclic_type_test/02: CompileTimeError
+cyclic_type_test/02: Crash
cyclic_type_test/03: RuntimeError
-cyclic_type_test/04: CompileTimeError
+cyclic_type_test/04: Crash
cyclic_type_variable_test/01: Crash
cyclic_type_variable_test/02: Crash
cyclic_type_variable_test/03: Crash
@@ -149,7 +154,6 @@
f_bounded_equality_test: RuntimeError
field_initialization_order_test: RuntimeError
final_field_initialization_order_test: RuntimeError
-final_super_field_set_test/01: RuntimeError
final_syntax_test/01: MissingCompileTimeError
final_syntax_test/02: MissingCompileTimeError
final_syntax_test/03: MissingCompileTimeError
@@ -165,7 +169,6 @@
fixed_type_variable_test/06: RuntimeError
for2_test: RuntimeError
for_variable_capture_test: RuntimeError
-forwarding_factory_constructor_default_values_test: RuntimeError
function_subtype2_test: RuntimeError
function_subtype_bound_closure3_test: RuntimeError
function_subtype_bound_closure4_test: RuntimeError
@@ -187,6 +190,7 @@
generic_inheritance_test: RuntimeError
generic_local_functions_test: CompileTimeError
generic_methods_function_type_test: CompileTimeError
+generic_methods_generic_function_parameter_test: CompileTimeError
generic_methods_new_test: CompileTimeError
generic_methods_test: CompileTimeError
generic_methods_type_expression_test: CompileTimeError
@@ -198,26 +202,25 @@
initializing_formal_access_test: CompileTimeError
initializing_formal_capture_test: CompileTimeError
initializing_formal_final_test: CompileTimeError
+initializing_formal_promotion_test: CompileTimeError
initializing_formal_type_test: CompileTimeError
instance_creation_in_function_annotation_test: RuntimeError
-invocation_mirror_test: RuntimeError
is_not_class2_test: RuntimeError
issue13474_test: RuntimeError
-issue23244_test: Crash
issue_1751477_test: RuntimeError
-least_upper_bound_expansive_test/01: CompileTimeError
-least_upper_bound_expansive_test/02: CompileTimeError
-least_upper_bound_expansive_test/03: CompileTimeError
-least_upper_bound_expansive_test/04: CompileTimeError
-least_upper_bound_expansive_test/05: CompileTimeError
-least_upper_bound_expansive_test/06: CompileTimeError
-least_upper_bound_expansive_test/07: CompileTimeError
-least_upper_bound_expansive_test/08: CompileTimeError
-least_upper_bound_expansive_test/09: CompileTimeError
-least_upper_bound_expansive_test/10: CompileTimeError
-least_upper_bound_expansive_test/11: CompileTimeError
-least_upper_bound_expansive_test/12: CompileTimeError
-least_upper_bound_expansive_test/none: CompileTimeError
+least_upper_bound_expansive_test/01: Crash
+least_upper_bound_expansive_test/02: Crash
+least_upper_bound_expansive_test/03: Crash
+least_upper_bound_expansive_test/04: Crash
+least_upper_bound_expansive_test/05: Crash
+least_upper_bound_expansive_test/06: Crash
+least_upper_bound_expansive_test/07: Crash
+least_upper_bound_expansive_test/08: Crash
+least_upper_bound_expansive_test/09: Crash
+least_upper_bound_expansive_test/10: Crash
+least_upper_bound_expansive_test/11: Crash
+least_upper_bound_expansive_test/12: Crash
+least_upper_bound_expansive_test/none: Crash
library_env_test/has_html_support: RuntimeError
library_env_test/has_no_io_support: RuntimeError
library_env_test/has_no_mirror_support: RuntimeError
@@ -295,23 +298,22 @@
named_parameters_type_test/03: MissingRuntimeError
no_main_test/01: Crash
not_enough_positional_arguments_test/01: CompileTimeError
-not_enough_positional_arguments_test/02: Crash
-not_enough_positional_arguments_test/05: Crash
+not_enough_positional_arguments_test/02: MissingRuntimeError
+not_enough_positional_arguments_test/05: MissingRuntimeError
null_test/none: RuntimeError
number_identifier_test/05: RuntimeError
positional_parameters_type_test/01: MissingRuntimeError
positional_parameters_type_test/02: MissingRuntimeError
prefix10_negative_test: Fail
-prefix16_test: RuntimeError
prefix21_test: RuntimeError
redirecting_constructor_initializer_test: RuntimeError
-redirecting_factory_default_values_test/none: RuntimeError
redirecting_factory_reflection_test: RuntimeError
regress_18713_test: RuntimeError
regress_22443_test: RuntimeError
regress_22700_test: RuntimeError
regress_23408_test: RuntimeError
regress_27164_test: CompileTimeError
+regress_27617_test/1: MissingCompileTimeError
regress_r24720_test: RuntimeError
reify_typevar_static_test/00: MissingCompileTimeError
reify_typevar_test: RuntimeError
@@ -320,26 +322,12 @@
setter_no_getter_call_test/none: RuntimeError
static_setter_get_test/01: RuntimeError
super_call3_test/01: Crash
-super_call4_test: RuntimeError
-super_getter_setter_test: RuntimeError
-super_no_such_method1_test/01: RuntimeError
-super_no_such_method2_test/01: RuntimeError
-super_no_such_method3_test/01: RuntimeError
-super_no_such_method4_test/01: RuntimeError
-super_no_such_method5_test/01: RuntimeError
-super_operator_index3_test: RuntimeError
-super_operator_index4_test: RuntimeError
-super_operator_index5_test: RuntimeError
-super_operator_index6_test: RuntimeError
-super_operator_index7_test: RuntimeError
-super_operator_index8_test: RuntimeError
super_test: RuntimeError
switch7_negative_test: Fail
switch_try_catch_test: RuntimeError
sync_generator3_test/test2: RuntimeError
tearoff_basic_test: CompileTimeError
tearoff_constructor_basic_test: CompileTimeError
-throw8_test: RuntimeError
try_catch_on_syntax_test/10: MissingRuntimeError
try_catch_on_syntax_test/11: MissingRuntimeError
try_finally_regress_25654_test: RuntimeError
@@ -482,8 +470,6 @@
enum_test: RuntimeError
evaluation_redirecting_constructor_test: RuntimeError
example_constructor_test: RuntimeError
-execute_finally8_test: RuntimeError
-execute_finally9_test: RuntimeError
export_double_same_main_test: Crash
export_main_test: Crash
external_test/10: MissingRuntimeError
@@ -711,4 +697,4 @@
vm/debug_break_enabled_vm_test/none: CompileTimeError
vm/reflect_core_vm_test: CompileTimeError
vm/type_cast_vm_test: RuntimeError
-vm/type_vm_test: RuntimeError
+vm/type_vm_test: RuntimeError
\ No newline at end of file
diff --git a/tests/language/vm/optimized_unique_selector_test.dart b/tests/language/vm/optimized_unique_selector_test.dart
new file mode 100644
index 0000000..bf0b5e4d
--- /dev/null
+++ b/tests/language/vm/optimized_unique_selector_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2013, 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";
+
+class A {
+ _uniqueSelector() { }
+ final uniqueField = 10;
+}
+
+test1(obj) {
+ var res = 0;
+ for (var i = 0; i < 2; i++) {
+ obj._uniqueSelector();
+ res += obj.uniqueField; // This load must not be hoisted out of the loop.
+ }
+ return res;
+}
+
+test2(obj) {
+ final objAlias = obj;
+ closure() => objAlias;
+ var res = 0;
+ for (var i = 0; i < 2; i++) {
+ obj._uniqueSelector();
+ res += objAlias.uniqueField; // This load must not be hoisted out of the loop.
+ }
+ return res;
+}
+
+var foofoo_ = test1;
+
+main () {
+ Expect.equals(20, foofoo_(new A()));
+ Expect.throws(() => foofoo_(0));
+
+ foofoo_ = test2;
+
+ Expect.equals(20, foofoo_(new A()));
+ Expect.throws(() => foofoo_(0));
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 8f43474..9bcdd8e 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -417,3 +417,4 @@
mirrors/generic_bounded_test/02: Fail # Type equality - Issue 26869
mirrors/typedef_reflected_type_test/01: Fail # Type equality - Issue 26869
mirrors/generic_bounded_by_type_parameter_test/02: Fail # Type equality - Issue 26869
+async/timer_regress22626_test: Pass, RuntimeError # Timing dependent.
diff --git a/tests/standalone/io/file_blocking_lock_script.dart b/tests/standalone/io/file_blocking_lock_script.dart
index 5c955c4..9ba2feb 100644
--- a/tests/standalone/io/file_blocking_lock_script.dart
+++ b/tests/standalone/io/file_blocking_lock_script.dart
@@ -11,32 +11,15 @@
var raf = await file.open(mode: APPEND);
await raf.setPosition(0);
int nextToWrite = 1;
- while (nextToWrite <= len) {
- await raf.lock(FileLock.BLOCKING_EXCLUSIVE, 0, len);
-
- int at;
- int p;
- while (true) {
- p = await raf.position();
- at = await raf.readByte();
- if (at == 0 || at == -1) break;
- nextToWrite++;
- }
- await raf.setPosition(p);
- await raf.writeByte(nextToWrite);
- await raf.flush();
- nextToWrite++;
- await raf.unlock(0, len);
- }
-
await raf.lock(FileLock.BLOCKING_EXCLUSIVE, 0, len);
- await raf.setPosition(0);
- for (int i = 1; i <= len; i++) {
- if ((await raf.readByte()) != i) {
- await raf.unlock(0, len);
- await raf.close();
- return 1;
- }
+
+ // Make sure the peer fails a non-blocking lock at some point.
+ await new Future.delayed(const Duration(seconds: 1));
+
+ int p = 0;
+ while (p < len) {
+ await raf.writeByte(1);
+ p++;
}
await raf.unlock(0, len);
await raf.close();
diff --git a/tests/standalone/io/file_blocking_lock_test.dart b/tests/standalone/io/file_blocking_lock_test.dart
index aa44bd1..9f665b6 100644
--- a/tests/standalone/io/file_blocking_lock_test.dart
+++ b/tests/standalone/io/file_blocking_lock_test.dart
@@ -39,69 +39,55 @@
});
}
+const int peerTimeoutMilliseconds = 10000;
+
+Future<bool> waitForPeer(RandomAccessFile raf, int length) async {
+ Stopwatch s = new Stopwatch();
+ s.start();
+ while (true) {
+ await raf.unlock(0, length);
+ if (s.elapsedMilliseconds > peerTimeoutMilliseconds) {
+ s.stop();
+ return false;
+ }
+ try {
+ await raf.lock(FileLock.EXCLUSIVE, 0, length);
+ } on dynamic {
+ await raf.lock(FileLock.BLOCKING_EXCLUSIVE, 0, length);
+ break;
+ }
+ }
+ s.stop();
+ return true;
+}
+
testLockWholeFile() async {
const int length = 25;
Directory directory = await Directory.systemTemp.createTemp('dart_file_lock');
File file = new File(join(directory.path, "file"));
await file.writeAsBytes(new List.filled(length, 0));
var raf = await file.open(mode: APPEND);
- await raf.setPosition(0);
await raf.lock(FileLock.BLOCKING_EXCLUSIVE, 0, length);
Process peer = await runPeer(file.path, length, FileLock.BLOCKING_EXCLUSIVE);
- int nextToWrite = 1;
- int at = 0;
- List iWrote = new List.filled(length, 0);
- bool nonBlockingFailed = false;
- while (nextToWrite <= length) {
- int p = await raf.position();
- await raf.writeByte(nextToWrite);
- await raf.flush();
- // Record which bytes this process wrote so that we can check that the
- // other process was able to take the lock and write some bytes.
- iWrote[nextToWrite-1] = nextToWrite;
- nextToWrite++;
- // Let the other process get the lock at least once by spinning until the
- // non-blocking lock fails.
- while (!nonBlockingFailed) {
- await raf.unlock(0, length);
- try {
- await raf.lock(FileLock.EXCLUSIVE, 0, length);
- } catch(e) {
- // Check that at some point the non-blocking lock fails.
- nonBlockingFailed = true;
- await raf.lock(FileLock.BLOCKING_EXCLUSIVE, 0, length);
- }
- }
- while (true) {
- p = await raf.position();
- at = await raf.readByte();
- if (at == 0 || at == -1) break;
- nextToWrite++;
- }
- await raf.setPosition(p);
- }
+ // Waits for the peer to take the lock, then takes the lock.
+ Expect.isTrue(await waitForPeer(raf, length));
+ // Check that the peer wrote to the file.
+ int p = 0;
await raf.setPosition(0);
- for (int i = 1; i <= length; i++) {
- Expect.equals(i, await raf.readByte());
+ while (p < length) {
+ int at = await raf.readByte();
+ Expect.equals(1, at);
+ p++;
}
await raf.unlock(0, length);
- bool wroteAll = true;
- for (int i = 0; i < length; i++) {
- // If there's a 0 entry, this process didn't write all bytes.
- wroteAll = wroteAll && (iWrote[i] == 0);
- }
- Expect.equals(false, wroteAll);
-
- Expect.equals(true, nonBlockingFailed);
-
- await peer.exitCode.then((v) async {
- Expect.equals(0, v);
- await raf.close();
- await directory.delete(recursive: true);
- });
+ // Check that the peer exited successfully.
+ int v = await peer.exitCode;
+ Expect.equals(0, v);
+ await raf.close();
+ await directory.delete(recursive: true);
}
main() async {
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 866135b..fb7510f 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -309,12 +309,16 @@
# SIMDBC interpreter doesn't support --no_lazy_dispatchers
no_lazy_dispatchers_test: SkipByDesign
-[ $compiler == precompiler && $runtime == dart_precompiled && $system == android ]
+[ $system == android ]
# Issue 26376
+io/platform_resolved_executable_test: RuntimeError
+io/process_path_test: RuntimeError
+io/file_test: RuntimeError
+io/process_path_environment_test: RuntimeError
io/file_system_watcher_test: RuntimeError
io/resolve_symbolic_links_test: RuntimeError
io/file_stat_test: RuntimeError
-# Issue #27638
+# Issue 27638
io/raw_datagram_socket_test: RuntimeError
io/http_proxy_advanced_test: RuntimeError
io/regress_21160_test: RuntimeError
@@ -343,6 +347,9 @@
[ $hot_reload || $hot_reload_rollback ]
deferred_transitive_import_error_test: Crash # Uses deferred imports.
package/*: SkipByDesign # Launches VMs in interesting ways.
+io/raw_datagram_read_all_test: Pass, Fail # Timing dependent.
+io/test_runner_test: Pass, Slow # Slow.
+io/skipping_dart2js_compilations_test: Pass, Slow # Slow.
[ $builder_tag == no_ipv6 ]
io/http_bind_test: Skip
diff --git a/tools/VERSION b/tools/VERSION
index 4b02ee1e..da4c303 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,5 +28,5 @@
MAJOR 1
MINOR 21
PATCH 0
-PRERELEASE 6
+PRERELEASE 7
PRERELEASE_PATCH 0
diff --git a/tools/build.py b/tools/build.py
index 0858c27..4f5d2e1 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -408,7 +408,6 @@
'-m', mode,
'-a', arch,
'--os', gn_os,
- '--check',
'-v',
]
process = subprocess.Popen(gn_command)
diff --git a/tools/dom/src/dart2js_CustomElementSupport.dart b/tools/dom/src/dart2js_CustomElementSupport.dart
index 62c120d..e82d3fd 100644
--- a/tools/dom/src/dart2js_CustomElementSupport.dart
+++ b/tools/dom/src/dart2js_CustomElementSupport.dart
@@ -47,6 +47,21 @@
convertDartClosureToJS(callback, 4));
}
+/// Checks whether the given [element] correctly extends from the native class
+/// with the given [baseClassName]. This method will throw if the base class
+/// doesn't match, except when the element extends from `template` and it's base
+/// class is `HTMLUnknownElement`. This exclusion is needed to support extension
+/// of template elements (used heavily in Polymer 1.0) on IE11 when using the
+/// webcomponents-lite.js polyfill.
+void _checkExtendsNativeClassOrTemplate(
+ Element element, String extendsTag, String baseClassName) {
+ if (!JS('bool', '(# instanceof window[#])', element, baseClassName) &&
+ !((extendsTag == 'template' &&
+ JS('bool', '(# instanceof window["HTMLUnknownElement"])', element)))) {
+ throw new UnsupportedError('extendsTag does not match base native class');
+ }
+}
+
void _registerCustomElement(context, document, String tag, Type type,
String extendsTagName) {
// Function follows the same pattern as the following JavaScript code for
@@ -90,10 +105,8 @@
'native class is not HtmlElement');
}
} else {
- if (!JS('bool', '(#.createElement(#) instanceof window[#])',
- document, extendsTagName, baseClassName)) {
- throw new UnsupportedError('extendsTag does not match base native class');
- }
+ var element = document.createElement(extendsTagName);
+ _checkExtendsNativeClassOrTemplate(element, extendsTagName, baseClassName);
}
var baseConstructor = JS('=Object', '#[#]', context, baseClassName);
@@ -163,11 +176,7 @@
_nativeType = HtmlElement;
} else {
var element = document.createElement(extendsTag);
- if (!JS('bool', '(# instanceof window[#])',
- element, baseClassName)) {
- throw new UnsupportedError(
- 'extendsTag does not match base native class');
- }
+ _checkExtendsNativeClassOrTemplate(element, extendsTag, baseClassName);
_nativeType = element.runtimeType;
}
diff --git a/tools/generate_buildfiles.py b/tools/generate_buildfiles.py
index 391a15a..9aa26e7 100644
--- a/tools/generate_buildfiles.py
+++ b/tools/generate_buildfiles.py
@@ -12,12 +12,17 @@
SCRIPT_DIR = os.path.dirname(sys.argv[0])
DART_ROOT = os.path.realpath(os.path.join(SCRIPT_DIR, '..'))
DART_USE_GN = "DART_USE_GN"
+DART_DISABLE_BUILDFILES = "DART_DISABLE_BUILDFILES"
def use_gn():
return DART_USE_GN in os.environ
+def disable_buildfiles():
+ return DART_DISABLE_BUILDFILES in os.environ
+
+
def execute(args):
process = subprocess.Popen(args, cwd=DART_ROOT)
process.wait()
@@ -68,6 +73,9 @@
def main(argv):
+ # Check the environment and become a no-op if directed.
+ if disable_buildfiles():
+ return 0
options = parse_args(argv)
if options.gn:
return run_gn()
diff --git a/tools/get_archive.py b/tools/get_archive.py
index 7517f54..fe1ac51 100755
--- a/tools/get_archive.py
+++ b/tools/get_archive.py
@@ -114,7 +114,7 @@
None, we return the latest revision. If the revision number is specified
but unavailable, find the nearest older revision and use that instead.
"""
- osdict = {'Darwin':'mac', 'Linux':'lucid64', 'Windows':'win'}
+ osdict = {'Darwin':'mac-x64', 'Linux':'linux-x64', 'Windows':'win-ia32'}
def FindPermanentUrl(out, osname, the_revision_num):
output_lines = out.split()
@@ -318,7 +318,9 @@
# Issue 13399 Quick fix, update with channel support.
bot = 'inc-be'
if args.debug:
- bot = 'debug-be'
+ print >>sys.stderr, (
+ 'Debug versions of Dartium and content_shell not available')
+ return 1
if positional[0] == 'dartium':
GetDartiumRevision('Dartium', bot, DARTIUM_DIR, DARTIUM_VERSION,
diff --git a/tools/gn.py b/tools/gn.py
index 2ff3bc2..304bdaa 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -112,7 +112,8 @@
has_clang = (host_os != 'win'
and args.os not in ['android']
and not (gn_args['target_os'] == 'linux' and
- gn_args['host_cpu'] == 'x86')
+ gn_args['host_cpu'] == 'x86' and
+ not args.asan) # Use clang for asan builds.
and not gn_args['target_cpu'].startswith('arm')
and not gn_args['target_cpu'].startswith('mips'))
gn_args['is_clang'] = args.clang and has_clang
diff --git a/tools/patch_sdk.dart b/tools/patch_sdk.dart
index 3bb9965..d92f0a6 100644
--- a/tools/patch_sdk.dart
+++ b/tools/patch_sdk.dart
@@ -264,6 +264,17 @@
partUnit.accept(new PatchApplier(partEdits, patchFinder));
results.add(partEdits);
}
+
+ if (patchFinder.patches.length != patchFinder.applied.length) {
+ print('Some elements marked as @patch do not have corresponding elements:');
+ for (var patched in patchFinder.patches.keys) {
+ if (!patchFinder.applied.contains(patched)) {
+ print('*** ${patched}');
+ }
+ }
+ throw "Failed to apply all @patch-es";
+ }
+
return new List<String>.from(results.map((e) => e.toString()));
}
@@ -343,14 +354,16 @@
if (node is FieldDeclaration) return;
var externalKeyword = (node as dynamic).externalKeyword;
- if (externalKeyword == null) return;
var name = _qualifiedName(node);
var patchNode = patch.patches[name];
if (patchNode == null) {
- print('warning: patch not found for $name: $node');
+ if (externalKeyword != null) {
+ print('warning: patch not found for $name: $node');
+ }
return;
}
+ patch.applied.add(name);
Annotation patchMeta = patchNode.metadata.lastWhere(_isPatchAnnotation);
int start = patchMeta.endToken.next.offset;
@@ -359,7 +372,7 @@
// For some node like static fields, the node's offset doesn't include
// the external keyword. Also starting from the keyword lets us preserve
// documentation comments.
- edits.replace(externalKeyword.offset, node.end, code);
+ edits.replace(externalKeyword?.offset ?? node.offset, node.end, code);
}
}
@@ -370,6 +383,7 @@
final Map patches = <String, Declaration>{};
final Map mergeMembers = <String, List<ClassMember>>{};
final List mergeDeclarations = <CompilationUnitMember>[];
+ final Set<String> applied = new Set<String>();
PatchFinder.parseAndVisit(String name, String contents)
: contents = contents,
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 5e8be6e..97c918a 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -310,8 +310,10 @@
}
String precompiledRunner = suite.dartPrecompiledBinaryFileName;
+ String processTest = suite.processTestBinaryFileName;
return <Command>[
commandBuilder.getAdbPrecompiledCommand(precompiledRunner,
+ processTest,
script,
arguments,
useBlobs)
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 7b1e596..f9d7b99 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -364,12 +364,16 @@
class AdbPrecompilationCommand extends Command {
final String precompiledRunnerFilename;
+ final String processTestFilename;
final String precompiledTestDirectory;
final List<String> arguments;
final bool useBlobs;
AdbPrecompilationCommand._(this.precompiledRunnerFilename,
- this.precompiledTestDirectory, this.arguments, this.useBlobs)
+ this.processTestFilename,
+ this.precompiledTestDirectory,
+ this.arguments,
+ this.useBlobs)
: super._("adb_precompilation");
void _buildHashCode(HashCodeBuilder builder) {
@@ -698,9 +702,12 @@
}
AdbPrecompilationCommand getAdbPrecompiledCommand(String precompiledRunner,
- String testDirectory, List<String> arguments, bool useBlobs) {
+ String processTest,
+ String testDirectory,
+ List<String> arguments,
+ bool useBlobs) {
var command = new AdbPrecompilationCommand._(
- precompiledRunner, testDirectory, arguments, useBlobs);
+ precompiledRunner, processTest, testDirectory, arguments, useBlobs);
return _getUniqueCommand(command);
}
@@ -2638,6 +2645,7 @@
Future<CommandOutput> _runAdbPrecompilationCommand(
AdbDevice device, AdbPrecompilationCommand command, int timeout) async {
var runner = command.precompiledRunnerFilename;
+ var processTest = command.processTestFilename;
var testdir = command.precompiledTestDirectory;
var arguments = command.arguments;
var devicedir = '/data/local/tmp/precompilation-testing';
@@ -2663,8 +2671,10 @@
// timing).
steps.add(() => device.runAdbCommand(
['push', runner, '$devicedir/dart_precompiled_runtime']));
+ steps.add(() => device.runAdbCommand(
+ ['push', processTest, '$devicedir/process_test']));
steps.add(() => device.runAdbShellCommand(
- ['chmod', '777', '$devicedir/dart_precompiled_runtime']));
+ ['chmod', '777', '$devicedir/dart_precompiled_runtime $devicedir/process_test']));
for (var file in files) {
steps.add(() => device
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index e994822..c13b69a 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -234,6 +234,13 @@
return dartExecutable;
}
+ String get processTestBinaryFileName {
+ String suffix = executableBinarySuffix;
+ String processTestExecutable = '$buildDir/process_test$suffix';
+ TestUtils.ensureExists(processTestExecutable, configuration);
+ return processTestExecutable;
+ }
+
String get d8FileName {
var suffix = getExecutableSuffix('d8');
var d8Dir = TestUtils.dartDir.append('third_party/d8');
diff --git a/utils/compiler/BUILD.gn b/utils/compiler/BUILD.gn
index c0e428d..9ec1093 100644
--- a/utils/compiler/BUILD.gn
+++ b/utils/compiler/BUILD.gn
@@ -62,7 +62,8 @@
main_dart = "$root_gen_dir/dart2js.dart"
training_args = [
"--library-root=" + rebase_path("../../sdk"),
- rebase_path("../../tests/language/first_test.dart"),
+ "--categories=all",
+ rebase_path("$root_gen_dir/dart2js.dart"),
]
}