Version 1.15.0-dev.5.0
Merge commit 'a28bfa98796cfc31676211f474b1c6e0ee68f776' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a4cf5bf..dd219f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,28 +1,39 @@
## 1.15.0
+### Language features
+* Added support for [configuration-specific imports](https://github.com/munificent/dep-interface-libraries/blob/master/Proposal.md).
+ On the VM and dart2js, they can be enabled with `--conditional-directives`.
+
+ The analyzer requires an additional option in an `options` file:
+ ```yaml
+ analyzer:
+ language:
+ enableConditionalDirectives: true
+ ```
+ Then run the analyzer with `--options=<path-to-options-file>`.
+
### Core library changes
+
+* `dart:async`
+ * Made `StreamView` class a `const` class.
+
+* `dart:core`
* Added `Uri.queryParametersAll` to handle multiple query parameters with
the same name.
* `dart:io`
* Added `SecurityContext.usePrivateKeyBytes`,
- `SecurityContext.useCertificateChainBytes`,
- `SecurityContext.setTrustedCertificatesBytes`, and
- `SecurityContext.setClientAuthoritiesBytes`.
- * The non-`Bytes` methods of `SecurityContext` are being renamed -`Sync`, as
- they will do synchronous IO. The non-`Bytes` and non-`Sync` methods are
- deprecated and will be removed in a later release.
+ `SecurityContext.useCertificateChainBytes`,
+ `SecurityContext.setTrustedCertificatesBytes`, and
+ `SecurityContext.setClientAuthoritiesBytes`.
* **Breaking** The named `directory` argument of
- `SecurityContext.setTrustedCertificates` is no longer supported.
- The method now only supports one argument for the PEM file name containing
- the trusted certificates.
- * Added support to SecurityContext for PKCS12 certificate and key containers.
+ `SecurityContext.setTrustedCertificates` has been removed.
+ * Added support to `SecurityContext` for PKCS12 certificate and key
+ containers.
* All calls in `SecurityContext` that accept certificate data now accept an
optional named parameter `password`, similar to
`SecurityContext.usePrivateKeyBytes`, for use as the password for PKCS12
data.
-* `dart:async`
- * Made `StreamView` class a `const` class.
## 1.14.2 - 2016-02-09
diff --git a/DEPS b/DEPS
index 274afa0..38ccb51 100644
--- a/DEPS
+++ b/DEPS
@@ -292,10 +292,6 @@
# without the runtime being available.
hooks = [
{
- "pattern": ".",
- "action": ["python", Var("dart_root") + "/tools/gyp_dart.py"],
- },
- {
'name': 'd8_testing_binaries',
'pattern': '.',
'action': [
@@ -429,4 +425,8 @@
Var('dart_root') + "/third_party/clang.tar.gz.sha1",
],
},
+ {
+ "pattern": ".",
+ "action": ["python", Var("dart_root") + "/tools/gyp_dart.py"],
+ },
]
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index df9075e..887c34b 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -116,6 +116,12 @@
final ServerPlugin serverPlugin;
/**
+ * A list of the globs used to determine which files should be analyzed. The
+ * list is lazily created and should be accessed using [analyzedFilesGlobs].
+ */
+ List<Glob> _analyzedFilesGlobs = null;
+
+ /**
* The [ContextManager] that handles the mapping from analysis roots to
* context directories.
*/
@@ -156,12 +162,6 @@
final InstrumentationService instrumentationService;
/**
- * A table mapping [Folder]s to the [AnalysisContext]s associated with them.
- */
- final Map<Folder, AnalysisContext> folderMap =
- new HashMap<Folder, AnalysisContext>();
-
- /**
* A queue of the operations to perform in this server.
*/
ServerOperationQueue operationQueue;
@@ -280,9 +280,10 @@
Set<String> prevAnalyzedFiles;
/**
- * The default options used to create new analysis contexts.
+ * The default options used to create new analysis contexts. This object is
+ * also referenced by the ContextManager.
*/
- AnalysisOptionsImpl defaultContextOptions = new AnalysisOptionsImpl();
+ final AnalysisOptionsImpl defaultContextOptions = new AnalysisOptionsImpl();
/**
* The controller for sending [ContextsChangedEvent]s.
@@ -314,22 +315,24 @@
: index = _index,
searchEngine = _index != null ? createSearchEngine(_index) : null {
_performance = performanceDuringStartup;
- operationQueue = new ServerOperationQueue();
- contextManager = new ContextManagerImpl(
- resourceProvider,
- packageResolverProvider,
- embeddedResolverProvider,
- packageMapProvider,
- instrumentationService);
- ServerContextManagerCallbacks contextManagerCallbacks =
- new ServerContextManagerCallbacks(this, resourceProvider);
- contextManager.callbacks = contextManagerCallbacks;
defaultContextOptions.incremental = true;
defaultContextOptions.incrementalApi =
options.enableIncrementalResolutionApi;
defaultContextOptions.incrementalValidation =
options.enableIncrementalResolutionValidation;
defaultContextOptions.generateImplicitErrors = false;
+ operationQueue = new ServerOperationQueue();
+ contextManager = new ContextManagerImpl(
+ resourceProvider,
+ packageResolverProvider,
+ embeddedResolverProvider,
+ packageMapProvider,
+ analyzedFilesGlobs,
+ instrumentationService,
+ defaultContextOptions);
+ ServerContextManagerCallbacks contextManagerCallbacks =
+ new ServerContextManagerCallbacks(this, resourceProvider);
+ contextManager.callbacks = contextManagerCallbacks;
_noErrorNotification = options.noErrorNotification;
AnalysisEngine.instance.logger = new AnalysisLogger(this);
_onAnalysisStartedController = new StreamController.broadcast();
@@ -352,6 +355,40 @@
}
/**
+ * Return the [AnalysisContext]s that are being used to analyze the analysis
+ * roots.
+ */
+ Iterable<AnalysisContext> get analysisContexts =>
+ contextManager.analysisContexts;
+
+ /**
+ * Return a list of the globs used to determine which files should be analyzed.
+ */
+ List<Glob> get analyzedFilesGlobs {
+ if (_analyzedFilesGlobs == null) {
+ _analyzedFilesGlobs = <Glob>[];
+ List<String> patterns = serverPlugin.analyzedFilePatterns;
+ for (String pattern in patterns) {
+ try {
+ _analyzedFilesGlobs
+ .add(new Glob(JavaFile.pathContext.separator, pattern));
+ } catch (exception, stackTrace) {
+ AnalysisEngine.instance.logger.logError(
+ 'Invalid glob pattern: "$pattern"',
+ new CaughtException(exception, stackTrace));
+ }
+ }
+ }
+ return _analyzedFilesGlobs;
+ }
+
+ /**
+ * Return a table mapping [Folder]s to the [AnalysisContext]s associated with
+ * them.
+ */
+ Map<Folder, AnalysisContext> get folderMap => contextManager.folderMap;
+
+ /**
* The [Future] that completes when analysis is complete.
*/
Future get onAnalysisComplete {
@@ -462,7 +499,7 @@
* explicitly or implicitly. Return `null` if there is no such context.
*/
AnalysisContext getAnalysisContextForSource(Source source) {
- for (AnalysisContext context in folderMap.values) {
+ for (AnalysisContext context in analysisContexts) {
SourceKind kind = context.getKindOf(source);
if (kind != SourceKind.UNKNOWN) {
return context;
@@ -471,14 +508,6 @@
return null;
}
- /**
- * Return the [AnalysisContext]s that are being used to analyze the analysis
- * roots.
- */
- Iterable<AnalysisContext> getAnalysisContexts() {
- return folderMap.values;
- }
-
CompilationUnitElement getCompilationUnitElement(String file) {
ContextSourcePair pair = getContextSourcePair(file);
if (pair == null) {
@@ -554,7 +583,7 @@
}
}
// try to find a context that analysed the file
- for (AnalysisContext context in folderMap.values) {
+ for (AnalysisContext context in analysisContexts) {
Source source = ContextManagerImpl.createSourceInContext(context, file);
SourceKind kind = context.getKindOf(source);
if (kind != SourceKind.UNKNOWN) {
@@ -562,7 +591,7 @@
}
}
// try to find a context for which the file is a priority source
- for (InternalAnalysisContext context in folderMap.values) {
+ for (InternalAnalysisContext context in analysisContexts) {
List<Source> sources = context.getSourcesWithFullName(path);
if (sources.isNotEmpty) {
Source source = sources.first;
@@ -612,23 +641,6 @@
return elements;
}
-// TODO(brianwilkerson) Add the following method after 'prioritySources' has
-// been added to InternalAnalysisContext.
-// /**
-// * Return a list containing the full names of all of the sources that are
-// * priority sources.
-// */
-// List<String> getPriorityFiles() {
-// List<String> priorityFiles = new List<String>();
-// folderMap.values.forEach((ContextDirectory directory) {
-// InternalAnalysisContext context = directory.context;
-// context.prioritySources.forEach((Source source) {
-// priorityFiles.add(source.fullName);
-// });
-// });
-// return priorityFiles;
-// }
-
/**
* Return an analysis error info containing the array of all of the errors and
* the line info associated with [file].
@@ -655,6 +667,23 @@
return context.getErrors(source);
}
+// TODO(brianwilkerson) Add the following method after 'prioritySources' has
+// been added to InternalAnalysisContext.
+// /**
+// * Return a list containing the full names of all of the sources that are
+// * priority sources.
+// */
+// List<String> getPriorityFiles() {
+// List<String> priorityFiles = new List<String>();
+// folderMap.values.forEach((ContextDirectory directory) {
+// InternalAnalysisContext context = directory.context;
+// context.prioritySources.forEach((Source source) {
+// priorityFiles.add(source.fullName);
+// });
+// });
+// return priorityFiles;
+// }
+
/**
* Returns resolved [AstNode]s at the given [offset] of the given [file].
*
@@ -1114,7 +1143,7 @@
if (preferredContext == null) {
Resource resource = resourceProvider.getResource(file);
if (resource is File && resource.exists) {
- for (AnalysisContext context in folderMap.values) {
+ for (AnalysisContext context in analysisContexts) {
Uri uri = context.sourceFactory.restoreUri(source);
if (uri.scheme != 'file') {
preferredContext = context;
@@ -1131,7 +1160,7 @@
sourceMap.putIfAbsent(preferredContext, () => <Source>[]).add(source);
contextFound = true;
}
- for (AnalysisContext context in folderMap.values) {
+ for (AnalysisContext context in analysisContexts) {
if (context != preferredContext &&
context.getKindOf(source) != SourceKind.UNKNOWN) {
sourceMap.putIfAbsent(context, () => <Source>[]).add(source);
@@ -1245,7 +1274,7 @@
// If the source does not exist, then it was an overlay-only one.
// Remove it from contexts.
if (newContents == null && !source.exists()) {
- for (InternalAnalysisContext context in folderMap.values) {
+ for (InternalAnalysisContext context in analysisContexts) {
List<Source> sources = context.getSourcesWithFullName(file);
ChangeSet changeSet = new ChangeSet();
sources.forEach(changeSet.removedSource);
@@ -1256,7 +1285,7 @@
}
// Update all contexts.
bool anyContextUpdated = false;
- for (InternalAnalysisContext context in folderMap.values) {
+ for (InternalAnalysisContext context in analysisContexts) {
List<Source> sources = context.getSourcesWithFullName(file);
sources.forEach((Source source) {
anyContextUpdated = true;
@@ -1313,7 +1342,7 @@
//
// Update existing contexts.
//
- folderMap.forEach((Folder folder, AnalysisContext context) {
+ for (AnalysisContext context in analysisContexts) {
AnalysisOptionsImpl options =
new AnalysisOptionsImpl.from(context.analysisOptions);
optionUpdaters.forEach((OptionUpdater optionUpdater) {
@@ -1322,7 +1351,7 @@
context.analysisOptions = options;
// TODO(brianwilkerson) As far as I can tell, this doesn't cause analysis
// to be scheduled for this context.
- });
+ }
//
// Update the defaults used to create new contexts.
//
@@ -1331,6 +1360,14 @@
});
}
+ void _computingPackageMap(bool computing) {
+ if (serverServices.contains(ServerService.STATUS)) {
+ PubStatus pubStatus = new PubStatus(computing);
+ ServerStatusParams params = new ServerStatusParams(pub: pubStatus);
+ sendNotification(params.toNotification());
+ }
+ }
+
/**
* Return a set of all contexts whose associated folder is contained within,
* or equal to, one of the resources in the given list of [resources].
@@ -1451,39 +1488,8 @@
*/
final ResourceProvider resourceProvider;
- /**
- * A list of the globs used to determine which files should be analyzed. The
- * list is lazily created and should be accessed using [analyzedFilesGlobs].
- */
- List<Glob> _analyzedFilesGlobs = null;
-
ServerContextManagerCallbacks(this.analysisServer, this.resourceProvider);
- /**
- * Return a list of the globs used to determine which files should be analyzed.
- */
- List<Glob> get analyzedFilesGlobs {
- if (_analyzedFilesGlobs == null) {
- _analyzedFilesGlobs = <Glob>[];
- List<String> patterns = analysisServer.serverPlugin.analyzedFilePatterns;
- for (String pattern in patterns) {
- try {
- _analyzedFilesGlobs
- .add(new Glob(JavaFile.pathContext.separator, pattern));
- } catch (exception, stackTrace) {
- AnalysisEngine.instance.logger.logError(
- 'Invalid glob pattern: "$pattern"',
- new CaughtException(exception, stackTrace));
- }
- }
- }
- return _analyzedFilesGlobs;
- }
-
- @override
- AnalysisOptions get defaultAnalysisOptions =>
- analysisServer.defaultContextOptions;
-
@override
AnalysisContext addContext(
Folder folder, AnalysisOptions options, FolderDisposition disposition) {
@@ -1518,14 +1524,8 @@
}
@override
- void beginComputePackageMap() {
- _computingPackageMap(true);
- }
-
- @override
- void endComputePackageMap() {
- _computingPackageMap(false);
- }
+ void computingPackageMap(bool computing) =>
+ analysisServer._computingPackageMap(computing);
@override
void removeContext(Folder folder, List<String> flushedFiles) {
@@ -1544,22 +1544,6 @@
}
@override
- bool shouldFileBeAnalyzed(File file) {
- for (Glob glob in analyzedFilesGlobs) {
- if (glob.matches(file.path)) {
- // Emacs creates dummy links to track the fact that a file is open for
- // editing and has unsaved changes (e.g. having unsaved changes to
- // 'foo.dart' causes a link '.#foo.dart' to be created, which points to
- // the non-existent file 'username@hostname.pid'. To avoid these dummy
- // links causing the analyzer to thrash, just ignore links to
- // non-existent files.
- return file.exists;
- }
- }
- return false;
- }
-
- @override
void updateContextPackageUriResolver(
Folder contextFolder, FolderDisposition disposition) {
AnalysisContext context = analysisServer.folderMap[contextFolder];
@@ -1570,14 +1554,6 @@
analysisServer.schedulePerformAnalysisOperation(context);
}
- void _computingPackageMap(bool computing) {
- if (analysisServer.serverServices.contains(ServerService.STATUS)) {
- PubStatus pubStatus = new PubStatus(computing);
- ServerStatusParams params = new ServerStatusParams(pub: pubStatus);
- analysisServer.sendNotification(params.toNotification());
- }
- }
-
/**
* Set up a [SourceFactory] that resolves packages as appropriate for the
* given [disposition].
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 8575086..c81ce7f 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -31,6 +31,7 @@
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/util/absolute_path.dart';
+import 'package:analyzer/src/util/glob.dart';
import 'package:analyzer/src/util/yaml.dart';
import 'package:package_config/packages.dart';
import 'package:package_config/packages_file.dart' as pkgfile show parse;
@@ -228,6 +229,12 @@
// TODO(brianwilkerson) Move this class to a public library.
/**
+ * Return the [AnalysisContext]s that are being used to analyze the analysis
+ * roots.
+ */
+ Iterable<AnalysisContext> get analysisContexts;
+
+ /**
* Get the callback interface used to create, destroy, and update contexts.
*/
ContextManagerCallbacks get callbacks;
@@ -244,6 +251,12 @@
List<String> get excludedPaths;
/**
+ * Return a table mapping [Folder]s to the [AnalysisContext]s associated with
+ * them.
+ */
+ Map<Folder, AnalysisContext> get folderMap;
+
+ /**
* Return the list of included paths (folders and files) most recently passed
* to [setRoots].
*/
@@ -307,12 +320,6 @@
*/
abstract class ContextManagerCallbacks {
/**
- * Return the default analysis options to be used when creating an analysis
- * context.
- */
- AnalysisOptions get defaultAnalysisOptions;
-
- /**
* Create and return a new analysis context rooted at the given [folder], with
* the given analysis [options], allowing [disposition] to govern details of
* how the context is to be created.
@@ -328,19 +335,10 @@
void applyChangesToContext(Folder contextFolder, ChangeSet changeSet);
/**
- * Called when the ContextManager is about to start computing the package
- * map.
+ * Signals that the context manager has started to compute a package map (if
+ * [computing] is `true`) or has finished (if [computing] is `false`).
*/
- void beginComputePackageMap() {
- // By default, do nothing.
- }
-
- /**
- * Called when the ContextManager has finished computing the package map.
- */
- void endComputePackageMap() {
- // By default, do nothing.
- }
+ void computingPackageMap(bool computing);
/**
* Remove the context associated with the given [folder]. [flushedFiles] is
@@ -350,11 +348,6 @@
void removeContext(Folder folder, List<String> flushedFiles);
/**
- * Return `true` if the given [file] should be analyzed.
- */
- bool shouldFileBeAnalyzed(File file);
-
- /**
* Called when the disposition for a context has changed.
*/
void updateContextPackageUriResolver(
@@ -456,6 +449,16 @@
new AnalysisOptionsProvider();
/**
+ * A list of the globs used to determine which files should be analyzed.
+ */
+ final List<Glob> analyzedFilesGlobs;
+
+ /**
+ * The default options used to create new analysis contexts.
+ */
+ final AnalysisOptionsImpl defaultContextOptions;
+
+ /**
* The instrumentation service used to report instrumentation data.
*/
final InstrumentationService _instrumentationService;
@@ -470,6 +473,13 @@
final ContextInfo rootInfo = new ContextInfo._root();
/**
+ * A table mapping [Folder]s to the [AnalysisContext]s associated with them.
+ */
+ @override
+ final Map<Folder, AnalysisContext> folderMap =
+ new HashMap<Folder, AnalysisContext>();
+
+ /**
* Stream subscription we are using to watch each analysis root directory for
* changes.
*/
@@ -481,12 +491,17 @@
this.packageResolverProvider,
this.embeddedUriResolverProvider,
this._packageMapProvider,
- this._instrumentationService) {
+ this.analyzedFilesGlobs,
+ this._instrumentationService,
+ this.defaultContextOptions) {
absolutePathContext = resourceProvider.absolutePathContext;
pathContext = resourceProvider.pathContext;
}
@override
+ Iterable<AnalysisContext> get analysisContexts => folderMap.values;
+
+ @override
List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) {
List<AnalysisContext> contexts = <AnalysisContext>[];
ContextInfo innermostContainingInfo =
@@ -783,7 +798,7 @@
// add files, recurse into folders
if (child is File) {
// ignore if should not be analyzed at all
- if (!callbacks.shouldFileBeAnalyzed(child)) {
+ if (!_shouldFileBeAnalyzed(child)) {
continue;
}
// ignore if was not excluded
@@ -830,7 +845,7 @@
}
// add files, recurse into folders
if (child is File) {
- if (callbacks.shouldFileBeAnalyzed(child)) {
+ if (_shouldFileBeAnalyzed(child)) {
Source source = createSourceInContext(info.context, child);
changeSet.addedSource(source);
info.sources[path] = source;
@@ -892,7 +907,6 @@
if (sourceFactory is SourceFactoryImpl) {
if (!sourceFactory.resolvers
.any((UriResolver r) => r is EmbedderUriResolver)) {
-
// Get all but the dart: Uri resolver.
List<UriResolver> resolvers = sourceFactory.resolvers
.where((r) => r is! DartUriResolver)
@@ -995,7 +1009,7 @@
return new NoPackageFolderDisposition(packageRoot: packageRoot);
} else {
PackageMapInfo packageMapInfo;
- callbacks.beginComputePackageMap();
+ callbacks.computingPackageMap(true);
try {
// Try .packages first.
if (absolutePathContext.basename(packagespecFile.path) ==
@@ -1014,7 +1028,7 @@
packageMapInfo = _packageMapProvider.computePackageMap(folder);
});
} finally {
- callbacks.endComputePackageMap();
+ callbacks.computingPackageMap(false);
}
for (String dependencyPath in packageMapInfo.dependencies) {
addDependency(dependencyPath);
@@ -1046,7 +1060,7 @@
Map<String, Object> optionMap = readOptions(info.folder);
AnalysisOptions options =
- new AnalysisOptionsImpl.from(callbacks.defaultAnalysisOptions);
+ new AnalysisOptionsImpl.from(defaultContextOptions);
applyToAnalysisOptions(options, optionMap);
info.setDependencies(dependencies);
@@ -1305,7 +1319,7 @@
// that case don't add it.
if (resource is File) {
File file = resource;
- if (callbacks.shouldFileBeAnalyzed(file)) {
+ if (_shouldFileBeAnalyzed(file)) {
ChangeSet changeSet = new ChangeSet();
Source source = createSourceInContext(info.context, file);
changeSet.addedSource(source);
@@ -1489,6 +1503,24 @@
}
/**
+ * Return `true` if the given [file] should be analyzed.
+ */
+ bool _shouldFileBeAnalyzed(File file) {
+ for (Glob glob in analyzedFilesGlobs) {
+ if (glob.matches(file.path)) {
+ // Emacs creates dummy links to track the fact that a file is open for
+ // editing and has unsaved changes (e.g. having unsaved changes to
+ // 'foo.dart' causes a link '.#foo.dart' to be created, which points to
+ // the non-existent file 'username@hostname.pid'. To avoid these dummy
+ // links causing the analyzer to thrash, just ignore links to
+ // non-existent files.
+ return file.exists;
+ }
+ }
+ return false;
+ }
+
+ /**
* Create and return a source representing the given [file] within the given
* [context].
*/
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 0c8d28b..7bfb354 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -110,7 +110,7 @@
Response getLibraryDependencies(Request request) {
server.onAnalysisComplete.then((_) {
LibraryDependencyCollector collector =
- new LibraryDependencyCollector(server.getAnalysisContexts());
+ new LibraryDependencyCollector(server.analysisContexts);
Set<String> libraries = collector.collectLibraryDependencies();
Map<String, Map<String, List<String>>> packageMap =
collector.calculatePackageMap(server.folderMap);
@@ -378,7 +378,7 @@
.putIfAbsent(descriptor,
() => new StreamController<engine.ComputedResult>.broadcast())
.stream;
- server.getAnalysisContexts().forEach(_subscribeForContext);
+ server.analysisContexts.forEach(_subscribeForContext);
return stream;
}
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index 94b1c3a..df32e9e 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -9,7 +9,6 @@
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -40,15 +39,14 @@
/// Answer the `diagnostic.diagnostics` request.
Response computeDiagnostics(Request request) {
List<ContextData> infos = <ContextData>[];
- server.folderMap.forEach((Folder folder, AnalysisContext context) {
- infos.add(extractData(folder, context));
- });
-
+ for (AnalysisContext context in server.analysisContexts) {
+ infos.add(extractData(context));
+ }
return new DiagnosticGetDiagnosticsResult(infos).toResponse(request.id);
}
/// Extract context data from the given [context].
- ContextData extractData(Folder folder, AnalysisContext context) {
+ ContextData extractData(AnalysisContext context) {
int explicitFiles = 0;
int implicitFiles = 0;
int workItems = 0;
diff --git a/pkg/analysis_server/lib/src/domain_execution.dart b/pkg/analysis_server/lib/src/domain_execution.dart
index 3988de2..4954152 100644
--- a/pkg/analysis_server/lib/src/domain_execution.dart
+++ b/pkg/analysis_server/lib/src/domain_execution.dart
@@ -195,7 +195,7 @@
server.contextManager.isInAnalysisRoot(filePath);
void _reportCurrentFileStatus() {
- for (AnalysisContext context in server.getAnalysisContexts()) {
+ for (AnalysisContext context in server.analysisContexts) {
List<Source> librarySources = context.librarySources;
List<Source> clientSources = context.launchableClientLibrarySources;
List<Source> serverSources = context.launchableServerLibrarySources;
@@ -220,7 +220,8 @@
List<Source> libraries =
context.getLibrariesReferencedFromHtml(source);
server.sendNotification(new ExecutionLaunchDataParams(filePath,
- referencedFiles: _getFullNames(libraries)).toNotification());
+ referencedFiles: _getFullNames(libraries))
+ .toNotification());
}
}
}
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 2267250..3b2c724 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -134,7 +134,7 @@
// analysis engine to update this set incrementally as analysis is
// performed.
LibraryDependencyCollector collector =
- new LibraryDependencyCollector(server.getAnalysisContexts().toList());
+ new LibraryDependencyCollector(server.analysisContexts.toList());
Set<String> analyzedFiles = collector.collectLibraryDependencies();
Set<String> prevAnalyzedFiles = server.prevAnalyzedFiles;
if (prevAnalyzedFiles != null &&
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index be95ec1..b5a7ea2 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -287,10 +287,6 @@
void _addProposal_addTypeAnnotation_VariableDeclaration() {
AstNode node = this.node;
- // check if "var v = 42;^"
- if (node is VariableDeclarationStatement) {
- node = (node as VariableDeclarationStatement).variables;
- }
// prepare VariableDeclarationList
VariableDeclarationList declarationList =
node.getAncestor((node) => node is VariableDeclarationList);
@@ -310,6 +306,11 @@
return;
}
VariableDeclaration variable = variables[0];
+ // must be not after the name of the variable
+ if (selectionOffset > variable.name.end) {
+ _coverageMarker();
+ return;
+ }
// we need an initializer to get the type from
Expression initializer = variable.initializer;
if (initializer == null) {
@@ -1431,44 +1432,32 @@
}
void _addProposal_removeTypeAnnotation() {
- VariableDeclarationList variableList;
- // try top-level variable
- {
- TopLevelVariableDeclaration declaration =
- node.getAncestor((node) => node is TopLevelVariableDeclaration);
- if (declaration != null) {
- variableList = declaration.variables;
- }
- }
- // try class field
- if (variableList == null) {
- FieldDeclaration fieldDeclaration =
- node.getAncestor((node) => node is FieldDeclaration);
- if (fieldDeclaration != null) {
- variableList = fieldDeclaration.fields;
- }
- }
- // try local variable
- if (variableList == null) {
- VariableDeclarationStatement statement =
- node.getAncestor((node) => node is VariableDeclarationStatement);
- if (statement != null) {
- variableList = statement.variables;
- }
- }
- if (variableList == null) {
+ VariableDeclarationList declarationList =
+ node.getAncestor((n) => n is VariableDeclarationList);
+ if (declarationList == null) {
_coverageMarker();
return;
}
// we need a type
- TypeName typeNode = variableList.type;
+ TypeName typeNode = declarationList.type;
if (typeNode == null) {
_coverageMarker();
return;
}
+ // ignore if an incomplete variable declaration
+ if (declarationList.variables.length == 1 &&
+ declarationList.variables[0].name.isSynthetic) {
+ _coverageMarker();
+ return;
+ }
+ // must be not after the name of the variable
+ VariableDeclaration firstVariable = declarationList.variables[0];
+ if (selectionOffset > firstVariable.name.end) {
+ _coverageMarker();
+ return;
+ }
// add edit
- Token keyword = variableList.keyword;
- VariableDeclaration firstVariable = variableList.variables[0];
+ Token keyword = declarationList.keyword;
SourceRange typeRange = rangeStartStart(typeNode, firstVariable);
if (keyword != null && keyword.lexeme != 'var') {
_addReplaceEdit(typeRange, '');
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 7525b74f..49d616d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -46,8 +47,8 @@
/**
* Return true if this [errorCode] is likely to have a fix associated with it.
*/
-bool hasFix(ErrorCode errorCode) => errorCode ==
- StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
+bool hasFix(ErrorCode errorCode) =>
+ errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER ||
errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR ||
@@ -60,7 +61,8 @@
errorCode ==
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR ||
errorCode ==
- StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
+ StaticWarningCode
+ .NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
errorCode == StaticWarningCode.UNDEFINED_CLASS ||
@@ -99,7 +101,8 @@
errorCode == StaticTypeWarningCode.UNDEFINED_FUNCTION ||
errorCode == StaticTypeWarningCode.UNDEFINED_GETTER ||
errorCode == StaticTypeWarningCode.UNDEFINED_METHOD ||
- errorCode == StaticTypeWarningCode.UNDEFINED_SETTER;
+ errorCode == StaticTypeWarningCode.UNDEFINED_SETTER ||
+ (errorCode is LintCode && errorCode.name == LintNames.annotate_overrides);
/**
* An enumeration of possible quick fix kinds.
@@ -165,6 +168,8 @@
const FixKind('IMPORT_LIBRARY_SHOW', 49, "Update library '{0}' import");
static const INSERT_SEMICOLON =
const FixKind('INSERT_SEMICOLON', 50, "Insert ';'");
+ static const LINT_ADD_OVERRIDE =
+ const FixKind('LINT_ADD_OVERRIDE', 50, "Add '@override' annotation");
static const MAKE_CLASS_ABSTRACT =
const FixKind('MAKE_CLASS_ABSTRACT', 50, "Make class '{0}' abstract");
static const REMOVE_DEAD_CODE =
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 01ddada..dc66c45 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -343,6 +343,12 @@
_addFix_undefinedClassAccessor_useSimilar();
_addFix_createField();
}
+ // lints
+ if (errorCode is LintCode) {
+ if (errorCode.name == LintNames.annotate_overrides) {
+ _addLintFixAddOverrideAnnotation();
+ }
+ }
// done
return fixes;
}
@@ -2202,6 +2208,26 @@
group.addPosition(position, range.length);
}
+ void _addLintFixAddOverrideAnnotation() {
+ ClassMember member = node.getAncestor((n) => n is ClassMember);
+ if (member == null) {
+ return;
+ }
+
+ //TODO(pq): migrate annotation edit building to change_builder
+
+ // Handle doc comments.
+ Token token = member.beginToken;
+ if (token is CommentToken) {
+ token = (token as CommentToken).parent;
+ }
+
+ exitPosition = new Position(file, token.offset - 1);
+ String indent = utils.getIndent(1);
+ _addReplaceEdit(rf.rangeStartLength(token, 0), '@override$eol$indent');
+ _addFix(DartFixKind.LINT_ADD_OVERRIDE, []);
+ }
+
/**
* Prepares proposal for creating function corresponding to the given
* [FunctionType].
@@ -2884,6 +2910,13 @@
}
/**
+ * An enumeration of lint names.
+ */
+class LintNames {
+ static const String annotate_overrides = 'annotate_overrides';
+}
+
+/**
* Helper for finding [Element] with name closest to the given.
*/
class _ClosestElementFinder {
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index a65b1610..835488e 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -646,8 +646,8 @@
int implicitSourceCount = 0;
int implicitLineInfoCount = 0;
int implicitLineCount = 0;
- analysisServer.folderMap
- .forEach((Folder folder, InternalAnalysisContext context) {
+ for (InternalAnalysisContext context
+ in analysisServer.analysisContexts) {
Set<Source> explicitSources = new HashSet<Source>();
Set<Source> implicitSources = new HashSet<Source>();
AnalysisCache cache = context.analysisCache;
@@ -708,7 +708,7 @@
explicitLineCount += lineCount(explicitSources, true);
implicitSourceCount += implicitSources.length;
implicitLineCount += lineCount(implicitSources, false);
- });
+ }
List<String> sourceTypeNames = sourceTypeCounts.keys.toList();
sourceTypeNames.sort();
List<String> typeNames = typeCounts.keys.toList();
@@ -1354,7 +1354,7 @@
int processorCount = errorProcessors?.length ?? 0;
buffer.write('<p><b>Error Processor count</b>: $processorCount</p>');
});
-
+
SourceFactory sourceFactory = context.sourceFactory;
if (sourceFactory is SourceFactoryImpl) {
buffer.write('<h3>Resolvers</h3>');
diff --git a/pkg/analysis_server/test/analysis/reanalyze_test.dart b/pkg/analysis_server/test/analysis/reanalyze_test.dart
index 0b39e88..b7f62d0 100644
--- a/pkg/analysis_server/test/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/analysis/reanalyze_test.dart
@@ -32,13 +32,13 @@
test_reanalyze() {
createProject();
- List<AnalysisContext> contexts = server.folderMap.values.toList();
+ List<AnalysisContext> contexts = server.analysisContexts.toList();
expect(contexts, hasLength(1));
AnalysisContext oldContext = contexts[0];
// Reanalyze should cause a brand new context to be built.
Request request = new Request("0", ANALYSIS_REANALYZE);
handleSuccessfulRequest(request);
- contexts = server.folderMap.values.toList();
+ contexts = server.analysisContexts.toList();
expect(contexts, hasLength(1));
AnalysisContext newContext = contexts[0];
expect(newContext, isNot(same(oldContext)));
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index e12a691..85a6bbc 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -131,6 +131,9 @@
}
void setUp() {
+ ExtensionManager manager = new ExtensionManager();
+ ServerPlugin plugin = new ServerPlugin();
+ manager.processPlugins([plugin]);
channel = new MockServerChannel();
resourceProvider = new MemoryResourceProvider();
packageMapProvider = new MockPackageMapProvider();
@@ -139,7 +142,7 @@
resourceProvider,
packageMapProvider,
null,
- new ServerPlugin(),
+ plugin,
new AnalysisServerOptions(),
() => new MockSdk(),
InstrumentationService.NULL_SERVICE,
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index a94314b..1472027 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -18,6 +18,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer/src/util/glob.dart';
import 'package:linter/src/plugin/linter_plugin.dart';
import 'package:linter/src/rules/avoid_as.dart';
import 'package:package_config/packages.dart';
@@ -92,6 +93,18 @@
['x']
]);
+ List<Glob> get analysisFilesGlobs {
+ List<String> patterns = <String>[
+ '**/*.${AnalysisEngine.SUFFIX_DART}',
+ '**/*.${AnalysisEngine.SUFFIX_HTML}',
+ '**/*.${AnalysisEngine.SUFFIX_HTM}',
+ '**/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}'
+ ];
+ return patterns
+ .map((pattern) => new Glob(JavaFile.pathContext.separator, pattern))
+ .toList();
+ }
+
List<ErrorProcessor> get errorProcessors => callbacks.currentContext
.getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
@@ -142,7 +155,9 @@
providePackageResolver,
provideEmbeddedUriResolver,
packageMapProvider,
- InstrumentationService.NULL_SERVICE);
+ analysisFilesGlobs,
+ InstrumentationService.NULL_SERVICE,
+ new AnalysisOptionsImpl());
callbacks = new TestContextManagerCallbacks(resourceProvider);
manager.callbacks = callbacks;
resourceProvider.newFolder(projPath);
@@ -403,8 +418,10 @@
// * from `.analysis_options`:
expect(context.analysisOptions.enableGenericMethods, isTrue);
// * verify tests are excluded
- expect(callbacks.currentContextFilePaths[projPath].keys,
- ['/my/proj/sdk_ext/entry.dart']);
+ expect(
+ callbacks.currentContextFilePaths[projPath].keys,
+ unorderedEquals(
+ ['/my/proj/sdk_ext/entry.dart', '/my/proj/.analysis_options']));
// Verify filter setup.
expect(errorProcessors, hasLength(2));
@@ -656,8 +673,10 @@
callbacks.currentContextFilePaths[projPath];
expect(fileTimestamps, isNotEmpty);
List<String> files = fileTimestamps.keys.toList();
- expect(files.length, equals(1));
- expect(files[0], equals('/my/proj/lib/main.dart'));
+ expect(
+ files,
+ unorderedEquals(
+ ['/my/proj/lib/main.dart', '/my/proj/.analysis_options']));
}
test_path_filter_child_contexts_option() async {
@@ -2363,9 +2382,6 @@
Iterable<String> get currentContextPaths => currentContextTimestamps.keys;
@override
- AnalysisOptions get defaultAnalysisOptions => new AnalysisOptionsImpl();
-
- @override
AnalysisContext addContext(
Folder folder, AnalysisOptions options, FolderDisposition disposition) {
String path = folder.path;
@@ -2429,6 +2445,11 @@
}
@override
+ void computingPackageMap(bool computing) {
+ // Do nothing.
+ }
+
+ @override
void removeContext(Folder folder, List<String> flushedFiles) {
String path = folder.path;
expect(currentContextPaths, contains(path));
@@ -2439,20 +2460,6 @@
}
@override
- bool shouldFileBeAnalyzed(File file) {
- if (!(AnalysisEngine.isDartFileName(file.path) ||
- AnalysisEngine.isHtmlFileName(file.path))) {
- return false;
- }
- // Emacs creates dummy links to track the fact that a file is open for
- // editing and has unsaved changes (e.g. having unsaved changes to
- // 'foo.dart' causes a link '.#foo.dart' to be created, which points to the
- // non-existent file 'username@hostname.pid'. To avoid these dummy links
- // causing the analyzer to thrash, just ignore links to non-existent files.
- return file.exists;
- }
-
- @override
void updateContextPackageUriResolver(
Folder contextFolder, FolderDisposition disposition) {
currentContextDispositions[contextFolder.path] = disposition;
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index 1274eab..e6d1dfb 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -223,7 +223,7 @@
when(manager.isInAnalysisRoot(anyString)).thenReturn(true);
AnalysisServer server = new AnalysisServerMock();
- when(server.getAnalysisContexts()).thenReturn([context]);
+ when(server.analysisContexts).thenReturn([context]);
when(server.contextManager).thenReturn(manager);
StreamController controller = new StreamController.broadcast(sync: true);
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 859f248..5c84d35 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -390,6 +390,15 @@
await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
}
+ test_addTypeAnnotation_local_BAD_onInitializer() async {
+ resolveTestUnit('''
+main() {
+ var abc = 0;
+}
+''');
+ await assertNoAssistAt('0;', DartAssistKind.ADD_TYPE_ANNOTATION);
+ }
+
test_addTypeAnnotation_local_BAD_unknown() async {
verifyNoTestUnitErrors = false;
resolveTestUnit('''
@@ -623,22 +632,6 @@
''');
}
- test_addTypeAnnotation_local_OK_onInitializer() async {
- resolveTestUnit('''
-main() {
- var v = 123;
-}
-''');
- await assertHasAssistAt(
- '23',
- DartAssistKind.ADD_TYPE_ANNOTATION,
- '''
-main() {
- int v = 123;
-}
-''');
- }
-
test_addTypeAnnotation_local_OK_onName() async {
resolveTestUnit('''
main() {
@@ -671,22 +664,6 @@
''');
}
- test_addTypeAnnotation_local_OK_onVariableDeclarationStatement() async {
- resolveTestUnit('''
-main() {
- var v = 123; // marker
-}
-''');
- await assertHasAssistAt(
- ' // marker',
- DartAssistKind.ADD_TYPE_ANNOTATION,
- '''
-main() {
- int v = 123; // marker
-}
-''');
- }
-
test_addTypeAnnotation_OK_privateType_sameLibrary() async {
resolveTestUnit('''
class _A {}
@@ -3283,6 +3260,15 @@
''');
}
+ test_removeTypeAnnotation_localVariable_BAD_onInitializer() async {
+ resolveTestUnit('''
+main() {
+ final int v = 1;
+}
+''');
+ await assertNoAssistAt('1;', DartAssistKind.REMOVE_TYPE_ANNOTATION);
+ }
+
test_removeTypeAnnotation_localVariable_OK() async {
resolveTestUnit('''
main() {
@@ -3331,6 +3317,14 @@
''');
}
+ test_removeTypeAnnotation_topLevelVariable_BAD_syntheticName() async {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+MyType
+''');
+ await assertNoAssistAt('MyType', DartAssistKind.REMOVE_TYPE_ANNOTATION);
+ }
+
test_removeTypeAnnotation_topLevelVariable_OK() async {
resolveTestUnit('''
int V = 1;
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 0d89134..da08e99 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -27,12 +27,15 @@
main() {
initializeTestEnvironment();
defineReflectiveTests(FixProcessorTest);
+ defineReflectiveTests(LintFixTest);
}
typedef bool AnalysisErrorFilter(AnalysisError error);
-@reflectiveTest
-class FixProcessorTest extends AbstractSingleUnitTest {
+/**
+ * Base class for fix processor tests.
+ */
+class BaseFixProcessorTest extends AbstractSingleUnitTest {
AnalysisErrorFilter errorFilter = (AnalysisError error) {
return error.errorCode != HintCode.UNUSED_CATCH_CLAUSE &&
error.errorCode != HintCode.UNUSED_CATCH_STACK &&
@@ -112,6 +115,80 @@
verifyNoTestUnitErrors = false;
}
+ /**
+ * Computes fixes and verifies that there is a fix of the given kind.
+ */
+ Future<Fix> _assertHasFix(FixKind kind, AnalysisError error) async {
+ List<Fix> fixes = await _computeFixes(error);
+ for (Fix fix in fixes) {
+ if (fix.kind == kind) {
+ return fix;
+ }
+ }
+ throw fail('Expected to find fix $kind in\n${fixes.join('\n')}');
+ }
+
+ void _assertLinkedGroup(LinkedEditGroup group, List<String> expectedStrings,
+ [List<LinkedEditSuggestion> expectedSuggestions]) {
+ List<Position> expectedPositions = _findResultPositions(expectedStrings);
+ expect(group.positions, unorderedEquals(expectedPositions));
+ if (expectedSuggestions != null) {
+ expect(group.suggestions, unorderedEquals(expectedSuggestions));
+ }
+ }
+
+ /**
+ * Computes fixes for the given [error] in [testUnit].
+ */
+ Future<List<Fix>> _computeFixes(AnalysisError error) async {
+ DartFixContext dartContext = new DartFixContextImpl(
+ new FixContextImpl(provider, context, error), testUnit);
+ FixProcessor processor = new FixProcessor(dartContext);
+ return processor.compute();
+ }
+
+ /**
+ * Configures the [SourceFactory] to have the `my_pkg` package in
+ * `/packages/my_pkg/lib` folder.
+ */
+ void _configureMyPkg(String myLibCode) {
+ provider.newFile('/packages/my_pkg/lib/my_lib.dart', myLibCode);
+ // configure SourceFactory
+ Folder myPkgFolder = provider.getResource('/packages/my_pkg/lib');
+ UriResolver pkgResolver = new PackageMapUriResolver(provider, {
+ 'my_pkg': [myPkgFolder]
+ });
+ context.sourceFactory = new SourceFactory(
+ [AbstractContextTest.SDK_RESOLVER, pkgResolver, resourceResolver]);
+ // force 'my_pkg' resolution
+ addSource('/tmp/other.dart', "import 'package:my_pkg/my_lib.dart';");
+ }
+
+ AnalysisError _findErrorToFix() {
+ List<AnalysisError> errors = context.computeErrors(testSource);
+ if (errorFilter != null) {
+ errors = errors.where(errorFilter).toList();
+ }
+ expect(errors, hasLength(1));
+ return errors[0];
+ }
+
+ List<Position> _findResultPositions(List<String> searchStrings) {
+ List<Position> positions = <Position>[];
+ for (String search in searchStrings) {
+ int offset = resultCode.indexOf(search);
+ positions.add(new Position(testFile, offset));
+ }
+ return positions;
+ }
+
+ void _performAnalysis() {
+ while (context.performAnalysisTask().hasMoreWork);
+ }
+}
+
+@reflectiveTest
+class FixProcessorTest extends BaseFixProcessorTest {
test_addFieldFormalParameters_hasRequiredParameter() async {
resolveTestUnit('''
class Test {
@@ -4946,75 +5023,211 @@
}
''');
}
+}
+@reflectiveTest
+class LintFixTest extends BaseFixProcessorTest {
+ AnalysisError error;
+
+ Future applyFix(FixKind kind) async {
+ fix = await _assertHasFix(kind, error);
+ change = fix.change;
+ // apply to "file"
+ List<SourceFileEdit> fileEdits = change.edits;
+ expect(fileEdits, hasLength(1));
+ resultCode = SourceEdit.applySequence(testCode, change.edits[0].edits);
+ }
+
+ void findLint(String src, String lintCode) {
+ int errorOffset = src.indexOf('/*LINT*/');
+ resolveTestUnit(src.replaceAll('/*LINT*/', ''));
+ error = new AnalysisError(testUnit.element.source, errorOffset, 1,
+ new LintCode(lintCode, '<ignored>'));
+ }
+
+ test_lint_addMissingOverride_field() async {
+ String src = '''
+class abstract Test {
+ int get t;
+}
+class Sub extends Test {
+ int /*LINT*/t = 42;
+}
+''';
+ findLint(src, LintNames.annotate_overrides);
+
+ await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+ verifyResult('''
+class abstract Test {
+ int get t;
+}
+class Sub extends Test {
+ @override
+ int t = 42;
+}
+''');
+ }
+
+ test_lint_addMissingOverride_getter() async {
+ String src = '''
+class Test {
+ int get t => null;
+}
+class Sub extends Test {
+ int get /*LINT*/t => null;
+}
+''';
+ findLint(src, LintNames.annotate_overrides);
+
+ await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+ verifyResult('''
+class Test {
+ int get t => null;
+}
+class Sub extends Test {
+ @override
+ int get t => null;
+}
+''');
+ }
+
+ test_lint_addMissingOverride_method() async {
+ String src = '''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
+ void /*LINT*/t() { }
+}
+''';
+ findLint(src, LintNames.annotate_overrides);
+
+ await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+ verifyResult('''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
+ @override
+ void t() { }
+}
+''');
+ }
+
+ test_lint_addMissingOverride_method_with_doc_comment() async {
+ String src = '''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
+ /// Doc comment.
+ void /*LINT*/t() { }
+}
+''';
+ findLint(src, LintNames.annotate_overrides);
+
+ await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+ verifyResult('''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
+ /// Doc comment.
+ @override
+ void t() { }
+}
+''');
+ }
+
+ test_lint_addMissingOverride_method_with_doc_comment_2() async {
+ String src = '''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
/**
- * Computes fixes and verifies that there is a fix of the given kind.
+ * Doc comment.
*/
- Future<Fix> _assertHasFix(FixKind kind, AnalysisError error) async {
- List<Fix> fixes = await _computeFixes(error);
- for (Fix fix in fixes) {
- if (fix.kind == kind) {
- return fix;
- }
- }
- throw fail('Expected to find fix $kind in\n${fixes.join('\n')}');
- }
+ void /*LINT*/t() { }
+}
+''';
+ findLint(src, LintNames.annotate_overrides);
- void _assertLinkedGroup(LinkedEditGroup group, List<String> expectedStrings,
- [List<LinkedEditSuggestion> expectedSuggestions]) {
- List<Position> expectedPositions = _findResultPositions(expectedStrings);
- expect(group.positions, unorderedEquals(expectedPositions));
- if (expectedSuggestions != null) {
- expect(group.suggestions, unorderedEquals(expectedSuggestions));
- }
- }
+ await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+ verifyResult('''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
/**
- * Computes fixes for the given [error] in [testUnit].
+ * Doc comment.
*/
- Future<List<Fix>> _computeFixes(AnalysisError error) async {
- DartFixContext dartContext = new DartFixContextImpl(
- new FixContextImpl(provider, context, error), testUnit);
- FixProcessor processor = new FixProcessor(dartContext);
- return processor.compute();
+ @override
+ void t() { }
+}
+''');
}
- /**
- * Configures the [SourceFactory] to have the `my_pkg` package in
- * `/packages/my_pkg/lib` folder.
- */
- void _configureMyPkg(String myLibCode) {
- provider.newFile('/packages/my_pkg/lib/my_lib.dart', myLibCode);
- // configure SourceFactory
- Folder myPkgFolder = provider.getResource('/packages/my_pkg/lib');
- UriResolver pkgResolver = new PackageMapUriResolver(provider, {
- 'my_pkg': [myPkgFolder]
- });
- context.sourceFactory = new SourceFactory(
- [AbstractContextTest.SDK_RESOLVER, pkgResolver, resourceResolver]);
- // force 'my_pkg' resolution
- addSource('/tmp/other.dart', "import 'package:my_pkg/my_lib.dart';");
+ test_lint_addMissingOverride_method_with_doc_comment_and_metadata() async {
+ String src = '''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
+ /// Doc comment.
+ @foo
+ void /*LINT*/t() { }
+}
+''';
+ findLint(src, LintNames.annotate_overrides);
+
+ await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+ verifyResult('''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
+ /// Doc comment.
+ @override
+ @foo
+ void t() { }
+}
+''');
}
- AnalysisError _findErrorToFix() {
- List<AnalysisError> errors = context.computeErrors(testSource);
- if (errorFilter != null) {
- errors = errors.where(errorFilter).toList();
- }
- expect(errors, hasLength(1));
- return errors[0];
+ test_lint_addMissingOverride_method_with_non_doc_comment() async {
+ String src = '''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
+ // Non-doc comment.
+ void /*LINT*/t() { }
+}
+''';
+ findLint(src, LintNames.annotate_overrides);
+
+ await applyFix(DartFixKind.LINT_ADD_OVERRIDE);
+
+ verifyResult('''
+class Test {
+ void t() { }
+}
+class Sub extends Test {
+ // Non-doc comment.
+ @override
+ void t() { }
+}
+''');
}
- List<Position> _findResultPositions(List<String> searchStrings) {
- List<Position> positions = <Position>[];
- for (String search in searchStrings) {
- int offset = resultCode.indexOf(search);
- positions.add(new Position(testFile, offset));
- }
- return positions;
- }
-
- void _performAnalysis() {
- while (context.performAnalysisTask().hasMoreWork);
+ void verifyResult(String expectedResult) {
+ expect(resultCode, expectedResult);
}
}
diff --git a/pkg/analyzer/.analysis_options b/pkg/analyzer/.analysis_options
index 7b230dd..7c974bd 100644
--- a/pkg/analyzer/.analysis_options
+++ b/pkg/analyzer/.analysis_options
@@ -1,4 +1,5 @@
linter:
rules:
- - unnecessary_brace_in_string_interp
+ - annotate_overrides
- empty_constructor_bodies
+ - unnecessary_brace_in_string_interp
diff --git a/pkg/analyzer/example/parser_driver.dart b/pkg/analyzer/example/parser_driver.dart
index c302e41..ccc5bb9 100644
--- a/pkg/analyzer/example/parser_driver.dart
+++ b/pkg/analyzer/example/parser_driver.dart
@@ -43,6 +43,7 @@
}
class _ASTVisitor extends GeneralizingAstVisitor {
+ @override
visitNode(AstNode node) {
print('${node.runtimeType} : <"$node">');
return super.visitNode(node);
@@ -52,5 +53,6 @@
class _ErrorCollector extends AnalysisErrorListener {
List<AnalysisError> errors;
_ErrorCollector() : errors = new List<AnalysisError>();
+ @override
onError(error) => errors.add(error);
}
diff --git a/pkg/analyzer/example/resolver_driver.dart b/pkg/analyzer/example/resolver_driver.dart
index fa2af7f..3ba20f7 100755
--- a/pkg/analyzer/example/resolver_driver.dart
+++ b/pkg/analyzer/example/resolver_driver.dart
@@ -57,6 +57,7 @@
'Usage: resolve_driver <path_to_sdk> <file_to_resolve> [<packages_root>]';
class _ASTVisitor extends GeneralizingAstVisitor {
+ @override
visitNode(AstNode node) {
var lines = <String>['${node.runtimeType} : <"$node">'];
if (node is SimpleIdentifier) {
diff --git a/pkg/analyzer/lib/analyzer.dart b/pkg/analyzer/lib/analyzer.dart
index 0ac8cf4..fffb006 100644
--- a/pkg/analyzer/lib/analyzer.dart
+++ b/pkg/analyzer/lib/analyzer.dart
@@ -127,5 +127,6 @@
/// Whether any errors where collected.
bool get hasErrors => !_errors.isEmpty;
+ @override
void onError(AnalysisError error) => _errors.add(error);
}
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 547094b..d0680c4 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -53,8 +53,8 @@
* the same kind (single line or multi-line), this class doesn't enforce that
* restriction.
*
- * > adjacentStrings ::=
- * > [StringLiteral] [StringLiteral]+
+ * adjacentStrings ::=
+ * [StringLiteral] [StringLiteral]+
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -110,11 +110,11 @@
/**
* An annotation that can be associated with an AST node.
*
- * > metadata ::=
- * > annotation*
- * >
- * > annotation ::=
- * > '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+ * metadata ::=
+ * annotation*
+ *
+ * annotation ::=
+ * '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -215,12 +215,12 @@
* A list of arguments in the invocation of an executable element (that is, a
* function, method, or constructor).
*
- * > argumentList ::=
- * > '(' arguments? ')'
- * >
- * > arguments ::=
- * > [NamedExpression] (',' [NamedExpression])*
- * > | [Expression] (',' [Expression])* (',' [NamedExpression])*
+ * argumentList ::=
+ * '(' arguments? ')'
+ *
+ * arguments ::=
+ * [NamedExpression] (',' [NamedExpression])*
+ * | [Expression] (',' [Expression])* (',' [NamedExpression])*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -279,8 +279,8 @@
/**
* An as expression.
*
- * > asExpression ::=
- * > [Expression] 'as' [TypeName]
+ * asExpression ::=
+ * [Expression] 'as' [TypeName]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -326,8 +326,8 @@
/**
* An assert statement.
*
- * > assertStatement ::=
- * > 'assert' '(' [Expression] ')' ';'
+ * assertStatement ::=
+ * 'assert' '(' [Expression] ')' ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -423,8 +423,8 @@
/**
* An assignment expression.
*
- * > assignmentExpression ::=
- * > [Expression] operator [Expression]
+ * assignmentExpression ::=
+ * [Expression] operator [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -853,8 +853,8 @@
/**
* An await expression.
*
- * > awaitExpression ::=
- * > 'await' [Expression]
+ * awaitExpression ::=
+ * 'await' [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -889,8 +889,8 @@
/**
* A binary (infix) expression.
*
- * > binaryExpression ::=
- * > [Expression] [Token] [Expression]
+ * binaryExpression ::=
+ * [Expression] [Token] [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -975,8 +975,8 @@
/**
* A sequence of statements.
*
- * > block ::=
- * > '{' statement* '}'
+ * block ::=
+ * '{' statement* '}'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1017,8 +1017,8 @@
/**
* A function body that consists of a block of statements.
*
- * > blockFunctionBody ::=
- * > ('async' | 'async' '*' | 'sync' '*')? [Block]
+ * blockFunctionBody ::=
+ * ('async' | 'async' '*' | 'sync' '*')? [Block]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1056,8 +1056,8 @@
/**
* A boolean literal expression.
*
- * > booleanLiteral ::=
- * > 'false' | 'true'
+ * booleanLiteral ::=
+ * 'false' | 'true'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1086,8 +1086,8 @@
/**
* A break statement.
*
- * > breakStatement ::=
- * > 'break' [SimpleIdentifier]? ';'
+ * breakStatement ::=
+ * 'break' [SimpleIdentifier]? ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1154,16 +1154,16 @@
* There are three kinds of expressions that can be used in a cascade
* expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
*
- * > cascadeExpression ::=
- * > [Expression] cascadeSection*
- * >
- * > cascadeSection ::=
- * > '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
- * > (assignmentOperator expressionWithoutCascade)?
- * >
- * > cascadeSelector ::=
- * > '[ ' expression '] '
- * > | identifier
+ * cascadeExpression ::=
+ * [Expression] cascadeSection*
+ *
+ * cascadeSection ::=
+ * '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
+ * (assignmentOperator expressionWithoutCascade)?
+ *
+ * cascadeSelector ::=
+ * '[ ' expression '] '
+ * | identifier
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1195,12 +1195,12 @@
/**
* A catch clause within a try statement.
*
- * > onPart ::=
- * > catchPart [Block]
- * > | 'on' type catchPart? [Block]
- * >
- * > catchPart ::=
- * > 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
+ * onPart ::=
+ * catchPart [Block]
+ * | 'on' type catchPart? [Block]
+ *
+ * catchPart ::=
+ * 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1326,11 +1326,11 @@
/**
* The declaration of a class.
*
- * > classDeclaration ::=
- * > 'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
- * > ([ExtendsClause] [WithClause]?)?
- * > [ImplementsClause]?
- * > '{' [ClassMember]* '}'
+ * classDeclaration ::=
+ * 'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
+ * ([ExtendsClause] [WithClause]?)?
+ * [ImplementsClause]?
+ * '{' [ClassMember]* '}'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1497,11 +1497,11 @@
/**
* A class type alias.
*
- * > classTypeAlias ::=
- * > [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
- * >
- * > mixinApplication ::=
- * > [TypeName] [WithClause] [ImplementsClause]? ';'
+ * classTypeAlias ::=
+ * [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+ *
+ * mixinApplication ::=
+ * [TypeName] [WithClause] [ImplementsClause]? ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1601,9 +1601,9 @@
/**
* A combinator associated with an import or export directive.
*
- * > combinator ::=
- * > [HideCombinator]
- * > | [ShowCombinator]
+ * combinator ::=
+ * [HideCombinator]
+ * | [ShowCombinator]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1624,20 +1624,20 @@
/**
* A comment within the source code.
*
- * > comment ::=
- * > endOfLineComment
- * > | blockComment
- * > | documentationComment
- * >
- * > endOfLineComment ::=
- * > '//' (CHARACTER - EOL)* EOL
- * >
- * > blockComment ::=
- * > '/ *' CHARACTER* '*/'
- * >
- * > documentationComment ::=
- * > '/ **' (CHARACTER | [CommentReference])* '*/'
- * > | ('///' (CHARACTER - EOL)* EOL)+
+ * comment ::=
+ * endOfLineComment
+ * | blockComment
+ * | documentationComment
+ *
+ * endOfLineComment ::=
+ * '//' (CHARACTER - EOL)* EOL
+ *
+ * blockComment ::=
+ * '/ *' CHARACTER* '*/'
+ *
+ * documentationComment ::=
+ * '/ **' (CHARACTER | [CommentReference])* '*/'
+ * | ('///' (CHARACTER - EOL)* EOL)+
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1706,8 +1706,8 @@
/**
* A reference to a Dart element that is found within a documentation comment.
*
- * > commentReference ::=
- * > '[' 'new'? [Identifier] ']'
+ * commentReference ::=
+ * '[' 'new'? [Identifier] ']'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1750,19 +1750,19 @@
* order even if lexical order does not conform to the restrictions of the
* grammar.
*
- * > compilationUnit ::=
- * > directives declarations
- * >
- * > directives ::=
- * > [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
- * > | [PartOfDirective]
- * >
- * > namespaceDirective ::=
- * > [ImportDirective]
- * > | [ExportDirective]
- * >
- * > declarations ::=
- * > [CompilationUnitMember]*
+ * compilationUnit ::=
+ * directives declarations
+ *
+ * directives ::=
+ * [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
+ * | [PartOfDirective]
+ *
+ * namespaceDirective ::=
+ * [ImportDirective]
+ * | [ExportDirective]
+ *
+ * declarations ::=
+ * [CompilationUnitMember]*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1848,13 +1848,13 @@
* A node that declares one or more names within the scope of a compilation
* unit.
*
- * > compilationUnitMember ::=
- * > [ClassDeclaration]
- * > | [TypeAlias]
- * > | [FunctionDeclaration]
- * > | [MethodDeclaration]
- * > | [VariableDeclaration]
- * > | [VariableDeclaration]
+ * compilationUnitMember ::=
+ * [ClassDeclaration]
+ * | [TypeAlias]
+ * | [FunctionDeclaration]
+ * | [MethodDeclaration]
+ * | [VariableDeclaration]
+ * | [VariableDeclaration]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1863,8 +1863,8 @@
/**
* A conditional expression.
*
- * > conditionalExpression ::=
- * > [Expression] '?' [Expression] ':' [Expression]
+ * conditionalExpression ::=
+ * [Expression] '?' [Expression] ':' [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -1942,14 +1942,14 @@
/**
* A configuration in either an import or export directive.
*
- * > configuration ::=
- * > 'if' '(' test ')' uri
- * >
- * > test ::=
- * > dottedName ('==' stringLiteral)?
- * >
- * > dottedName ::=
- * > identifier ('.' identifier)*
+ * configuration ::=
+ * 'if' '(' test ')' uri
+ *
+ * test ::=
+ * dottedName ('==' stringLiteral)?
+ *
+ * dottedName ::=
+ * identifier ('.' identifier)*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2047,23 +2047,23 @@
/**
* A constructor declaration.
*
- * > constructorDeclaration ::=
- * > constructorSignature [FunctionBody]?
- * > | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
- * >
- * > constructorSignature ::=
- * > 'external'? constructorName formalParameterList initializerList?
- * > | 'external'? 'factory' factoryName formalParameterList initializerList?
- * > | 'external'? 'const' constructorName formalParameterList initializerList?
- * >
- * > constructorName ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])?
- * >
- * > factoryName ::=
- * > [Identifier] ('.' [SimpleIdentifier])?
- * >
- * > initializerList ::=
- * > ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
+ * constructorDeclaration ::=
+ * constructorSignature [FunctionBody]?
+ * | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
+ *
+ * constructorSignature ::=
+ * 'external'? constructorName formalParameterList initializerList?
+ * | 'external'? 'factory' factoryName formalParameterList initializerList?
+ * | 'external'? 'const' constructorName formalParameterList initializerList?
+ *
+ * constructorName ::=
+ * [SimpleIdentifier] ('.' [SimpleIdentifier])?
+ *
+ * factoryName ::=
+ * [Identifier] ('.' [SimpleIdentifier])?
+ *
+ * initializerList ::=
+ * ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2229,8 +2229,8 @@
/**
* The initialization of a field within a constructor's initialization list.
*
- * > fieldInitializer ::=
- * > ('this' '.')? [SimpleIdentifier] '=' [Expression]
+ * fieldInitializer ::=
+ * ('this' '.')? [SimpleIdentifier] '=' [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2307,10 +2307,10 @@
/**
* A node that can occur in the initializer list of a constructor declaration.
*
- * > constructorInitializer ::=
- * > [SuperConstructorInvocation]
- * > | [ConstructorFieldInitializer]
- * > | [RedirectingConstructorInvocation]
+ * constructorInitializer ::=
+ * [SuperConstructorInvocation]
+ * | [ConstructorFieldInitializer]
+ * | [RedirectingConstructorInvocation]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2319,8 +2319,8 @@
/**
* The name of a constructor.
*
- * > constructorName ::=
- * > type ('.' identifier)?
+ * constructorName ::=
+ * type ('.' identifier)?
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2382,8 +2382,8 @@
/**
* A continue statement.
*
- * > continueStatement ::=
- * > 'continue' [SimpleIdentifier]? ';'
+ * continueStatement ::=
+ * 'continue' [SimpleIdentifier]? ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2462,8 +2462,8 @@
/**
* The declaration of a single identifier.
*
- * > declaredIdentifier ::=
- * > [Annotation] finalConstVarOrType [SimpleIdentifier]
+ * declaredIdentifier ::=
+ * [Annotation] finalConstVarOrType [SimpleIdentifier]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2535,11 +2535,11 @@
* that are both represented by this class: named formal parameters and
* positional formal parameters.
*
- * > defaultFormalParameter ::=
- * > [NormalFormalParameter] ('=' [Expression])?
- * >
- * > defaultNamedParameter ::=
- * > [NormalFormalParameter] (':' [Expression])?
+ * defaultFormalParameter ::=
+ * [NormalFormalParameter] ('=' [Expression])?
+ *
+ * defaultNamedParameter ::=
+ * [NormalFormalParameter] (':' [Expression])?
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2598,12 +2598,12 @@
/**
* A node that represents a directive.
*
- * > directive ::=
- * > [ExportDirective]
- * > | [ImportDirective]
- * > | [LibraryDirective]
- * > | [PartDirective]
- * > | [PartOfDirective]
+ * directive ::=
+ * [ExportDirective]
+ * | [ImportDirective]
+ * | [LibraryDirective]
+ * | [PartDirective]
+ * | [PartOfDirective]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2629,8 +2629,8 @@
/**
* A do statement.
*
- * > doStatement ::=
- * > 'do' [Statement] 'while' '(' [Expression] ')' ';'
+ * doStatement ::=
+ * 'do' [Statement] 'while' '(' [Expression] ')' ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2722,8 +2722,8 @@
/**
* A dotted name, used in a configuration within an import or export directive.
*
- * > dottedName ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ * dottedName ::=
+ * [SimpleIdentifier] ('.' [SimpleIdentifier])*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2742,12 +2742,12 @@
/**
* A floating point literal expression.
*
- * > doubleLiteral ::=
- * > decimalDigit+ ('.' decimalDigit*)? exponent?
- * > | '.' decimalDigit+ exponent?
- * >
- * > exponent ::=
- * > ('e' | 'E') ('+' | '-')? decimalDigit+
+ * doubleLiteral ::=
+ * decimalDigit+ ('.' decimalDigit*)? exponent?
+ * | '.' decimalDigit+ exponent?
+ *
+ * exponent ::=
+ * ('e' | 'E') ('+' | '-')? decimalDigit+
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2782,8 +2782,8 @@
* An empty function body, which can only appear in constructors or abstract
* methods.
*
- * > emptyFunctionBody ::=
- * > ';'
+ * emptyFunctionBody ::=
+ * ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2809,8 +2809,8 @@
/**
* An empty statement.
*
- * > emptyStatement ::=
- * > ';'
+ * emptyStatement ::=
+ * ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2861,8 +2861,8 @@
/**
* The declaration of an enumeration.
*
- * > enumType ::=
- * > metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
+ * enumType ::=
+ * metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2924,8 +2924,8 @@
/**
* An export directive.
*
- * > exportDirective ::=
- * > [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+ * exportDirective ::=
+ * [Annotation] 'export' [StringLiteral] [Combinator]* ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -2949,10 +2949,10 @@
/**
* A node that represents an expression.
*
- * > expression ::=
- * > [AssignmentExpression]
- * > | [ConditionalExpression] cascadeSection*
- * > | [ThrowExpression]
+ * expression ::=
+ * [AssignmentExpression]
+ * | [ConditionalExpression] cascadeSection*
+ * | [ThrowExpression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3043,8 +3043,8 @@
/**
* A function body consisting of a single expression.
*
- * > expressionFunctionBody ::=
- * > 'async'? '=>' [Expression] ';'
+ * expressionFunctionBody ::=
+ * 'async'? '=>' [Expression] ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3099,8 +3099,8 @@
/**
* An expression used as a statement.
*
- * > expressionStatement ::=
- * > [Expression]? ';'
+ * expressionStatement ::=
+ * [Expression]? ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3136,8 +3136,8 @@
/**
* The "extends" clause in a class declaration.
*
- * > extendsClause ::=
- * > 'extends' [TypeName]
+ * extendsClause ::=
+ * 'extends' [TypeName]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3172,8 +3172,8 @@
/**
* The declaration of one or more fields of the same type.
*
- * > fieldDeclaration ::=
- * > 'static'? [VariableDeclarationList] ';'
+ * fieldDeclaration ::=
+ * 'static'? [VariableDeclarationList] ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3231,9 +3231,9 @@
/**
* A field formal parameter.
*
- * > fieldFormalParameter ::=
- * > ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
- * > 'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
+ * fieldFormalParameter ::=
+ * ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+ * 'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3331,9 +3331,9 @@
/**
* A for-each statement.
*
- * > forEachStatement ::=
- * > 'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
- * > | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
+ * forEachStatement ::=
+ * 'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
+ * | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3466,9 +3466,9 @@
/**
* A node representing a parameter to a function.
*
- * > formalParameter ::=
- * > [NormalFormalParameter]
- * > | [DefaultFormalParameter]
+ * formalParameter ::=
+ * [NormalFormalParameter]
+ * | [DefaultFormalParameter]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3517,23 +3517,23 @@
* flattened into a single list, which can have any or all kinds of parameters
* (normal, named, and positional) in any order.
*
- * > formalParameterList ::=
- * > '(' ')'
- * > | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
- * > | '(' optionalFormalParameters ')'
- * >
- * > normalFormalParameters ::=
- * > [NormalFormalParameter] (',' [NormalFormalParameter])*
- * >
- * > optionalFormalParameters ::=
- * > optionalPositionalFormalParameters
- * > | namedFormalParameters
- * >
- * > optionalPositionalFormalParameters ::=
- * > '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
- * >
- * > namedFormalParameters ::=
- * > '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
+ * formalParameterList ::=
+ * '(' ')'
+ * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
+ * | '(' optionalFormalParameters ')'
+ *
+ * normalFormalParameters ::=
+ * [NormalFormalParameter] (',' [NormalFormalParameter])*
+ *
+ * optionalFormalParameters ::=
+ * optionalPositionalFormalParameters
+ * | namedFormalParameters
+ *
+ * optionalPositionalFormalParameters ::=
+ * '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
+ *
+ * namedFormalParameters ::=
+ * '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3610,15 +3610,15 @@
/**
* A for statement.
*
- * > forStatement ::=
- * > 'for' '(' forLoopParts ')' [Statement]
- * >
- * > forLoopParts ::=
- * > forInitializerStatement ';' [Expression]? ';' [Expression]?
- * >
- * > forInitializerStatement ::=
- * > [DefaultFormalParameter]
- * > | [Expression]?
+ * forStatement ::=
+ * 'for' '(' forLoopParts ')' [Statement]
+ *
+ * forLoopParts ::=
+ * forInitializerStatement ';' [Expression]? ';' [Expression]?
+ *
+ * forInitializerStatement ::=
+ * [DefaultFormalParameter]
+ * | [Expression]?
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3746,10 +3746,10 @@
/**
* A node representing the body of a function or method.
*
- * > functionBody ::=
- * > [BlockFunctionBody]
- * > | [EmptyFunctionBody]
- * > | [ExpressionFunctionBody]
+ * functionBody ::=
+ * [BlockFunctionBody]
+ * | [EmptyFunctionBody]
+ * | [ExpressionFunctionBody]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3811,12 +3811,12 @@
/**
* A top-level declaration.
*
- * > functionDeclaration ::=
- * > 'external' functionSignature
- * > | functionSignature [FunctionBody]
- * >
- * > functionSignature ::=
- * > [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+ * functionDeclaration ::=
+ * 'external' functionSignature
+ * | functionSignature [FunctionBody]
+ *
+ * functionSignature ::=
+ * [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3924,8 +3924,8 @@
/**
* A function expression.
*
- * > functionExpression ::=
- * > [TypeParameterList]? [FormalParameterList] [FunctionBody]
+ * functionExpression ::=
+ * [TypeParameterList]? [FormalParameterList] [FunctionBody]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -3989,8 +3989,8 @@
* [MethodInvocation] nodes. Invocations of getters and setters are represented
* by either [PrefixedIdentifier] or [PropertyAccess] nodes.
*
- * > functionExpressionInvocation ::=
- * > [Expression] [TypeArgumentList]? [ArgumentList]
+ * functionExpressionInvocation ::=
+ * [Expression] [TypeArgumentList]? [ArgumentList]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4020,6 +4020,7 @@
/**
* Return the expression producing the function being invoked.
*/
+ @override
Expression get function;
/**
@@ -4050,12 +4051,14 @@
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
* interface type that implements `Function`.
*/
+ @override
DartType get propagatedInvokeType;
/**
* Set the function type of the method invocation based on the propagated type
* information to the given [type].
*/
+ @override
void set propagatedInvokeType(DartType type);
/**
@@ -4080,12 +4083,14 @@
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
* interface type that implements `Function`.
*/
+ @override
DartType get staticInvokeType;
/**
* Set the function type of the method invocation based on the static type
* information to the given [type].
*/
+ @override
void set staticInvokeType(DartType type);
/**
@@ -4098,11 +4103,11 @@
/**
* A function type alias.
*
- * > functionTypeAlias ::=
- * > functionPrefix [TypeParameterList]? [FormalParameterList] ';'
- * >
- * > functionPrefix ::=
- * > [TypeName]? [SimpleIdentifier]
+ * functionTypeAlias ::=
+ * functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+ *
+ * functionPrefix ::=
+ * [TypeName]? [SimpleIdentifier]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4163,8 +4168,8 @@
/**
* A function-typed formal parameter.
*
- * > functionSignature ::=
- * > [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+ * functionSignature ::=
+ * [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4222,8 +4227,8 @@
* A combinator that restricts the names being imported to those that are not in
* a given list.
*
- * > hideCombinator ::=
- * > 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ * hideCombinator ::=
+ * 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4244,9 +4249,9 @@
/**
* A node that represents an identifier.
*
- * > identifier ::=
- * > [SimpleIdentifier]
- * > | [PrefixedIdentifier]
+ * identifier ::=
+ * [SimpleIdentifier]
+ * | [PrefixedIdentifier]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4292,8 +4297,8 @@
/**
* An if statement.
*
- * > ifStatement ::=
- * > 'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
+ * ifStatement ::=
+ * 'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4391,8 +4396,8 @@
/**
* The "implements" clause in an class declaration.
*
- * > implementsClause ::=
- * > 'implements' [TypeName] (',' [TypeName])*
+ * implementsClause ::=
+ * 'implements' [TypeName] (',' [TypeName])*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4422,9 +4427,9 @@
/**
* An import directive.
*
- * > importDirective ::=
- * > [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
- * > | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+ * importDirective ::=
+ * [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+ * | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4580,8 +4585,8 @@
/**
* An index expression.
*
- * > indexExpression ::=
- * > [Expression] '[' [Expression] ']'
+ * indexExpression ::=
+ * [Expression] '[' [Expression] ']'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4744,8 +4749,8 @@
/**
* An instance creation expression.
*
- * > newExpression ::=
- * > ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+ * newExpression ::=
+ * ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4813,16 +4818,16 @@
/**
* An integer literal expression.
*
- * > integerLiteral ::=
- * > decimalIntegerLiteral
- * > | hexadecimalIntegerLiteral
- * >
- * > decimalIntegerLiteral ::=
- * > decimalDigit+
- * >
- * > hexadecimalIntegerLiteral ::=
- * > '0x' hexadecimalDigit+
- * > | '0X' hexadecimalDigit+
+ * integerLiteral ::=
+ * decimalIntegerLiteral
+ * | hexadecimalIntegerLiteral
+ *
+ * decimalIntegerLiteral ::=
+ * decimalDigit+
+ *
+ * hexadecimalIntegerLiteral ::=
+ * '0x' hexadecimalDigit+
+ * | '0X' hexadecimalDigit+
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4856,9 +4861,9 @@
/**
* A node within a [StringInterpolation].
*
- * > interpolationElement ::=
- * > [InterpolationExpression]
- * > | [InterpolationString]
+ * interpolationElement ::=
+ * [InterpolationExpression]
+ * | [InterpolationString]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4867,9 +4872,9 @@
/**
* An expression embedded in a string interpolation.
*
- * > interpolationExpression ::=
- * > '$' [SimpleIdentifier]
- * > | '$' '{' [Expression] '}'
+ * interpolationExpression ::=
+ * '$' [SimpleIdentifier]
+ * | '$' '{' [Expression] '}'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -4922,8 +4927,8 @@
/**
* A non-empty substring of an interpolated string.
*
- * > interpolationString ::=
- * > characters
+ * interpolationString ::=
+ * characters
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5036,8 +5041,8 @@
/**
* An is expression.
*
- * > isExpression ::=
- * > [Expression] 'is' '!'? [TypeName]
+ * isExpression ::=
+ * [Expression] 'is' '!'? [TypeName]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5094,8 +5099,8 @@
/**
* A label on either a [LabeledStatement] or a [NamedExpression].
*
- * > label ::=
- * > [SimpleIdentifier] ':'
+ * label ::=
+ * [SimpleIdentifier] ':'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5130,8 +5135,8 @@
/**
* A statement that has a label associated with them.
*
- * > labeledStatement ::=
- * > [Label]+ [Statement]
+ * labeledStatement ::=
+ * [Label]+ [Statement]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5162,8 +5167,8 @@
/**
* A library directive.
*
- * > libraryDirective ::=
- * > [Annotation] 'library' [Identifier] ';'
+ * libraryDirective ::=
+ * [Annotation] 'library' [Identifier] ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5214,8 +5219,8 @@
/**
* The identifier for a library.
*
- * > libraryIdentifier ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ * libraryIdentifier ::=
+ * [SimpleIdentifier] ('.' [SimpleIdentifier])*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5235,8 +5240,8 @@
/**
* A list literal.
*
- * > listLiteral ::=
- * > 'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+ * listLiteral ::=
+ * 'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5283,14 +5288,14 @@
/**
* A node that represents a literal expression.
*
- * > literal ::=
- * > [BooleanLiteral]
- * > | [DoubleLiteral]
- * > | [IntegerLiteral]
- * > | [ListLiteral]
- * > | [MapLiteral]
- * > | [NullLiteral]
- * > | [StringLiteral]
+ * literal ::=
+ * [BooleanLiteral]
+ * | [DoubleLiteral]
+ * | [IntegerLiteral]
+ * | [ListLiteral]
+ * | [MapLiteral]
+ * | [NullLiteral]
+ * | [StringLiteral]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5299,9 +5304,9 @@
/**
* A literal map.
*
- * > mapLiteral ::=
- * > 'const'? ('<' [TypeName] (',' [TypeName])* '>')?
- * > '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+ * mapLiteral ::=
+ * 'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+ * '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5347,8 +5352,8 @@
/**
* A single key/value pair in a map literal.
*
- * > mapLiteralEntry ::=
- * > [Expression] ':' [Expression]
+ * mapLiteralEntry ::=
+ * [Expression] ':' [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5397,16 +5402,16 @@
/**
* A method declaration.
*
- * > methodDeclaration ::=
- * > methodSignature [FunctionBody]
- * >
- * > methodSignature ::=
- * > 'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
- * > methodName [TypeParameterList] [FormalParameterList]
- * >
- * > methodName ::=
- * > [SimpleIdentifier]
- * > | 'operator' [SimpleIdentifier]
+ * methodDeclaration ::=
+ * methodSignature [FunctionBody]
+ *
+ * methodSignature ::=
+ * 'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
+ * methodName [TypeParameterList] [FormalParameterList]
+ *
+ * methodName ::=
+ * [SimpleIdentifier]
+ * | 'operator' [SimpleIdentifier]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5570,8 +5575,8 @@
* [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
* represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
*
- * > methodInvocation ::=
- * > ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+ * methodInvocation ::=
+ * ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5632,12 +5637,14 @@
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
* interface type that implements `Function`.
*/
+ @override
DartType get propagatedInvokeType;
/**
* Set the function type of the method invocation based on the propagated type
* information to the given [type].
*/
+ @override
void set propagatedInvokeType(DartType type);
/**
@@ -5657,12 +5664,14 @@
* [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
* interface type that implements `Function`.
*/
+ @override
DartType get staticInvokeType;
/**
* Set the function type of the method invocation based on the static type
* information to the given [type].
*/
+ @override
void set staticInvokeType(DartType type);
/**
@@ -5709,8 +5718,8 @@
* An expression that has a name associated with it. They are used in method
* invocations when there are named parameters.
*
- * > namedExpression ::=
- * > [Label] [Expression]
+ * namedExpression ::=
+ * [Label] [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5753,9 +5762,9 @@
/**
* A node that represents a directive that impacts the namespace of a library.
*
- * > directive ::=
- * > [ExportDirective]
- * > | [ImportDirective]
+ * directive ::=
+ * [ExportDirective]
+ * | [ImportDirective]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5791,8 +5800,8 @@
/**
* The "native" clause in an class declaration.
*
- * > nativeClause ::=
- * > 'native' [StringLiteral]
+ * nativeClause ::=
+ * 'native' [StringLiteral]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5829,8 +5838,8 @@
* A function body that consists of a native keyword followed by a string
* literal.
*
- * > nativeFunctionBody ::=
- * > 'native' [SimpleStringLiteral] ';'
+ * nativeFunctionBody ::=
+ * 'native' [SimpleStringLiteral] ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5920,12 +5929,14 @@
* Return the node at the given [index] in the list or throw a [RangeError] if
* [index] is out of bounds.
*/
+ @override
E operator [](int index);
/**
* Set the node at the given [index] in the list to the given [node] or throw
* a [RangeError] if [index] is out of bounds.
*/
+ @override
void operator []=(int index, E node);
/**
@@ -5937,10 +5948,10 @@
/**
* A formal parameter that is required (is not optional).
*
- * > normalFormalParameter ::=
- * > [FunctionTypedFormalParameter]
- * > | [FieldFormalParameter]
- * > | [SimpleFormalParameter]
+ * normalFormalParameter ::=
+ * [FunctionTypedFormalParameter]
+ * | [FieldFormalParameter]
+ * | [SimpleFormalParameter]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -5977,8 +5988,8 @@
/**
* A null literal expression.
*
- * > nullLiteral ::=
- * > 'null'
+ * nullLiteral ::=
+ * 'null'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6002,8 +6013,8 @@
/**
* A parenthesized expression.
*
- * > parenthesizedExpression ::=
- * > '(' [Expression] ')'
+ * parenthesizedExpression ::=
+ * '(' [Expression] ')'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6048,8 +6059,8 @@
/**
* A part directive.
*
- * > partDirective ::=
- * > [Annotation] 'part' [StringLiteral] ';'
+ * partDirective ::=
+ * [Annotation] 'part' [StringLiteral] ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6090,8 +6101,8 @@
/**
* A part-of directive.
*
- * > partOfDirective ::=
- * > [Annotation] 'part' 'of' [Identifier] ';'
+ * partOfDirective ::=
+ * [Annotation] 'part' 'of' [Identifier] ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6155,8 +6166,8 @@
/**
* A postfix unary expression.
*
- * > postfixExpression ::=
- * > [Expression] [Token]
+ * postfixExpression ::=
+ * [Expression] [Token]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6229,8 +6240,8 @@
* An identifier that is prefixed or an access to an object property where the
* target of the property access is a simple identifier.
*
- * > prefixedIdentifier ::=
- * > [SimpleIdentifier] '.' [SimpleIdentifier]
+ * prefixedIdentifier ::=
+ * [SimpleIdentifier] '.' [SimpleIdentifier]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6288,8 +6299,8 @@
/**
* A prefix unary expression.
*
- * > prefixExpression ::=
- * > [Token] [Expression]
+ * prefixExpression ::=
+ * [Token] [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6365,8 +6376,8 @@
* as [PrefixedIdentifier] nodes in cases where the target is also a simple
* identifier.
*
- * > propertyAccess ::=
- * > [Expression] '.' [SimpleIdentifier]
+ * propertyAccess ::=
+ * [Expression] '.' [SimpleIdentifier]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6433,8 +6444,8 @@
* The invocation of a constructor in the same class from within a constructor's
* initialization list.
*
- * > redirectingConstructorInvocation ::=
- * > 'this' ('.' identifier)? arguments
+ * redirectingConstructorInvocation ::=
+ * 'this' ('.' identifier)? arguments
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6511,8 +6522,8 @@
/**
* A rethrow expression.
*
- * > rethrowExpression ::=
- * > 'rethrow'
+ * rethrowExpression ::=
+ * 'rethrow'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6536,8 +6547,8 @@
/**
* A return statement.
*
- * > returnStatement ::=
- * > 'return' [Expression]? ';'
+ * returnStatement ::=
+ * 'return' [Expression]? ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6586,8 +6597,8 @@
/**
* A script tag that can optionally occur at the beginning of a compilation unit.
*
- * > scriptTag ::=
- * > '#!' (~NEWLINE)* NEWLINE
+ * scriptTag ::=
+ * '#!' (~NEWLINE)* NEWLINE
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6611,8 +6622,8 @@
/**
* A combinator that restricts the names being imported to those in a given list.
*
- * > showCombinator ::=
- * > 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ * showCombinator ::=
+ * 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6633,8 +6644,8 @@
/**
* A simple formal parameter.
*
- * > simpleFormalParameter ::=
- * > ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+ * simpleFormalParameter ::=
+ * ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6679,12 +6690,12 @@
/**
* A simple identifier.
*
- * > simpleIdentifier ::=
- * > initialCharacter internalCharacter*
- * >
- * > initialCharacter ::= '_' | '$' | letter
- * >
- * > internalCharacter ::= '_' | '$' | letter | digit
+ * simpleIdentifier ::=
+ * initialCharacter internalCharacter*
+ *
+ * initialCharacter ::= '_' | '$' | letter
+ *
+ * internalCharacter ::= '_' | '$' | letter | digit
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6769,24 +6780,24 @@
/**
* A string literal expression that does not contain any interpolations.
*
- * > simpleStringLiteral ::=
- * > rawStringLiteral
- * > | basicStringLiteral
- * >
- * > rawStringLiteral ::=
- * > 'r' basicStringLiteral
- * >
- * > simpleStringLiteral ::=
- * > multiLineStringLiteral
- * > | singleLineStringLiteral
- * >
- * > multiLineStringLiteral ::=
- * > "'''" characters "'''"
- * > | '"""' characters '"""'
- * >
- * > singleLineStringLiteral ::=
- * > "'" characters "'"
- * > | '"' characters '"'
+ * simpleStringLiteral ::=
+ * rawStringLiteral
+ * | basicStringLiteral
+ *
+ * rawStringLiteral ::=
+ * 'r' basicStringLiteral
+ *
+ * simpleStringLiteral ::=
+ * multiLineStringLiteral
+ * | singleLineStringLiteral
+ *
+ * multiLineStringLiteral ::=
+ * "'''" characters "'''"
+ * | '"""' characters '"""'
+ *
+ * singleLineStringLiteral ::=
+ * "'" characters "'"
+ * | '"' characters '"'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6821,9 +6832,9 @@
/**
* A single string literal expression.
*
- * > singleStringLiteral ::=
- * > [SimpleStringLiteral]
- * > | [StringInterpolation]
+ * singleStringLiteral ::=
+ * [SimpleStringLiteral]
+ * | [StringInterpolation]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6859,21 +6870,21 @@
/**
* A node that represents a statement.
*
- * > statement ::=
- * > [Block]
- * > | [VariableDeclarationStatement]
- * > | [ForStatement]
- * > | [ForEachStatement]
- * > | [WhileStatement]
- * > | [DoStatement]
- * > | [SwitchStatement]
- * > | [IfStatement]
- * > | [TryStatement]
- * > | [BreakStatement]
- * > | [ContinueStatement]
- * > | [ReturnStatement]
- * > | [ExpressionStatement]
- * > | [FunctionDeclarationStatement]
+ * statement ::=
+ * [Block]
+ * | [VariableDeclarationStatement]
+ * | [ForStatement]
+ * | [ForEachStatement]
+ * | [WhileStatement]
+ * | [DoStatement]
+ * | [SwitchStatement]
+ * | [IfStatement]
+ * | [TryStatement]
+ * | [BreakStatement]
+ * | [ContinueStatement]
+ * | [ReturnStatement]
+ * | [ExpressionStatement]
+ * | [FunctionDeclarationStatement]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6888,9 +6899,9 @@
/**
* A string interpolation literal.
*
- * > stringInterpolation ::=
- * > ''' [InterpolationElement]* '''
- * > | '"' [InterpolationElement]* '"'
+ * stringInterpolation ::=
+ * ''' [InterpolationElement]* '''
+ * | '"' [InterpolationElement]* '"'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6910,10 +6921,10 @@
/**
* A string literal expression.
*
- * > stringLiteral ::=
- * > [SimpleStringLiteral]
- * > | [AdjacentStrings]
- * > | [StringInterpolation]
+ * stringLiteral ::=
+ * [SimpleStringLiteral]
+ * | [AdjacentStrings]
+ * | [StringInterpolation]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -6929,8 +6940,8 @@
* The invocation of a superclass' constructor from within a constructor's
* initialization list.
*
- * > superInvocation ::=
- * > 'super' ('.' [SimpleIdentifier])? [ArgumentList]
+ * superInvocation ::=
+ * 'super' ('.' [SimpleIdentifier])? [ArgumentList]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7008,8 +7019,8 @@
/**
* A super expression.
*
- * > superExpression ::=
- * > 'super'
+ * superExpression ::=
+ * 'super'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7033,8 +7044,8 @@
/**
* A case in a switch statement.
*
- * > switchCase ::=
- * > [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+ * switchCase ::=
+ * [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7061,8 +7072,8 @@
/**
* The default case in a switch statement.
*
- * > switchDefault ::=
- * > [SimpleIdentifier]* 'default' ':' [Statement]*
+ * switchDefault ::=
+ * [SimpleIdentifier]* 'default' ':' [Statement]*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7078,9 +7089,9 @@
/**
* An element within a switch statement.
*
- * > switchMember ::=
- * > switchCase
- * > | switchDefault
+ * switchMember ::=
+ * switchCase
+ * | switchDefault
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7123,8 +7134,8 @@
/**
* A switch statement.
*
- * > switchStatement ::=
- * > 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+ * switchStatement ::=
+ * 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7213,8 +7224,8 @@
/**
* A symbol literal expression.
*
- * > symbolLiteral ::=
- * > '#' (operator | (identifier ('.' identifier)*))
+ * symbolLiteral ::=
+ * '#' (operator | (identifier ('.' identifier)*))
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7244,8 +7255,8 @@
/**
* A this expression.
*
- * > thisExpression ::=
- * > 'this'
+ * thisExpression ::=
+ * 'this'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7269,8 +7280,8 @@
/**
* A throw expression.
*
- * > throwExpression ::=
- * > 'throw' [Expression]
+ * throwExpression ::=
+ * 'throw' [Expression]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7306,9 +7317,9 @@
/**
* The declaration of one or more top-level variables of the same type.
*
- * > topLevelVariableDeclaration ::=
- * > ('final' | 'const') type? staticFinalDeclarationList ';'
- * > | variableDeclaration ';'
+ * topLevelVariableDeclaration ::=
+ * ('final' | 'const') type? staticFinalDeclarationList ';'
+ * | variableDeclaration ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7349,11 +7360,11 @@
/**
* A try statement.
*
- * > tryStatement ::=
- * > 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
- * >
- * > finallyClause ::=
- * > 'finally' [Block]
+ * tryStatement ::=
+ * 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+ *
+ * finallyClause ::=
+ * 'finally' [Block]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7421,12 +7432,12 @@
/**
* The declaration of a type alias.
*
- * > typeAlias ::=
- * > 'typedef' typeAliasBody
- * >
- * > typeAliasBody ::=
- * > classTypeAlias
- * > | functionTypeAlias
+ * typeAlias ::=
+ * 'typedef' typeAliasBody
+ *
+ * typeAliasBody ::=
+ * classTypeAlias
+ * | functionTypeAlias
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7455,8 +7466,8 @@
/**
* A list of type arguments.
*
- * > typeArguments ::=
- * > '<' typeName (',' typeName)* '>'
+ * typeArguments ::=
+ * '<' typeName (',' typeName)* '>'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7497,9 +7508,9 @@
/**
* A literal that has a type associated with it.
*
- * > typedLiteral ::=
- * > [ListLiteral]
- * > | [MapLiteral]
+ * typedLiteral ::=
+ * [ListLiteral]
+ * | [MapLiteral]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7531,8 +7542,8 @@
/**
* The name of a type, which can optionally include type arguments.
*
- * > typeName ::=
- * > [Identifier] typeArguments?
+ * typeName ::=
+ * [Identifier] typeArguments?
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7589,8 +7600,8 @@
/**
* A type parameter.
*
- * > typeParameter ::=
- * > [SimpleIdentifier] ('extends' [TypeName])?
+ * typeParameter ::=
+ * [SimpleIdentifier] ('extends' [TypeName])?
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7645,8 +7656,8 @@
/**
* Type parameters within a declaration.
*
- * > typeParameterList ::=
- * > '<' [TypeParameter] (',' [TypeParameter])* '>'
+ * typeParameterList ::=
+ * '<' [TypeParameter] (',' [TypeParameter])* '>'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7678,10 +7689,10 @@
/**
* A directive that references a URI.
*
- * > uriBasedDirective ::=
- * > [ExportDirective]
- * > | [ImportDirective]
- * > | [PartDirective]
+ * uriBasedDirective ::=
+ * [ExportDirective]
+ * | [ImportDirective]
+ * | [PartDirective]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7751,8 +7762,8 @@
* An identifier that has an initial value associated with it. Instances of this
* class are always children of the class [VariableDeclarationList].
*
- * > variableDeclaration ::=
- * > [SimpleIdentifier] ('=' [Expression])?
+ * variableDeclaration ::=
+ * [SimpleIdentifier] ('=' [Expression])?
*
* TODO(paulberry): the grammar does not allow metadata to be associated with
* a VariableDeclaration, and currently we don't record comments for it either.
@@ -7823,14 +7834,14 @@
/**
* The declaration of one or more variables of the same type.
*
- * > variableDeclarationList ::=
- * > finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
- * >
- * > finalConstVarOrType ::=
- * > | 'final' [TypeName]?
- * > | 'const' [TypeName]?
- * > | 'var'
- * > | [TypeName]
+ * variableDeclarationList ::=
+ * finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+ *
+ * finalConstVarOrType ::=
+ * | 'final' [TypeName]?
+ * | 'const' [TypeName]?
+ * | 'var'
+ * | [TypeName]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7895,8 +7906,8 @@
* A list of variables that are being declared in a context where a statement is
* required.
*
- * > variableDeclarationStatement ::=
- * > [VariableDeclarationList] ';'
+ * variableDeclarationStatement ::=
+ * [VariableDeclarationList] ';'
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -7932,8 +7943,8 @@
/**
* A while statement.
*
- * > whileStatement ::=
- * > 'while' '(' [Expression] ')' [Statement]
+ * whileStatement ::=
+ * 'while' '(' [Expression] ')' [Statement]
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -8004,8 +8015,8 @@
/**
* The with clause in a class declaration.
*
- * > withClause ::=
- * > 'with' [TypeName] (',' [TypeName])*
+ * withClause ::=
+ * 'with' [TypeName] (',' [TypeName])*
*
* Clients may not extend, implement or mix-in this class.
*/
@@ -8035,8 +8046,8 @@
/**
* A yield statement.
*
- * > yieldStatement ::=
- * > 'yield' '*'? [Expression] ‘;’
+ * yieldStatement ::=
+ * 'yield' '*'? [Expression] ‘;’
*
* Clients may not extend, implement or mix-in this class.
*/
diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart
index 0cdb170..f76fb1d 100644
--- a/pkg/analyzer/lib/dart/ast/visitor.dart
+++ b/pkg/analyzer/lib/dart/ast/visitor.dart
@@ -93,6 +93,809 @@
/**
* An AST visitor that will recursively visit all of the nodes in an AST
+ * structure. For each node that is visited, the corresponding visit method on
+ * one or more other visitors (the 'delegates') will be invoked.
+ *
+ * For example, if an instance of this class is created with two delegates V1
+ * and V2, and that instance is used to visit the expression 'x + 1', then the
+ * following visit methods will be invoked:
+ * 1. V1.visitBinaryExpression
+ * 2. V2.visitBinaryExpression
+ * 3. V1.visitSimpleIdentifier
+ * 4. V2.visitSimpleIdentifier
+ * 5. V1.visitIntegerLiteral
+ * 6. V2.visitIntegerLiteral
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class DelegatingAstVisitor<T> implements AstVisitor<T> {
+ /**
+ * The delegates whose visit methods will be invoked.
+ */
+ final Iterable<AstVisitor<T>> _delegates;
+
+ /**
+ * Initialize a newly created visitor to use each of the given delegate
+ * visitors to visit the nodes of an AST structure.
+ */
+ DelegatingAstVisitor(this._delegates);
+
+ @override
+ T visitAdjacentStrings(AdjacentStrings node) {
+ _delegates.forEach((delegate) => delegate.visitAdjacentStrings(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitAnnotation(Annotation node) {
+ _delegates.forEach((delegate) => delegate.visitAnnotation(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitArgumentList(ArgumentList node) {
+ _delegates.forEach((delegate) => delegate.visitArgumentList(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitAsExpression(AsExpression node) {
+ _delegates.forEach((delegate) => delegate.visitAsExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitAssertStatement(AssertStatement node) {
+ _delegates.forEach((delegate) => delegate.visitAssertStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitAssignmentExpression(AssignmentExpression node) {
+ _delegates.forEach((delegate) => delegate.visitAssignmentExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitAwaitExpression(AwaitExpression node) {
+ _delegates.forEach((delegate) => delegate.visitAwaitExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitBinaryExpression(BinaryExpression node) {
+ _delegates.forEach((delegate) => delegate.visitBinaryExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitBlock(Block node) {
+ _delegates.forEach((delegate) => delegate.visitBlock(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitBlockFunctionBody(BlockFunctionBody node) {
+ _delegates.forEach((delegate) => delegate.visitBlockFunctionBody(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitBooleanLiteral(BooleanLiteral node) {
+ _delegates.forEach((delegate) => delegate.visitBooleanLiteral(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitBreakStatement(BreakStatement node) {
+ _delegates.forEach((delegate) => delegate.visitBreakStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitCascadeExpression(CascadeExpression node) {
+ _delegates.forEach((delegate) => delegate.visitCascadeExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitCatchClause(CatchClause node) {
+ _delegates.forEach((delegate) => delegate.visitCatchClause(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitClassDeclaration(ClassDeclaration node) {
+ _delegates.forEach((delegate) => delegate.visitClassDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitClassTypeAlias(ClassTypeAlias node) {
+ _delegates.forEach((delegate) => delegate.visitClassTypeAlias(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitComment(Comment node) {
+ _delegates.forEach((delegate) => delegate.visitComment(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitCommentReference(CommentReference node) {
+ _delegates.forEach((delegate) => delegate.visitCommentReference(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitCompilationUnit(CompilationUnit node) {
+ _delegates.forEach((delegate) => delegate.visitCompilationUnit(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitConditionalExpression(ConditionalExpression node) {
+ _delegates.forEach((delegate) => delegate.visitConditionalExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitConfiguration(Configuration node) {
+ _delegates.forEach((delegate) => delegate.visitConfiguration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitConstructorDeclaration(ConstructorDeclaration node) {
+ _delegates
+ .forEach((delegate) => delegate.visitConstructorDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+ _delegates
+ .forEach((delegate) => delegate.visitConstructorFieldInitializer(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitConstructorName(ConstructorName node) {
+ _delegates.forEach((delegate) => delegate.visitConstructorName(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitContinueStatement(ContinueStatement node) {
+ _delegates.forEach((delegate) => delegate.visitContinueStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitDeclaredIdentifier(DeclaredIdentifier node) {
+ _delegates.forEach((delegate) => delegate.visitDeclaredIdentifier(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitDefaultFormalParameter(DefaultFormalParameter node) {
+ _delegates
+ .forEach((delegate) => delegate.visitDefaultFormalParameter(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitDoStatement(DoStatement node) {
+ _delegates.forEach((delegate) => delegate.visitDoStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitDottedName(DottedName node) {
+ _delegates.forEach((delegate) => delegate.visitDottedName(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitDoubleLiteral(DoubleLiteral node) {
+ _delegates.forEach((delegate) => delegate.visitDoubleLiteral(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitEmptyFunctionBody(EmptyFunctionBody node) {
+ _delegates.forEach((delegate) => delegate.visitEmptyFunctionBody(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitEmptyStatement(EmptyStatement node) {
+ _delegates.forEach((delegate) => delegate.visitEmptyStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitEnumConstantDeclaration(EnumConstantDeclaration node) {
+ _delegates
+ .forEach((delegate) => delegate.visitEnumConstantDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitEnumDeclaration(EnumDeclaration node) {
+ _delegates.forEach((delegate) => delegate.visitEnumDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitExportDirective(ExportDirective node) {
+ _delegates.forEach((delegate) => delegate.visitExportDirective(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitExpressionFunctionBody(ExpressionFunctionBody node) {
+ _delegates
+ .forEach((delegate) => delegate.visitExpressionFunctionBody(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitExpressionStatement(ExpressionStatement node) {
+ _delegates.forEach((delegate) => delegate.visitExpressionStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitExtendsClause(ExtendsClause node) {
+ _delegates.forEach((delegate) => delegate.visitExtendsClause(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFieldDeclaration(FieldDeclaration node) {
+ _delegates.forEach((delegate) => delegate.visitFieldDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFieldFormalParameter(FieldFormalParameter node) {
+ _delegates.forEach((delegate) => delegate.visitFieldFormalParameter(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitForEachStatement(ForEachStatement node) {
+ _delegates.forEach((delegate) => delegate.visitForEachStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFormalParameterList(FormalParameterList node) {
+ _delegates.forEach((delegate) => delegate.visitFormalParameterList(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitForStatement(ForStatement node) {
+ _delegates.forEach((delegate) => delegate.visitForStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFunctionDeclaration(FunctionDeclaration node) {
+ _delegates.forEach((delegate) => delegate.visitFunctionDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
+ _delegates.forEach(
+ (delegate) => delegate.visitFunctionDeclarationStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFunctionExpression(FunctionExpression node) {
+ _delegates.forEach((delegate) => delegate.visitFunctionExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+ _delegates.forEach(
+ (delegate) => delegate.visitFunctionExpressionInvocation(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFunctionTypeAlias(FunctionTypeAlias node) {
+ _delegates.forEach((delegate) => delegate.visitFunctionTypeAlias(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+ _delegates.forEach(
+ (delegate) => delegate.visitFunctionTypedFormalParameter(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitHideCombinator(HideCombinator node) {
+ _delegates.forEach((delegate) => delegate.visitHideCombinator(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitIfStatement(IfStatement node) {
+ _delegates.forEach((delegate) => delegate.visitIfStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitImplementsClause(ImplementsClause node) {
+ _delegates.forEach((delegate) => delegate.visitImplementsClause(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitImportDirective(ImportDirective node) {
+ _delegates.forEach((delegate) => delegate.visitImportDirective(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitIndexExpression(IndexExpression node) {
+ _delegates.forEach((delegate) => delegate.visitIndexExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitInstanceCreationExpression(InstanceCreationExpression node) {
+ _delegates
+ .forEach((delegate) => delegate.visitInstanceCreationExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitIntegerLiteral(IntegerLiteral node) {
+ _delegates.forEach((delegate) => delegate.visitIntegerLiteral(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitInterpolationExpression(InterpolationExpression node) {
+ _delegates
+ .forEach((delegate) => delegate.visitInterpolationExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitInterpolationString(InterpolationString node) {
+ _delegates.forEach((delegate) => delegate.visitInterpolationString(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitIsExpression(IsExpression node) {
+ _delegates.forEach((delegate) => delegate.visitIsExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitLabel(Label node) {
+ _delegates.forEach((delegate) => delegate.visitLabel(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitLabeledStatement(LabeledStatement node) {
+ _delegates.forEach((delegate) => delegate.visitLabeledStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitLibraryDirective(LibraryDirective node) {
+ _delegates.forEach((delegate) => delegate.visitLibraryDirective(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitLibraryIdentifier(LibraryIdentifier node) {
+ _delegates.forEach((delegate) => delegate.visitLibraryIdentifier(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitListLiteral(ListLiteral node) {
+ _delegates.forEach((delegate) => delegate.visitListLiteral(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitMapLiteral(MapLiteral node) {
+ _delegates.forEach((delegate) => delegate.visitMapLiteral(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitMapLiteralEntry(MapLiteralEntry node) {
+ _delegates.forEach((delegate) => delegate.visitMapLiteralEntry(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitMethodDeclaration(MethodDeclaration node) {
+ _delegates.forEach((delegate) => delegate.visitMethodDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitMethodInvocation(MethodInvocation node) {
+ _delegates.forEach((delegate) => delegate.visitMethodInvocation(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitNamedExpression(NamedExpression node) {
+ _delegates.forEach((delegate) => delegate.visitNamedExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitNativeClause(NativeClause node) {
+ _delegates.forEach((delegate) => delegate.visitNativeClause(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitNativeFunctionBody(NativeFunctionBody node) {
+ _delegates.forEach((delegate) => delegate.visitNativeFunctionBody(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitNullLiteral(NullLiteral node) {
+ _delegates.forEach((delegate) => delegate.visitNullLiteral(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitParenthesizedExpression(ParenthesizedExpression node) {
+ _delegates
+ .forEach((delegate) => delegate.visitParenthesizedExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitPartDirective(PartDirective node) {
+ _delegates.forEach((delegate) => delegate.visitPartDirective(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitPartOfDirective(PartOfDirective node) {
+ _delegates.forEach((delegate) => delegate.visitPartOfDirective(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitPostfixExpression(PostfixExpression node) {
+ _delegates.forEach((delegate) => delegate.visitPostfixExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitPrefixedIdentifier(PrefixedIdentifier node) {
+ _delegates.forEach((delegate) => delegate.visitPrefixedIdentifier(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitPrefixExpression(PrefixExpression node) {
+ _delegates.forEach((delegate) => delegate.visitPrefixExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitPropertyAccess(PropertyAccess node) {
+ _delegates.forEach((delegate) => delegate.visitPropertyAccess(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitRedirectingConstructorInvocation(
+ RedirectingConstructorInvocation node) {
+ _delegates.forEach(
+ (delegate) => delegate.visitRedirectingConstructorInvocation(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitRethrowExpression(RethrowExpression node) {
+ _delegates.forEach((delegate) => delegate.visitRethrowExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitReturnStatement(ReturnStatement node) {
+ _delegates.forEach((delegate) => delegate.visitReturnStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitScriptTag(ScriptTag node) {
+ _delegates.forEach((delegate) => delegate.visitScriptTag(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitShowCombinator(ShowCombinator node) {
+ _delegates.forEach((delegate) => delegate.visitShowCombinator(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSimpleFormalParameter(SimpleFormalParameter node) {
+ _delegates.forEach((delegate) => delegate.visitSimpleFormalParameter(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSimpleIdentifier(SimpleIdentifier node) {
+ _delegates.forEach((delegate) => delegate.visitSimpleIdentifier(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSimpleStringLiteral(SimpleStringLiteral node) {
+ _delegates.forEach((delegate) => delegate.visitSimpleStringLiteral(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitStringInterpolation(StringInterpolation node) {
+ _delegates.forEach((delegate) => delegate.visitStringInterpolation(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+ _delegates
+ .forEach((delegate) => delegate.visitSuperConstructorInvocation(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSuperExpression(SuperExpression node) {
+ _delegates.forEach((delegate) => delegate.visitSuperExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSwitchCase(SwitchCase node) {
+ _delegates.forEach((delegate) => delegate.visitSwitchCase(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSwitchDefault(SwitchDefault node) {
+ _delegates.forEach((delegate) => delegate.visitSwitchDefault(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSwitchStatement(SwitchStatement node) {
+ _delegates.forEach((delegate) => delegate.visitSwitchStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitSymbolLiteral(SymbolLiteral node) {
+ _delegates.forEach((delegate) => delegate.visitSymbolLiteral(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitThisExpression(ThisExpression node) {
+ _delegates.forEach((delegate) => delegate.visitThisExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitThrowExpression(ThrowExpression node) {
+ _delegates.forEach((delegate) => delegate.visitThrowExpression(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+ _delegates
+ .forEach((delegate) => delegate.visitTopLevelVariableDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitTryStatement(TryStatement node) {
+ _delegates.forEach((delegate) => delegate.visitTryStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitTypeArgumentList(TypeArgumentList node) {
+ _delegates.forEach((delegate) => delegate.visitTypeArgumentList(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitTypeName(TypeName node) {
+ _delegates.forEach((delegate) => delegate.visitTypeName(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitTypeParameter(TypeParameter node) {
+ _delegates.forEach((delegate) => delegate.visitTypeParameter(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitTypeParameterList(TypeParameterList node) {
+ _delegates.forEach((delegate) => delegate.visitTypeParameterList(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitVariableDeclaration(VariableDeclaration node) {
+ _delegates.forEach((delegate) => delegate.visitVariableDeclaration(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitVariableDeclarationList(VariableDeclarationList node) {
+ _delegates
+ .forEach((delegate) => delegate.visitVariableDeclarationList(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitVariableDeclarationStatement(VariableDeclarationStatement node) {
+ _delegates.forEach(
+ (delegate) => delegate.visitVariableDeclarationStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitWhileStatement(WhileStatement node) {
+ _delegates.forEach((delegate) => delegate.visitWhileStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitWithClause(WithClause node) {
+ _delegates.forEach((delegate) => delegate.visitWithClause(node));
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ T visitYieldStatement(YieldStatement node) {
+ _delegates.forEach((delegate) => delegate.visitYieldStatement(node));
+ node.visitChildren(this);
+ return null;
+ }
+}
+
+/**
+ * An AST visitor that will recursively visit all of the nodes in an AST
* structure (like instances of the class [RecursiveAstVisitor]). In addition,
* when a node of a specific type is visited not only will the visit method for
* that specific type of node be invoked, but additional methods for the
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index d210229..e89eb22 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -635,6 +635,11 @@
bool get isPrivate;
/**
+ * Return `true` if this element has an annotation of the form '@protected'.
+ */
+ bool get isProtected;
+
+ /**
* Return `true` if this element is public. Public elements are visible within
* any library that imports the library in which they are declared.
*/
@@ -808,6 +813,13 @@
*/
bool get isOverride;
+
+ /**
+ * Return `true` if this annotation marks the associated member as being
+ * protected.
+ */
+ bool get isProtected;
+
/**
* Return `true` if this annotation marks the associated class as implementing
* a proxy object.
@@ -1313,6 +1325,12 @@
static const List<LibraryElement> EMPTY_LIST = const <LibraryElement>[];
/**
+ * Return a list containing the strongly connected component in the
+ * import/export graph in which the current library resides.
+ */
+ List<LibraryElement> get libraryCycle;
+
+ /**
* Return the compilation unit that defines this library.
*/
CompilationUnitElement get definingCompilationUnit;
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 05bd4e7..c9b3e96 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -47,6 +47,7 @@
FileSystemException(this.path, this.message);
+ @override
String toString() => 'FileSystemException(path=$path; message=$message)';
}
diff --git a/pkg/analyzer/lib/file_system/memory_file_system.dart b/pkg/analyzer/lib/file_system/memory_file_system.dart
index a8aca38..fd26eb1 100644
--- a/pkg/analyzer/lib/file_system/memory_file_system.dart
+++ b/pkg/analyzer/lib/file_system/memory_file_system.dart
@@ -29,6 +29,7 @@
int nextStamp = 0;
final Context _pathContext;
+ @override
final AbsolutePathContext absolutePathContext;
MemoryResourceProvider({bool isWindows: false})
@@ -211,6 +212,7 @@
@override
bool get exists => false;
+ @override
int get modificationStamp {
int stamp = _provider._pathToTimestamp[path];
if (stamp == null) {
@@ -249,6 +251,7 @@
@override
bool get exists => _provider._pathToResource[path] is _MemoryFile;
+ @override
int get modificationStamp {
int stamp = _provider._pathToTimestamp[path];
if (stamp == null) {
@@ -303,6 +306,7 @@
final _MemoryFile file;
+ @override
final Uri uri;
/**
@@ -453,6 +457,7 @@
*/
abstract class _MemoryResource implements Resource {
final MemoryResourceProvider _provider;
+ @override
final String path;
_MemoryResource(this._provider, this.path);
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index e7a83a4..cdfa9a6 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -31,6 +31,7 @@
*/
static final String SERVER_DIR = ".dartServer";
+ @override
final AbsolutePathContext absolutePathContext =
new AbsolutePathContext(io.Platform.isWindows);
diff --git a/pkg/analyzer/lib/source/path_filter.dart b/pkg/analyzer/lib/source/path_filter.dart
index f449610..816bc55 100644
--- a/pkg/analyzer/lib/source/path_filter.dart
+++ b/pkg/analyzer/lib/source/path_filter.dart
@@ -44,6 +44,7 @@
}
}
+ @override
String toString() {
StringBuffer sb = new StringBuffer();
for (Glob pattern in _ignorePatterns) {
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index cc1d41e..def719f 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -72,6 +72,7 @@
* A client-provided name used to identify this context, or `null` if the
* client has not provided a name.
*/
+ @override
String name;
/**
@@ -129,6 +130,7 @@
/**
* A list of all [WorkManager]s used by this context.
*/
+ @override
final List<WorkManager> workManagers = <WorkManager>[];
/**
@@ -260,6 +262,8 @@
options.enableStrictCallChecks ||
this._options.enableGenericMethods != options.enableGenericMethods ||
this._options.enableAsync != options.enableAsync ||
+ this._options.enableConditionalDirectives !=
+ options.enableConditionalDirectives ||
this._options.enableSuperMixins != options.enableSuperMixins;
int cacheSize = options.cacheSize;
if (this._options.cacheSize != cacheSize) {
@@ -274,6 +278,8 @@
this._options.enableAssertMessage = options.enableAssertMessage;
this._options.enableStrictCallChecks = options.enableStrictCallChecks;
this._options.enableAsync = options.enableAsync;
+ this._options.enableConditionalDirectives =
+ options.enableConditionalDirectives;
this._options.enableSuperMixins = options.enableSuperMixins;
this._options.hint = options.hint;
this._options.incremental = options.incremental;
@@ -486,6 +492,7 @@
/**
* Sets the [TypeProvider] for this context.
*/
+ @override
void set typeProvider(TypeProvider typeProvider) {
_typeProvider = typeProvider;
}
@@ -1017,7 +1024,9 @@
if (changed) {
if (!analysisOptions.incremental ||
!_tryPoorMansIncrementalResolution(source, newContents)) {
- _sourceChanged(source);
+ // Don't compare with old contents because the cache has already been
+ // updated, and we know at this point that it changed.
+ _sourceChanged(source, compareWithOld: false);
}
entry.modificationTime = _contentCache.getModificationStamp(source);
entry.setValue(CONTENT, newContents, TargetedResult.EMPTY_LIST);
@@ -1754,21 +1763,28 @@
/**
* Invalidate the [source] that was changed and any sources that referenced
* the source before it existed.
+ *
+ * Note: source may be considered "changed" if it was previously missing,
+ * but pointed to by an import or export directive.
*/
- void _sourceChanged(Source source) {
+ void _sourceChanged(Source source, {bool compareWithOld: true}) {
CacheEntry entry = _cache.get(source);
- // If the source is removed, we don't care about it.
+ // If the source has no cache entry, there is nothing to invalidate.
if (entry == null) {
return;
}
- // Check whether the content of the source is the same as it was the last
- // time.
- String sourceContent = entry.getValue(CONTENT);
- if (sourceContent != null) {
- entry.setState(CONTENT, CacheState.FLUSHED);
+
+ String oldContents = compareWithOld ? entry.getValue(CONTENT) : null;
+
+ // Flush so that from now on we will get new contents.
+ // (For example, in getLibrariesContaining.)
+ entry.setState(CONTENT, CacheState.FLUSHED);
+
+ if (oldContents != null) {
+ // Fast path if the content is the same as it was last time.
try {
TimestampedData<String> fileContents = getContents(source);
- if (fileContents.data == sourceContent) {
+ if (fileContents.data == oldContents) {
int time = fileContents.modificationTime;
for (CacheEntry entry in _entriesFor(source)) {
entry.modificationTime = time;
@@ -1813,6 +1829,8 @@
}
}
entry.setState(CONTENT, CacheState.INVALID);
+ entry.setState(MODIFICATION_TIME, CacheState.INVALID);
+ entry.setState(SOURCE_KIND, CacheState.INVALID);
}
driver.reset();
for (WorkManager workManager in workManagers) {
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
index faf8eaa..5d18886 100644
--- a/pkg/analyzer/lib/src/context/source.dart
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -23,6 +23,7 @@
/**
* The analysis context that this source factory is associated with.
*/
+ @override
AnalysisContext context;
/**
@@ -63,6 +64,7 @@
* @return the [DartSdk] associated with this [SourceFactory], or `null` if
* there is no such SDK
*/
+ @override
DartSdk get dartSdk {
for (UriResolver resolver in resolvers) {
if (resolver is DartUriResolver) {
@@ -78,12 +80,14 @@
*
* @param localSourcePredicate the predicate to determine is [Source] is local
*/
+ @override
void set localSourcePredicate(LocalSourcePredicate localSourcePredicate) {
this._localSourcePredicate = localSourcePredicate;
}
/// A table mapping package names to paths of directories containing
/// the package (or [null] if there is no registered package URI resolver).
+ @override
Map<String, List<Folder>> get packageMap {
// Start by looking in .packages.
if (_packages != null) {
@@ -108,6 +112,7 @@
* Return a source factory that will resolve URI's in the same way that this
* source factory does.
*/
+ @override
SourceFactory clone() {
SourceFactory factory =
new SourceFactory(resolvers, _packages, _resourceProvider);
@@ -122,6 +127,7 @@
* @param absoluteUri the absolute URI to be resolved
* @return a source object representing the absolute URI
*/
+ @override
Source forUri(String absoluteUri) {
try {
Uri uri = parseUriWithException(absoluteUri);
@@ -143,6 +149,7 @@
* @param absoluteUri the absolute URI to be resolved
* @return a source object representing the absolute URI
*/
+ @override
Source forUri2(Uri absoluteUri) {
if (absoluteUri.isAbsolute) {
try {
@@ -165,6 +172,7 @@
* @throws IllegalArgumentException if the argument is not a valid encoding
* See [Source.encoding].
*/
+ @override
Source fromEncoding(String encoding) {
Source source = forUri(encoding);
if (source == null) {
@@ -180,6 +188,7 @@
* @param source the [Source] to analyze
* @return `true` if the given [Source] is local
*/
+ @override
bool isLocalSource(Source source) => _localSourcePredicate.isLocal(source);
/**
@@ -189,6 +198,7 @@
* if either the [containedUri] is invalid or if it cannot be resolved against
* the [containingSource]'s URI.
*/
+ @override
Source resolveUri(Source containingSource, String containedUri) {
if (containedUri == null || containedUri.isEmpty) {
return null;
@@ -217,6 +227,7 @@
* @param source the source to get URI for
* @return the absolute URI representing the given source
*/
+ @override
Uri restoreUri(Source source) {
// First see if a resolver can restore the URI.
for (UriResolver resolver in resolvers) {
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 48332fb..d2e09de 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -29,8 +29,8 @@
* the same kind (single line or multi-line), this class doesn't enforce that
* restriction.
*
- * > adjacentStrings ::=
- * > [StringLiteral] [StringLiteral]+
+ * adjacentStrings ::=
+ * [StringLiteral] [StringLiteral]+
*/
class AdjacentStringsImpl extends StringLiteralImpl implements AdjacentStrings {
/**
@@ -181,16 +181,17 @@
/**
* An annotation that can be associated with an AST node.
*
- * > metadata ::=
- * > annotation*
- * >
- * > annotation ::=
- * > '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+ * metadata ::=
+ * annotation*
+ *
+ * annotation ::=
+ * '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
*/
class AnnotationImpl extends AstNodeImpl implements Annotation {
/**
* The at sign that introduced the annotation.
*/
+ @override
Token atSign;
/**
@@ -203,6 +204,7 @@
* The period before the constructor name, or `null` if this annotation is not
* the invocation of a named constructor.
*/
+ @override
Token period;
/**
@@ -226,6 +228,7 @@
/**
* The element annotation representing this annotation in the element model.
*/
+ @override
ElementAnnotation elementAnnotation;
/**
@@ -316,17 +319,18 @@
* A list of arguments in the invocation of an executable element (that is, a
* function, method, or constructor).
*
- * > argumentList ::=
- * > '(' arguments? ')'
- * >
- * > arguments ::=
- * > [NamedExpression] (',' [NamedExpression])*
- * > | [Expression] (',' [Expression])* (',' [NamedExpression])*
+ * argumentList ::=
+ * '(' arguments? ')'
+ *
+ * arguments ::=
+ * [NamedExpression] (',' [NamedExpression])*
+ * | [Expression] (',' [Expression])* (',' [NamedExpression])*
*/
class ArgumentListImpl extends AstNodeImpl implements ArgumentList {
/**
* The left parenthesis.
*/
+ @override
Token leftParenthesis;
/**
@@ -337,6 +341,7 @@
/**
* The right parenthesis.
*/
+ @override
Token rightParenthesis;
/**
@@ -468,8 +473,8 @@
/**
* An as expression.
*
- * > asExpression ::=
- * > [Expression] 'as' [TypeName]
+ * asExpression ::=
+ * [Expression] 'as' [TypeName]
*/
class AsExpressionImpl extends ExpressionImpl implements AsExpression {
/**
@@ -480,6 +485,7 @@
/**
* The 'as' operator.
*/
+ @override
Token asOperator;
/**
@@ -537,18 +543,20 @@
/**
* An assert statement.
*
- * > assertStatement ::=
- * > 'assert' '(' [Expression] ')' ';'
+ * assertStatement ::=
+ * 'assert' '(' [Expression] ')' ';'
*/
class AssertStatementImpl extends StatementImpl implements AssertStatement {
/**
* The token representing the 'assert' keyword.
*/
+ @override
Token assertKeyword;
/**
* The left parenthesis.
*/
+ @override
Token leftParenthesis;
/**
@@ -559,6 +567,7 @@
/**
* The comma, if a message expression was supplied. Otherwise `null`.
*/
+ @override
Token comma;
/**
@@ -570,11 +579,13 @@
/**
* The right parenthesis.
*/
+ @override
Token rightParenthesis;
/**
* The semicolon terminating the statement.
*/
+ @override
Token semicolon;
/**
@@ -637,8 +648,8 @@
/**
* An assignment expression.
*
- * > assignmentExpression ::=
- * > [Expression] operator [Expression]
+ * assignmentExpression ::=
+ * [Expression] operator [Expression]
*/
class AssignmentExpressionImpl extends ExpressionImpl
implements AssignmentExpression {
@@ -650,6 +661,7 @@
/**
* The assignment operator being applied.
*/
+ @override
Token operator;
/**
@@ -663,6 +675,7 @@
* the operator is not a compound operator, or if the operator could not be
* resolved.
*/
+ @override
MethodElement staticElement;
/**
@@ -671,6 +684,7 @@
* if the operator is not a compound operator, or if the operator could not be
* resolved.
*/
+ @override
MethodElement propagatedElement;
/**
@@ -941,13 +955,14 @@
/**
* An await expression.
*
- * > awaitExpression ::=
- * > 'await' [Expression]
+ * awaitExpression ::=
+ * 'await' [Expression]
*/
class AwaitExpressionImpl extends ExpressionImpl implements AwaitExpression {
/**
* The 'await' keyword.
*/
+ @override
Token awaitKeyword;
/**
@@ -1000,8 +1015,8 @@
/**
* A binary (infix) expression.
*
- * > binaryExpression ::=
- * > [Expression] [Token] [Expression]
+ * binaryExpression ::=
+ * [Expression] [Token] [Expression]
*/
class BinaryExpressionImpl extends ExpressionImpl implements BinaryExpression {
/**
@@ -1012,6 +1027,7 @@
/**
* The binary operator being applied.
*/
+ @override
Token operator;
/**
@@ -1024,6 +1040,7 @@
* left operand, or `null` if the AST structure has not been resolved, if the
* operator is not user definable, or if the operator could not be resolved.
*/
+ @override
MethodElement staticElement;
/**
@@ -1032,6 +1049,7 @@
* the operator is not user definable, or if the operator could not be
* resolved.
*/
+ @override
MethodElement propagatedElement;
/**
@@ -1128,8 +1146,8 @@
/**
* A function body that consists of a block of statements.
*
- * > blockFunctionBody ::=
- * > ('async' | 'async' '*' | 'sync' '*')? [Block]
+ * blockFunctionBody ::=
+ * ('async' | 'async' '*' | 'sync' '*')? [Block]
*/
class BlockFunctionBodyImpl extends FunctionBodyImpl
implements BlockFunctionBody {
@@ -1137,12 +1155,14 @@
* The token representing the 'async' or 'sync' keyword, or `null` if there is
* no such keyword.
*/
+ @override
Token keyword;
/**
* The star optionally following the 'async' or 'sync' keyword, or `null` if
* there is wither no such keyword or no star.
*/
+ @override
Token star;
/**
@@ -1204,13 +1224,14 @@
/**
* A sequence of statements.
*
- * > block ::=
- * > '{' statement* '}'
+ * block ::=
+ * '{' statement* '}'
*/
class BlockImpl extends StatementImpl implements Block {
/**
* The left curly bracket.
*/
+ @override
Token leftBracket;
/**
@@ -1221,6 +1242,7 @@
/**
* The right curly bracket.
*/
+ @override
Token rightBracket;
/**
@@ -1257,18 +1279,20 @@
/**
* A boolean literal expression.
*
- * > booleanLiteral ::=
- * > 'false' | 'true'
+ * booleanLiteral ::=
+ * 'false' | 'true'
*/
class BooleanLiteralImpl extends LiteralImpl implements BooleanLiteral {
/**
* The token representing the literal.
*/
+ @override
Token literal;
/**
* The value of the literal.
*/
+ @override
bool value = false;
/**
@@ -1300,13 +1324,14 @@
/**
* A break statement.
*
- * > breakStatement ::=
- * > 'break' [SimpleIdentifier]? ';'
+ * breakStatement ::=
+ * 'break' [SimpleIdentifier]? ';'
*/
class BreakStatementImpl extends StatementImpl implements BreakStatement {
/**
* The token representing the 'break' keyword.
*/
+ @override
Token breakKeyword;
/**
@@ -1317,6 +1342,7 @@
/**
* The semicolon terminating the statement.
*/
+ @override
Token semicolon;
/**
@@ -1328,6 +1354,7 @@
* resolved. Note that if the source code has errors, the target might be
* invalid (e.g. trying to break to a switch case).
*/
+ @override
AstNode target;
/**
@@ -1371,16 +1398,16 @@
* There are three kinds of expressions that can be used in a cascade
* expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
*
- * > cascadeExpression ::=
- * > [Expression] cascadeSection*
- * >
- * > cascadeSection ::=
- * > '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
- * > (assignmentOperator expressionWithoutCascade)?
- * >
- * > cascadeSelector ::=
- * > '[ ' expression '] '
- * > | identifier
+ * cascadeExpression ::=
+ * [Expression] cascadeSection*
+ *
+ * cascadeSection ::=
+ * '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
+ * (assignmentOperator expressionWithoutCascade)?
+ *
+ * cascadeSelector ::=
+ * '[ ' expression '] '
+ * | identifier
*/
class CascadeExpressionImpl extends ExpressionImpl
implements CascadeExpression {
@@ -1441,18 +1468,19 @@
/**
* A catch clause within a try statement.
*
- * > onPart ::=
- * > catchPart [Block]
- * > | 'on' type catchPart? [Block]
- * >
- * > catchPart ::=
- * > 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
+ * onPart ::=
+ * catchPart [Block]
+ * | 'on' type catchPart? [Block]
+ *
+ * catchPart ::=
+ * 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
*/
class CatchClauseImpl extends AstNodeImpl implements CatchClause {
/**
* The token representing the 'on' keyword, or `null` if there is no 'on'
* keyword.
*/
+ @override
Token onKeyword;
/**
@@ -1465,11 +1493,13 @@
* The token representing the 'catch' keyword, or `null` if there is no
* 'catch' keyword.
*/
+ @override
Token catchKeyword;
/**
* The left parenthesis, or `null` if there is no 'catch' keyword.
*/
+ @override
Token leftParenthesis;
/**
@@ -1482,6 +1512,7 @@
* The comma separating the exception parameter from the stack trace
* parameter, or `null` if there is no stack trace parameter.
*/
+ @override
Token comma;
/**
@@ -1493,6 +1524,7 @@
/**
* The right parenthesis, or `null` if there is no 'catch' keyword.
*/
+ @override
Token rightParenthesis;
/**
@@ -1624,22 +1656,24 @@
/**
* The declaration of a class.
*
- * > classDeclaration ::=
- * > 'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
- * > ([ExtendsClause] [WithClause]?)?
- * > [ImplementsClause]?
- * > '{' [ClassMember]* '}'
+ * classDeclaration ::=
+ * 'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
+ * ([ExtendsClause] [WithClause]?)?
+ * [ImplementsClause]?
+ * '{' [ClassMember]* '}'
*/
class ClassDeclarationImpl extends NamedCompilationUnitMemberImpl
implements ClassDeclaration {
/**
* The 'abstract' keyword, or `null` if the keyword was absent.
*/
+ @override
Token abstractKeyword;
/**
* The token representing the 'class' keyword.
*/
+ @override
Token classKeyword;
/**
@@ -1675,6 +1709,7 @@
/**
* The left curly bracket.
*/
+ @override
Token leftBracket;
/**
@@ -1685,6 +1720,7 @@
/**
* The right curly bracket.
*/
+ @override
Token rightBracket;
/**
@@ -1874,11 +1910,11 @@
/**
* A class type alias.
*
- * > classTypeAlias ::=
- * > [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
- * >
- * > mixinApplication ::=
- * > [TypeName] [WithClause] [ImplementsClause]? ';'
+ * classTypeAlias ::=
+ * [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+ *
+ * mixinApplication ::=
+ * [TypeName] [WithClause] [ImplementsClause]? ';'
*/
class ClassTypeAliasImpl extends TypeAliasImpl implements ClassTypeAlias {
/**
@@ -1890,12 +1926,14 @@
/**
* The token for the '=' separating the name from the definition.
*/
+ @override
Token equals;
/**
* The token for the 'abstract' keyword, or `null` if this is not defining an
* abstract class.
*/
+ @override
Token abstractKeyword;
/**
@@ -2017,15 +2055,16 @@
/**
* A combinator associated with an import or export directive.
*
- * > combinator ::=
- * > [HideCombinator]
- * > | [ShowCombinator]
+ * combinator ::=
+ * [HideCombinator]
+ * | [ShowCombinator]
*/
abstract class CombinatorImpl extends AstNodeImpl implements Combinator {
/**
* The 'hide' or 'show' keyword specifying what kind of processing is to be
* done on the names.
*/
+ @override
Token keyword;
/**
@@ -2040,25 +2079,26 @@
/**
* A comment within the source code.
*
- * > comment ::=
- * > endOfLineComment
- * > | blockComment
- * > | documentationComment
- * >
- * > endOfLineComment ::=
- * > '//' (CHARACTER - EOL)* EOL
- * >
- * > blockComment ::=
- * > '/ *' CHARACTER* '*/'
- * >
- * > documentationComment ::=
- * > '/ **' (CHARACTER | [CommentReference])* '*/'
- * > | ('///' (CHARACTER - EOL)* EOL)+
+ * comment ::=
+ * endOfLineComment
+ * | blockComment
+ * | documentationComment
+ *
+ * endOfLineComment ::=
+ * '//' (CHARACTER - EOL)* EOL
+ *
+ * blockComment ::=
+ * '/ *' CHARACTER* '*/'
+ *
+ * documentationComment ::=
+ * '/ **' (CHARACTER | [CommentReference])* '*/'
+ * | ('///' (CHARACTER - EOL)* EOL)+
*/
class CommentImpl extends AstNodeImpl implements Comment {
/**
* The tokens representing the comment.
*/
+ @override
final List<Token> tokens;
/**
@@ -2143,14 +2183,15 @@
/**
* A reference to a Dart element that is found within a documentation comment.
*
- * > commentReference ::=
- * > '[' 'new'? [Identifier] ']'
+ * commentReference ::=
+ * '[' 'new'? [Identifier] ']'
*/
class CommentReferenceImpl extends AstNodeImpl implements CommentReference {
/**
* The token representing the 'new' keyword, or `null` if there was no 'new'
* keyword.
*/
+ @override
Token newKeyword;
/**
@@ -2235,25 +2276,26 @@
* order even if lexical order does not conform to the restrictions of the
* grammar.
*
- * > compilationUnit ::=
- * > directives declarations
- * >
- * > directives ::=
- * > [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
- * > | [PartOfDirective]
- * >
- * > namespaceDirective ::=
- * > [ImportDirective]
- * > | [ExportDirective]
- * >
- * > declarations ::=
- * > [CompilationUnitMember]*
+ * compilationUnit ::=
+ * directives declarations
+ *
+ * directives ::=
+ * [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
+ * | [PartOfDirective]
+ *
+ * namespaceDirective ::=
+ * [ImportDirective]
+ * | [ExportDirective]
+ *
+ * declarations ::=
+ * [CompilationUnitMember]*
*/
class CompilationUnitImpl extends AstNodeImpl implements CompilationUnit {
/**
* The first token in the token stream that was parsed to form this
* compilation unit.
*/
+ @override
Token beginToken;
/**
@@ -2276,17 +2318,20 @@
* The last token in the token stream that was parsed to form this compilation
* unit. This token should always have a type of [TokenType.EOF].
*/
+ @override
Token endToken;
/**
* The element associated with this compilation unit, or `null` if the AST
* structure has not been resolved.
*/
+ @override
CompilationUnitElement element;
/**
* The line information for this compilation unit.
*/
+ @override
LineInfo lineInfo;
/**
@@ -2386,13 +2431,13 @@
* A node that declares one or more names within the scope of a compilation
* unit.
*
- * > compilationUnitMember ::=
- * > [ClassDeclaration]
- * > | [TypeAlias]
- * > | [FunctionDeclaration]
- * > | [MethodDeclaration]
- * > | [VariableDeclaration]
- * > | [VariableDeclaration]
+ * compilationUnitMember ::=
+ * [ClassDeclaration]
+ * | [TypeAlias]
+ * | [FunctionDeclaration]
+ * | [MethodDeclaration]
+ * | [VariableDeclaration]
+ * | [VariableDeclaration]
*/
abstract class CompilationUnitMemberImpl extends DeclarationImpl
implements CompilationUnitMember {
@@ -2408,8 +2453,8 @@
/**
* A conditional expression.
*
- * > conditionalExpression ::=
- * > [Expression] '?' [Expression] ':' [Expression]
+ * conditionalExpression ::=
+ * [Expression] '?' [Expression] ':' [Expression]
*/
class ConditionalExpressionImpl extends ExpressionImpl
implements ConditionalExpression {
@@ -2421,6 +2466,7 @@
/**
* The token used to separate the condition from the then expression.
*/
+ @override
Token question;
/**
@@ -2431,6 +2477,7 @@
/**
* The token used to separate the then expression from the else expression.
*/
+ @override
Token colon;
/**
@@ -2513,11 +2560,15 @@
* identifier ('.' identifier)*
*/
class ConfigurationImpl extends AstNodeImpl implements Configuration {
+ @override
Token ifKeyword;
+ @override
Token leftParenthesis;
DottedName _name;
+ @override
Token equalToken;
StringLiteral _value;
+ @override
Token rightParenthesis;
StringLiteral _libraryUri;
@@ -2588,23 +2639,23 @@
/**
* A constructor declaration.
*
- * > constructorDeclaration ::=
- * > constructorSignature [FunctionBody]?
- * > | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
- * >
- * > constructorSignature ::=
- * > 'external'? constructorName formalParameterList initializerList?
- * > | 'external'? 'factory' factoryName formalParameterList initializerList?
- * > | 'external'? 'const' constructorName formalParameterList initializerList?
- * >
- * > constructorName ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])?
- * >
- * > factoryName ::=
- * > [Identifier] ('.' [SimpleIdentifier])?
- * >
- * > initializerList ::=
- * > ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
+ * constructorDeclaration ::=
+ * constructorSignature [FunctionBody]?
+ * | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
+ *
+ * constructorSignature ::=
+ * 'external'? constructorName formalParameterList initializerList?
+ * | 'external'? 'factory' factoryName formalParameterList initializerList?
+ * | 'external'? 'const' constructorName formalParameterList initializerList?
+ *
+ * constructorName ::=
+ * [SimpleIdentifier] ('.' [SimpleIdentifier])?
+ *
+ * factoryName ::=
+ * [Identifier] ('.' [SimpleIdentifier])?
+ *
+ * initializerList ::=
+ * ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
*/
class ConstructorDeclarationImpl extends ClassMemberImpl
implements ConstructorDeclaration {
@@ -2612,18 +2663,21 @@
* The token for the 'external' keyword, or `null` if the constructor is not
* external.
*/
+ @override
Token externalKeyword;
/**
* The token for the 'const' keyword, or `null` if the constructor is not a
* const constructor.
*/
+ @override
Token constKeyword;
/**
* The token for the 'factory' keyword, or `null` if the constructor is not a
* factory constructor.
*/
+ @override
Token factoryKeyword;
/**
@@ -2637,6 +2691,7 @@
* The token for the period before the constructor name, or `null` if the
* constructor being declared is unnamed.
*/
+ @override
Token period;
/**
@@ -2654,6 +2709,7 @@
* The token for the separator (colon or equals) before the initializer list
* or redirection, or `null` if there are no initializers.
*/
+ @override
Token separator;
/**
@@ -2678,6 +2734,7 @@
* structure has not been resolved or if this constructor could not be
* resolved.
*/
+ @override
ConstructorElement element;
/**
@@ -2813,20 +2870,22 @@
/**
* The initialization of a field within a constructor's initialization list.
*
- * > fieldInitializer ::=
- * > ('this' '.')? [SimpleIdentifier] '=' [Expression]
+ * fieldInitializer ::=
+ * ('this' '.')? [SimpleIdentifier] '=' [Expression]
*/
class ConstructorFieldInitializerImpl extends ConstructorInitializerImpl
implements ConstructorFieldInitializer {
/**
* The token for the 'this' keyword, or `null` if there is no 'this' keyword.
*/
+ @override
Token thisKeyword;
/**
* The token for the period after the 'this' keyword, or `null` if there is no
* 'this' keyword.
*/
+ @override
Token period;
/**
@@ -2837,6 +2896,7 @@
/**
* The token for the equal sign between the field name and the expression.
*/
+ @override
Token equals;
/**
@@ -2903,10 +2963,10 @@
/**
* A node that can occur in the initializer list of a constructor declaration.
*
- * > constructorInitializer ::=
- * > [SuperConstructorInvocation]
- * > | [ConstructorFieldInitializer]
- * > | [RedirectingConstructorInvocation]
+ * constructorInitializer ::=
+ * [SuperConstructorInvocation]
+ * | [ConstructorFieldInitializer]
+ * | [RedirectingConstructorInvocation]
*/
abstract class ConstructorInitializerImpl extends AstNodeImpl
implements ConstructorInitializer {}
@@ -2914,8 +2974,8 @@
/**
* The name of the constructor.
*
- * > constructorName ::=
- * > type ('.' identifier)?
+ * constructorName ::=
+ * type ('.' identifier)?
*/
class ConstructorNameImpl extends AstNodeImpl implements ConstructorName {
/**
@@ -2927,6 +2987,7 @@
* The token for the period before the constructor name, or `null` if the
* specified constructor is the unnamed constructor.
*/
+ @override
Token period;
/**
@@ -2940,6 +3001,7 @@
* information, or `null` if the AST structure has not been resolved or if
* this constructor name could not be resolved.
*/
+ @override
ConstructorElement staticElement;
/**
@@ -2995,13 +3057,14 @@
/**
* A continue statement.
*
- * > continueStatement ::=
- * > 'continue' [SimpleIdentifier]? ';'
+ * continueStatement ::=
+ * 'continue' [SimpleIdentifier]? ';'
*/
class ContinueStatementImpl extends StatementImpl implements ContinueStatement {
/**
* The token representing the 'continue' keyword.
*/
+ @override
Token continueKeyword;
/**
@@ -3012,6 +3075,7 @@
/**
* The semicolon terminating the statement.
*/
+ @override
Token semicolon;
/**
@@ -3078,8 +3142,8 @@
/**
* The declaration of a single identifier.
*
- * > declaredIdentifier ::=
- * > [Annotation] finalConstVarOrType [SimpleIdentifier]
+ * declaredIdentifier ::=
+ * [Annotation] finalConstVarOrType [SimpleIdentifier]
*/
class DeclaredIdentifierImpl extends DeclarationImpl
implements DeclaredIdentifier {
@@ -3087,6 +3151,7 @@
* The token representing either the 'final', 'const' or 'var' keyword, or
* `null` if no keyword was used.
*/
+ @override
Token keyword;
/**
@@ -3180,11 +3245,11 @@
* that are both represented by this class: named formal parameters and
* positional formal parameters.
*
- * > defaultFormalParameter ::=
- * > [NormalFormalParameter] ('=' [Expression])?
- * >
- * > defaultNamedParameter ::=
- * > [NormalFormalParameter] (':' [Expression])?
+ * defaultFormalParameter ::=
+ * [NormalFormalParameter] ('=' [Expression])?
+ *
+ * defaultNamedParameter ::=
+ * [NormalFormalParameter] (':' [Expression])?
*/
class DefaultFormalParameterImpl extends FormalParameterImpl
implements DefaultFormalParameter {
@@ -3196,12 +3261,14 @@
/**
* The kind of this parameter.
*/
+ @override
ParameterKind kind;
/**
* The token separating the parameter from the default value, or `null` if
* there is no default value.
*/
+ @override
Token separator;
/**
@@ -3276,18 +3343,19 @@
/**
* A node that represents a directive.
*
- * > directive ::=
- * > [ExportDirective]
- * > | [ImportDirective]
- * > | [LibraryDirective]
- * > | [PartDirective]
- * > | [PartOfDirective]
+ * directive ::=
+ * [ExportDirective]
+ * | [ImportDirective]
+ * | [LibraryDirective]
+ * | [PartDirective]
+ * | [PartOfDirective]
*/
abstract class DirectiveImpl extends AnnotatedNodeImpl implements Directive {
/**
* The element associated with this directive, or `null` if the AST structure
* has not been resolved or if this directive could not be resolved.
*/
+ @override
Element element;
/**
@@ -3302,13 +3370,14 @@
/**
* A do statement.
*
- * > doStatement ::=
- * > 'do' [Statement] 'while' '(' [Expression] ')' ';'
+ * doStatement ::=
+ * 'do' [Statement] 'while' '(' [Expression] ')' ';'
*/
class DoStatementImpl extends StatementImpl implements DoStatement {
/**
* The token representing the 'do' keyword.
*/
+ @override
Token doKeyword;
/**
@@ -3319,6 +3388,7 @@
/**
* The token representing the 'while' keyword.
*/
+ @override
Token whileKeyword;
/**
@@ -3334,11 +3404,13 @@
/**
* The right parenthesis.
*/
+ @override
Token rightParenthesis;
/**
* The semicolon terminating the statement.
*/
+ @override
Token semicolon;
/**
@@ -3401,8 +3473,8 @@
/**
* A dotted name, used in a configuration within an import or export directive.
*
- * > dottedName ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ * dottedName ::=
+ * [SimpleIdentifier] ('.' [SimpleIdentifier])*
*/
class DottedNameImpl extends AstNodeImpl implements DottedName {
/**
@@ -3442,22 +3514,24 @@
/**
* A floating point literal expression.
*
- * > doubleLiteral ::=
- * > decimalDigit+ ('.' decimalDigit*)? exponent?
- * > | '.' decimalDigit+ exponent?
- * >
- * > exponent ::=
- * > ('e' | 'E') ('+' | '-')? decimalDigit+
+ * doubleLiteral ::=
+ * decimalDigit+ ('.' decimalDigit*)? exponent?
+ * | '.' decimalDigit+ exponent?
+ *
+ * exponent ::=
+ * ('e' | 'E') ('+' | '-')? decimalDigit+
*/
class DoubleLiteralImpl extends LiteralImpl implements DoubleLiteral {
/**
* The token representing the literal.
*/
+ @override
Token literal;
/**
* The value of the literal.
*/
+ @override
double value;
/**
@@ -3487,8 +3561,8 @@
* An empty function body, which can only appear in constructors or abstract
* methods.
*
- * > emptyFunctionBody ::=
- * > ';'
+ * emptyFunctionBody ::=
+ * ';'
*/
class EmptyFunctionBodyImpl extends FunctionBodyImpl
implements EmptyFunctionBody {
@@ -3496,6 +3570,7 @@
* The token representing the semicolon that marks the end of the function
* body.
*/
+ @override
Token semicolon;
/**
@@ -3524,8 +3599,8 @@
/**
* An empty statement.
*
- * > emptyStatement ::=
- * > ';'
+ * emptyStatement ::=
+ * ';'
*/
class EmptyStatementImpl extends StatementImpl implements EmptyStatement {
/**
@@ -3612,19 +3687,21 @@
/**
* The declaration of an enumeration.
*
- * > enumType ::=
- * > metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
+ * enumType ::=
+ * metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
*/
class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
implements EnumDeclaration {
/**
* The 'enum' keyword.
*/
+ @override
Token enumKeyword;
/**
* The left curly bracket.
*/
+ @override
Token leftBracket;
/**
@@ -3635,6 +3712,7 @@
/**
* The right curly bracket.
*/
+ @override
Token rightBracket;
/**
@@ -3702,8 +3780,8 @@
/**
* An export directive.
*
- * > exportDirective ::=
- * > [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+ * exportDirective ::=
+ * [Annotation] 'export' [StringLiteral] [Combinator]* ';'
*/
class ExportDirectiveImpl extends NamespaceDirectiveImpl
implements ExportDirective {
@@ -3754,8 +3832,8 @@
/**
* A function body consisting of a single expression.
*
- * > expressionFunctionBody ::=
- * > 'async'? '=>' [Expression] ';'
+ * expressionFunctionBody ::=
+ * 'async'? '=>' [Expression] ';'
*/
class ExpressionFunctionBodyImpl extends FunctionBodyImpl
implements ExpressionFunctionBody {
@@ -3763,12 +3841,14 @@
* The token representing the 'async' keyword, or `null` if there is no such
* keyword.
*/
+ @override
Token keyword;
/**
* The token introducing the expression that represents the body of the
* function.
*/
+ @override
Token functionDefinition;
/**
@@ -3779,6 +3859,7 @@
/**
* The semicolon terminating the statement.
*/
+ @override
Token semicolon;
/**
@@ -3840,22 +3921,24 @@
/**
* A node that represents an expression.
*
- * > expression ::=
- * > [AssignmentExpression]
- * > | [ConditionalExpression] cascadeSection*
- * > | [ThrowExpression]
+ * expression ::=
+ * [AssignmentExpression]
+ * | [ConditionalExpression] cascadeSection*
+ * | [ThrowExpression]
*/
abstract class ExpressionImpl extends AstNodeImpl implements Expression {
/**
* The static type of this expression, or `null` if the AST structure has not
* been resolved.
*/
+ @override
DartType staticType;
/**
* The propagated type of this expression, or `null` if type propagation has
* not been performed on the AST structure.
*/
+ @override
DartType propagatedType;
/**
@@ -3939,8 +4022,8 @@
/**
* An expression used as a statement.
*
- * > expressionStatement ::=
- * > [Expression]? ';'
+ * expressionStatement ::=
+ * [Expression]? ';'
*/
class ExpressionStatementImpl extends StatementImpl
implements ExpressionStatement {
@@ -3953,6 +4036,7 @@
* The semicolon terminating the statement, or `null` if the expression is a
* function expression and therefore isn't followed by a semicolon.
*/
+ @override
Token semicolon;
/**
@@ -4000,13 +4084,14 @@
/**
* The "extends" clause in a class declaration.
*
- * > extendsClause ::=
- * > 'extends' [TypeName]
+ * extendsClause ::=
+ * 'extends' [TypeName]
*/
class ExtendsClauseImpl extends AstNodeImpl implements ExtendsClause {
/**
* The token representing the 'extends' keyword.
*/
+ @override
Token extendsKeyword;
/**
@@ -4051,14 +4136,15 @@
/**
* The declaration of one or more fields of the same type.
*
- * > fieldDeclaration ::=
- * > 'static'? [VariableDeclarationList] ';'
+ * fieldDeclaration ::=
+ * 'static'? [VariableDeclarationList] ';'
*/
class FieldDeclarationImpl extends ClassMemberImpl implements FieldDeclaration {
/**
* The token representing the 'static' keyword, or `null` if the fields are
* not static.
*/
+ @override
Token staticKeyword;
/**
@@ -4069,6 +4155,7 @@
/**
* The semicolon terminating the declaration.
*/
+ @override
Token semicolon;
/**
@@ -4125,9 +4212,9 @@
/**
* A field formal parameter.
*
- * > fieldFormalParameter ::=
- * > ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
- * > 'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
+ * fieldFormalParameter ::=
+ * ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+ * 'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
*/
class FieldFormalParameterImpl extends NormalFormalParameterImpl
implements FieldFormalParameter {
@@ -4135,6 +4222,7 @@
* The token representing either the 'final', 'const' or 'var' keyword, or
* `null` if no keyword was used.
*/
+ @override
Token keyword;
/**
@@ -4146,11 +4234,13 @@
/**
* The token representing the 'this' keyword.
*/
+ @override
Token thisKeyword;
/**
* The token representing the period.
*/
+ @override
Token period;
/**
@@ -4267,25 +4357,28 @@
/**
* A for-each statement.
*
- * > forEachStatement ::=
- * > 'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
- * > | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
+ * forEachStatement ::=
+ * 'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
+ * | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
*/
class ForEachStatementImpl extends StatementImpl implements ForEachStatement {
/**
* The token representing the 'await' keyword, or `null` if there is no
* 'await' keyword.
*/
+ @override
Token awaitKeyword;
/**
* The token representing the 'for' keyword.
*/
+ @override
Token forKeyword;
/**
* The left parenthesis.
*/
+ @override
Token leftParenthesis;
/**
@@ -4302,6 +4395,7 @@
/**
* The token representing the 'in' keyword.
*/
+ @override
Token inKeyword;
/**
@@ -4312,6 +4406,7 @@
/**
* The right parenthesis.
*/
+ @override
Token rightParenthesis;
/**
@@ -4422,9 +4517,9 @@
/**
* A node representing a parameter to a function.
*
- * > formalParameter ::=
- * > [NormalFormalParameter]
- * > | [DefaultFormalParameter]
+ * formalParameter ::=
+ * [NormalFormalParameter]
+ * | [DefaultFormalParameter]
*/
abstract class FormalParameterImpl extends AstNodeImpl
implements FormalParameter {
@@ -4448,29 +4543,30 @@
* flattened into a single list, which can have any or all kinds of parameters
* (normal, named, and positional) in any order.
*
- * > formalParameterList ::=
- * > '(' ')'
- * > | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
- * > | '(' optionalFormalParameters ')'
- * >
- * > normalFormalParameters ::=
- * > [NormalFormalParameter] (',' [NormalFormalParameter])*
- * >
- * > optionalFormalParameters ::=
- * > optionalPositionalFormalParameters
- * > | namedFormalParameters
- * >
- * > optionalPositionalFormalParameters ::=
- * > '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
- * >
- * > namedFormalParameters ::=
- * > '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
+ * formalParameterList ::=
+ * '(' ')'
+ * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
+ * | '(' optionalFormalParameters ')'
+ *
+ * normalFormalParameters ::=
+ * [NormalFormalParameter] (',' [NormalFormalParameter])*
+ *
+ * optionalFormalParameters ::=
+ * optionalPositionalFormalParameters
+ * | namedFormalParameters
+ *
+ * optionalPositionalFormalParameters ::=
+ * '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
+ *
+ * namedFormalParameters ::=
+ * '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
*/
class FormalParameterListImpl extends AstNodeImpl
implements FormalParameterList {
/**
* The left parenthesis.
*/
+ @override
Token leftParenthesis;
/**
@@ -4482,17 +4578,20 @@
* The left square bracket ('[') or left curly brace ('{') introducing the
* optional parameters, or `null` if there are no optional parameters.
*/
+ @override
Token leftDelimiter;
/**
* The right square bracket (']') or right curly brace ('}') terminating the
* optional parameters, or `null` if there are no optional parameters.
*/
+ @override
Token rightDelimiter;
/**
* The right parenthesis.
*/
+ @override
Token rightParenthesis;
/**
@@ -4555,25 +4654,27 @@
/**
* A for statement.
*
- * > forStatement ::=
- * > 'for' '(' forLoopParts ')' [Statement]
- * >
- * > forLoopParts ::=
- * > forInitializerStatement ';' [Expression]? ';' [Expression]?
- * >
- * > forInitializerStatement ::=
- * > [DefaultFormalParameter]
- * > | [Expression]?
+ * forStatement ::=
+ * 'for' '(' forLoopParts ')' [Statement]
+ *
+ * forLoopParts ::=
+ * forInitializerStatement ';' [Expression]? ';' [Expression]?
+ *
+ * forInitializerStatement ::=
+ * [DefaultFormalParameter]
+ * | [Expression]?
*/
class ForStatementImpl extends StatementImpl implements ForStatement {
/**
* The token representing the 'for' keyword.
*/
+ @override
Token forKeyword;
/**
* The left parenthesis.
*/
+ @override
Token leftParenthesis;
/**
@@ -4593,6 +4694,7 @@
/**
* The semicolon separating the initializer and the condition.
*/
+ @override
Token leftSeparator;
/**
@@ -4604,6 +4706,7 @@
/**
* The semicolon separating the condition and the updater.
*/
+ @override
Token rightSeparator;
/**
@@ -4614,6 +4717,7 @@
/**
* The right parenthesis.
*/
+ @override
Token rightParenthesis;
/**
@@ -4715,10 +4819,10 @@
/**
* A node representing the body of a function or method.
*
- * > functionBody ::=
- * > [BlockFunctionBody]
- * > | [EmptyFunctionBody]
- * > | [ExpressionFunctionBody]
+ * functionBody ::=
+ * [BlockFunctionBody]
+ * | [EmptyFunctionBody]
+ * | [ExpressionFunctionBody]
*/
abstract class FunctionBodyImpl extends AstNodeImpl implements FunctionBody {
/**
@@ -4731,28 +4835,33 @@
/**
* Return `true` if this function body is asynchronous.
*/
+ @override
bool get isAsynchronous => false;
/**
* Return `true` if this function body is a generator.
*/
+ @override
bool get isGenerator => false;
/**
* Return `true` if this function body is synchronous.
*/
+ @override
bool get isSynchronous => true;
/**
* Return the token representing the 'async' or 'sync' keyword, or `null` if
* there is no such keyword.
*/
+ @override
Token get keyword => null;
/**
* Return the star following the 'async' or 'sync' keyword, or `null` if there
* is no star.
*/
+ @override
Token get star => null;
@override
@@ -4775,12 +4884,12 @@
/**
* A top-level declaration.
*
- * > functionDeclaration ::=
- * > 'external' functionSignature
- * > | functionSignature [FunctionBody]
- * >
- * > functionSignature ::=
- * > [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+ * functionDeclaration ::=
+ * 'external' functionSignature
+ * | functionSignature [FunctionBody]
+ *
+ * functionSignature ::=
+ * [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
*/
class FunctionDeclarationImpl extends NamedCompilationUnitMemberImpl
implements FunctionDeclaration {
@@ -4788,6 +4897,7 @@
* The token representing the 'external' keyword, or `null` if this is not an
* external function.
*/
+ @override
Token externalKeyword;
/**
@@ -4799,6 +4909,7 @@
* The token representing the 'get' or 'set' keyword, or `null` if this is a
* function declaration rather than a property declaration.
*/
+ @override
Token propertyKeyword;
/**
@@ -4940,8 +5051,8 @@
/**
* A function expression.
*
- * > functionExpression ::=
- * > [TypeParameterList]? [FormalParameterList] [FunctionBody]
+ * functionExpression ::=
+ * [TypeParameterList]? [FormalParameterList] [FunctionBody]
*/
class FunctionExpressionImpl extends ExpressionImpl
implements FunctionExpression {
@@ -4965,6 +5076,7 @@
* The element associated with the function, or `null` if the AST structure
* has not been resolved.
*/
+ @override
ExecutableElement element;
/**
@@ -5051,8 +5163,8 @@
* [MethodInvocation] nodes. Invocations of getters and setters are represented
* by either [PrefixedIdentifier] or [PropertyAccess] nodes.
*
- * > functionExpressionInvocation ::=
- * > [Expression] [TypeArgumentList]? [ArgumentList]
+ * functionExpressionInvocation ::=
+ * [Expression] [TypeArgumentList]? [ArgumentList]
*/
class FunctionExpressionInvocationImpl extends InvocationExpressionImpl
implements FunctionExpressionInvocation {
@@ -5066,6 +5178,7 @@
* information, or `null` if the AST structure has not been resolved or the
* function could not be resolved.
*/
+ @override
ExecutableElement staticElement;
/**
@@ -5073,6 +5186,7 @@
* type information, or `null` if the AST structure has not been resolved or
* the function could not be resolved.
*/
+ @override
ExecutableElement propagatedElement;
/**
@@ -5128,11 +5242,11 @@
/**
* A function type alias.
*
- * > functionTypeAlias ::=
- * > functionPrefix [TypeParameterList]? [FormalParameterList] ';'
- * >
- * > functionPrefix ::=
- * > [TypeName]? [SimpleIdentifier]
+ * functionTypeAlias ::=
+ * functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+ *
+ * functionPrefix ::=
+ * [TypeName]? [SimpleIdentifier]
*/
class FunctionTypeAliasImpl extends TypeAliasImpl implements FunctionTypeAlias {
/**
@@ -5227,8 +5341,8 @@
/**
* A function-typed formal parameter.
*
- * > functionSignature ::=
- * > [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+ * functionSignature ::=
+ * [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
*/
class FunctionTypedFormalParameterImpl extends NormalFormalParameterImpl
implements FunctionTypedFormalParameter {
@@ -5330,8 +5444,8 @@
* A combinator that restricts the names being imported to those that are not in
* a given list.
*
- * > hideCombinator ::=
- * > 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ * hideCombinator ::=
+ * 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
*/
class HideCombinatorImpl extends CombinatorImpl implements HideCombinator {
/**
@@ -5370,9 +5484,9 @@
/**
* A node that represents an identifier.
*
- * > identifier ::=
- * > [SimpleIdentifier]
- * > | [PrefixedIdentifier]
+ * identifier ::=
+ * [SimpleIdentifier]
+ * | [PrefixedIdentifier]
*/
abstract class IdentifierImpl extends ExpressionImpl implements Identifier {
/**
@@ -5391,18 +5505,20 @@
/**
* An if statement.
*
- * > ifStatement ::=
- * > 'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
+ * ifStatement ::=
+ * 'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
*/
class IfStatementImpl extends StatementImpl implements IfStatement {
/**
* The token representing the 'if' keyword.
*/
+ @override
Token ifKeyword;
/**
* The left parenthesis.
*/
+ @override
Token leftParenthesis;
/**
@@ -5413,6 +5529,7 @@
/**
* The right parenthesis.
*/
+ @override
Token rightParenthesis;
/**
@@ -5424,6 +5541,7 @@
* The token representing the 'else' keyword, or `null` if there is no else
* statement.
*/
+ @override
Token elseKeyword;
/**
@@ -5508,13 +5626,14 @@
/**
* The "implements" clause in an class declaration.
*
- * > implementsClause ::=
- * > 'implements' [TypeName] (',' [TypeName])*
+ * implementsClause ::=
+ * 'implements' [TypeName] (',' [TypeName])*
*/
class ImplementsClauseImpl extends AstNodeImpl implements ImplementsClause {
/**
* The token representing the 'implements' keyword.
*/
+ @override
Token implementsKeyword;
/**
@@ -5556,9 +5675,9 @@
/**
* An import directive.
*
- * > importDirective ::=
- * > [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
- * > | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+ * importDirective ::=
+ * [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+ * | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
*/
class ImportDirectiveImpl extends NamespaceDirectiveImpl
implements ImportDirective {
@@ -5572,6 +5691,7 @@
* The token representing the 'as' keyword, or `null` if the imported names are
* not prefixed.
*/
+ @override
Token asKeyword;
/**
@@ -5647,8 +5767,8 @@
/**
* An index expression.
*
- * > indexExpression ::=
- * > [Expression] '[' [Expression] ']'
+ * indexExpression ::=
+ * [Expression] '[' [Expression] ']'
*/
class IndexExpressionImpl extends ExpressionImpl implements IndexExpression {
/**
@@ -5661,11 +5781,13 @@
* The period ("..") before a cascaded index expression, or `null` if this
* index expression is not part of a cascade expression.
*/
+ @override
Token period;
/**
* The left square bracket.
*/
+ @override
Token leftBracket;
/**
@@ -5676,6 +5798,7 @@
/**
* The right square bracket.
*/
+ @override
Token rightBracket;
/**
@@ -5683,6 +5806,7 @@
* target, or `null` if the AST structure has not been resolved or if the
* operator could not be resolved.
*/
+ @override
MethodElement staticElement;
/**
@@ -5690,6 +5814,8 @@
* the target, or `null` if the AST structure has not been resolved or if the
* operator could not be resolved.
*/
+
+ @override
MethodElement propagatedElement;
/**
@@ -5860,8 +5986,8 @@
/**
* An instance creation expression.
*
- * > newExpression ::=
- * > ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+ * newExpression ::=
+ * ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
*/
class InstanceCreationExpressionImpl extends ExpressionImpl
implements InstanceCreationExpression {
@@ -5869,6 +5995,7 @@
* The 'new' or 'const' keyword used to indicate how an object should be
* created.
*/
+ @override
Token keyword;
/**
@@ -5886,6 +6013,7 @@
* information, or `null` if the AST structure has not been resolved or if the
* constructor could not be resolved.
*/
+ @override
ConstructorElement staticElement;
/**
@@ -5946,26 +6074,28 @@
/**
* An integer literal expression.
*
- * > integerLiteral ::=
- * > decimalIntegerLiteral
- * > | hexadecimalIntegerLiteral
- * >
- * > decimalIntegerLiteral ::=
- * > decimalDigit+
- * >
- * > hexadecimalIntegerLiteral ::=
- * > '0x' hexadecimalDigit+
- * > | '0X' hexadecimalDigit+
+ * integerLiteral ::=
+ * decimalIntegerLiteral
+ * | hexadecimalIntegerLiteral
+ *
+ * decimalIntegerLiteral ::=
+ * decimalDigit+
+ *
+ * hexadecimalIntegerLiteral ::=
+ * '0x' hexadecimalDigit+
+ * | '0X' hexadecimalDigit+
*/
class IntegerLiteralImpl extends LiteralImpl implements IntegerLiteral {
/**
* The token representing the literal.
*/
+ @override
Token literal;
/**
* The value of the literal.
*/
+ @override
int value = 0;
/**
@@ -5994,9 +6124,9 @@
/**
* A node within a [StringInterpolation].
*
- * > interpolationElement ::=
- * > [InterpolationExpression]
- * > | [InterpolationString]
+ * interpolationElement ::=
+ * [InterpolationExpression]
+ * | [InterpolationString]
*/
abstract class InterpolationElementImpl extends AstNodeImpl
implements InterpolationElement {}
@@ -6004,9 +6134,9 @@
/**
* An expression embedded in a string interpolation.
*
- * > interpolationExpression ::=
- * > '$' [SimpleIdentifier]
- * > | '$' '{' [Expression] '}'
+ * interpolationExpression ::=
+ * '$' [SimpleIdentifier]
+ * | '$' '{' [Expression] '}'
*/
class InterpolationExpressionImpl extends InterpolationElementImpl
implements InterpolationExpression {
@@ -6015,6 +6145,7 @@
* expression is a simple identifier or '${' if the expression is a full
* expression.
*/
+ @override
Token leftBracket;
/**
@@ -6026,6 +6157,7 @@
* The right curly bracket, or `null` if the expression is an identifier
* without brackets.
*/
+ @override
Token rightBracket;
/**
@@ -6073,19 +6205,21 @@
/**
* A non-empty substring of an interpolated string.
*
- * > interpolationString ::=
- * > characters
+ * interpolationString ::=
+ * characters
*/
class InterpolationStringImpl extends InterpolationElementImpl
implements InterpolationString {
/**
* The characters that will be added to the string.
*/
+ @override
Token contents;
/**
* The value of the literal.
*/
+ @override
String value;
/**
@@ -6158,7 +6292,6 @@
@override
ArgumentList get argumentList => _argumentList;
- @override
void set argumentList(ArgumentList argumentList) {
_argumentList = _becomeParentOf(argumentList);
}
@@ -6166,7 +6299,6 @@
@override
TypeArgumentList get typeArguments => _typeArguments;
- @override
void set typeArguments(TypeArgumentList typeArguments) {
_typeArguments = _becomeParentOf(typeArguments);
}
@@ -6175,8 +6307,8 @@
/**
* An is expression.
*
- * > isExpression ::=
- * > [Expression] 'is' '!'? [TypeName]
+ * isExpression ::=
+ * [Expression] 'is' '!'? [TypeName]
*/
class IsExpressionImpl extends ExpressionImpl implements IsExpression {
/**
@@ -6187,11 +6319,13 @@
/**
* The is operator.
*/
+ @override
Token isOperator;
/**
* The not operator, or `null` if the sense of the test is not negated.
*/
+ @override
Token notOperator;
/**
@@ -6254,8 +6388,8 @@
/**
* A statement that has a label associated with them.
*
- * > labeledStatement ::=
- * > [Label]+ [Statement]
+ * labeledStatement ::=
+ * [Label]+ [Statement]
*/
class LabeledStatementImpl extends StatementImpl implements LabeledStatement {
/**
@@ -6319,8 +6453,8 @@
/**
* A label on either a [LabeledStatement] or a [NamedExpression].
*
- * > label ::=
- * > [SimpleIdentifier] ':'
+ * label ::=
+ * [SimpleIdentifier] ':'
*/
class LabelImpl extends AstNodeImpl implements Label {
/**
@@ -6331,6 +6465,7 @@
/**
* The colon that separates the label from the statement.
*/
+ @override
Token colon;
/**
@@ -6369,13 +6504,14 @@
/**
* A library directive.
*
- * > libraryDirective ::=
- * > [Annotation] 'library' [Identifier] ';'
+ * libraryDirective ::=
+ * [Annotation] 'library' [Identifier] ';'
*/
class LibraryDirectiveImpl extends DirectiveImpl implements LibraryDirective {
/**
* The token representing the 'library' keyword.
*/
+ @override
Token libraryKeyword;
/**
@@ -6386,6 +6522,7 @@
/**
* The semicolon terminating the directive.
*/
+ @override
Token semicolon;
/**
@@ -6433,8 +6570,8 @@
/**
* The identifier for a library.
*
- * > libraryIdentifier ::=
- * > [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ * libraryIdentifier ::=
+ * [SimpleIdentifier] ('.' [SimpleIdentifier])*
*/
class LibraryIdentifierImpl extends IdentifierImpl
implements LibraryIdentifier {
@@ -6502,13 +6639,14 @@
/**
* A list literal.
*
- * > listLiteral ::=
- * > 'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+ * listLiteral ::=
+ * 'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
*/
class ListLiteralImpl extends TypedLiteralImpl implements ListLiteral {
/**
* The left square bracket.
*/
+ @override
Token leftBracket;
/**
@@ -6519,6 +6657,7 @@
/**
* The right square bracket.
*/
+ @override
Token rightBracket;
/**
@@ -6571,14 +6710,14 @@
/**
* A node that represents a literal expression.
*
- * > literal ::=
- * > [BooleanLiteral]
- * > | [DoubleLiteral]
- * > | [IntegerLiteral]
- * > | [ListLiteral]
- * > | [MapLiteral]
- * > | [NullLiteral]
- * > | [StringLiteral]
+ * literal ::=
+ * [BooleanLiteral]
+ * | [DoubleLiteral]
+ * | [IntegerLiteral]
+ * | [ListLiteral]
+ * | [MapLiteral]
+ * | [NullLiteral]
+ * | [StringLiteral]
*/
abstract class LiteralImpl extends ExpressionImpl implements Literal {
@override
@@ -6608,8 +6747,8 @@
/**
* A single key/value pair in a map literal.
*
- * > mapLiteralEntry ::=
- * > [Expression] ':' [Expression]
+ * mapLiteralEntry ::=
+ * [Expression] ':' [Expression]
*/
class MapLiteralEntryImpl extends AstNodeImpl implements MapLiteralEntry {
/**
@@ -6620,6 +6759,7 @@
/**
* The colon that separates the key from the value.
*/
+ @override
Token separator;
/**
@@ -6674,14 +6814,15 @@
/**
* A literal map.
*
- * > mapLiteral ::=
- * > 'const'? ('<' [TypeName] (',' [TypeName])* '>')?
- * > '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+ * mapLiteral ::=
+ * 'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+ * '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
*/
class MapLiteralImpl extends TypedLiteralImpl implements MapLiteral {
/**
* The left curly bracket.
*/
+ @override
Token leftBracket;
/**
@@ -6692,6 +6833,7 @@
/**
* The right curly bracket.
*/
+ @override
Token rightBracket;
/**
@@ -6743,16 +6885,16 @@
/**
* A method declaration.
*
- * > methodDeclaration ::=
- * > methodSignature [FunctionBody]
- * >
- * > methodSignature ::=
- * > 'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
- * > methodName [TypeParameterList] [FormalParameterList]
- * >
- * > methodName ::=
- * > [SimpleIdentifier]
- * > | 'operator' [SimpleIdentifier]
+ * methodDeclaration ::=
+ * methodSignature [FunctionBody]
+ *
+ * methodSignature ::=
+ * 'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
+ * methodName [TypeParameterList] [FormalParameterList]
+ *
+ * methodName ::=
+ * [SimpleIdentifier]
+ * | 'operator' [SimpleIdentifier]
*/
class MethodDeclarationImpl extends ClassMemberImpl
implements MethodDeclaration {
@@ -6760,12 +6902,14 @@
* The token for the 'external' keyword, or `null` if the constructor is not
* external.
*/
+ @override
Token externalKeyword;
/**
* The token representing the 'abstract' or 'static' keyword, or `null` if
* neither modifier was specified.
*/
+ @override
Token modifierKeyword;
/**
@@ -6777,12 +6921,14 @@
* The token representing the 'get' or 'set' keyword, or `null` if this is a
* method declaration rather than a property declaration.
*/
+ @override
Token propertyKeyword;
/**
* The token representing the 'operator' keyword, or `null` if this method
* does not declare an operator.
*/
+ @override
Token operatorKeyword;
/**
@@ -6962,8 +7108,8 @@
* [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
* represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
*
- * > methodInvocation ::=
- * > ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+ * methodInvocation ::=
+ * ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
*/
class MethodInvocationImpl extends InvocationExpressionImpl
implements MethodInvocation {
@@ -6979,6 +7125,7 @@
* period ('.'). In a cascade section this will be the cascade operator
* ('..').
*/
+ @override
Token operator;
/**
@@ -7108,8 +7255,8 @@
* An expression that has a name associated with it. They are used in method
* invocations when there are named parameters.
*
- * > namedExpression ::=
- * > [Label] [Expression]
+ * namedExpression ::=
+ * [Label] [Expression]
*/
class NamedExpressionImpl extends ExpressionImpl implements NamedExpression {
/**
@@ -7181,15 +7328,16 @@
/**
* A node that represents a directive that impacts the namespace of a library.
*
- * > directive ::=
- * > [ExportDirective]
- * > | [ImportDirective]
+ * directive ::=
+ * [ExportDirective]
+ * | [ImportDirective]
*/
abstract class NamespaceDirectiveImpl extends UriBasedDirectiveImpl
implements NamespaceDirective {
/**
* The token representing the 'import' or 'export' keyword.
*/
+ @override
Token keyword;
/**
@@ -7206,6 +7354,7 @@
/**
* The semicolon terminating the directive.
*/
+ @override
Token semicolon;
/**
@@ -7246,13 +7395,14 @@
/**
* The "native" clause in an class declaration.
*
- * > nativeClause ::=
- * > 'native' [StringLiteral]
+ * nativeClause ::=
+ * 'native' [StringLiteral]
*/
class NativeClauseImpl extends AstNodeImpl implements NativeClause {
/**
* The token representing the 'native' keyword.
*/
+ @override
Token nativeKeyword;
/**
@@ -7298,14 +7448,15 @@
* A function body that consists of a native keyword followed by a string
* literal.
*
- * > nativeFunctionBody ::=
- * > 'native' [SimpleStringLiteral] ';'
+ * nativeFunctionBody ::=
+ * 'native' [SimpleStringLiteral] ';'
*/
class NativeFunctionBodyImpl extends FunctionBodyImpl
implements NativeFunctionBody {
/**
* The token representing 'native' that marks the start of the function body.
*/
+ @override
Token nativeKeyword;
/**
@@ -7317,6 +7468,7 @@
* The token representing the semicolon that marks the end of the function
* body.
*/
+ @override
Token semicolon;
/**
@@ -7366,6 +7518,7 @@
/**
* The node that is the parent of each of the elements in the list.
*/
+ @override
AstNodeImpl owner;
/**
@@ -7480,10 +7633,10 @@
/**
* A formal parameter that is required (is not optional).
*
- * > normalFormalParameter ::=
- * > [FunctionTypedFormalParameter]
- * > | [FieldFormalParameter]
- * > | [SimpleFormalParameter]
+ * normalFormalParameter ::=
+ * [FunctionTypedFormalParameter]
+ * | [FieldFormalParameter]
+ * | [SimpleFormalParameter]
*/
abstract class NormalFormalParameterImpl extends FormalParameterImpl
implements NormalFormalParameter {
@@ -7600,8 +7753,8 @@
/**
* A null literal expression.
*
- * > nullLiteral ::=
- * > 'null'
+ * nullLiteral ::=
+ * 'null'
*/
class NullLiteralImpl extends LiteralImpl implements NullLiteral {
/**
@@ -7635,8 +7788,8 @@
/**
* A parenthesized expression.
*
- * > parenthesizedExpression ::=
- * > '(' [Expression] ')'
+ * parenthesizedExpression ::=
+ * '(' [Expression] ')'
*/
class ParenthesizedExpressionImpl extends ExpressionImpl
implements ParenthesizedExpression {
@@ -7698,18 +7851,20 @@
/**
* A part directive.
*
- * > partDirective ::=
- * > [Annotation] 'part' [StringLiteral] ';'
+ * partDirective ::=
+ * [Annotation] 'part' [StringLiteral] ';'
*/
class PartDirectiveImpl extends UriBasedDirectiveImpl implements PartDirective {
/**
* The token representing the 'part' keyword.
*/
+ @override
Token partKeyword;
/**
* The semicolon terminating the directive.
*/
+ @override
Token semicolon;
/**
@@ -7744,18 +7899,20 @@
/**
* A part-of directive.
*
- * > partOfDirective ::=
- * > [Annotation] 'part' 'of' [Identifier] ';'
+ * partOfDirective ::=
+ * [Annotation] 'part' 'of' [Identifier] ';'
*/
class PartOfDirectiveImpl extends DirectiveImpl implements PartOfDirective {
/**
* The token representing the 'part' keyword.
*/
+ @override
Token partKeyword;
/**
* The token representing the 'of' keyword.
*/
+ @override
Token ofKeyword;
/**
@@ -7766,6 +7923,7 @@
/**
* The semicolon terminating the directive.
*/
+ @override
Token semicolon;
/**
@@ -7821,8 +7979,8 @@
/**
* A postfix unary expression.
*
- * > postfixExpression ::=
- * > [Expression] [Token]
+ * postfixExpression ::=
+ * [Expression] [Token]
*/
class PostfixExpressionImpl extends ExpressionImpl
implements PostfixExpression {
@@ -7834,6 +7992,7 @@
/**
* The postfix operator being applied to the operand.
*/
+ @override
Token operator;
/**
@@ -7842,6 +8001,7 @@
* the operator is not user definable, or if the operator could not be
* resolved.
*/
+ @override
MethodElement propagatedElement;
/**
@@ -7849,6 +8009,7 @@
* operand, or `null` if the AST structure has not been resolved, if the
* operator is not user definable, or if the operator could not be resolved.
*/
+ @override
MethodElement staticElement;
/**
@@ -7935,8 +8096,8 @@
* An identifier that is prefixed or an access to an object property where the
* target of the property access is a simple identifier.
*
- * > prefixedIdentifier ::=
- * > [SimpleIdentifier] '.' [SimpleIdentifier]
+ * prefixedIdentifier ::=
+ * [SimpleIdentifier] '.' [SimpleIdentifier]
*/
class PrefixedIdentifierImpl extends IdentifierImpl
implements PrefixedIdentifier {
@@ -8048,8 +8209,8 @@
/**
* A prefix unary expression.
*
- * > prefixExpression ::=
- * > [Token] [Expression]
+ * prefixExpression ::=
+ * [Token] [Expression]
*/
class PrefixExpressionImpl extends ExpressionImpl implements PrefixExpression {
/**
@@ -8163,8 +8324,8 @@
* as [PrefixedIdentifier] nodes in cases where the target is also a simple
* identifier.
*
- * > propertyAccess ::=
- * > [Expression] '.' [SimpleIdentifier]
+ * propertyAccess ::=
+ * [Expression] '.' [SimpleIdentifier]
*/
class PropertyAccessImpl extends ExpressionImpl implements PropertyAccess {
/**
@@ -8261,8 +8422,8 @@
* The invocation of a constructor in the same class from within a constructor's
* initialization list.
*
- * > redirectingConstructorInvocation ::=
- * > 'this' ('.' identifier)? arguments
+ * redirectingConstructorInvocation ::=
+ * 'this' ('.' identifier)? arguments
*/
class RedirectingConstructorInvocationImpl extends ConstructorInitializerImpl
implements RedirectingConstructorInvocation {
@@ -8349,8 +8510,8 @@
/**
* A rethrow expression.
*
- * > rethrowExpression ::=
- * > 'rethrow'
+ * rethrowExpression ::=
+ * 'rethrow'
*/
class RethrowExpressionImpl extends ExpressionImpl
implements RethrowExpression {
@@ -8388,8 +8549,8 @@
/**
* A return statement.
*
- * > returnStatement ::=
- * > 'return' [Expression]? ';'
+ * returnStatement ::=
+ * 'return' [Expression]? ';'
*/
class ReturnStatementImpl extends StatementImpl implements ReturnStatement {
/**
@@ -8447,8 +8608,8 @@
/**
* A script tag that can optionally occur at the beginning of a compilation unit.
*
- * > scriptTag ::=
- * > '#!' (~NEWLINE)* NEWLINE
+ * scriptTag ::=
+ * '#!' (~NEWLINE)* NEWLINE
*/
class ScriptTagImpl extends AstNodeImpl implements ScriptTag {
/**
@@ -8482,8 +8643,8 @@
/**
* A combinator that restricts the names being imported to those in a given list.
*
- * > showCombinator ::=
- * > 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ * showCombinator ::=
+ * 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
*/
class ShowCombinatorImpl extends CombinatorImpl implements ShowCombinator {
/**
@@ -8523,8 +8684,8 @@
/**
* A simple formal parameter.
*
- * > simpleFormalParameter ::=
- * > ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+ * simpleFormalParameter ::=
+ * ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
*/
class SimpleFormalParameterImpl extends NormalFormalParameterImpl
implements SimpleFormalParameter {
@@ -8604,12 +8765,12 @@
/**
* A simple identifier.
*
- * > simpleIdentifier ::=
- * > initialCharacter internalCharacter*
- * >
- * > initialCharacter ::= '_' | '$' | letter
- * >
- * > internalCharacter ::= '_' | '$' | letter | digit
+ * simpleIdentifier ::=
+ * initialCharacter internalCharacter*
+ *
+ * initialCharacter ::= '_' | '$' | letter
+ *
+ * internalCharacter ::= '_' | '$' | letter | digit
*/
class SimpleIdentifierImpl extends IdentifierImpl implements SimpleIdentifier {
/**
@@ -8892,24 +9053,24 @@
/**
* A string literal expression that does not contain any interpolations.
*
- * > simpleStringLiteral ::=
- * > rawStringLiteral
- * > | basicStringLiteral
- * >
- * > rawStringLiteral ::=
- * > 'r' basicStringLiteral
- * >
- * > simpleStringLiteral ::=
- * > multiLineStringLiteral
- * > | singleLineStringLiteral
- * >
- * > multiLineStringLiteral ::=
- * > "'''" characters "'''"
- * > | '"""' characters '"""'
- * >
- * > singleLineStringLiteral ::=
- * > "'" characters "'"
- * > | '"' characters '"'
+ * simpleStringLiteral ::=
+ * rawStringLiteral
+ * | basicStringLiteral
+ *
+ * rawStringLiteral ::=
+ * 'r' basicStringLiteral
+ *
+ * simpleStringLiteral ::=
+ * multiLineStringLiteral
+ * | singleLineStringLiteral
+ *
+ * multiLineStringLiteral ::=
+ * "'''" characters "'''"
+ * | '"""' characters '"""'
+ *
+ * singleLineStringLiteral ::=
+ * "'" characters "'"
+ * | '"' characters '"'
*/
class SimpleStringLiteralImpl extends SingleStringLiteralImpl
implements SimpleStringLiteral {
@@ -8986,9 +9147,9 @@
/**
* A single string literal expression.
*
- * > singleStringLiteral ::=
- * > [SimpleStringLiteral]
- * > | [StringInterpolation]
+ * singleStringLiteral ::=
+ * [SimpleStringLiteral]
+ * | [StringInterpolation]
*/
abstract class SingleStringLiteralImpl extends StringLiteralImpl
implements SingleStringLiteral {}
@@ -8996,21 +9157,21 @@
/**
* A node that represents a statement.
*
- * > statement ::=
- * > [Block]
- * > | [VariableDeclarationStatement]
- * > | [ForStatement]
- * > | [ForEachStatement]
- * > | [WhileStatement]
- * > | [DoStatement]
- * > | [SwitchStatement]
- * > | [IfStatement]
- * > | [TryStatement]
- * > | [BreakStatement]
- * > | [ContinueStatement]
- * > | [ReturnStatement]
- * > | [ExpressionStatement]
- * > | [FunctionDeclarationStatement]
+ * statement ::=
+ * [Block]
+ * | [VariableDeclarationStatement]
+ * | [ForStatement]
+ * | [ForEachStatement]
+ * | [WhileStatement]
+ * | [DoStatement]
+ * | [SwitchStatement]
+ * | [IfStatement]
+ * | [TryStatement]
+ * | [BreakStatement]
+ * | [ContinueStatement]
+ * | [ReturnStatement]
+ * | [ExpressionStatement]
+ * | [FunctionDeclarationStatement]
*/
abstract class StatementImpl extends AstNodeImpl implements Statement {
@override
@@ -9020,9 +9181,9 @@
/**
* A string interpolation literal.
*
- * > stringInterpolation ::=
- * > ''' [InterpolationElement]* '''
- * > | '"' [InterpolationElement]* '"'
+ * stringInterpolation ::=
+ * ''' [InterpolationElement]* '''
+ * | '"' [InterpolationElement]* '"'
*/
class StringInterpolationImpl extends SingleStringLiteralImpl
implements StringInterpolation {
@@ -9191,10 +9352,10 @@
/**
* A string literal expression.
*
- * > stringLiteral ::=
- * > [SimpleStringLiteral]
- * > | [AdjacentStrings]
- * > | [StringInterpolation]
+ * stringLiteral ::=
+ * [SimpleStringLiteral]
+ * | [AdjacentStrings]
+ * | [StringInterpolation]
*/
abstract class StringLiteralImpl extends LiteralImpl implements StringLiteral {
@override
@@ -9220,8 +9381,8 @@
* The invocation of a superclass' constructor from within a constructor's
* initialization list.
*
- * > superInvocation ::=
- * > 'super' ('.' [SimpleIdentifier])? [ArgumentList]
+ * superInvocation ::=
+ * 'super' ('.' [SimpleIdentifier])? [ArgumentList]
*/
class SuperConstructorInvocationImpl extends ConstructorInitializerImpl
implements SuperConstructorInvocation {
@@ -9308,8 +9469,8 @@
/**
* A super expression.
*
- * > superExpression ::=
- * > 'super'
+ * superExpression ::=
+ * 'super'
*/
class SuperExpressionImpl extends ExpressionImpl implements SuperExpression {
/**
@@ -9346,8 +9507,8 @@
/**
* A case in a switch statement.
*
- * > switchCase ::=
- * > [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+ * switchCase ::=
+ * [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
*/
class SwitchCaseImpl extends SwitchMemberImpl implements SwitchCase {
/**
@@ -9395,8 +9556,8 @@
/**
* The default case in a switch statement.
*
- * > switchDefault ::=
- * > [SimpleIdentifier]* 'default' ':' [Statement]*
+ * switchDefault ::=
+ * [SimpleIdentifier]* 'default' ':' [Statement]*
*/
class SwitchDefaultImpl extends SwitchMemberImpl implements SwitchDefault {
/**
@@ -9427,9 +9588,9 @@
/**
* An element within a switch statement.
*
- * > switchMember ::=
- * > switchCase
- * > | switchDefault
+ * switchMember ::=
+ * switchCase
+ * | switchDefault
*/
abstract class SwitchMemberImpl extends AstNodeImpl implements SwitchMember {
/**
@@ -9488,8 +9649,8 @@
/**
* A switch statement.
*
- * > switchStatement ::=
- * > 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+ * switchStatement ::=
+ * 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
*/
class SwitchStatementImpl extends StatementImpl implements SwitchStatement {
/**
@@ -9584,8 +9745,8 @@
/**
* A symbol literal expression.
*
- * > symbolLiteral ::=
- * > '#' (operator | (identifier ('.' identifier)*))
+ * symbolLiteral ::=
+ * '#' (operator | (identifier ('.' identifier)*))
*/
class SymbolLiteralImpl extends LiteralImpl implements SymbolLiteral {
/**
@@ -9627,8 +9788,8 @@
/**
* A this expression.
*
- * > thisExpression ::=
- * > 'this'
+ * thisExpression ::=
+ * 'this'
*/
class ThisExpressionImpl extends ExpressionImpl implements ThisExpression {
/**
@@ -9665,8 +9826,8 @@
/**
* A throw expression.
*
- * > throwExpression ::=
- * > 'throw' [Expression]
+ * throwExpression ::=
+ * 'throw' [Expression]
*/
class ThrowExpressionImpl extends ExpressionImpl implements ThrowExpression {
/**
@@ -9724,9 +9885,9 @@
/**
* The declaration of one or more top-level variables of the same type.
*
- * > topLevelVariableDeclaration ::=
- * > ('final' | 'const') type? staticFinalDeclarationList ';'
- * > | variableDeclaration ';'
+ * topLevelVariableDeclaration ::=
+ * ('final' | 'const') type? staticFinalDeclarationList ';'
+ * | variableDeclaration ';'
*/
class TopLevelVariableDeclarationImpl extends CompilationUnitMemberImpl
implements TopLevelVariableDeclaration {
@@ -9785,11 +9946,11 @@
/**
* A try statement.
*
- * > tryStatement ::=
- * > 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
- * >
- * > finallyClause ::=
- * > 'finally' [Block]
+ * tryStatement ::=
+ * 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+ *
+ * finallyClause ::=
+ * 'finally' [Block]
*/
class TryStatementImpl extends StatementImpl implements TryStatement {
/**
@@ -9887,12 +10048,12 @@
/**
* The declaration of a type alias.
*
- * > typeAlias ::=
- * > 'typedef' typeAliasBody
- * >
- * > typeAliasBody ::=
- * > classTypeAlias
- * > | functionTypeAlias
+ * typeAlias ::=
+ * 'typedef' typeAliasBody
+ *
+ * typeAliasBody ::=
+ * classTypeAlias
+ * | functionTypeAlias
*/
abstract class TypeAliasImpl extends NamedCompilationUnitMemberImpl
implements TypeAlias {
@@ -9925,8 +10086,8 @@
/**
* A list of type arguments.
*
- * > typeArguments ::=
- * > '<' typeName (',' typeName)* '>'
+ * typeArguments ::=
+ * '<' typeName (',' typeName)* '>'
*/
class TypeArgumentListImpl extends AstNodeImpl implements TypeArgumentList {
/**
@@ -9980,9 +10141,9 @@
/**
* A literal that has a type associated with it.
*
- * > typedLiteral ::=
- * > [ListLiteral]
- * > | [MapLiteral]
+ * typedLiteral ::=
+ * [ListLiteral]
+ * | [MapLiteral]
*/
abstract class TypedLiteralImpl extends LiteralImpl implements TypedLiteral {
/**
@@ -10026,8 +10187,8 @@
/**
* The name of a type, which can optionally include type arguments.
*
- * > typeName ::=
- * > [Identifier] typeArguments?
+ * typeName ::=
+ * [Identifier] typeArguments?
*/
class TypeNameImpl extends AstNodeImpl implements TypeName {
/**
@@ -10111,8 +10272,8 @@
/**
* A type parameter.
*
- * > typeParameter ::=
- * > [SimpleIdentifier] ('extends' [TypeName])?
+ * typeParameter ::=
+ * [SimpleIdentifier] ('extends' [TypeName])?
*/
class TypeParameterImpl extends DeclarationImpl implements TypeParameter {
/**
@@ -10194,8 +10355,8 @@
/**
* Type parameters within a declaration.
*
- * > typeParameterList ::=
- * > '<' [TypeParameter] (',' [TypeParameter])* '>'
+ * typeParameterList ::=
+ * '<' [TypeParameter] (',' [TypeParameter])* '>'
*/
class TypeParameterListImpl extends AstNodeImpl implements TypeParameterList {
/**
@@ -10248,10 +10409,10 @@
/**
* A directive that references a URI.
*
- * > uriBasedDirective ::=
- * > [ExportDirective]
- * > | [ImportDirective]
- * > | [PartDirective]
+ * uriBasedDirective ::=
+ * [ExportDirective]
+ * | [ImportDirective]
+ * | [PartDirective]
*/
abstract class UriBasedDirectiveImpl extends DirectiveImpl
implements UriBasedDirective {
@@ -10354,8 +10515,8 @@
* An identifier that has an initial value associated with it. Instances of this
* class are always children of the class [VariableDeclarationList].
*
- * > variableDeclaration ::=
- * > [SimpleIdentifier] ('=' [Expression])?
+ * variableDeclaration ::=
+ * [SimpleIdentifier] ('=' [Expression])?
*
* TODO(paulberry): the grammar does not allow metadata to be associated with
* a VariableDeclaration, and currently we don't record comments for it either.
@@ -10472,14 +10633,14 @@
/**
* The declaration of one or more variables of the same type.
*
- * > variableDeclarationList ::=
- * > finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
- * >
- * > finalConstVarOrType ::=
- * > | 'final' [TypeName]?
- * > | 'const' [TypeName]?
- * > | 'var'
- * > | [TypeName]
+ * variableDeclarationList ::=
+ * finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+ *
+ * finalConstVarOrType ::=
+ * | 'final' [TypeName]?
+ * | 'const' [TypeName]?
+ * | 'var'
+ * | [TypeName]
*/
class VariableDeclarationListImpl extends AnnotatedNodeImpl
implements VariableDeclarationList {
@@ -10568,8 +10729,8 @@
* A list of variables that are being declared in a context where a statement is
* required.
*
- * > variableDeclarationStatement ::=
- * > [VariableDeclarationList] ';'
+ * variableDeclarationStatement ::=
+ * [VariableDeclarationList] ';'
*/
class VariableDeclarationStatementImpl extends StatementImpl
implements VariableDeclarationStatement {
@@ -10621,8 +10782,8 @@
/**
* A while statement.
*
- * > whileStatement ::=
- * > 'while' '(' [Expression] ')' [Statement]
+ * whileStatement ::=
+ * 'while' '(' [Expression] ')' [Statement]
*/
class WhileStatementImpl extends StatementImpl implements WhileStatement {
/**
@@ -10702,8 +10863,8 @@
/**
* The with clause in a class declaration.
*
- * > withClause ::=
- * > 'with' [TypeName] (',' [TypeName])*
+ * withClause ::=
+ * 'with' [TypeName] (',' [TypeName])*
*/
class WithClauseImpl extends AstNodeImpl implements WithClause {
/**
@@ -10750,8 +10911,8 @@
/**
* A yield statement.
*
- * > yieldStatement ::=
- * > 'yield' '*'? [Expression] ‘;’
+ * yieldStatement ::=
+ * 'yield' '*'? [Expression] ‘;’
*/
class YieldStatementImpl extends StatementImpl implements YieldStatement {
/**
diff --git a/pkg/analyzer/lib/src/dart/ast/token.dart b/pkg/analyzer/lib/src/dart/ast/token.dart
index 02d28e5..1791990 100644
--- a/pkg/analyzer/lib/src/dart/ast/token.dart
+++ b/pkg/analyzer/lib/src/dart/ast/token.dart
@@ -39,6 +39,7 @@
/**
* The first comment in the list of comments that precede this token.
*/
+ @override
CommentToken _precedingComment;
/**
@@ -54,6 +55,7 @@
@override
CommentToken get precedingComments => _precedingComment;
+ @override
void set precedingComments(CommentToken comment) {
_precedingComment = comment;
_setCommentParent(_precedingComment);
@@ -168,6 +170,7 @@
/**
* The first comment in the list of comments that precede this token.
*/
+ @override
CommentToken _precedingComment;
/**
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 82d3761..23869ee 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -160,6 +160,8 @@
@override
Object visitExportDirective(ExportDirective node) {
+ // Remove previous element. (It will remain null if the target is missing.)
+ node.element = null;
Source exportedSource = node.source;
if (exportedSource != null && context.exists(exportedSource)) {
// The exported source will be null if the URI in the export
@@ -180,10 +182,16 @@
node.element = exportElement;
exports.add(exportElement);
if (exportSourceKindMap[exportedSource] != SourceKind.LIBRARY) {
+ int offset = node.offset;
+ int length = node.length;
+ if (uriLiteral != null) {
+ offset = uriLiteral.offset;
+ length = uriLiteral.length;
+ }
errors.add(new AnalysisError(
- exportedSource,
- uriLiteral.offset,
- uriLiteral.length,
+ libraryElement.source,
+ offset,
+ length,
CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
[uriLiteral.toSource()]));
}
@@ -194,6 +202,9 @@
@override
Object visitImportDirective(ImportDirective node) {
+ // Remove previous element. (It will remain null if the target is missing.)
+ node.element = null;
+
String uriContent = node.uriContent;
if (DartUriResolver.isDartExtUri(uriContent)) {
libraryElement.hasExtUri = true;
@@ -234,11 +245,17 @@
node.element = importElement;
imports.add(importElement);
if (importSourceKindMap[importedSource] != SourceKind.LIBRARY) {
+ int offset = node.offset;
+ int length = node.length;
+ if (uriLiteral != null) {
+ offset = uriLiteral.offset;
+ length = uriLiteral.length;
+ }
ErrorCode errorCode = (importElement.isDeferred
? StaticWarningCode.IMPORT_OF_NON_LIBRARY
: CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
- errors.add(new AnalysisError(importedSource, uriLiteral.offset,
- uriLiteral.length, errorCode, [uriLiteral.toSource()]));
+ errors.add(new AnalysisError(libraryElement.source, offset, length,
+ errorCode, [uriLiteral.toSource()]));
}
}
}
@@ -365,6 +382,7 @@
if (stackTraceParameter != null) {
LocalVariableElementImpl stackTrace =
new LocalVariableElementImpl.forNode(stackTraceParameter);
+ _setCodeRange(stackTrace, stackTraceParameter);
_currentHolder.addLocalVariable(stackTrace);
stackTraceParameter.staticElement = stackTrace;
}
@@ -396,6 +414,7 @@
}
SimpleIdentifier className = node.name;
ClassElementImpl element = new ClassElementImpl.forNode(className);
+ _setCodeRange(element, node);
element.metadata = _createElementAnnotations(node.metadata);
List<TypeParameterElement> typeParameters = holder.typeParameters;
List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
@@ -445,6 +464,7 @@
_visitChildren(holder, node);
SimpleIdentifier className = node.name;
ClassElementImpl element = new ClassElementImpl.forNode(className);
+ _setCodeRange(element, node);
element.metadata = _createElementAnnotations(node.metadata);
element.abstract = node.abstractKeyword != null;
element.mixinApplication = true;
@@ -462,6 +482,14 @@
}
@override
+ Object visitCompilationUnit(CompilationUnit node) {
+ if (compilationUnitElement is ElementImpl) {
+ _setCodeRange(compilationUnitElement as ElementImpl, node);
+ }
+ return super.visitCompilationUnit(node);
+ }
+
+ @override
Object visitConstructorDeclaration(ConstructorDeclaration node) {
ElementHolder holder = new ElementHolder();
bool wasInFunction = _inFunction;
@@ -475,6 +503,7 @@
SimpleIdentifier constructorName = node.name;
ConstructorElementImpl element =
new ConstructorElementImpl.forNode(constructorName);
+ _setCodeRange(element, node);
element.metadata = _createElementAnnotations(node.metadata);
setElementDocumentationComment(element, node);
if (node.externalKeyword != null) {
@@ -516,6 +545,7 @@
SimpleIdentifier variableName = node.identifier;
LocalVariableElementImpl element =
new LocalVariableElementImpl.forNode(variableName);
+ _setCodeRange(element, node);
element.metadata = _createElementAnnotations(node.metadata);
ForEachStatement statement = node.parent as ForEachStatement;
int declarationEnd = node.offset + node.length;
@@ -548,6 +578,7 @@
} else {
parameter = new DefaultParameterElementImpl.forNode(parameterName);
}
+ _setCodeRange(parameter, node);
parameter.const3 = node.isConst;
parameter.final2 = node.isFinal;
parameter.parameterKind = node.kind;
@@ -584,6 +615,7 @@
Object visitEnumDeclaration(EnumDeclaration node) {
SimpleIdentifier enumName = node.name;
ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
+ _setCodeRange(enumElement, node);
enumElement.metadata = _createElementAnnotations(node.metadata);
enumElement.enum2 = true;
setElementDocumentationComment(enumElement, node);
@@ -613,6 +645,7 @@
_fieldMap == null ? null : _fieldMap[parameterName.name];
FieldFormalParameterElementImpl parameter =
new FieldFormalParameterElementImpl.forNode(parameterName);
+ _setCodeRange(parameter, node);
parameter.const3 = node.isConst;
parameter.final2 = node.isFinal;
parameter.parameterKind = node.kind;
@@ -654,6 +687,7 @@
SimpleIdentifier functionName = node.name;
FunctionElementImpl element =
new FunctionElementImpl.forNode(functionName);
+ _setCodeRange(element, node);
element.metadata = _createElementAnnotations(node.metadata);
setElementDocumentationComment(element, node);
if (node.externalKeyword != null) {
@@ -701,6 +735,7 @@
if (node.isGetter) {
PropertyAccessorElementImpl getter =
new PropertyAccessorElementImpl.forNode(propertyNameNode);
+ _setCodeRange(getter, node);
getter.metadata = _createElementAnnotations(node.metadata);
setElementDocumentationComment(getter, node);
if (node.externalKeyword != null) {
@@ -728,6 +763,7 @@
} else {
PropertyAccessorElementImpl setter =
new PropertyAccessorElementImpl.forNode(propertyNameNode);
+ _setCodeRange(setter, node);
setter.metadata = _createElementAnnotations(node.metadata);
setElementDocumentationComment(setter, node);
if (node.externalKeyword != null) {
@@ -779,6 +815,7 @@
FunctionBody body = node.body;
FunctionElementImpl element =
new FunctionElementImpl.forOffset(node.beginToken.offset);
+ _setCodeRange(element, node);
element.functions = holder.functions;
element.labels = holder.labels;
element.localVariables = holder.localVariables;
@@ -817,6 +854,7 @@
List<TypeParameterElement> typeParameters = holder.typeParameters;
FunctionTypeAliasElementImpl element =
new FunctionTypeAliasElementImpl.forNode(aliasName);
+ _setCodeRange(element, node);
element.metadata = _createElementAnnotations(node.metadata);
setElementDocumentationComment(element, node);
element.parameters = parameters;
@@ -835,6 +873,7 @@
SimpleIdentifier parameterName = node.identifier;
ParameterElementImpl parameter =
new ParameterElementImpl.forNode(parameterName);
+ _setCodeRange(parameter, node);
parameter.parameterKind = node.kind;
_setParameterVisibleRange(node, parameter);
_currentHolder.addParameter(parameter);
@@ -867,6 +906,7 @@
SimpleIdentifier labelName = label.label;
LabelElementImpl element =
new LabelElementImpl.forNode(labelName, onSwitchStatement, false);
+ _setCodeRange(element, node);
_currentHolder.addLabel(element);
labelName.staticElement = element;
}
@@ -902,6 +942,7 @@
}
MethodElementImpl element =
new MethodElementImpl(nameOfMethod, methodName.offset);
+ _setCodeRange(element, node);
element.metadata = _createElementAnnotations(node.metadata);
setElementDocumentationComment(element, node);
element.abstract = node.isAbstract;
@@ -940,6 +981,7 @@
if (node.isGetter) {
PropertyAccessorElementImpl getter =
new PropertyAccessorElementImpl.forNode(propertyNameNode);
+ _setCodeRange(getter, node);
getter.metadata = _createElementAnnotations(node.metadata);
setElementDocumentationComment(getter, node);
if (node.externalKeyword != null) {
@@ -967,6 +1009,7 @@
} else {
PropertyAccessorElementImpl setter =
new PropertyAccessorElementImpl.forNode(propertyNameNode);
+ _setCodeRange(setter, node);
setter.metadata = _createElementAnnotations(node.metadata);
setElementDocumentationComment(setter, node);
if (node.externalKeyword != null) {
@@ -1045,6 +1088,7 @@
SimpleIdentifier parameterName = node.identifier;
ParameterElementImpl parameter =
new ParameterElementImpl.forNode(parameterName);
+ _setCodeRange(parameter, node);
parameter.const3 = node.isConst;
parameter.final2 = node.isFinal;
parameter.parameterKind = node.kind;
@@ -1065,7 +1109,8 @@
Object visitSwitchCase(SwitchCase node) {
for (Label label in node.labels) {
SimpleIdentifier labelName = label.label;
- LabelElementImpl element = new LabelElementImpl.forNode(labelName, false, true);
+ LabelElementImpl element =
+ new LabelElementImpl.forNode(labelName, false, true);
_currentHolder.addLabel(element);
labelName.staticElement = element;
}
@@ -1076,7 +1121,8 @@
Object visitSwitchDefault(SwitchDefault node) {
for (Label label in node.labels) {
SimpleIdentifier labelName = label.label;
- LabelElementImpl element = new LabelElementImpl.forNode(labelName, false, true);
+ LabelElementImpl element =
+ new LabelElementImpl.forNode(labelName, false, true);
_currentHolder.addLabel(element);
labelName.staticElement = element;
}
@@ -1088,6 +1134,7 @@
SimpleIdentifier parameterName = node.name;
TypeParameterElementImpl typeParameter =
new TypeParameterElementImpl.forNode(parameterName);
+ _setCodeRange(typeParameter, node);
typeParameter.metadata = _createElementAnnotations(node.metadata);
TypeParameterTypeImpl typeParameterType =
new TypeParameterTypeImpl(typeParameter);
@@ -1116,6 +1163,7 @@
}
element = field;
field.static = fieldNode.isStatic;
+ _setCodeRange(element, node);
setElementDocumentationComment(element, fieldNode);
field.hasImplicitType = varList.type == null;
_currentHolder.addField(field);
@@ -1129,6 +1177,7 @@
variable = new LocalVariableElementImpl.forNode(variableName);
}
element = variable;
+ _setCodeRange(element, node);
Block enclosingBlock = node.getAncestor((node) => node is Block);
// TODO(brianwilkerson) This isn't right for variables declared in a for
// loop.
@@ -1145,6 +1194,7 @@
variable = new TopLevelVariableElementImpl.forNode(variableName);
}
element = variable;
+ _setCodeRange(element, node);
if (varList.parent is TopLevelVariableDeclaration) {
setElementDocumentationComment(element, varList.parent);
}
@@ -1207,8 +1257,9 @@
elementAnnotations = _createElementAnnotations(node.metadata);
}
for (VariableDeclaration variableDeclaration in node.variables) {
- (variableDeclaration.element as ElementImpl).metadata =
- elementAnnotations;
+ ElementImpl element = variableDeclaration.element as ElementImpl;
+ _setCodeRange(element, node.parent);
+ element.metadata = elementAnnotations;
}
return null;
}
@@ -1300,6 +1351,10 @@
return null;
}
+ void _setCodeRange(ElementImpl element, AstNode node) {
+ element.setCodeRange(node.offset, node.length);
+ }
+
/**
* Sets the visible source range for formal parameter.
*/
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 5305395..e3f4dfe 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -16,6 +16,7 @@
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/constant.dart'
show DartObject, EvaluationResultImpl;
+import 'package:analyzer/src/generated/element_handle.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisEngine;
import 'package:analyzer/src/generated/java_core.dart';
@@ -85,11 +86,13 @@
* A list containing all of the mixins that are applied to the class being
* extended in order to derive the superclass of this class.
*/
+ @override
List<InterfaceType> mixins = InterfaceType.EMPTY_LIST;
/**
* A list containing all of the interfaces that are implemented by this class.
*/
+ @override
List<InterfaceType> interfaces = InterfaceType.EMPTY_LIST;
/**
@@ -101,11 +104,13 @@
* The superclass of the class, or `null` if the class does not have an
* explicit superclass.
*/
+ @override
InterfaceType supertype;
/**
* The type defined by the class.
*/
+ @override
InterfaceType type;
/**
@@ -910,6 +915,7 @@
/**
* The source that corresponds to this compilation unit.
*/
+ @override
Source source;
/**
@@ -1562,12 +1568,23 @@
static String _DEPRECATED_VARIABLE_NAME = "deprecated";
/**
+ * The name of `meta` library, used to define analysis annotations.
+ */
+ static String _META_LIB_NAME = "meta";
+
+ /**
* The name of the top-level variable used to mark a method as being expected
* to override an inherited method.
*/
static String _OVERRIDE_VARIABLE_NAME = "override";
/**
+ * The name of the top-level variable used to mark a method as being
+ * protected.
+ */
+ static String _PROTECTED_VARIABLE_NAME = "protected";
+
+ /**
* The name of the top-level variable used to mark a class as implementing a
* proxy object.
*/
@@ -1580,7 +1597,7 @@
Element element;
/**
- * The compliation unit in which this annotation appears.
+ * The compilation unit in which this annotation appears.
*/
final CompilationUnitElementImpl compilationUnit;
@@ -1611,51 +1628,33 @@
@override
bool get isDeprecated {
- if (element != null) {
- LibraryElement library = element.library;
- if (library != null && library.isDartCore) {
- if (element is ConstructorElement) {
- ConstructorElement constructorElement = element as ConstructorElement;
- if (constructorElement.enclosingElement.name ==
- _DEPRECATED_CLASS_NAME) {
- return true;
- }
- } else if (element is PropertyAccessorElement &&
- element.name == _DEPRECATED_VARIABLE_NAME) {
- return true;
- }
+ if (element?.library?.isDartCore == true) {
+ if (element is ConstructorElement) {
+ return element.enclosingElement.name == _DEPRECATED_CLASS_NAME;
+ } else if (element is PropertyAccessorElement) {
+ return element.name == _DEPRECATED_VARIABLE_NAME;
}
}
return false;
}
@override
- bool get isOverride {
- if (element != null) {
- LibraryElement library = element.library;
- if (library != null && library.isDartCore) {
- if (element is PropertyAccessorElement &&
- element.name == _OVERRIDE_VARIABLE_NAME) {
- return true;
- }
- }
- }
- return false;
- }
+ bool get isOverride =>
+ element is PropertyAccessorElement &&
+ element.name == _OVERRIDE_VARIABLE_NAME &&
+ element.library?.isDartCore == true;
@override
- bool get isProxy {
- if (element != null) {
- LibraryElement library = element.library;
- if (library != null && library.isDartCore) {
- if (element is PropertyAccessorElement &&
- element.name == PROXY_VARIABLE_NAME) {
- return true;
- }
- }
- }
- return false;
- }
+ bool get isProtected =>
+ element is PropertyAccessorElement &&
+ element.name == _PROTECTED_VARIABLE_NAME &&
+ element.library?.name == _META_LIB_NAME;
+
+ @override
+ bool get isProxy =>
+ element is PropertyAccessorElement &&
+ element.name == PROXY_VARIABLE_NAME &&
+ element.library?.isDartCore == true;
/**
* Get the library containing this annotation.
@@ -1736,6 +1735,17 @@
int _docRangeLength;
/**
+ * The offset of the beginning of the element's code in the file that contains
+ * the element, or `null` if the element is synthetic.
+ */
+ int _codeOffset;
+
+ /**
+ * The length of the element's code, or `null` if the element is synthetic.
+ */
+ int _codeLength;
+
+ /**
* Initialize a newly created element to have the given [name] at the given
* [_nameOffset].
*/
@@ -1749,6 +1759,17 @@
ElementImpl.forNode(Identifier name)
: this(name == null ? "" : name.name, name == null ? -1 : name.offset);
+ /**
+ * The length of the element's code, or `null` if the element is synthetic.
+ */
+ int get codeLength => _codeLength;
+
+ /**
+ * The offset of the beginning of the element's code in the file that contains
+ * the element, or `null` if the element is synthetic.
+ */
+ int get codeOffset => _codeOffset;
+
@override
AnalysisContext get context {
if (_enclosingElement == null) {
@@ -1837,6 +1858,16 @@
}
@override
+ bool get isProtected {
+ for (ElementAnnotation annotation in metadata) {
+ if (annotation.isProtected) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @override
bool get isPublic => !isPrivate;
@override
@@ -2019,6 +2050,14 @@
}
/**
+ * Set the code range for this element.
+ */
+ void setCodeRange(int offset, int length) {
+ _codeOffset = offset;
+ _codeLength = length;
+ }
+
+ /**
* Set the documentation comment source range for this element.
*/
void setDocRange(int offset, int length) {
@@ -3098,6 +3137,24 @@
nameLength = name != null ? name.length : 0;
@override
+ int get codeLength {
+ if (_definingCompilationUnit is CompilationUnitElementImpl) {
+ return (_definingCompilationUnit as CompilationUnitElementImpl)
+ .codeLength;
+ }
+ return null;
+ }
+
+ @override
+ int get codeOffset {
+ if (_definingCompilationUnit is CompilationUnitElementImpl) {
+ return (_definingCompilationUnit as CompilationUnitElementImpl)
+ .codeOffset;
+ }
+ return null;
+ }
+
+ @override
CompilationUnitElement get definingCompilationUnit =>
_definingCompilationUnit;
@@ -3148,9 +3205,6 @@
}
@override
- int get hashCode => _definingCompilationUnit.hashCode;
-
- @override
bool get hasLoadLibraryFunction {
if (_definingCompilationUnit.hasLoadLibraryFunction) {
return true;
@@ -3244,6 +3298,7 @@
@override
LibraryElement get library => this;
+ @override
List<LibraryElement> get libraryCycle {
if (_libraryCycle != null) {
return _libraryCycle;
@@ -3265,6 +3320,17 @@
indices[library] = index;
active.add(library);
stack.add(library);
+ LibraryElementImpl getActualLibrary(LibraryElement lib) {
+ // TODO(paulberry): this means that computing a library cycle will be
+ // expensive for libraries resynthesized from summaries, since it will
+ // require fully resynthesizing all the libraries in the cycle as well
+ // as any libraries they import or export. Try to find a better way.
+ if (lib is LibraryElementHandle) {
+ return lib.actualElement;
+ } else {
+ return lib;
+ }
+ }
void recurse(LibraryElementImpl child) {
if (!indices.containsKey(child)) {
// We haven't visited this child yet, so recurse on the child,
@@ -3282,9 +3348,11 @@
// Recurse on all of the children in the import/export graph, filtering
// out those for which library cycles have already been computed.
library.exportedLibraries
+ .map(getActualLibrary)
.where((l) => l._libraryCycle == null)
.forEach(recurse);
library.importedLibraries
+ .map(getActualLibrary)
.where((l) => l._libraryCycle == null)
.forEach(recurse);
@@ -3365,11 +3433,6 @@
}
@override
- bool operator ==(Object object) =>
- object is LibraryElementImpl &&
- _definingCompilationUnit == object.definingCompilationUnit;
-
- @override
accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
/**
@@ -3929,6 +3992,9 @@
}
@override
+ bool get isProtected => false;
+
+ @override
bool get isPublic => !isPrivate;
@override
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 558b5ec..28bce1e 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -455,6 +455,7 @@
@override
String get documentationComment => _baseElement.documentationComment;
+ @override
int get id => _baseElement.id;
@override
@@ -467,6 +468,9 @@
bool get isPrivate => _baseElement.isPrivate;
@override
+ bool get isProtected => _baseElement.isProtected;
+
+ @override
bool get isPublic => _baseElement.isPublic;
@override
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index cfc076ff..29658fb 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1285,13 +1285,13 @@
// In other words, given the set of all types R such that T << Future<R>,
// let S be the most specific of those types, if any such S exists.
//
- // Since we only care about the most specific type, it is sufficent to
+ // Since we only care about the most specific type, it is sufficient to
// look at the types appearing as a parameter to Future in the type
// hierarchy of T. We don't need to consider the supertypes of those
// types, since they are by definition less specific.
List<DartType> candidateTypes =
_searchTypeHierarchyForFutureTypeParameters();
- DartType flattenResult = _findMostSpecificType(candidateTypes, typeSystem);
+ DartType flattenResult = findMostSpecificType(candidateTypes, typeSystem);
if (flattenResult != null) {
return flattenResult;
}
@@ -1923,7 +1923,7 @@
* If there is a single type which is at least as specific as all of the
* types in [types], return it. Otherwise return `null`.
*/
- static DartType _findMostSpecificType(
+ static DartType findMostSpecificType(
List<DartType> types, TypeSystem typeSystem) {
// The << relation ("more specific than") is a partial ordering on types,
// so to find the most specific type of a set, we keep a bucket of the most
diff --git a/pkg/analyzer/lib/src/error.dart b/pkg/analyzer/lib/src/error.dart
index 35ffb7c..166ba13 100644
--- a/pkg/analyzer/lib/src/error.dart
+++ b/pkg/analyzer/lib/src/error.dart
@@ -20,6 +20,7 @@
String get message => toString();
+ @override
String toString() {
var builder = new StringBuffer();
@@ -89,5 +90,6 @@
new UnmodifiableListView<AnalyzerError>(_errors);
String get message => toString();
+ @override
String toString() => errors.join("\n");
}
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index b2d1e0d..8d4de8e 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -2505,6 +2505,7 @@
/**
* The run-time type of this object.
*/
+ @override
final ParameterizedType type;
/**
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 84b4bdc..9ed587f 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -4,10 +4,10 @@
library analyzer.src.generated.element_handle;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
@@ -358,6 +358,9 @@
bool get isPrivate => actualElement.isPrivate;
@override
+ bool get isProtected => actualElement.isProtected;
+
+ @override
bool get isPublic => actualElement.isPublic;
@override
@@ -766,6 +769,9 @@
ElementKind get kind => ElementKind.LIBRARY;
@override
+ List<LibraryElement> get libraryCycle => actualElement.libraryCycle;
+
+ @override
FunctionElement get loadLibraryFunction => actualElement.loadLibraryFunction;
@override
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index c3c343b..a9a3881 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -2539,6 +2539,7 @@
/**
* The name of the synthetic identifier.
*/
+ @override
final String name;
/**
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index c3aa019..57d35d9 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -922,6 +922,7 @@
* The analysis errors associated with a source, or `null` if there are no
* errors.
*/
+ @override
final List<AnalysisError> errors;
/**
@@ -1528,18 +1529,21 @@
/**
* The source for which the result is being reported.
*/
+ @override
final Source source;
/**
* The parsed, but maybe not resolved Dart AST that changed as a result of
* the analysis, or `null` if the AST was not changed.
*/
+ @override
CompilationUnit parsedDartUnit;
/**
* The fully resolved Dart AST that changed as a result of the analysis, or
* `null` if the AST was not changed.
*/
+ @override
CompilationUnit resolvedDartUnit;
/**
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 446ca59..59879fc 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -85,7 +85,7 @@
/**
* The source in which the error occurred, or `null` if unknown.
*/
- Source source;
+ final Source source;
/**
* The character offset from the beginning of the source (zero based) where
@@ -2482,8 +2482,10 @@
// error.dart:
//
AnalysisOptionsErrorCode.PARSE_ERROR,
- AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE,
AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES,
+ AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE,
+ AnalysisOptionsWarningCode.UNSUPPORTED_VALUE,
+ AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
CheckedModeCompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
@@ -2549,6 +2551,7 @@
CompileTimeErrorCode.EXTENDS_NON_CLASS,
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS,
+ CompileTimeErrorCode.EXTRA_ARGUMENT_TO_ASSERT,
CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS,
CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS,
CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER,
@@ -2664,6 +2667,7 @@
CompileTimeErrorCode.YIELD_EACH_IN_NON_GENERATOR,
CompileTimeErrorCode.YIELD_IN_NON_GENERATOR,
HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
+ HintCode.CAN_BE_NULL_AFTER_NULL_AWARE,
HintCode.DEAD_CODE,
HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH,
HintCode.DEAD_CODE_ON_CATCH_SUBTYPE,
@@ -2676,7 +2680,9 @@
HintCode.IS_NOT_INT,
HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION,
HintCode.INVALID_ASSIGNMENT,
+ HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
HintCode.MISSING_RETURN,
+ HintCode.NULL_AWARE_IN_CONDITION,
HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER,
HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD,
HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER,
@@ -2688,6 +2694,7 @@
HintCode.UNDEFINED_OPERATOR,
HintCode.UNDEFINED_SETTER,
HintCode.UNNECESSARY_CAST,
+ HintCode.UNNECESSARY_NO_SUCH_METHOD,
HintCode.UNNECESSARY_TYPE_CHECK_FALSE,
HintCode.UNNECESSARY_TYPE_CHECK_TRUE,
HintCode.UNUSED_ELEMENT,
@@ -2699,7 +2706,6 @@
HintCode.USE_OF_VOID_RESULT,
HintCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE,
HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE,
- HintCode.NULL_AWARE_IN_CONDITION,
HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT,
HtmlErrorCode.PARSE_ERROR,
HtmlWarningCode.INVALID_URI,
@@ -2727,6 +2733,7 @@
StaticTypeWarningCode.UNDEFINED_FUNCTION,
StaticTypeWarningCode.UNDEFINED_GETTER,
StaticTypeWarningCode.UNDEFINED_METHOD,
+ StaticTypeWarningCode.UNDEFINED_METHOD_WITH_CONSTRUCTOR,
StaticTypeWarningCode.UNDEFINED_OPERATOR,
StaticTypeWarningCode.UNDEFINED_SETTER,
StaticTypeWarningCode.UNDEFINED_SUPER_GETTER,
@@ -2773,11 +2780,11 @@
StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC,
StaticWarningCode.INVALID_GETTER_OVERRIDE_RETURN_TYPE,
StaticWarningCode.INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE,
+ StaticWarningCode.INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS,
+ StaticWarningCode.INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND,
StaticWarningCode.INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE,
StaticWarningCode.INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE,
StaticWarningCode.INVALID_METHOD_OVERRIDE_RETURN_TYPE,
- StaticWarningCode.INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND,
- StaticWarningCode.INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS,
StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
StaticWarningCode.INVALID_OVERRIDE_NAMED,
@@ -2845,6 +2852,7 @@
ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW,
ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW,
ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER,
+ ParserErrorCode.ASYNC_NOT_SUPPORTED,
ParserErrorCode.BREAK_OUTSIDE_OF_LOOP,
ParserErrorCode.CLASS_IN_CLASS,
ParserErrorCode.COLON_IN_PLACE_OF_IN,
@@ -2908,6 +2916,7 @@
ParserErrorCode.INVALID_CODE_POINT,
ParserErrorCode.INVALID_COMMENT_REFERENCE,
ParserErrorCode.INVALID_HEX_ESCAPE,
+ ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION,
ParserErrorCode.INVALID_OPERATOR,
ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
ParserErrorCode.INVALID_STAR_AFTER_ASYNC,
@@ -3533,6 +3542,18 @@
"A value of type '{0}' cannot be assigned to a variable of type '{1}'");
/**
+ * This hint is generated anywhere where a member annotated with `@protected`
+ * is used outside an instance member of a subclass.
+ *
+ * Parameters:
+ * 0: the name of the member
+ * 1: the name of the defining class
+ */
+ static const HintCode INVALID_USE_OF_PROTECTED_MEMBER = const HintCode(
+ 'INVALID_USE_OF_PROTECTED_MEMBER',
+ "The member '{0}' can only be used within instance members of subclasses of '{1}'");
+
+ /**
* Generate a hint for methods or functions that have a return type, but do
* not have a non-void return statement on all branches. At the end of methods
* or functions with no return, Dart implicitly returns `null`, avoiding these
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 7cc84d3..fc8c860 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -1621,6 +1621,7 @@
RecordingErrorListener errorListener = new RecordingErrorListener();
Parser parser = new Parser(_unitSource, errorListener);
AnalysisOptions options = _unitElement.context.analysisOptions;
+ parser.parseConditionalDirectives = options.enableConditionalDirectives;
parser.parseGenericMethods = options.enableGenericMethods;
CompilationUnit unit = parser.parseCompilationUnit(token);
_newParseErrors = errorListener.errors;
diff --git a/pkg/analyzer/lib/src/generated/java_io.dart b/pkg/analyzer/lib/src/generated/java_io.dart
index dc054d0..2e0deb1 100644
--- a/pkg/analyzer/lib/src/generated/java_io.dart
+++ b/pkg/analyzer/lib/src/generated/java_io.dart
@@ -25,7 +25,9 @@
this._path = pathContext.join(base._path, child);
}
}
+ @override
int get hashCode => _path.hashCode;
+ @override
bool operator ==(other) {
return other is JavaFile && other._path == _path;
}
@@ -101,6 +103,7 @@
}
String readAsStringSync() => _newFile().readAsStringSync();
+ @override
String toString() => _path.toString();
Uri toURI() {
String path = getAbsolutePath();
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 8ec719a..9eff933 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -125,8 +125,6 @@
'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()),
'expectKeyword_1': new MethodTrampoline(
1, (Parser target, arg0) => target._expectKeyword(arg0)),
- 'expectSemicolon_0':
- new MethodTrampoline(0, (Parser target) => target._expectSemicolon()),
'findRange_2': new MethodTrampoline(
2, (Parser target, arg0, arg1) => target._findRange(arg0, arg1)),
'getCodeBlockRanges_1': new MethodTrampoline(
@@ -2510,7 +2508,7 @@
commentAndMetadata.metadata,
null,
new VariableDeclarationList(null, null, keyword, null, variables),
- _expectSemicolon());
+ _expect(TokenType.SEMICOLON));
}
_reportErrorForToken(
ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
@@ -3797,10 +3795,9 @@
}
_reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
_currentToken.previous, [type.lexeme]);
- } else {
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
+ return _createSyntheticToken(TokenType.SEMICOLON);
}
+ _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
return _currentToken;
}
@@ -3834,21 +3831,6 @@
}
/**
- * If the current token is a semicolon, return it after advancing to the next
- * token. Otherwise report an error and create a synthetic semicolon.
- */
- Token _expectSemicolon() {
- // TODO(scheglov) consider pushing this behavior into [_expect]
- if (_matches(TokenType.SEMICOLON)) {
- return getAndAdvance();
- } else {
- _reportErrorForToken(
- ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [";"]);
- return _createSyntheticToken(TokenType.SEMICOLON);
- }
- }
-
- /**
* Search the given list of [ranges] for a range that contains the given
* [index]. Return the range that was found, or `null` if none of the ranges
* contain the index.
@@ -5241,7 +5223,7 @@
commentAndMetadata.comment,
commentAndMetadata.metadata,
new VariableDeclarationList(null, null, keyword, null, variables),
- _expectSemicolon());
+ _expect(TokenType.SEMICOLON));
}
_reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
return null;
@@ -5817,7 +5799,7 @@
StringLiteral libraryUri = _parseUri();
List<Configuration> configurations = _parseConfigurations();
List<Combinator> combinators = _parseCombinators();
- Token semicolon = _expectSemicolon();
+ Token semicolon = _expect(TokenType.SEMICOLON);
return new ExportDirective(
commentAndMetadata.comment,
commentAndMetadata.metadata,
@@ -6040,12 +6022,12 @@
_reportErrorForToken(
ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword);
}
- Token leftSeparator = _expectSemicolon();
+ Token leftSeparator = _expect(TokenType.SEMICOLON);
Expression condition = null;
if (!_matches(TokenType.SEMICOLON)) {
condition = parseExpression2();
}
- Token rightSeparator = _expectSemicolon();
+ Token rightSeparator = _expect(TokenType.SEMICOLON);
List<Expression> updaters = null;
if (!_matches(TokenType.CLOSE_PAREN)) {
updaters = _parseExpressionList();
@@ -6520,7 +6502,7 @@
}
}
List<Combinator> combinators = _parseCombinators();
- Token semicolon = _expectSemicolon();
+ Token semicolon = _expect(TokenType.SEMICOLON);
return new ImportDirective(
commentAndMetadata.comment,
commentAndMetadata.metadata,
@@ -7154,7 +7136,8 @@
_reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
} else {
- return new ExpressionStatement(parseExpression2(), _expectSemicolon());
+ return new ExpressionStatement(
+ parseExpression2(), _expect(TokenType.SEMICOLON));
}
}
@@ -9973,7 +9956,12 @@
@override
bool visitAdjacentStrings(AdjacentStrings node) {
AdjacentStrings toNode = this._toNode as AdjacentStrings;
- return _isEqualNodeLists(node.strings, toNode.strings);
+ if (_isEqualNodeLists(node.strings, toNode.strings)) {
+ toNode.staticType = node.staticType;
+ toNode.propagatedType = node.propagatedType;
+ return true;
+ }
+ return false;
}
@override
@@ -10523,7 +10511,9 @@
if (_and(_isEqualNodes(node.function, toNode.function),
_isEqualNodes(node.argumentList, toNode.argumentList))) {
toNode.propagatedElement = node.propagatedElement;
+ toNode.propagatedInvokeType = node.propagatedInvokeType;
toNode.propagatedType = node.propagatedType;
+ toNode.staticInvokeType = node.staticInvokeType;
toNode.staticElement = node.staticElement;
toNode.staticType = node.staticType;
return true;
@@ -10785,7 +10775,9 @@
_isEqualTokens(node.operator, toNode.operator),
_isEqualNodes(node.methodName, toNode.methodName),
_isEqualNodes(node.argumentList, toNode.argumentList))) {
+ toNode.propagatedInvokeType = node.propagatedInvokeType;
toNode.propagatedType = node.propagatedType;
+ toNode.staticInvokeType = node.staticInvokeType;
toNode.staticType = node.staticType;
return true;
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 45c75b2..491d391 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -206,6 +206,7 @@
@override
Object visitMethodInvocation(MethodInvocation node) {
_checkForCanBeNullAfterNullAware(node.realTarget, node.operator);
+ _checkForInvalidProtectedMethodCalls(node);
return super.visitMethodInvocation(node);
}
@@ -237,6 +238,7 @@
@override
Object visitSimpleIdentifier(SimpleIdentifier node) {
_checkForDeprecatedMemberUseAtIdentifier(node);
+ _checkForInvalidProtectedPropertyAccess(node);
return super.visitSimpleIdentifier(node);
}
@@ -608,6 +610,70 @@
}
/**
+ * Produces a hint if the given invocation is of a protected method outside
+ * a subclass instance method.
+ */
+ void _checkForInvalidProtectedMethodCalls(MethodInvocation node) {
+ Element element = node.methodName.bestElement;
+ if (element == null || !element.isProtected) {
+ return;
+ }
+
+ ClassElement definingClass = element.enclosingElement;
+
+ MethodDeclaration decl =
+ node.getAncestor((AstNode node) => node is MethodDeclaration);
+ if (decl == null) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+ node,
+ [node.methodName.toString(), definingClass.name]);
+ return;
+ }
+
+ ClassElement invokingClass = decl.element?.enclosingElement;
+ if (invokingClass != null) {
+ if (!_hasSuperClassOrMixin(invokingClass, definingClass.type)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+ node,
+ [node.methodName.toString(), definingClass.name]);
+ }
+ }
+ }
+
+ /**
+ * Produces a hint if the given identifier is a protected field or getter
+ * accessed outside a subclass.
+ */
+ void _checkForInvalidProtectedPropertyAccess(SimpleIdentifier identifier) {
+ if (identifier.inDeclarationContext()) {
+ return;
+ }
+ Element element = identifier.bestElement;
+ if (element is PropertyAccessorElement &&
+ element.enclosingElement is ClassElement &&
+ (element.isProtected || element.variable.isProtected)) {
+ ClassElement definingClass = element.enclosingElement;
+ ClassDeclaration accessingClass =
+ identifier.getAncestor((AstNode node) => node is ClassDeclaration);
+
+ if (accessingClass == null) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+ identifier,
+ [identifier.name.toString(), definingClass.name]);
+ } else if (!_hasSuperClassOrMixin(
+ accessingClass.element, definingClass.type)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
+ identifier,
+ [identifier.name.toString(), definingClass.name]);
+ }
+ }
+ }
+
+ /**
* Check that the imported library does not define a loadLibrary function. The import has already
* been determined to be deferred when this is called.
*
@@ -790,35 +856,6 @@
}
/**
- * Check for the passed class declaration for the
- * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
- *
- * @param node the class declaration to check
- * @return `true` if and only if a hint code is generated on the passed node
- * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
- */
-// bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
-// ClassElement classElement = node.element;
-// if (classElement == null) {
-// return false;
-// }
-// MethodElement equalsOperatorMethodElement =
-// classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
-// if (equalsOperatorMethodElement != null) {
-// PropertyAccessorElement hashCodeElement =
-// classElement.getGetter(_HASHCODE_GETTER_NAME);
-// if (hashCodeElement == null) {
-// _errorReporter.reportErrorForNode(
-// HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
-// node.name,
-// [classElement.displayName]);
-// return true;
-// }
-// }
-// return false;
-// }
-
- /**
* Generate a hint for `noSuchMethod` methods that do nothing except of
* calling another `noSuchMethod` that is not defined by `Object`.
*
@@ -867,6 +904,35 @@
}
/**
+ * Check for the passed class declaration for the
+ * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
+ *
+ * @param node the class declaration to check
+ * @return `true` if and only if a hint code is generated on the passed node
+ * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
+ */
+// bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
+// ClassElement classElement = node.element;
+// if (classElement == null) {
+// return false;
+// }
+// MethodElement equalsOperatorMethodElement =
+// classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
+// if (equalsOperatorMethodElement != null) {
+// PropertyAccessorElement hashCodeElement =
+// classElement.getGetter(_HASHCODE_GETTER_NAME);
+// if (hashCodeElement == null) {
+// _errorReporter.reportErrorForNode(
+// HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
+// node.name,
+// [classElement.displayName]);
+// return true;
+// }
+// }
+// return false;
+// }
+
+ /**
* Check for situations where the result of a method or function is used, when it returns 'void'.
*
* TODO(jwren) Many other situations of use could be covered. We currently cover the cases var x =
@@ -891,6 +957,24 @@
return false;
}
+ bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) {
+ List<ClassElement> seenClasses = <ClassElement>[];
+ while (element != null && !seenClasses.contains(element)) {
+ if (element.type == type) {
+ return true;
+ }
+
+ if (element.mixins.any((InterfaceType t) => t == type)) {
+ return true;
+ }
+
+ seenClasses.add(element);
+ element = element.supertype?.element;
+ }
+
+ return false;
+ }
+
/**
* Given a parenthesized expression, this returns the parent (or recursively grand-parent) of the
* expression that is a parenthesized expression, but whose parent is not a parenthesized
@@ -2038,6 +2122,11 @@
*/
class DeclarationResolver extends RecursiveAstVisitor<Object> {
/**
+ * The analysis context containing the sources to be analyzed.
+ */
+ AnalysisContext _context;
+
+ /**
* The elements that are reachable from the compilation unit element. When a
* compilation unit has been resolved, this set should be empty.
*/
@@ -2078,6 +2167,7 @@
* if the element model and compilation unit do not match each other.
*/
void resolve(CompilationUnit unit, CompilationUnitElement element) {
+ _context = element.context;
ElementGatherer gatherer = new ElementGatherer();
element.accept(gatherer);
_expectedElements = gatherer.elements;
@@ -2215,11 +2305,9 @@
ExportElement exportElement;
if (uri != null) {
LibraryElement library = _enclosingUnit.library;
- exportElement = _findExport(
- node,
- library.exports,
- _enclosingUnit.context.sourceFactory
- .resolveUri(_enclosingUnit.source, uri));
+ Source source = _enclosingUnit.context.sourceFactory
+ .resolveUri(_enclosingUnit.source, uri);
+ exportElement = _findExport(node, library.exports, source);
node.element = exportElement;
}
super.visitExportDirective(node);
@@ -2356,11 +2444,9 @@
ImportElement importElement;
if (uri != null) {
LibraryElement library = _enclosingUnit.library;
- importElement = _findImport(
- node,
- library.imports,
- _enclosingUnit.context.sourceFactory
- .resolveUri(_enclosingUnit.source, uri));
+ Source source = _enclosingUnit.context.sourceFactory
+ .resolveUri(_enclosingUnit.source, uri);
+ importElement = _findImport(node, library.imports, source);
node.element = importElement;
}
super.visitImportDirective(node);
@@ -2571,6 +2657,9 @@
*/
ExportElement _findExport(
ExportDirective node, List<ExportElement> exports, Source source) {
+ if (source == null || !_context.exists(source)) {
+ return null;
+ }
for (ExportElement export in exports) {
if (export.exportedLibrary.source == source) {
return export;
@@ -2599,12 +2688,14 @@
/**
* Return the import element from the given list of [imports] whose library
- * has the given [source] and that has the given [prefix]. Throw an
- * [ElementMismatchException] if an element corresponding to the identifier
- * cannot be found.
+ * has the given [source]. Throw an [ElementMismatchException] if an element
+ * corresponding to the [source] cannot be found.
*/
ImportElement _findImport(
ImportDirective node, List<ImportElement> imports, Source source) {
+ if (source == null || !_context.exists(source)) {
+ return null;
+ }
SimpleIdentifier prefix = node.prefix;
bool foundSource = false;
for (ImportElement element in imports) {
@@ -4598,12 +4689,20 @@
final TypeSystem _typeSystem;
/**
+ * When no context type is available, this will track the least upper bound
+ * of all return statements in a lambda.
+ *
+ * This will always be kept in sync with [_returnStack].
+ */
+ final List<DartType> _inferredReturn = <DartType>[];
+
+ /**
* A stack of return types for all of the enclosing
* functions and methods.
*/
// TODO(leafp) Handle the implicit union type for Futures
// https://github.com/dart-lang/sdk/issues/25322
- List<DartType> _returnStack = <DartType>[];
+ final List<DartType> _returnStack = <DartType>[];
InferenceContext._(this._errorListener, TypeProvider typeProvider,
this._typeSystem, this._inferenceHints)
@@ -4622,6 +4721,24 @@
_returnStack.isNotEmpty ? _returnStack.last : null;
/**
+ * Records the type of the expression of a return statement.
+ *
+ * This will be used for inferring a block bodied lambda, if no context
+ * type was available.
+ */
+ void addReturnOrYieldType(DartType type) {
+ if (_returnStack.isEmpty) {
+ return;
+ }
+ DartType context = _returnStack.last;
+ if (context == null || context.isDynamic) {
+ DartType inferred = _inferredReturn.last;
+ inferred = _typeSystem.getLeastUpperBound(_typeProvider, type, inferred);
+ _inferredReturn[_inferredReturn.length - 1] = inferred;
+ }
+ }
+
+ /**
* Match type [t1] against type [t2] as follows.
* If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype
* of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
@@ -4634,19 +4751,31 @@
/**
* Pop a return type off of the return stack.
+ *
+ * Also record any inferred return type using [setType], unless this node
+ * already has a context type. This recorded type will be the least upper
+ * bound of all types added with [addReturnOrYieldType].
*/
- void popReturnContext() {
- assert(_returnStack.isNotEmpty);
+ void popReturnContext(BlockFunctionBody node) {
+ assert(_returnStack.isNotEmpty && _inferredReturn.isNotEmpty);
if (_returnStack.isNotEmpty) {
_returnStack.removeLast();
}
+ if (_inferredReturn.isNotEmpty) {
+ DartType inferred = _inferredReturn.removeLast();
+ if (!inferred.isBottom) {
+ setType(node, inferred);
+ }
+ }
}
/**
- * Push a [returnType] onto the return stack.
+ * Push a block function body's return type onto the return stack.
*/
- void pushReturnContext(DartType returnType) {
+ void pushReturnContext(BlockFunctionBody node) {
+ DartType returnType = getType(node);
_returnStack.add(returnType);
+ _inferredReturn.add(BottomTypeImpl.instance);
}
/**
@@ -7653,11 +7782,11 @@
Object visitBlockFunctionBody(BlockFunctionBody node) {
_overrideManager.enterScope();
try {
- inferenceContext.pushReturnContext(InferenceContext.getType(node));
+ inferenceContext.pushReturnContext(node);
super.visitBlockFunctionBody(node);
} finally {
_overrideManager.exitScope();
- inferenceContext.popReturnContext();
+ inferenceContext.popReturnContext(node);
}
return null;
}
@@ -8135,10 +8264,8 @@
matchFunctionTypeParameters(node.typeParameters, functionType);
if (functionType is FunctionType) {
_inferFormalParameterList(node.parameters, functionType);
- DartType returnType = _computeReturnOrYieldType(
- functionType.returnType,
- _enclosingFunction.isGenerator,
- _enclosingFunction.isAsynchronous);
+ DartType returnType =
+ _computeReturnOrYieldType(functionType.returnType);
InferenceContext.setType(node.body, returnType);
}
}
@@ -8348,10 +8475,8 @@
try {
_currentFunctionBody = node.body;
_enclosingFunction = node.element;
- DartType returnType = _computeReturnOrYieldType(
- _enclosingFunction.type?.returnType,
- _enclosingFunction.isGenerator,
- _enclosingFunction.isAsynchronous);
+ DartType returnType =
+ _computeReturnOrYieldType(_enclosingFunction.type?.returnType);
InferenceContext.setType(node.body, returnType);
super.visitMethodDeclaration(node);
} finally {
@@ -8383,26 +8508,6 @@
return null;
}
- void _inferArgumentTypesFromContext(InvocationExpression node) {
- DartType contextType = node.staticInvokeType;
- if (contextType is FunctionType) {
- DartType originalType = node.function.staticType;
- DartType returnContextType = InferenceContext.getType(node);
- TypeSystem ts = typeSystem;
- if (returnContextType != null &&
- node.typeArguments == null &&
- originalType is FunctionType &&
- originalType.typeFormals.isNotEmpty &&
- ts is StrongTypeSystemImpl) {
-
- contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
- DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
- }
-
- InferenceContext.setType(node.argumentList, contextType);
- }
- }
-
@override
Object visitNamedExpression(NamedExpression node) {
InferenceContext.setType(node.expression, InferenceContext.getType(node));
@@ -8464,8 +8569,19 @@
@override
Object visitReturnStatement(ReturnStatement node) {
- InferenceContext.setType(node.expression, inferenceContext.returnContext);
- return super.visitReturnStatement(node);
+ Expression e = node.expression;
+ InferenceContext.setType(e, inferenceContext.returnContext);
+ super.visitReturnStatement(node);
+ DartType type = e?.staticType;
+ // Generators cannot return values, so don't try to do any inference if
+ // we're processing erroneous code.
+ if (type != null && _enclosingFunction?.isGenerator == false) {
+ if (_enclosingFunction.isAsynchronous) {
+ type = type.flattenFutures(typeSystem);
+ }
+ inferenceContext.addReturnOrYieldType(type);
+ }
+ return null;
}
@override
@@ -8587,25 +8703,44 @@
@override
Object visitYieldStatement(YieldStatement node) {
+ Expression e = node.expression;
DartType returnType = inferenceContext.returnContext;
- if (returnType != null && _enclosingFunction != null) {
+ bool isGenerator = _enclosingFunction?.isGenerator ?? false;
+ if (returnType != null && isGenerator) {
// If we're not in a generator ([a]sync*, then we shouldn't have a yield.
// so don't infer
- if (_enclosingFunction.isGenerator) {
- // If this just a yield, then we just pass on the element type
- DartType type = returnType;
- if (node.star != null) {
- // If this is a yield*, then we wrap the element return type
- // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
- InterfaceType wrapperType = _enclosingFunction.isSynchronous
- ? typeProvider.iterableType
- : typeProvider.streamType;
- type = wrapperType.substitute4(<DartType>[type]);
- }
- InferenceContext.setType(node.expression, type);
+
+ // If this just a yield, then we just pass on the element type
+ DartType type = returnType;
+ if (node.star != null) {
+ // If this is a yield*, then we wrap the element return type
+ // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
+ InterfaceType wrapperType = _enclosingFunction.isSynchronous
+ ? typeProvider.iterableType
+ : typeProvider.streamType;
+ type = wrapperType.substitute4(<DartType>[type]);
+ }
+ InferenceContext.setType(e, type);
+ }
+ super.visitYieldStatement(node);
+ DartType type = e?.staticType;
+ if (type != null && isGenerator) {
+ // If this just a yield, then we just pass on the element type
+ if (node.star != null) {
+ // If this is a yield*, then we unwrap the element return type
+ // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
+ InterfaceType wrapperType = _enclosingFunction.isSynchronous
+ ? typeProvider.iterableType
+ : typeProvider.streamType;
+ List<DartType> candidates =
+ _findImplementedTypeArgument(type, wrapperType);
+ type = InterfaceTypeImpl.findMostSpecificType(candidates, typeSystem);
+ }
+ if (type != null) {
+ inferenceContext.addReturnOrYieldType(type);
}
}
- return super.visitYieldStatement(node);
+ return null;
}
/**
@@ -8645,8 +8780,10 @@
* values which should be returned or yielded as appropriate. If a type
* cannot be computed from the declared return type, return null.
*/
- DartType _computeReturnOrYieldType(
- DartType declaredType, bool isGenerator, bool isAsynchronous) {
+ DartType _computeReturnOrYieldType(DartType declaredType) {
+ bool isGenerator = _enclosingFunction.isGenerator;
+ bool isAsynchronous = _enclosingFunction.isAsynchronous;
+
// Ordinary functions just return their declared types.
if (!isGenerator && !isAsynchronous) {
return declaredType;
@@ -8669,6 +8806,39 @@
}
/**
+ * Starting from t1, search its class hierarchy for types of the form
+ * `t2<R>`, and return a list of the resulting R's.
+ *
+ * For example, given t1 = `List<int>` and t2 = `Iterable<T>`, this will
+ * return [int].
+ */
+ // TODO(jmesserly): this is very similar to code used for flattening futures.
+ // The only difference is, because of a lack of TypeProvider, the other method
+ // has to match the Future type by its name and library. Here was are passed
+ // in the correct type.
+ List<DartType> _findImplementedTypeArgument(DartType t1, InterfaceType t2) {
+ List<DartType> result = <DartType>[];
+ HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
+ void recurse(InterfaceTypeImpl type) {
+ if (type.element == t2.element && type.typeArguments.isNotEmpty) {
+ result.add(type.typeArguments[0]);
+ }
+ if (visitedClasses.add(type.element)) {
+ if (type.superclass != null) {
+ recurse(type.superclass);
+ }
+ type.mixins.forEach(recurse);
+ type.interfaces.forEach(recurse);
+ visitedClasses.remove(type.element);
+ }
+ }
+ if (t1 is InterfaceType) {
+ recurse(t1);
+ }
+ return result;
+ }
+
+ /**
* The given expression is the expression used to compute the iterator for a
* for-each statement. Attempt to compute the type of objects that will be
* assigned to the loop variable and return that type. Return `null` if the
@@ -8730,6 +8900,25 @@
return null;
}
+ void _inferArgumentTypesFromContext(InvocationExpression node) {
+ DartType contextType = node.staticInvokeType;
+ if (contextType is FunctionType) {
+ DartType originalType = node.function.staticType;
+ DartType returnContextType = InferenceContext.getType(node);
+ TypeSystem ts = typeSystem;
+ if (returnContextType != null &&
+ node.typeArguments == null &&
+ originalType is FunctionType &&
+ originalType.typeFormals.isNotEmpty &&
+ ts is StrongTypeSystemImpl) {
+ contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
+ DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
+ }
+
+ InferenceContext.setType(node.argumentList, contextType);
+ }
+ }
+
void _inferFormalParameterList(FormalParameterList node, DartType type) {
if (typeAnalyzer.inferFormalParameterList(node, type)) {
// TODO(leafp): This gets dropped on the floor if we're in the field
@@ -11444,6 +11633,7 @@
Object visitTypeName(TypeName node) {
super.visitTypeName(node);
Identifier typeName = node.name;
+ _setElement(typeName, null); // Clear old Elements from previous run.
TypeArgumentList argumentList = node.typeArguments;
Element element = nameScope.lookup(typeName, definingLibrary);
if (element == null) {
@@ -11592,8 +11782,6 @@
if (!elementValid) {
if (element is MultiplyDefinedElement) {
_setElement(typeName, element);
- } else {
- _setElement(typeName, null);
}
typeName.staticType = _undefinedType;
node.type = _undefinedType;
@@ -11658,7 +11846,6 @@
StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
}
}
- _setElement(typeName, null);
typeName.staticType = _dynamicType;
node.type = _dynamicType;
return null;
@@ -12159,25 +12346,19 @@
}
/**
- * If the given [element] is not `null`, set `staticElement` of the
- * [typeName] to it. If the [typeName] is a prefixed identifier, and the
- * prefix can be resolved to a not `null` element, set also the
- * `staticElement` of the prefix.
+ * Records the new Element for a TypeName's Identifier.
+ *
+ * A null may be passed in to indicate that the element can't be resolved.
+ * (During a re-run of a task, it's important to clear any previous value
+ * of the element.)
*/
void _setElement(Identifier typeName, Element element) {
if (typeName is SimpleIdentifier) {
- if (element != null) {
- typeName.staticElement = element;
- }
+ typeName.staticElement = element;
} else if (typeName is PrefixedIdentifier) {
- if (element != null) {
- typeName.identifier.staticElement = element;
- }
+ typeName.identifier.staticElement = element;
SimpleIdentifier prefix = typeName.prefix;
- Element prefixElement = nameScope.lookup(prefix, definingLibrary);
- if (prefixElement != null) {
- prefix.staticElement = prefixElement;
- }
+ prefix.staticElement = nameScope.lookup(prefix, definingLibrary);
}
}
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index 7319a72..0670b7c 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -377,12 +377,14 @@
* The short name of the library. This is the name used after 'dart:' in a
* URI.
*/
+ @override
final String shortName;
/**
* The path to the file defining the library. The path is relative to the
* 'lib' directory within the SDK.
*/
+ @override
String path = null;
/**
@@ -390,6 +392,7 @@
* in the libraries file all libraries are assumed to be shared between server
* and client.
*/
+ @override
String category = "Shared";
/**
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index e7a9dea..6f03a84 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -9,8 +9,8 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_core.dart';
@@ -264,14 +264,6 @@
_analysisContext = new SdkAnalysisContext();
SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
_analysisContext.sourceFactory = factory;
- // Try to use summaries.
- if (_useSummary) {
- PackageBundle sdkBundle = _getSummarySdkBundle();
- if (sdkBundle != null) {
- _analysisContext.resultProvider =
- new SdkSummaryResultProvider(_analysisContext, sdkBundle);
- }
- }
}
return _analysisContext;
}
@@ -398,14 +390,17 @@
List<String> get uris => _libraryMap.uris;
/**
- * Specify whether SDK summary should be used. This property can only be set
- * before [context] is invoked.
+ * Specify whether SDK summary should be used.
*/
void set useSummary(bool use) {
- if (_analysisContext != null) {
- throw new StateError('SDK analysis context has been already created.');
- }
_useSummary = use;
+ if (_useSummary) {
+ PackageBundle sdkBundle = _getSummarySdkBundle();
+ if (sdkBundle != null) {
+ _analysisContext.resultProvider =
+ new SdkSummaryResultProvider(_analysisContext, sdkBundle);
+ }
+ }
}
/**
@@ -557,7 +552,9 @@
*/
PackageBundle _getSummarySdkBundle() {
String rootPath = directory.getAbsolutePath();
- String path = pathos.join(rootPath, 'lib', '_internal', 'spec.sum');
+ String name =
+ context.analysisOptions.strongMode ? 'strong.sum' : 'spec.sum';
+ String path = pathos.join(rootPath, 'lib', '_internal', name);
try {
File file = new File(path);
if (file.existsSync()) {
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 8fcdad3..092671e 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -369,6 +369,7 @@
@override
final Uri uri;
+ @override
final UriKind uriKind;
NonExistingSource(this.fullName, this.uri, this.uriKind);
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 4847d9a..49641c8 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -102,6 +102,7 @@
/**
* The URI from which this source was originally derived.
*/
+ @override
final Uri uri;
/**
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index c487796..b54bc04 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -461,37 +461,37 @@
// node.
return null;
}
+ bool recordInference = false;
ExecutableElementImpl functionElement =
node.element as ExecutableElementImpl;
- DartType computedType = _computeStaticReturnTypeOfFunctionExpression(node);
- if (_strongMode) {
- // In strong mode, we don't want to allow the function's return type to
- // be bottom. If the surrounding context has a more precise type, we
- // will push it down with inference, below. If not we want to use dynamic.
- // TODO(jmesserly): should we do this for the `null` literal always in
- // strong mode, instead of handling it here?
- if (computedType.isBottom) {
- computedType = DynamicTypeImpl.instance;
- }
- DartType functionType = InferenceContext.getType(node);
- if (functionType is FunctionType) {
- functionType = _resolver.matchFunctionTypeParameters(
- node.typeParameters, functionType);
-
- if (functionType is FunctionType) {
- DartType returnType = functionType.returnType;
- if (computedType.isDynamic &&
- !(returnType.isDynamic || returnType.isBottom)) {
- computedType = returnType;
- _resolver.inferenceContext.recordInference(node, functionType);
- }
- }
- }
+ FunctionBody body = node.body;
+ DartType computedType;
+ if (body is ExpressionFunctionBody) {
+ computedType = _getStaticType(body.expression);
+ } else {
+ computedType = _dynamicType;
}
+
+ // If we had a better type from the function body, use it.
+ //
+ // This helps in a few cases:
+ // * ExpressionFunctionBody, when the surrounding context had a better type.
+ // * BlockFunctionBody, if we inferred a type from yield/return.
+ // * we also normalize bottom to dynamic here.
+ if (_strongMode && (computedType.isBottom || computedType.isDynamic)) {
+ computedType = InferenceContext.getType(body) ?? _dynamicType;
+ recordInference = !computedType.isDynamic;
+ }
+
+ computedType = _computeReturnTypeOfFunction(body, computedType);
+
functionElement.returnType = computedType;
_recordPropagatedTypeOfFunction(functionElement, node.body);
- _recordStaticType(node, node.element.type);
+ _recordStaticType(node, functionElement.type);
+ if (recordInference) {
+ _resolver.inferenceContext.recordInference(node, functionElement.type);
+ }
return null;
}
@@ -941,6 +941,7 @@
*/
@override
Object visitNullLiteral(NullLiteral node) {
+ // TODO(jmesserly): in strong mode, should we just use the context type?
_recordStaticType(node, _typeProvider.bottomType);
return null;
}
@@ -1473,6 +1474,27 @@
}
/**
+ * Given a function body and its return type, compute the return type of
+ * the entire function, taking into account whether the function body
+ * is `sync*`, `async` or `async*`.
+ *
+ * See also [FunctionBody.isAsynchronous], [FunctionBody.isGenerator].
+ */
+ DartType _computeReturnTypeOfFunction(FunctionBody body, DartType type) {
+ if (body.isGenerator) {
+ InterfaceType genericType = body.isAsynchronous
+ ? _typeProvider.streamType
+ : _typeProvider.iterableType;
+ return genericType.substitute4(<DartType>[type]);
+ } else if (body.isAsynchronous) {
+ return _typeProvider.futureType
+ .substitute4(<DartType>[type.flattenFutures(_typeSystem)]);
+ } else {
+ return type;
+ }
+ }
+
+ /**
* Compute the static return type of the method or function represented by the given element.
*
* @param element the element representing the method or function invoked by the given node
@@ -1514,38 +1536,6 @@
return returnType.type;
}
- /**
- * Given a function expression, compute the return type of the function. The return type of
- * functions with a block body is `dynamicType`, with an expression body it is the type of
- * the expression.
- *
- * @param node the function expression whose return type is to be computed
- * @return the return type that was computed
- */
- DartType _computeStaticReturnTypeOfFunctionExpression(
- FunctionExpression node) {
- FunctionBody body = node.body;
- if (body.isGenerator) {
- if (body.isAsynchronous) {
- return _typeProvider.streamDynamicType;
- } else {
- return _typeProvider.iterableDynamicType;
- }
- }
- DartType type;
- if (body is ExpressionFunctionBody) {
- type = _getStaticType(body.expression);
- } else {
- type = _dynamicType;
- }
- if (body.isAsynchronous) {
- return _typeProvider.futureType
- .substitute4(<DartType>[type.flattenFutures(_typeSystem)]);
- } else {
- return type;
- }
- }
-
DartType _findIteratedType(DartType type, DartType targetType) {
// TODO(vsm): Use leafp's matchType here?
// Set by _find if match is found
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index d5ac50f..2beeab4 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -251,6 +251,15 @@
Identifier name) =>
new FieldFormalParameterElementImpl.forNode(name);
+ /**
+ * Destroy any static state retained by [ElementFactory]. This should be
+ * called from the `setUp` method of any tests that use [ElementFactory], in
+ * order to ensure that state is not shared between multiple tests.
+ */
+ static void flushStaticState() {
+ _objectElement = null;
+ }
+
static FunctionElementImpl functionElement(String functionName) =>
functionElement4(functionName, null, null, null, null);
diff --git a/pkg/analyzer/lib/src/generated/visitors.dart b/pkg/analyzer/lib/src/generated/visitors.dart
index 31e5ddc..457d7f8 100644
--- a/pkg/analyzer/lib/src/generated/visitors.dart
+++ b/pkg/analyzer/lib/src/generated/visitors.dart
@@ -2,786 +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.
+@deprecated
library analyzer.src.generated.visitors;
-import 'package:analyzer/dart/ast/ast.dart';
-
-/// An [AstVisitor] that delegates calls to visit methods to all [delegates]
-/// before calling [visitChildren].
-class DelegatingAstVisitor<T> implements AstVisitor<T> {
- Iterable<AstVisitor<T>> _delegates;
- DelegatingAstVisitor(this._delegates);
-
- @override
- T visitAdjacentStrings(AdjacentStrings node) {
- _delegates.forEach((delegate) => delegate.visitAdjacentStrings(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitAnnotation(Annotation node) {
- _delegates.forEach((delegate) => delegate.visitAnnotation(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitArgumentList(ArgumentList node) {
- _delegates.forEach((delegate) => delegate.visitArgumentList(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitAsExpression(AsExpression node) {
- _delegates.forEach((delegate) => delegate.visitAsExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitAssertStatement(AssertStatement node) {
- _delegates.forEach((delegate) => delegate.visitAssertStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitAssignmentExpression(AssignmentExpression node) {
- _delegates.forEach((delegate) => delegate.visitAssignmentExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitAwaitExpression(AwaitExpression node) {
- _delegates.forEach((delegate) => delegate.visitAwaitExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitBinaryExpression(BinaryExpression node) {
- _delegates.forEach((delegate) => delegate.visitBinaryExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitBlock(Block node) {
- _delegates.forEach((delegate) => delegate.visitBlock(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitBlockFunctionBody(BlockFunctionBody node) {
- _delegates.forEach((delegate) => delegate.visitBlockFunctionBody(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitBooleanLiteral(BooleanLiteral node) {
- _delegates.forEach((delegate) => delegate.visitBooleanLiteral(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitBreakStatement(BreakStatement node) {
- _delegates.forEach((delegate) => delegate.visitBreakStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitCascadeExpression(CascadeExpression node) {
- _delegates.forEach((delegate) => delegate.visitCascadeExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitCatchClause(CatchClause node) {
- _delegates.forEach((delegate) => delegate.visitCatchClause(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitClassDeclaration(ClassDeclaration node) {
- _delegates.forEach((delegate) => delegate.visitClassDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitClassTypeAlias(ClassTypeAlias node) {
- _delegates.forEach((delegate) => delegate.visitClassTypeAlias(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitComment(Comment node) {
- _delegates.forEach((delegate) => delegate.visitComment(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitCommentReference(CommentReference node) {
- _delegates.forEach((delegate) => delegate.visitCommentReference(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitCompilationUnit(CompilationUnit node) {
- _delegates.forEach((delegate) => delegate.visitCompilationUnit(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitConditionalExpression(ConditionalExpression node) {
- _delegates.forEach((delegate) => delegate.visitConditionalExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitConfiguration(Configuration node) {
- _delegates.forEach((delegate) => delegate.visitConfiguration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitConstructorDeclaration(ConstructorDeclaration node) {
- _delegates
- .forEach((delegate) => delegate.visitConstructorDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
- _delegates
- .forEach((delegate) => delegate.visitConstructorFieldInitializer(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitConstructorName(ConstructorName node) {
- _delegates.forEach((delegate) => delegate.visitConstructorName(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitContinueStatement(ContinueStatement node) {
- _delegates.forEach((delegate) => delegate.visitContinueStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitDeclaredIdentifier(DeclaredIdentifier node) {
- _delegates.forEach((delegate) => delegate.visitDeclaredIdentifier(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitDefaultFormalParameter(DefaultFormalParameter node) {
- _delegates
- .forEach((delegate) => delegate.visitDefaultFormalParameter(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitDoStatement(DoStatement node) {
- _delegates.forEach((delegate) => delegate.visitDoStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitDottedName(DottedName node) {
- _delegates.forEach((delegate) => delegate.visitDottedName(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitDoubleLiteral(DoubleLiteral node) {
- _delegates.forEach((delegate) => delegate.visitDoubleLiteral(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitEmptyFunctionBody(EmptyFunctionBody node) {
- _delegates.forEach((delegate) => delegate.visitEmptyFunctionBody(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitEmptyStatement(EmptyStatement node) {
- _delegates.forEach((delegate) => delegate.visitEmptyStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitEnumConstantDeclaration(EnumConstantDeclaration node) {
- _delegates
- .forEach((delegate) => delegate.visitEnumConstantDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitEnumDeclaration(EnumDeclaration node) {
- _delegates.forEach((delegate) => delegate.visitEnumDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitExportDirective(ExportDirective node) {
- _delegates.forEach((delegate) => delegate.visitExportDirective(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitExpressionFunctionBody(ExpressionFunctionBody node) {
- _delegates
- .forEach((delegate) => delegate.visitExpressionFunctionBody(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitExpressionStatement(ExpressionStatement node) {
- _delegates.forEach((delegate) => delegate.visitExpressionStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitExtendsClause(ExtendsClause node) {
- _delegates.forEach((delegate) => delegate.visitExtendsClause(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFieldDeclaration(FieldDeclaration node) {
- _delegates.forEach((delegate) => delegate.visitFieldDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFieldFormalParameter(FieldFormalParameter node) {
- _delegates.forEach((delegate) => delegate.visitFieldFormalParameter(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitForEachStatement(ForEachStatement node) {
- _delegates.forEach((delegate) => delegate.visitForEachStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFormalParameterList(FormalParameterList node) {
- _delegates.forEach((delegate) => delegate.visitFormalParameterList(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitForStatement(ForStatement node) {
- _delegates.forEach((delegate) => delegate.visitForStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFunctionDeclaration(FunctionDeclaration node) {
- _delegates.forEach((delegate) => delegate.visitFunctionDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
- _delegates.forEach(
- (delegate) => delegate.visitFunctionDeclarationStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFunctionExpression(FunctionExpression node) {
- _delegates.forEach((delegate) => delegate.visitFunctionExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
- _delegates.forEach(
- (delegate) => delegate.visitFunctionExpressionInvocation(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFunctionTypeAlias(FunctionTypeAlias node) {
- _delegates.forEach((delegate) => delegate.visitFunctionTypeAlias(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
- _delegates.forEach(
- (delegate) => delegate.visitFunctionTypedFormalParameter(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitHideCombinator(HideCombinator node) {
- _delegates.forEach((delegate) => delegate.visitHideCombinator(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitIfStatement(IfStatement node) {
- _delegates.forEach((delegate) => delegate.visitIfStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitImplementsClause(ImplementsClause node) {
- _delegates.forEach((delegate) => delegate.visitImplementsClause(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitImportDirective(ImportDirective node) {
- _delegates.forEach((delegate) => delegate.visitImportDirective(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitIndexExpression(IndexExpression node) {
- _delegates.forEach((delegate) => delegate.visitIndexExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitInstanceCreationExpression(InstanceCreationExpression node) {
- _delegates
- .forEach((delegate) => delegate.visitInstanceCreationExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitIntegerLiteral(IntegerLiteral node) {
- _delegates.forEach((delegate) => delegate.visitIntegerLiteral(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitInterpolationExpression(InterpolationExpression node) {
- _delegates
- .forEach((delegate) => delegate.visitInterpolationExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitInterpolationString(InterpolationString node) {
- _delegates.forEach((delegate) => delegate.visitInterpolationString(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitIsExpression(IsExpression node) {
- _delegates.forEach((delegate) => delegate.visitIsExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitLabel(Label node) {
- _delegates.forEach((delegate) => delegate.visitLabel(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitLabeledStatement(LabeledStatement node) {
- _delegates.forEach((delegate) => delegate.visitLabeledStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitLibraryDirective(LibraryDirective node) {
- _delegates.forEach((delegate) => delegate.visitLibraryDirective(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitLibraryIdentifier(LibraryIdentifier node) {
- _delegates.forEach((delegate) => delegate.visitLibraryIdentifier(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitListLiteral(ListLiteral node) {
- _delegates.forEach((delegate) => delegate.visitListLiteral(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitMapLiteral(MapLiteral node) {
- _delegates.forEach((delegate) => delegate.visitMapLiteral(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitMapLiteralEntry(MapLiteralEntry node) {
- _delegates.forEach((delegate) => delegate.visitMapLiteralEntry(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitMethodDeclaration(MethodDeclaration node) {
- _delegates.forEach((delegate) => delegate.visitMethodDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitMethodInvocation(MethodInvocation node) {
- _delegates.forEach((delegate) => delegate.visitMethodInvocation(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitNamedExpression(NamedExpression node) {
- _delegates.forEach((delegate) => delegate.visitNamedExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitNativeClause(NativeClause node) {
- _delegates.forEach((delegate) => delegate.visitNativeClause(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitNativeFunctionBody(NativeFunctionBody node) {
- _delegates.forEach((delegate) => delegate.visitNativeFunctionBody(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitNullLiteral(NullLiteral node) {
- _delegates.forEach((delegate) => delegate.visitNullLiteral(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitParenthesizedExpression(ParenthesizedExpression node) {
- _delegates
- .forEach((delegate) => delegate.visitParenthesizedExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitPartDirective(PartDirective node) {
- _delegates.forEach((delegate) => delegate.visitPartDirective(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitPartOfDirective(PartOfDirective node) {
- _delegates.forEach((delegate) => delegate.visitPartOfDirective(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitPostfixExpression(PostfixExpression node) {
- _delegates.forEach((delegate) => delegate.visitPostfixExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitPrefixedIdentifier(PrefixedIdentifier node) {
- _delegates.forEach((delegate) => delegate.visitPrefixedIdentifier(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitPrefixExpression(PrefixExpression node) {
- _delegates.forEach((delegate) => delegate.visitPrefixExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitPropertyAccess(PropertyAccess node) {
- _delegates.forEach((delegate) => delegate.visitPropertyAccess(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitRedirectingConstructorInvocation(
- RedirectingConstructorInvocation node) {
- _delegates.forEach(
- (delegate) => delegate.visitRedirectingConstructorInvocation(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitRethrowExpression(RethrowExpression node) {
- _delegates.forEach((delegate) => delegate.visitRethrowExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitReturnStatement(ReturnStatement node) {
- _delegates.forEach((delegate) => delegate.visitReturnStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitScriptTag(ScriptTag node) {
- _delegates.forEach((delegate) => delegate.visitScriptTag(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitShowCombinator(ShowCombinator node) {
- _delegates.forEach((delegate) => delegate.visitShowCombinator(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSimpleFormalParameter(SimpleFormalParameter node) {
- _delegates.forEach((delegate) => delegate.visitSimpleFormalParameter(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSimpleIdentifier(SimpleIdentifier node) {
- _delegates.forEach((delegate) => delegate.visitSimpleIdentifier(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSimpleStringLiteral(SimpleStringLiteral node) {
- _delegates.forEach((delegate) => delegate.visitSimpleStringLiteral(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitStringInterpolation(StringInterpolation node) {
- _delegates.forEach((delegate) => delegate.visitStringInterpolation(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSuperConstructorInvocation(SuperConstructorInvocation node) {
- _delegates
- .forEach((delegate) => delegate.visitSuperConstructorInvocation(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSuperExpression(SuperExpression node) {
- _delegates.forEach((delegate) => delegate.visitSuperExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSwitchCase(SwitchCase node) {
- _delegates.forEach((delegate) => delegate.visitSwitchCase(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSwitchDefault(SwitchDefault node) {
- _delegates.forEach((delegate) => delegate.visitSwitchDefault(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSwitchStatement(SwitchStatement node) {
- _delegates.forEach((delegate) => delegate.visitSwitchStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitSymbolLiteral(SymbolLiteral node) {
- _delegates.forEach((delegate) => delegate.visitSymbolLiteral(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitThisExpression(ThisExpression node) {
- _delegates.forEach((delegate) => delegate.visitThisExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitThrowExpression(ThrowExpression node) {
- _delegates.forEach((delegate) => delegate.visitThrowExpression(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
- _delegates
- .forEach((delegate) => delegate.visitTopLevelVariableDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitTryStatement(TryStatement node) {
- _delegates.forEach((delegate) => delegate.visitTryStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitTypeArgumentList(TypeArgumentList node) {
- _delegates.forEach((delegate) => delegate.visitTypeArgumentList(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitTypeName(TypeName node) {
- _delegates.forEach((delegate) => delegate.visitTypeName(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitTypeParameter(TypeParameter node) {
- _delegates.forEach((delegate) => delegate.visitTypeParameter(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitTypeParameterList(TypeParameterList node) {
- _delegates.forEach((delegate) => delegate.visitTypeParameterList(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitVariableDeclaration(VariableDeclaration node) {
- _delegates.forEach((delegate) => delegate.visitVariableDeclaration(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitVariableDeclarationList(VariableDeclarationList node) {
- _delegates
- .forEach((delegate) => delegate.visitVariableDeclarationList(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitVariableDeclarationStatement(VariableDeclarationStatement node) {
- _delegates.forEach(
- (delegate) => delegate.visitVariableDeclarationStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitWhileStatement(WhileStatement node) {
- _delegates.forEach((delegate) => delegate.visitWhileStatement(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitWithClause(WithClause node) {
- _delegates.forEach((delegate) => delegate.visitWithClause(node));
- node.visitChildren(this);
- return null;
- }
-
- @override
- T visitYieldStatement(YieldStatement node) {
- _delegates.forEach((delegate) => delegate.visitYieldStatement(node));
- node.visitChildren(this);
- return null;
- }
-}
+export 'package:analyzer/dart/ast/visitor.dart' show DelegatingAstVisitor;
diff --git a/pkg/analyzer/lib/src/services/lint.dart b/pkg/analyzer/lib/src/services/lint.dart
index 953741b..af20f59 100644
--- a/pkg/analyzer/lib/src/services/lint.dart
+++ b/pkg/analyzer/lib/src/services/lint.dart
@@ -5,10 +5,10 @@
library analyzer.src.services.lint;
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/visitors.dart';
import 'package:analyzer/src/task/model.dart';
import 'package:analyzer/task/model.dart';
diff --git a/pkg/analyzer/lib/src/string_source.dart b/pkg/analyzer/lib/src/string_source.dart
index 3cfbd2e..04eb0a3 100644
--- a/pkg/analyzer/lib/src/string_source.dart
+++ b/pkg/analyzer/lib/src/string_source.dart
@@ -53,6 +53,7 @@
* Return `true` if the given [object] is a string source that is equal to
* this source.
*/
+ @override
bool operator ==(Object object) {
return object is StringSource &&
object._contents == _contents &&
diff --git a/pkg/analyzer/lib/src/summary/base.dart b/pkg/analyzer/lib/src/summary/base.dart
index 1a1626e..acdb839 100644
--- a/pkg/analyzer/lib/src/summary/base.dart
+++ b/pkg/analyzer/lib/src/summary/base.dart
@@ -23,6 +23,20 @@
}
/**
+ * Annotation used in the summary IDL to indicate that a summary class can be
+ * the top level object in an encoded summary.
+ */
+class TopLevel {
+ /**
+ * If non-null, identifier that will be stored in bytes 4-7 of the file,
+ * prior all other file data. Must be exactly 4 Latin1 characters.
+ */
+ final String fileIdentifier;
+
+ const TopLevel([this.fileIdentifier]);
+}
+
+/**
* Instances of this class represent data that has been read from a summary.
*/
abstract class SummaryClass {
diff --git a/pkg/analyzer/lib/src/summary/flat_buffers.dart b/pkg/analyzer/lib/src/summary/flat_buffers.dart
index c7a4f44..ba2c2ef 100644
--- a/pkg/analyzer/lib/src/summary/flat_buffers.dart
+++ b/pkg/analyzer/lib/src/summary/flat_buffers.dart
@@ -10,6 +10,21 @@
import 'dart:typed_data';
/**
+ * Reader of lists of boolean values.
+ *
+ * The returned unmodifiable lists lazily read values on access.
+ */
+class BoolListReader extends Reader<List<bool>> {
+ const BoolListReader();
+
+ @override
+ int get size => 4;
+
+ @override
+ List<bool> read(BufferPointer bp) => new _FbBoolList(bp.derefObject());
+}
+
+/**
* The reader of booleans.
*/
class BoolReader extends Reader<bool> {
@@ -246,12 +261,20 @@
/**
* Finish off the creation of the buffer. The given [offset] is used as the
* root object offset, and usually references directly or indirectly every
- * written object.
+ * written object. If [fileIdentifier] is specified (and not `null`), it is
+ * interpreted as a 4-byte Latin-1 encoded string that should be placed at
+ * bytes 4-7 of the file.
*/
- Uint8List finish(Offset offset) {
- _prepare(max(4, _maxAlign), 1);
+ Uint8List finish(Offset offset, [String fileIdentifier]) {
+ _prepare(max(4, _maxAlign), fileIdentifier == null ? 1 : 2);
int alignedTail = _tail + ((-_tail) % _maxAlign);
_setUint32AtTail(_buf, alignedTail, alignedTail - offset._tail);
+ if (fileIdentifier != null) {
+ for (int i = 0; i < 4; i++) {
+ _setUint8AtTail(
+ _buf, alignedTail - 4 - i, fileIdentifier.codeUnitAt(i));
+ }
+ }
return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
}
@@ -327,6 +350,38 @@
}
/**
+ * Write the given list of boolean [values].
+ */
+ Offset writeListBool(List<bool> values) {
+ int bitLength = values.length;
+ int padding = (-bitLength) % 8;
+ int byteLength = (bitLength + padding) ~/ 8;
+ // Prepare the backing Uint8List.
+ Uint8List bytes = new Uint8List(byteLength + 1);
+ // Record every bit.
+ int byteIndex = 0;
+ int byte = 0;
+ int mask = 1;
+ for (int bitIndex = 0; bitIndex < bitLength; bitIndex++) {
+ if (bitIndex != 0 && (bitIndex % 8 == 0)) {
+ bytes[byteIndex++] = byte;
+ byte = 0;
+ mask = 1;
+ }
+ if (values[bitIndex]) {
+ byte |= mask;
+ }
+ mask <<= 1;
+ }
+ // Write the last byte, even if it may be on the padding.
+ bytes[byteIndex] = byte;
+ // Write the padding length.
+ bytes[byteLength] = padding;
+ // Write as a Uint8 list.
+ return writeListUint8(bytes);
+ }
+
+ /**
* Write the given list of 64-bit float [values].
*/
Offset writeListFloat64(List<double> values) {
@@ -637,7 +692,7 @@
}
/**
- * Reader of lists of 32-bit float values.
+ * Reader of lists of unsigned 32-bit integer values.
*
* The returned unmodifiable lists lazily read values on access.
*/
@@ -678,6 +733,40 @@
}
/**
+ * List of booleans backed by 8-bit unsigned integers.
+ */
+class _FbBoolList extends Object with ListMixin<bool> implements List<bool> {
+ final List<int> uint8List;
+ int _length;
+
+ _FbBoolList(BufferPointer bp)
+ : uint8List = new _FbGenericList<int>(const Uint8Reader(), bp);
+
+ @override
+ int get length {
+ if (_length == null) {
+ _length = (uint8List.length - 1) * 8 - uint8List.last;
+ }
+ return _length;
+ }
+
+ @override
+ void set length(int i) =>
+ throw new StateError('Attempt to modify immutable list');
+
+ @override
+ bool operator [](int i) {
+ int index = i ~/ 8;
+ int mask = 1 << i % 8;
+ return uint8List[index] & mask != 0;
+ }
+
+ @override
+ void operator []=(int i, bool e) =>
+ throw new StateError('Attempt to modify immutable list');
+}
+
+/**
* The list backed by 64-bit values - Uint64 length and Float64.
*/
class _FbFloat64List extends _FbList<double> {
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 99dbbce..e5c4630 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -11,6 +11,45 @@
import 'idl.dart' as idl;
import 'dart:convert' as convert;
+class _IndexNameKindReader extends fb.Reader<idl.IndexNameKind> {
+ const _IndexNameKindReader() : super();
+
+ @override
+ int get size => 1;
+
+ @override
+ idl.IndexNameKind read(fb.BufferPointer bp) {
+ int index = const fb.Uint8Reader().read(bp);
+ return index < idl.IndexNameKind.values.length ? idl.IndexNameKind.values[index] : idl.IndexNameKind.topLevel;
+ }
+}
+
+class _IndexRelationKindReader extends fb.Reader<idl.IndexRelationKind> {
+ const _IndexRelationKindReader() : super();
+
+ @override
+ int get size => 1;
+
+ @override
+ idl.IndexRelationKind read(fb.BufferPointer bp) {
+ int index = const fb.Uint8Reader().read(bp);
+ return index < idl.IndexRelationKind.values.length ? idl.IndexRelationKind.values[index] : idl.IndexRelationKind.IS_EXTENDED_BY;
+ }
+}
+
+class _IndexSyntheticElementKindReader extends fb.Reader<idl.IndexSyntheticElementKind> {
+ const _IndexSyntheticElementKindReader() : super();
+
+ @override
+ int get size => 1;
+
+ @override
+ idl.IndexSyntheticElementKind read(fb.BufferPointer bp) {
+ int index = const fb.Uint8Reader().read(bp);
+ return index < idl.IndexSyntheticElementKind.values.length ? idl.IndexSyntheticElementKind.values[index] : idl.IndexSyntheticElementKind.notSynthetic;
+ }
+}
+
class _ReferenceKindReader extends fb.Reader<idl.ReferenceKind> {
const _ReferenceKindReader() : super();
@@ -20,7 +59,7 @@
@override
idl.ReferenceKind read(fb.BufferPointer bp) {
int index = const fb.Uint8Reader().read(bp);
- return idl.ReferenceKind.values[index];
+ return index < idl.ReferenceKind.values.length ? idl.ReferenceKind.values[index] : idl.ReferenceKind.classOrEnum;
}
}
@@ -33,7 +72,7 @@
@override
idl.UnlinkedConstOperation read(fb.BufferPointer bp) {
int index = const fb.Uint8Reader().read(bp);
- return idl.UnlinkedConstOperation.values[index];
+ return index < idl.UnlinkedConstOperation.values.length ? idl.UnlinkedConstOperation.values[index] : idl.UnlinkedConstOperation.pushInt;
}
}
@@ -46,7 +85,7 @@
@override
idl.UnlinkedConstructorInitializerKind read(fb.BufferPointer bp) {
int index = const fb.Uint8Reader().read(bp);
- return idl.UnlinkedConstructorInitializerKind.values[index];
+ return index < idl.UnlinkedConstructorInitializerKind.values.length ? idl.UnlinkedConstructorInitializerKind.values[index] : idl.UnlinkedConstructorInitializerKind.field;
}
}
@@ -59,7 +98,7 @@
@override
idl.UnlinkedExecutableKind read(fb.BufferPointer bp) {
int index = const fb.Uint8Reader().read(bp);
- return idl.UnlinkedExecutableKind.values[index];
+ return index < idl.UnlinkedExecutableKind.values.length ? idl.UnlinkedExecutableKind.values[index] : idl.UnlinkedExecutableKind.functionOrMethod;
}
}
@@ -72,7 +111,7 @@
@override
idl.UnlinkedParamKind read(fb.BufferPointer bp) {
int index = const fb.Uint8Reader().read(bp);
- return idl.UnlinkedParamKind.values[index];
+ return index < idl.UnlinkedParamKind.values.length ? idl.UnlinkedParamKind.values[index] : idl.UnlinkedParamKind.required;
}
}
@@ -83,6 +122,8 @@
int _paramReference;
int _reference;
int _slot;
+ List<UnlinkedParamBuilder> _syntheticParams;
+ EntityRefBuilder _syntheticReturnType;
List<EntityRefBuilder> _typeArguments;
@override
@@ -174,6 +215,34 @@
}
@override
+ List<UnlinkedParamBuilder> get syntheticParams => _syntheticParams ??= <UnlinkedParamBuilder>[];
+
+ /**
+ * If this [EntityRef] is a reference to a function type whose
+ * [FunctionElement] is not in any library (e.g. a function type that was
+ * synthesized by a LUB computation), the function parameters. Otherwise
+ * empty.
+ */
+ void set syntheticParams(List<UnlinkedParamBuilder> _value) {
+ assert(!_finished);
+ _syntheticParams = _value;
+ }
+
+ @override
+ EntityRefBuilder get syntheticReturnType => _syntheticReturnType;
+
+ /**
+ * If this [EntityRef] is a reference to a function type whose
+ * [FunctionElement] is not in any library (e.g. a function type that was
+ * synthesized by a LUB computation), the return type of the function.
+ * Otherwise `null`.
+ */
+ void set syntheticReturnType(EntityRefBuilder _value) {
+ assert(!_finished);
+ _syntheticReturnType = _value;
+ }
+
+ @override
List<EntityRefBuilder> get typeArguments => _typeArguments ??= <EntityRefBuilder>[];
/**
@@ -186,21 +255,31 @@
_typeArguments = _value;
}
- EntityRefBuilder({List<int> implicitFunctionTypeIndices, int paramReference, int reference, int slot, List<EntityRefBuilder> typeArguments})
+ EntityRefBuilder({List<int> implicitFunctionTypeIndices, int paramReference, int reference, int slot, List<UnlinkedParamBuilder> syntheticParams, EntityRefBuilder syntheticReturnType, List<EntityRefBuilder> typeArguments})
: _implicitFunctionTypeIndices = implicitFunctionTypeIndices,
_paramReference = paramReference,
_reference = reference,
_slot = slot,
+ _syntheticParams = syntheticParams,
+ _syntheticReturnType = syntheticReturnType,
_typeArguments = typeArguments;
fb.Offset finish(fb.Builder fbBuilder) {
assert(!_finished);
_finished = true;
fb.Offset offset_implicitFunctionTypeIndices;
+ fb.Offset offset_syntheticParams;
+ fb.Offset offset_syntheticReturnType;
fb.Offset offset_typeArguments;
if (!(_implicitFunctionTypeIndices == null || _implicitFunctionTypeIndices.isEmpty)) {
offset_implicitFunctionTypeIndices = fbBuilder.writeListUint32(_implicitFunctionTypeIndices);
}
+ if (!(_syntheticParams == null || _syntheticParams.isEmpty)) {
+ offset_syntheticParams = fbBuilder.writeList(_syntheticParams.map((b) => b.finish(fbBuilder)).toList());
+ }
+ if (_syntheticReturnType != null) {
+ offset_syntheticReturnType = _syntheticReturnType.finish(fbBuilder);
+ }
if (!(_typeArguments == null || _typeArguments.isEmpty)) {
offset_typeArguments = fbBuilder.writeList(_typeArguments.map((b) => b.finish(fbBuilder)).toList());
}
@@ -217,6 +296,12 @@
if (_slot != null && _slot != 0) {
fbBuilder.addUint32(2, _slot);
}
+ if (offset_syntheticParams != null) {
+ fbBuilder.addOffset(6, offset_syntheticParams);
+ }
+ if (offset_syntheticReturnType != null) {
+ fbBuilder.addOffset(5, offset_syntheticReturnType);
+ }
if (offset_typeArguments != null) {
fbBuilder.addOffset(1, offset_typeArguments);
}
@@ -240,6 +325,8 @@
int _paramReference;
int _reference;
int _slot;
+ List<idl.UnlinkedParam> _syntheticParams;
+ idl.EntityRef _syntheticReturnType;
List<idl.EntityRef> _typeArguments;
@override
@@ -267,6 +354,18 @@
}
@override
+ List<idl.UnlinkedParam> get syntheticParams {
+ _syntheticParams ??= const fb.ListReader<idl.UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 6, const <idl.UnlinkedParam>[]);
+ return _syntheticParams;
+ }
+
+ @override
+ idl.EntityRef get syntheticReturnType {
+ _syntheticReturnType ??= const _EntityRefReader().vTableGet(_bp, 5, null);
+ return _syntheticReturnType;
+ }
+
+ @override
List<idl.EntityRef> get typeArguments {
_typeArguments ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 1, const <idl.EntityRef>[]);
return _typeArguments;
@@ -281,6 +380,8 @@
if (paramReference != 0) _result["paramReference"] = paramReference;
if (reference != 0) _result["reference"] = reference;
if (slot != 0) _result["slot"] = slot;
+ if (syntheticParams.isNotEmpty) _result["syntheticParams"] = syntheticParams.map((_value) => _value.toJson()).toList();
+ if (syntheticReturnType != null) _result["syntheticReturnType"] = syntheticReturnType.toJson();
if (typeArguments.isNotEmpty) _result["typeArguments"] = typeArguments.map((_value) => _value.toJson()).toList();
return _result;
}
@@ -291,6 +392,8 @@
"paramReference": paramReference,
"reference": reference,
"slot": slot,
+ "syntheticParams": syntheticParams,
+ "syntheticReturnType": syntheticReturnType,
"typeArguments": typeArguments,
};
@@ -656,7 +759,7 @@
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
- return fbBuilder.finish(finish(fbBuilder));
+ return fbBuilder.finish(finish(fbBuilder), "LLib");
}
fb.Offset finish(fb.Builder fbBuilder) {
@@ -1143,6 +1246,8 @@
List<LinkedLibraryBuilder> _linkedLibraries;
List<String> _linkedLibraryUris;
+ int _majorVersion;
+ int _minorVersion;
List<String> _unlinkedUnitHashes;
List<UnlinkedUnitBuilder> _unlinkedUnits;
List<String> _unlinkedUnitUris;
@@ -1171,6 +1276,32 @@
}
@override
+ int get majorVersion => _majorVersion ??= 0;
+
+ /**
+ * Major version of the summary format. See
+ * [PackageBundleAssembler.currentMajorVersion].
+ */
+ void set majorVersion(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _majorVersion = _value;
+ }
+
+ @override
+ int get minorVersion => _minorVersion ??= 0;
+
+ /**
+ * Minor version of the summary format. See
+ * [PackageBundleAssembler.currentMinorVersion].
+ */
+ void set minorVersion(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _minorVersion = _value;
+ }
+
+ @override
List<String> get unlinkedUnitHashes => _unlinkedUnitHashes ??= <String>[];
/**
@@ -1204,16 +1335,18 @@
_unlinkedUnitUris = _value;
}
- PackageBundleBuilder({List<LinkedLibraryBuilder> linkedLibraries, List<String> linkedLibraryUris, List<String> unlinkedUnitHashes, List<UnlinkedUnitBuilder> unlinkedUnits, List<String> unlinkedUnitUris})
+ PackageBundleBuilder({List<LinkedLibraryBuilder> linkedLibraries, List<String> linkedLibraryUris, int majorVersion, int minorVersion, List<String> unlinkedUnitHashes, List<UnlinkedUnitBuilder> unlinkedUnits, List<String> unlinkedUnitUris})
: _linkedLibraries = linkedLibraries,
_linkedLibraryUris = linkedLibraryUris,
+ _majorVersion = majorVersion,
+ _minorVersion = minorVersion,
_unlinkedUnitHashes = unlinkedUnitHashes,
_unlinkedUnits = unlinkedUnits,
_unlinkedUnitUris = unlinkedUnitUris;
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
- return fbBuilder.finish(finish(fbBuilder));
+ return fbBuilder.finish(finish(fbBuilder), "PBdl");
}
fb.Offset finish(fb.Builder fbBuilder) {
@@ -1246,6 +1379,12 @@
if (offset_linkedLibraryUris != null) {
fbBuilder.addOffset(1, offset_linkedLibraryUris);
}
+ if (_majorVersion != null && _majorVersion != 0) {
+ fbBuilder.addUint32(5, _majorVersion);
+ }
+ if (_minorVersion != null && _minorVersion != 0) {
+ fbBuilder.addUint32(6, _minorVersion);
+ }
if (offset_unlinkedUnitHashes != null) {
fbBuilder.addOffset(4, offset_unlinkedUnitHashes);
}
@@ -1278,6 +1417,8 @@
List<idl.LinkedLibrary> _linkedLibraries;
List<String> _linkedLibraryUris;
+ int _majorVersion;
+ int _minorVersion;
List<String> _unlinkedUnitHashes;
List<idl.UnlinkedUnit> _unlinkedUnits;
List<String> _unlinkedUnitUris;
@@ -1295,6 +1436,18 @@
}
@override
+ int get majorVersion {
+ _majorVersion ??= const fb.Uint32Reader().vTableGet(_bp, 5, 0);
+ return _majorVersion;
+ }
+
+ @override
+ int get minorVersion {
+ _minorVersion ??= const fb.Uint32Reader().vTableGet(_bp, 6, 0);
+ return _minorVersion;
+ }
+
+ @override
List<String> get unlinkedUnitHashes {
_unlinkedUnitHashes ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 4, const <String>[]);
return _unlinkedUnitHashes;
@@ -1319,6 +1472,8 @@
Map<String, Object> _result = <String, Object>{};
if (linkedLibraries.isNotEmpty) _result["linkedLibraries"] = linkedLibraries.map((_value) => _value.toJson()).toList();
if (linkedLibraryUris.isNotEmpty) _result["linkedLibraryUris"] = linkedLibraryUris;
+ if (majorVersion != 0) _result["majorVersion"] = majorVersion;
+ if (minorVersion != 0) _result["minorVersion"] = minorVersion;
if (unlinkedUnitHashes.isNotEmpty) _result["unlinkedUnitHashes"] = unlinkedUnitHashes;
if (unlinkedUnits.isNotEmpty) _result["unlinkedUnits"] = unlinkedUnits.map((_value) => _value.toJson()).toList();
if (unlinkedUnitUris.isNotEmpty) _result["unlinkedUnitUris"] = unlinkedUnitUris;
@@ -1329,6 +1484,8 @@
Map<String, Object> toMap() => {
"linkedLibraries": linkedLibraries,
"linkedLibraryUris": linkedLibraryUris,
+ "majorVersion": majorVersion,
+ "minorVersion": minorVersion,
"unlinkedUnitHashes": unlinkedUnitHashes,
"unlinkedUnits": unlinkedUnits,
"unlinkedUnitUris": unlinkedUnitUris,
@@ -1338,6 +1495,683 @@
String toString() => convert.JSON.encode(toJson());
}
+class PackageIndexBuilder extends Object with _PackageIndexMixin implements idl.PackageIndex {
+ bool _finished = false;
+
+ List<idl.IndexSyntheticElementKind> _elementKinds;
+ List<int> _elementOffsets;
+ List<int> _elementUnits;
+ List<String> _strings;
+ List<int> _unitLibraryUris;
+ List<UnitIndexBuilder> _units;
+ List<int> _unitUnitUris;
+
+ @override
+ List<idl.IndexSyntheticElementKind> get elementKinds => _elementKinds ??= <idl.IndexSyntheticElementKind>[];
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the kind of the synthetic element.
+ */
+ void set elementKinds(List<idl.IndexSyntheticElementKind> _value) {
+ assert(!_finished);
+ _elementKinds = _value;
+ }
+
+ @override
+ List<int> get elementOffsets => _elementOffsets ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the offset of the element name relative to the beginning of the file. The
+ * list is sorted in ascending order, so that the client can quickly check
+ * whether an element is referenced in this [PackageIndex].
+ */
+ void set elementOffsets(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _elementOffsets = _value;
+ }
+
+ @override
+ List<int> get elementUnits => _elementUnits ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the index into [unitLibraryUris] and [unitUnitUris] for the library
+ * specific unit where the element is declared.
+ */
+ void set elementUnits(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _elementUnits = _value;
+ }
+
+ @override
+ List<String> get strings => _strings ??= <String>[];
+
+ /**
+ * List of unique element strings used in this [PackageIndex].
+ */
+ void set strings(List<String> _value) {
+ assert(!_finished);
+ _strings = _value;
+ }
+
+ @override
+ List<int> get unitLibraryUris => _unitLibraryUris ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique library
+ * specific unit referenced in the [PackageIndex]. It is an index into
+ * [strings] list.
+ */
+ void set unitLibraryUris(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _unitLibraryUris = _value;
+ }
+
+ @override
+ List<UnitIndexBuilder> get units => _units ??= <UnitIndexBuilder>[];
+
+ /**
+ * List of indexes of each unit in this [PackageIndex].
+ */
+ void set units(List<UnitIndexBuilder> _value) {
+ assert(!_finished);
+ _units = _value;
+ }
+
+ @override
+ List<int> get unitUnitUris => _unitUnitUris ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique library
+ * specific unit referenced in the [PackageIndex]. It is an index into
+ * [strings] list.
+ */
+ void set unitUnitUris(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _unitUnitUris = _value;
+ }
+
+ PackageIndexBuilder({List<idl.IndexSyntheticElementKind> elementKinds, List<int> elementOffsets, List<int> elementUnits, List<String> strings, List<int> unitLibraryUris, List<UnitIndexBuilder> units, List<int> unitUnitUris})
+ : _elementKinds = elementKinds,
+ _elementOffsets = elementOffsets,
+ _elementUnits = elementUnits,
+ _strings = strings,
+ _unitLibraryUris = unitLibraryUris,
+ _units = units,
+ _unitUnitUris = unitUnitUris;
+
+ List<int> toBuffer() {
+ fb.Builder fbBuilder = new fb.Builder();
+ return fbBuilder.finish(finish(fbBuilder), "Indx");
+ }
+
+ fb.Offset finish(fb.Builder fbBuilder) {
+ assert(!_finished);
+ _finished = true;
+ fb.Offset offset_elementKinds;
+ fb.Offset offset_elementOffsets;
+ fb.Offset offset_elementUnits;
+ fb.Offset offset_strings;
+ fb.Offset offset_unitLibraryUris;
+ fb.Offset offset_units;
+ fb.Offset offset_unitUnitUris;
+ if (!(_elementKinds == null || _elementKinds.isEmpty)) {
+ offset_elementKinds = fbBuilder.writeListUint8(_elementKinds.map((b) => b.index).toList());
+ }
+ if (!(_elementOffsets == null || _elementOffsets.isEmpty)) {
+ offset_elementOffsets = fbBuilder.writeListUint32(_elementOffsets);
+ }
+ if (!(_elementUnits == null || _elementUnits.isEmpty)) {
+ offset_elementUnits = fbBuilder.writeListUint32(_elementUnits);
+ }
+ if (!(_strings == null || _strings.isEmpty)) {
+ offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
+ }
+ if (!(_unitLibraryUris == null || _unitLibraryUris.isEmpty)) {
+ offset_unitLibraryUris = fbBuilder.writeListUint32(_unitLibraryUris);
+ }
+ if (!(_units == null || _units.isEmpty)) {
+ offset_units = fbBuilder.writeList(_units.map((b) => b.finish(fbBuilder)).toList());
+ }
+ if (!(_unitUnitUris == null || _unitUnitUris.isEmpty)) {
+ offset_unitUnitUris = fbBuilder.writeListUint32(_unitUnitUris);
+ }
+ fbBuilder.startTable();
+ if (offset_elementKinds != null) {
+ fbBuilder.addOffset(5, offset_elementKinds);
+ }
+ if (offset_elementOffsets != null) {
+ fbBuilder.addOffset(1, offset_elementOffsets);
+ }
+ if (offset_elementUnits != null) {
+ fbBuilder.addOffset(0, offset_elementUnits);
+ }
+ if (offset_strings != null) {
+ fbBuilder.addOffset(6, offset_strings);
+ }
+ if (offset_unitLibraryUris != null) {
+ fbBuilder.addOffset(2, offset_unitLibraryUris);
+ }
+ if (offset_units != null) {
+ fbBuilder.addOffset(4, offset_units);
+ }
+ if (offset_unitUnitUris != null) {
+ fbBuilder.addOffset(3, offset_unitUnitUris);
+ }
+ return fbBuilder.endTable();
+ }
+}
+
+idl.PackageIndex readPackageIndex(List<int> buffer) {
+ fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
+ return const _PackageIndexReader().read(rootRef);
+}
+
+class _PackageIndexReader extends fb.TableReader<_PackageIndexImpl> {
+ const _PackageIndexReader();
+
+ @override
+ _PackageIndexImpl createObject(fb.BufferPointer bp) => new _PackageIndexImpl(bp);
+}
+
+class _PackageIndexImpl extends Object with _PackageIndexMixin implements idl.PackageIndex {
+ final fb.BufferPointer _bp;
+
+ _PackageIndexImpl(this._bp);
+
+ List<idl.IndexSyntheticElementKind> _elementKinds;
+ List<int> _elementOffsets;
+ List<int> _elementUnits;
+ List<String> _strings;
+ List<int> _unitLibraryUris;
+ List<idl.UnitIndex> _units;
+ List<int> _unitUnitUris;
+
+ @override
+ List<idl.IndexSyntheticElementKind> get elementKinds {
+ _elementKinds ??= const fb.ListReader<idl.IndexSyntheticElementKind>(const _IndexSyntheticElementKindReader()).vTableGet(_bp, 5, const <idl.IndexSyntheticElementKind>[]);
+ return _elementKinds;
+ }
+
+ @override
+ List<int> get elementOffsets {
+ _elementOffsets ??= const fb.Uint32ListReader().vTableGet(_bp, 1, const <int>[]);
+ return _elementOffsets;
+ }
+
+ @override
+ List<int> get elementUnits {
+ _elementUnits ??= const fb.Uint32ListReader().vTableGet(_bp, 0, const <int>[]);
+ return _elementUnits;
+ }
+
+ @override
+ List<String> get strings {
+ _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 6, const <String>[]);
+ return _strings;
+ }
+
+ @override
+ List<int> get unitLibraryUris {
+ _unitLibraryUris ??= const fb.Uint32ListReader().vTableGet(_bp, 2, const <int>[]);
+ return _unitLibraryUris;
+ }
+
+ @override
+ List<idl.UnitIndex> get units {
+ _units ??= const fb.ListReader<idl.UnitIndex>(const _UnitIndexReader()).vTableGet(_bp, 4, const <idl.UnitIndex>[]);
+ return _units;
+ }
+
+ @override
+ List<int> get unitUnitUris {
+ _unitUnitUris ??= const fb.Uint32ListReader().vTableGet(_bp, 3, const <int>[]);
+ return _unitUnitUris;
+ }
+}
+
+abstract class _PackageIndexMixin implements idl.PackageIndex {
+ @override
+ Map<String, Object> toJson() {
+ Map<String, Object> _result = <String, Object>{};
+ if (elementKinds.isNotEmpty) _result["elementKinds"] = elementKinds.map((_value) => _value.toString().split('.')[1]).toList();
+ if (elementOffsets.isNotEmpty) _result["elementOffsets"] = elementOffsets;
+ if (elementUnits.isNotEmpty) _result["elementUnits"] = elementUnits;
+ if (strings.isNotEmpty) _result["strings"] = strings;
+ if (unitLibraryUris.isNotEmpty) _result["unitLibraryUris"] = unitLibraryUris;
+ if (units.isNotEmpty) _result["units"] = units.map((_value) => _value.toJson()).toList();
+ if (unitUnitUris.isNotEmpty) _result["unitUnitUris"] = unitUnitUris;
+ return _result;
+ }
+
+ @override
+ Map<String, Object> toMap() => {
+ "elementKinds": elementKinds,
+ "elementOffsets": elementOffsets,
+ "elementUnits": elementUnits,
+ "strings": strings,
+ "unitLibraryUris": unitLibraryUris,
+ "units": units,
+ "unitUnitUris": unitUnitUris,
+ };
+
+ @override
+ String toString() => convert.JSON.encode(toJson());
+}
+
+class UnitIndexBuilder extends Object with _UnitIndexMixin implements idl.UnitIndex {
+ bool _finished = false;
+
+ List<idl.IndexNameKind> _definedNameKinds;
+ List<int> _definedNameOffsets;
+ List<int> _definedNames;
+ int _unit;
+ List<bool> _usedElementIsQualifiedFlags;
+ List<idl.IndexRelationKind> _usedElementKinds;
+ List<int> _usedElementLengths;
+ List<int> _usedElementOffsets;
+ List<int> _usedElements;
+ List<idl.IndexRelationKind> _usedNameKinds;
+ List<int> _usedNameOffsets;
+ List<int> _usedNames;
+
+ @override
+ List<idl.IndexNameKind> get definedNameKinds => _definedNameKinds ??= <idl.IndexNameKind>[];
+
+ /**
+ * Each item of this list is the kind of an element defined in this unit.
+ */
+ void set definedNameKinds(List<idl.IndexNameKind> _value) {
+ assert(!_finished);
+ _definedNameKinds = _value;
+ }
+
+ @override
+ List<int> get definedNameOffsets => _definedNameOffsets ??= <int>[];
+
+ /**
+ * Each item of this list is the name offset of an element defined in this
+ * unit relative to the beginning of the file.
+ */
+ void set definedNameOffsets(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _definedNameOffsets = _value;
+ }
+
+ @override
+ List<int> get definedNames => _definedNames ??= <int>[];
+
+ /**
+ * Each item of this list corresponds to an element defined in this unit. It
+ * is an index into [PackageIndex.strings] list. The list is sorted in
+ * ascending order, so that the client can quickly find name definitions in
+ * this [UnitIndex].
+ */
+ void set definedNames(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _definedNames = _value;
+ }
+
+ @override
+ int get unit => _unit ??= 0;
+
+ /**
+ * Index into [PackageIndex.unitLibraryUris] and [PackageIndex.unitUnitUris]
+ * for the library specific unit that corresponds to this [UnitIndex].
+ */
+ void set unit(int _value) {
+ assert(!_finished);
+ assert(_value == null || _value >= 0);
+ _unit = _value;
+ }
+
+ @override
+ List<bool> get usedElementIsQualifiedFlags => _usedElementIsQualifiedFlags ??= <bool>[];
+
+ /**
+ * Each item of this list is the `true` if the corresponding element usage
+ * is qualified with some prefix.
+ */
+ void set usedElementIsQualifiedFlags(List<bool> _value) {
+ assert(!_finished);
+ _usedElementIsQualifiedFlags = _value;
+ }
+
+ @override
+ List<idl.IndexRelationKind> get usedElementKinds => _usedElementKinds ??= <idl.IndexRelationKind>[];
+
+ /**
+ * Each item of this list is the kind of the element usage.
+ */
+ void set usedElementKinds(List<idl.IndexRelationKind> _value) {
+ assert(!_finished);
+ _usedElementKinds = _value;
+ }
+
+ @override
+ List<int> get usedElementLengths => _usedElementLengths ??= <int>[];
+
+ /**
+ * Each item of this list is the length of the element usage.
+ */
+ void set usedElementLengths(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _usedElementLengths = _value;
+ }
+
+ @override
+ List<int> get usedElementOffsets => _usedElementOffsets ??= <int>[];
+
+ /**
+ * Each item of this list is the offset of the element usage relative to the
+ * beginning of the file.
+ */
+ void set usedElementOffsets(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _usedElementOffsets = _value;
+ }
+
+ @override
+ List<int> get usedElements => _usedElements ??= <int>[];
+
+ /**
+ * Each item of this list is the index into [PackageIndex.elementUnits] and
+ * [PackageIndex.elementOffsets]. The list is sorted in ascending order, so
+ * that the client can quickly find element references in this [UnitIndex].
+ */
+ void set usedElements(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _usedElements = _value;
+ }
+
+ @override
+ List<idl.IndexRelationKind> get usedNameKinds => _usedNameKinds ??= <idl.IndexRelationKind>[];
+
+ /**
+ * Each item of this list is the kind of the name usage.
+ */
+ void set usedNameKinds(List<idl.IndexRelationKind> _value) {
+ assert(!_finished);
+ _usedNameKinds = _value;
+ }
+
+ @override
+ List<int> get usedNameOffsets => _usedNameOffsets ??= <int>[];
+
+ /**
+ * Each item of this list is the offset of the name usage relative to the
+ * beginning of the file.
+ */
+ void set usedNameOffsets(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _usedNameOffsets = _value;
+ }
+
+ @override
+ List<int> get usedNames => _usedNames ??= <int>[];
+
+ /**
+ * Each item of this list is the index into [PackageIndex.strings] for a
+ * used name. The list is sorted in ascending order, so that the client can
+ * quickly find name uses in this [UnitIndex].
+ */
+ void set usedNames(List<int> _value) {
+ assert(!_finished);
+ assert(_value == null || _value.every((e) => e >= 0));
+ _usedNames = _value;
+ }
+
+ UnitIndexBuilder({List<idl.IndexNameKind> definedNameKinds, List<int> definedNameOffsets, List<int> definedNames, int unit, List<bool> usedElementIsQualifiedFlags, List<idl.IndexRelationKind> usedElementKinds, List<int> usedElementLengths, List<int> usedElementOffsets, List<int> usedElements, List<idl.IndexRelationKind> usedNameKinds, List<int> usedNameOffsets, List<int> usedNames})
+ : _definedNameKinds = definedNameKinds,
+ _definedNameOffsets = definedNameOffsets,
+ _definedNames = definedNames,
+ _unit = unit,
+ _usedElementIsQualifiedFlags = usedElementIsQualifiedFlags,
+ _usedElementKinds = usedElementKinds,
+ _usedElementLengths = usedElementLengths,
+ _usedElementOffsets = usedElementOffsets,
+ _usedElements = usedElements,
+ _usedNameKinds = usedNameKinds,
+ _usedNameOffsets = usedNameOffsets,
+ _usedNames = usedNames;
+
+ fb.Offset finish(fb.Builder fbBuilder) {
+ assert(!_finished);
+ _finished = true;
+ fb.Offset offset_definedNameKinds;
+ fb.Offset offset_definedNameOffsets;
+ fb.Offset offset_definedNames;
+ fb.Offset offset_usedElementIsQualifiedFlags;
+ fb.Offset offset_usedElementKinds;
+ fb.Offset offset_usedElementLengths;
+ fb.Offset offset_usedElementOffsets;
+ fb.Offset offset_usedElements;
+ fb.Offset offset_usedNameKinds;
+ fb.Offset offset_usedNameOffsets;
+ fb.Offset offset_usedNames;
+ if (!(_definedNameKinds == null || _definedNameKinds.isEmpty)) {
+ offset_definedNameKinds = fbBuilder.writeListUint8(_definedNameKinds.map((b) => b.index).toList());
+ }
+ if (!(_definedNameOffsets == null || _definedNameOffsets.isEmpty)) {
+ offset_definedNameOffsets = fbBuilder.writeListUint32(_definedNameOffsets);
+ }
+ if (!(_definedNames == null || _definedNames.isEmpty)) {
+ offset_definedNames = fbBuilder.writeListUint32(_definedNames);
+ }
+ if (!(_usedElementIsQualifiedFlags == null || _usedElementIsQualifiedFlags.isEmpty)) {
+ offset_usedElementIsQualifiedFlags = fbBuilder.writeListBool(_usedElementIsQualifiedFlags);
+ }
+ if (!(_usedElementKinds == null || _usedElementKinds.isEmpty)) {
+ offset_usedElementKinds = fbBuilder.writeListUint8(_usedElementKinds.map((b) => b.index).toList());
+ }
+ if (!(_usedElementLengths == null || _usedElementLengths.isEmpty)) {
+ offset_usedElementLengths = fbBuilder.writeListUint32(_usedElementLengths);
+ }
+ if (!(_usedElementOffsets == null || _usedElementOffsets.isEmpty)) {
+ offset_usedElementOffsets = fbBuilder.writeListUint32(_usedElementOffsets);
+ }
+ if (!(_usedElements == null || _usedElements.isEmpty)) {
+ offset_usedElements = fbBuilder.writeListUint32(_usedElements);
+ }
+ if (!(_usedNameKinds == null || _usedNameKinds.isEmpty)) {
+ offset_usedNameKinds = fbBuilder.writeListUint8(_usedNameKinds.map((b) => b.index).toList());
+ }
+ if (!(_usedNameOffsets == null || _usedNameOffsets.isEmpty)) {
+ offset_usedNameOffsets = fbBuilder.writeListUint32(_usedNameOffsets);
+ }
+ if (!(_usedNames == null || _usedNames.isEmpty)) {
+ offset_usedNames = fbBuilder.writeListUint32(_usedNames);
+ }
+ fbBuilder.startTable();
+ if (offset_definedNameKinds != null) {
+ fbBuilder.addOffset(6, offset_definedNameKinds);
+ }
+ if (offset_definedNameOffsets != null) {
+ fbBuilder.addOffset(7, offset_definedNameOffsets);
+ }
+ if (offset_definedNames != null) {
+ fbBuilder.addOffset(5, offset_definedNames);
+ }
+ if (_unit != null && _unit != 0) {
+ fbBuilder.addUint32(0, _unit);
+ }
+ if (offset_usedElementIsQualifiedFlags != null) {
+ fbBuilder.addOffset(11, offset_usedElementIsQualifiedFlags);
+ }
+ if (offset_usedElementKinds != null) {
+ fbBuilder.addOffset(4, offset_usedElementKinds);
+ }
+ if (offset_usedElementLengths != null) {
+ fbBuilder.addOffset(1, offset_usedElementLengths);
+ }
+ if (offset_usedElementOffsets != null) {
+ fbBuilder.addOffset(2, offset_usedElementOffsets);
+ }
+ if (offset_usedElements != null) {
+ fbBuilder.addOffset(3, offset_usedElements);
+ }
+ if (offset_usedNameKinds != null) {
+ fbBuilder.addOffset(10, offset_usedNameKinds);
+ }
+ if (offset_usedNameOffsets != null) {
+ fbBuilder.addOffset(9, offset_usedNameOffsets);
+ }
+ if (offset_usedNames != null) {
+ fbBuilder.addOffset(8, offset_usedNames);
+ }
+ return fbBuilder.endTable();
+ }
+}
+
+class _UnitIndexReader extends fb.TableReader<_UnitIndexImpl> {
+ const _UnitIndexReader();
+
+ @override
+ _UnitIndexImpl createObject(fb.BufferPointer bp) => new _UnitIndexImpl(bp);
+}
+
+class _UnitIndexImpl extends Object with _UnitIndexMixin implements idl.UnitIndex {
+ final fb.BufferPointer _bp;
+
+ _UnitIndexImpl(this._bp);
+
+ List<idl.IndexNameKind> _definedNameKinds;
+ List<int> _definedNameOffsets;
+ List<int> _definedNames;
+ int _unit;
+ List<bool> _usedElementIsQualifiedFlags;
+ List<idl.IndexRelationKind> _usedElementKinds;
+ List<int> _usedElementLengths;
+ List<int> _usedElementOffsets;
+ List<int> _usedElements;
+ List<idl.IndexRelationKind> _usedNameKinds;
+ List<int> _usedNameOffsets;
+ List<int> _usedNames;
+
+ @override
+ List<idl.IndexNameKind> get definedNameKinds {
+ _definedNameKinds ??= const fb.ListReader<idl.IndexNameKind>(const _IndexNameKindReader()).vTableGet(_bp, 6, const <idl.IndexNameKind>[]);
+ return _definedNameKinds;
+ }
+
+ @override
+ List<int> get definedNameOffsets {
+ _definedNameOffsets ??= const fb.Uint32ListReader().vTableGet(_bp, 7, const <int>[]);
+ return _definedNameOffsets;
+ }
+
+ @override
+ List<int> get definedNames {
+ _definedNames ??= const fb.Uint32ListReader().vTableGet(_bp, 5, const <int>[]);
+ return _definedNames;
+ }
+
+ @override
+ int get unit {
+ _unit ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+ return _unit;
+ }
+
+ @override
+ List<bool> get usedElementIsQualifiedFlags {
+ _usedElementIsQualifiedFlags ??= const fb.BoolListReader().vTableGet(_bp, 11, const <bool>[]);
+ return _usedElementIsQualifiedFlags;
+ }
+
+ @override
+ List<idl.IndexRelationKind> get usedElementKinds {
+ _usedElementKinds ??= const fb.ListReader<idl.IndexRelationKind>(const _IndexRelationKindReader()).vTableGet(_bp, 4, const <idl.IndexRelationKind>[]);
+ return _usedElementKinds;
+ }
+
+ @override
+ List<int> get usedElementLengths {
+ _usedElementLengths ??= const fb.Uint32ListReader().vTableGet(_bp, 1, const <int>[]);
+ return _usedElementLengths;
+ }
+
+ @override
+ List<int> get usedElementOffsets {
+ _usedElementOffsets ??= const fb.Uint32ListReader().vTableGet(_bp, 2, const <int>[]);
+ return _usedElementOffsets;
+ }
+
+ @override
+ List<int> get usedElements {
+ _usedElements ??= const fb.Uint32ListReader().vTableGet(_bp, 3, const <int>[]);
+ return _usedElements;
+ }
+
+ @override
+ List<idl.IndexRelationKind> get usedNameKinds {
+ _usedNameKinds ??= const fb.ListReader<idl.IndexRelationKind>(const _IndexRelationKindReader()).vTableGet(_bp, 10, const <idl.IndexRelationKind>[]);
+ return _usedNameKinds;
+ }
+
+ @override
+ List<int> get usedNameOffsets {
+ _usedNameOffsets ??= const fb.Uint32ListReader().vTableGet(_bp, 9, const <int>[]);
+ return _usedNameOffsets;
+ }
+
+ @override
+ List<int> get usedNames {
+ _usedNames ??= const fb.Uint32ListReader().vTableGet(_bp, 8, const <int>[]);
+ return _usedNames;
+ }
+}
+
+abstract class _UnitIndexMixin implements idl.UnitIndex {
+ @override
+ Map<String, Object> toJson() {
+ Map<String, Object> _result = <String, Object>{};
+ if (definedNameKinds.isNotEmpty) _result["definedNameKinds"] = definedNameKinds.map((_value) => _value.toString().split('.')[1]).toList();
+ if (definedNameOffsets.isNotEmpty) _result["definedNameOffsets"] = definedNameOffsets;
+ if (definedNames.isNotEmpty) _result["definedNames"] = definedNames;
+ if (unit != 0) _result["unit"] = unit;
+ if (usedElementIsQualifiedFlags.isNotEmpty) _result["usedElementIsQualifiedFlags"] = usedElementIsQualifiedFlags;
+ if (usedElementKinds.isNotEmpty) _result["usedElementKinds"] = usedElementKinds.map((_value) => _value.toString().split('.')[1]).toList();
+ if (usedElementLengths.isNotEmpty) _result["usedElementLengths"] = usedElementLengths;
+ if (usedElementOffsets.isNotEmpty) _result["usedElementOffsets"] = usedElementOffsets;
+ if (usedElements.isNotEmpty) _result["usedElements"] = usedElements;
+ if (usedNameKinds.isNotEmpty) _result["usedNameKinds"] = usedNameKinds.map((_value) => _value.toString().split('.')[1]).toList();
+ if (usedNameOffsets.isNotEmpty) _result["usedNameOffsets"] = usedNameOffsets;
+ if (usedNames.isNotEmpty) _result["usedNames"] = usedNames;
+ return _result;
+ }
+
+ @override
+ Map<String, Object> toMap() => {
+ "definedNameKinds": definedNameKinds,
+ "definedNameOffsets": definedNameOffsets,
+ "definedNames": definedNames,
+ "unit": unit,
+ "usedElementIsQualifiedFlags": usedElementIsQualifiedFlags,
+ "usedElementKinds": usedElementKinds,
+ "usedElementLengths": usedElementLengths,
+ "usedElementOffsets": usedElementOffsets,
+ "usedElements": usedElements,
+ "usedNameKinds": usedNameKinds,
+ "usedNameOffsets": usedNameOffsets,
+ "usedNames": usedNames,
+ };
+
+ @override
+ String toString() => convert.JSON.encode(toJson());
+}
+
class UnlinkedClassBuilder extends Object with _UnlinkedClassMixin implements idl.UnlinkedClass {
bool _finished = false;
@@ -4969,7 +5803,7 @@
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
- return fbBuilder.finish(finish(fbBuilder));
+ return fbBuilder.finish(finish(fbBuilder), "UPNS");
}
fb.Offset finish(fb.Builder fbBuilder) {
@@ -5782,7 +6616,7 @@
List<int> toBuffer() {
fb.Builder fbBuilder = new fb.Builder();
- return fbBuilder.finish(finish(fbBuilder));
+ return fbBuilder.finish(finish(fbBuilder), "UUnt");
}
fb.Offset finish(fb.Builder fbBuilder) {
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
new file mode 100644
index 0000000..63828ff
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -0,0 +1,1963 @@
+// 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.
+//
+// This file has been automatically generated. Please do not edit it manually.
+// To regenerate the file, use the script "pkg/analyzer/tool/generate_files".
+
+
+/**
+ * Enum used to indicate the kind of a name in index.
+ */
+enum IndexNameKind : byte {
+ /**
+ * A top-level element.
+ */
+ topLevel,
+
+ /**
+ * A class member.
+ */
+ classMember
+}
+
+/**
+ * Enum used to indicate the kind of an index relation.
+ */
+enum IndexRelationKind : byte {
+ /**
+ * Left: class.
+ * Is extended by.
+ * Right: other class declaration.
+ */
+ IS_EXTENDED_BY,
+
+ /**
+ * Left: class.
+ * Is implemented by.
+ * Right: other class declaration.
+ */
+ IS_IMPLEMENTED_BY,
+
+ /**
+ * Left: class.
+ * Is mixed into.
+ * Right: other class declaration.
+ */
+ IS_MIXED_IN_BY,
+
+ /**
+ * Left: method, property accessor, function, variable.
+ * Is invoked at.
+ * Right: location.
+ */
+ IS_INVOKED_BY,
+
+ /**
+ * Left: any element.
+ * Is referenced (and not invoked, read/written) at.
+ * Right: location.
+ */
+ IS_REFERENCED_BY
+}
+
+/**
+ * When we need to reference a synthetic element in [PackageIndex] we use a
+ * value of this enum to specify which kind of the synthetic element we
+ * actually reference.
+ */
+enum IndexSyntheticElementKind : byte {
+ /**
+ * Not a synthetic element.
+ */
+ notSynthetic,
+
+ /**
+ * The unnamed synthetic constructor a class element.
+ */
+ constructor,
+
+ /**
+ * The synthetic getter of a property introducing element.
+ */
+ getter,
+
+ /**
+ * The synthetic setter of a property introducing element.
+ */
+ setter
+}
+
+/**
+ * Enum used to indicate the kind of entity referred to by a
+ * [LinkedReference].
+ */
+enum ReferenceKind : byte {
+ /**
+ * The entity is a class or enum.
+ */
+ classOrEnum,
+
+ /**
+ * The entity is a constructor.
+ */
+ constructor,
+
+ /**
+ * The entity is a getter or setter inside a class. Note: this is used in
+ * the case where a constant refers to a static const declared inside a
+ * class.
+ */
+ propertyAccessor,
+
+ /**
+ * The entity is a method.
+ */
+ method,
+
+ /**
+ * The `length` property access.
+ */
+ length,
+
+ /**
+ * The entity is a typedef.
+ */
+ typedef,
+
+ /**
+ * The entity is a local function.
+ */
+ function,
+
+ /**
+ * The entity is a local variable.
+ */
+ variable,
+
+ /**
+ * The entity is a top level function.
+ */
+ topLevelFunction,
+
+ /**
+ * The entity is a top level getter or setter.
+ */
+ topLevelPropertyAccessor,
+
+ /**
+ * The entity is a prefix.
+ */
+ prefix,
+
+ /**
+ * The entity being referred to does not exist.
+ */
+ unresolved
+}
+
+/**
+ * Enum representing the various kinds of operations which may be performed to
+ * produce a constant value. These options are assumed to execute in the
+ * context of a stack which is initially empty.
+ */
+enum UnlinkedConstOperation : byte {
+ /**
+ * Push the next value from [UnlinkedConst.ints] (a 32-bit unsigned integer)
+ * onto the stack.
+ *
+ * Note that Dart supports integers larger than 32 bits; these are
+ * represented by composing 32-bit values using the [pushLongInt] operation.
+ */
+ pushInt,
+
+ /**
+ * Get the number of components from [UnlinkedConst.ints], then do this number
+ * of times the following operations: multiple the current value by 2^32, "or"
+ * it with the next value in [UnlinkedConst.ints]. The initial value is zero.
+ * Push the result into the stack.
+ */
+ pushLongInt,
+
+ /**
+ * Push the next value from [UnlinkedConst.doubles] (a double precision
+ * floating point value) onto the stack.
+ */
+ pushDouble,
+
+ /**
+ * Push the constant `true` onto the stack.
+ */
+ pushTrue,
+
+ /**
+ * Push the constant `false` onto the stack.
+ */
+ pushFalse,
+
+ /**
+ * Push the next value from [UnlinkedConst.strings] onto the stack.
+ */
+ pushString,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), convert them to strings (if they aren't already),
+ * concatenate them into a single string, and push it back onto the stack.
+ *
+ * This operation is used to represent constants whose value is a literal
+ * string containing string interpolations.
+ */
+ concatenate,
+
+ /**
+ * Get the next value from [UnlinkedConst.strings], convert it to a symbol,
+ * and push it onto the stack.
+ */
+ makeSymbol,
+
+ /**
+ * Push the constant `null` onto the stack.
+ */
+ pushNull,
+
+ /**
+ * Push the value of the constant constructor parameter with
+ * the name obtained from [UnlinkedConst.strings].
+ */
+ pushConstructorParameter,
+
+ /**
+ * Evaluate a (potentially qualified) identifier expression and push the
+ * resulting value onto the stack. The identifier to be evaluated is
+ * obtained from [UnlinkedConst.references].
+ *
+ * This operation is used to represent the following kinds of constants
+ * (which are indistinguishable from an unresolved AST alone):
+ *
+ * - A qualified reference to a static constant variable (e.g. `C.v`, where
+ * C is a class and `v` is a constant static variable in `C`).
+ * - An identifier expression referring to a constant variable.
+ * - A simple or qualified identifier denoting a class or type alias.
+ * - A simple or qualified identifier denoting a top-level function or a
+ * static method.
+ */
+ pushReference,
+
+ /**
+ * Pop the top `n` values from the stack (where `n` is obtained from
+ * [UnlinkedConst.ints]) into a list (filled from the end) and take the next
+ * `n` values from [UnlinkedConst.strings] and use the lists of names and
+ * values to create named arguments. Then pop the top `m` values from the
+ * stack (where `m` is obtained from [UnlinkedConst.ints]) into a list (filled
+ * from the end) and use them as positional arguments. Use the lists of
+ * positional and names arguments to invoke a constant constructor obtained
+ * from [UnlinkedConst.references], and push the resulting value back onto the
+ * stack.
+ *
+ * Note that for an invocation of the form `const a.b(...)` (where no type
+ * arguments are specified), it is impossible to tell from the unresolved AST
+ * alone whether `a` is a class name and `b` is a constructor name, or `a` is
+ * a prefix name and `b` is a class name. For consistency between AST based
+ * and elements based summaries, references to default constructors are always
+ * recorded as references to corresponding classes.
+ */
+ invokeConstructor,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), place them in a [List], and push the result back
+ * onto the stack. The type parameter for the [List] is implicitly `dynamic`.
+ */
+ makeUntypedList,
+
+ /**
+ * Pop the top 2*n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
+ * [Map], and push the result back onto the stack. The two type parameters
+ * for the [Map] are implicitly `dynamic`.
+ */
+ makeUntypedMap,
+
+ /**
+ * Pop the top n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), place them in a [List], and push the result back
+ * onto the stack. The type parameter for the [List] is obtained from
+ * [UnlinkedConst.references].
+ */
+ makeTypedList,
+
+ /**
+ * Pop the top 2*n values from the stack (where n is obtained from
+ * [UnlinkedConst.ints]), interpret them as key/value pairs, place them in a
+ * [Map], and push the result back onto the stack. The two type parameters for
+ * the [Map] are obtained from [UnlinkedConst.references].
+ */
+ makeTypedMap,
+
+ /**
+ * Pop the top 2 values from the stack, pass them to the predefined Dart
+ * function `identical`, and push the result back onto the stack.
+ */
+ identical,
+
+ /**
+ * Pop the top 2 values from the stack, evaluate `v1 == v2`, and push the
+ * result back onto the stack.
+ */
+ equal,
+
+ /**
+ * Pop the top 2 values from the stack, evaluate `v1 != v2`, and push the
+ * result back onto the stack.
+ */
+ notEqual,
+
+ /**
+ * Pop the top value from the stack, compute its boolean negation, and push
+ * the result back onto the stack.
+ */
+ not,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 && v2`, and push the
+ * result back onto the stack.
+ */
+ and,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 || v2`, and push the
+ * result back onto the stack.
+ */
+ or,
+
+ /**
+ * Pop the top value from the stack, compute its integer complement, and push
+ * the result back onto the stack.
+ */
+ complement,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 ^ v2`, and push the
+ * result back onto the stack.
+ */
+ bitXor,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 & v2`, and push the
+ * result back onto the stack.
+ */
+ bitAnd,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 | v2`, and push the
+ * result back onto the stack.
+ */
+ bitOr,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 >> v2`, and push the
+ * result back onto the stack.
+ */
+ bitShiftRight,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 << v2`, and push the
+ * result back onto the stack.
+ */
+ bitShiftLeft,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 + v2`, and push the
+ * result back onto the stack.
+ */
+ add,
+
+ /**
+ * Pop the top value from the stack, compute its integer negation, and push
+ * the result back onto the stack.
+ */
+ negate,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 - v2`, and push the
+ * result back onto the stack.
+ */
+ subtract,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 * v2`, and push the
+ * result back onto the stack.
+ */
+ multiply,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 / v2`, and push the
+ * result back onto the stack.
+ */
+ divide,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 ~/ v2`, and push the
+ * result back onto the stack.
+ */
+ floorDivide,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 > v2`, and push the
+ * result back onto the stack.
+ */
+ greater,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 < v2`, and push the
+ * result back onto the stack.
+ */
+ less,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 >= v2`, and push the
+ * result back onto the stack.
+ */
+ greaterEqual,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 <= v2`, and push the
+ * result back onto the stack.
+ */
+ lessEqual,
+
+ /**
+ * Pop the top 2 values from the stack, compute `v1 % v2`, and push the
+ * result back onto the stack.
+ */
+ modulo,
+
+ /**
+ * Pop the top 3 values from the stack, compute `v1 ? v2 : v3`, and push the
+ * result back onto the stack.
+ */
+ conditional,
+
+ /**
+ * Pop the top value from the stack, evaluate `v.length`, and push the result
+ * back onto the stack.
+ */
+ length
+}
+
+/**
+ * Enum used to indicate the kind of an constructor initializer.
+ */
+enum UnlinkedConstructorInitializerKind : byte {
+ /**
+ * Initialization of a field.
+ */
+ field,
+
+ /**
+ * Invocation of a constructor in the same class.
+ */
+ thisInvocation,
+
+ /**
+ * Invocation of a superclass' constructor.
+ */
+ superInvocation
+}
+
+/**
+ * Enum used to indicate the kind of an executable.
+ */
+enum UnlinkedExecutableKind : byte {
+ /**
+ * Executable is a function or method.
+ */
+ functionOrMethod,
+
+ /**
+ * Executable is a getter.
+ */
+ getter,
+
+ /**
+ * Executable is a setter.
+ */
+ setter,
+
+ /**
+ * Executable is a constructor.
+ */
+ constructor
+}
+
+/**
+ * Enum used to indicate the kind of a parameter.
+ */
+enum UnlinkedParamKind : byte {
+ /**
+ * Parameter is required.
+ */
+ required,
+
+ /**
+ * Parameter is positional optional (enclosed in `[]`)
+ */
+ positional,
+
+ /**
+ * Parameter is named optional (enclosed in `{}`)
+ */
+ named
+}
+
+/**
+ * Summary information about a reference to a an entity such as a type, top
+ * level executable, or executable within a class.
+ */
+table EntityRef {
+ /**
+ * If this is a reference to a function type implicitly defined by a
+ * function-typed parameter, a list of zero-based indices indicating the path
+ * from the entity referred to by [reference] to the appropriate type
+ * parameter. Otherwise the empty list.
+ *
+ * If there are N indices in this list, then the entity being referred to is
+ * the function type implicitly defined by a function-typed parameter of a
+ * function-typed parameter, to N levels of nesting. The first index in the
+ * list refers to the outermost level of nesting; for example if [reference]
+ * refers to the entity defined by:
+ *
+ * void f(x, void g(y, z, int h(String w))) { ... }
+ *
+ * Then to refer to the function type implicitly defined by parameter `h`
+ * (which is parameter 2 of parameter 1 of `f`), then
+ * [implicitFunctionTypeIndices] should be [1, 2].
+ *
+ * Note that if the entity being referred to is a generic method inside a
+ * generic class, then the type arguments in [typeArguments] are applied
+ * first to the class and then to the method.
+ */
+ implicitFunctionTypeIndices:[uint] (id: 4);
+
+ /**
+ * If this is a reference to a type parameter, one-based index into the list
+ * of [UnlinkedTypeParam]s currently in effect. Indexing is done using De
+ * Bruijn index conventions; that is, innermost parameters come first, and
+ * if a class or method has multiple parameters, they are indexed from right
+ * to left. So for instance, if the enclosing declaration is
+ *
+ * class C<T,U> {
+ * m<V,W> {
+ * ...
+ * }
+ * }
+ *
+ * Then [paramReference] values of 1, 2, 3, and 4 represent W, V, U, and T,
+ * respectively.
+ *
+ * If the type being referred to is not a type parameter, [paramReference] is
+ * zero.
+ */
+ paramReference:uint (id: 3);
+
+ /**
+ * Index into [UnlinkedUnit.references] for the entity being referred to, or
+ * zero if this is a reference to a type parameter.
+ */
+ reference:uint (id: 0);
+
+ /**
+ * If this [EntityRef] is contained within [LinkedUnit.types], slot id (which
+ * is unique within the compilation unit) identifying the target of type
+ * propagation or type inference with which this [EntityRef] is associated.
+ *
+ * Otherwise zero.
+ */
+ slot:uint (id: 2);
+
+ /**
+ * If this [EntityRef] is a reference to a function type whose
+ * [FunctionElement] is not in any library (e.g. a function type that was
+ * synthesized by a LUB computation), the function parameters. Otherwise
+ * empty.
+ */
+ syntheticParams:[UnlinkedParam] (id: 6);
+
+ /**
+ * If this [EntityRef] is a reference to a function type whose
+ * [FunctionElement] is not in any library (e.g. a function type that was
+ * synthesized by a LUB computation), the return type of the function.
+ * Otherwise `null`.
+ */
+ syntheticReturnType:EntityRef (id: 5);
+
+ /**
+ * If this is an instantiation of a generic type or generic executable, the
+ * type arguments used to instantiate it. Trailing type arguments of type
+ * `dynamic` are omitted.
+ */
+ typeArguments:[EntityRef] (id: 1);
+}
+
+/**
+ * Information about a dependency that exists between one library and another
+ * due to an "import" declaration.
+ */
+table LinkedDependency {
+ /**
+ * URI for the compilation units listed in the library's `part` declarations.
+ * These URIs are relative to the importing library.
+ */
+ parts:[string] (id: 1);
+
+ /**
+ * The relative URI of the dependent library. This URI is relative to the
+ * importing library, even if there are intervening `export` declarations.
+ * So, for example, if `a.dart` imports `b/c.dart` and `b/c.dart` exports
+ * `d/e.dart`, the URI listed for `a.dart`'s dependency on `e.dart` will be
+ * `b/d/e.dart`.
+ */
+ uri:string (id: 0);
+}
+
+/**
+ * Information about a single name in the export namespace of the library that
+ * is not in the public namespace.
+ */
+table LinkedExportName {
+ /**
+ * Index into [LinkedLibrary.dependencies] for the library in which the
+ * entity is defined.
+ */
+ dependency:uint (id: 0);
+
+ /**
+ * The kind of the entity being referred to.
+ */
+ kind:ReferenceKind (id: 3);
+
+ /**
+ * Name of the exported entity. For an exported setter, this name includes
+ * the trailing '='.
+ */
+ name:string (id: 1);
+
+ /**
+ * Integer index indicating which unit in the exported library contains the
+ * definition of the entity. As with indices into [LinkedLibrary.units],
+ * zero represents the defining compilation unit, and nonzero values
+ * represent parts in the order of the corresponding `part` declarations.
+ */
+ unit:uint (id: 2);
+}
+
+/**
+ * Linked summary of a library.
+ */
+table LinkedLibrary {
+ /**
+ * The libraries that this library depends on (either via an explicit import
+ * statement or via the implicit dependencies on `dart:core` and
+ * `dart:async`). The first element of this array is a pseudo-dependency
+ * representing the library itself (it is also used for `dynamic` and
+ * `void`). This is followed by elements representing "prelinked"
+ * dependencies (direct imports and the transitive closure of exports).
+ * After the prelinked dependencies are elements representing "linked"
+ * dependencies.
+ *
+ * A library is only included as a "linked" dependency if it is a true
+ * dependency (e.g. a propagated or inferred type or constant value
+ * implicitly refers to an element declared in the library) or
+ * anti-dependency (e.g. the result of type propagation or type inference
+ * depends on the lack of a certain declaration in the library).
+ */
+ dependencies:[LinkedDependency] (id: 0);
+
+ /**
+ * Information about entities in the export namespace of the library that are
+ * not in the public namespace of the library (that is, entities that are
+ * brought into the namespace via `export` directives).
+ *
+ * Sorted by name.
+ */
+ exportNames:[LinkedExportName] (id: 4);
+
+ /**
+ * For each import in [UnlinkedUnit.imports], an index into [dependencies]
+ * of the library being imported.
+ */
+ importDependencies:[uint] (id: 1);
+
+ /**
+ * The number of elements in [dependencies] which are not "linked"
+ * dependencies (that is, the number of libraries in the direct imports plus
+ * the transitive closure of exports, plus the library itself).
+ */
+ numPrelinkedDependencies:uint (id: 2);
+
+ /**
+ * The linked summary of all the compilation units constituting the
+ * library. The summary of the defining compilation unit is listed first,
+ * followed by the summary of each part, in the order of the `part`
+ * declarations in the defining compilation unit.
+ */
+ units:[LinkedUnit] (id: 3);
+}
+
+/**
+ * Information about the resolution of an [UnlinkedReference].
+ */
+table LinkedReference {
+ /**
+ * If this [LinkedReference] doesn't have an associated [UnlinkedReference],
+ * and the entity being referred to is contained within another entity, index
+ * of the containing entity. This behaves similarly to
+ * [UnlinkedReference.prefixReference], however it is only used for class
+ * members, not for prefixed imports.
+ *
+ * Containing references must always point backward; that is, for all i, if
+ * LinkedUnit.references[i].containingReference != 0, then
+ * LinkedUnit.references[i].containingReference < i.
+ */
+ containingReference:uint (id: 5);
+
+ /**
+ * Index into [LinkedLibrary.dependencies] indicating which imported library
+ * declares the entity being referred to.
+ *
+ * Zero if this entity is contained within another entity (e.g. a class
+ * member), or if [kind] is [ReferenceKind.prefix].
+ */
+ dependency:uint (id: 1);
+
+ /**
+ * The kind of the entity being referred to. For the pseudo-types `dynamic`
+ * and `void`, the kind is [ReferenceKind.classOrEnum].
+ */
+ kind:ReferenceKind (id: 2);
+
+ /**
+ * If [kind] is [ReferenceKind.function] (that is, the entity being referred
+ * to is a local function), the index of the function within
+ * [UnlinkedExecutable.localFunctions]. If [kind] is
+ * [ReferenceKind.variable], the index of the variable within
+ * [UnlinkedExecutable.localVariables]. Otherwise zero.
+ */
+ localIndex:uint (id: 6);
+
+ /**
+ * If this [LinkedReference] doesn't have an associated [UnlinkedReference],
+ * name of the entity being referred to. For the pseudo-type `dynamic`, the
+ * string is "dynamic". For the pseudo-type `void`, the string is "void".
+ */
+ name:string (id: 3);
+
+ /**
+ * If the entity being referred to is generic, the number of type parameters
+ * it declares (does not include type parameters of enclosing entities).
+ * Otherwise zero.
+ */
+ numTypeParameters:uint (id: 4);
+
+ /**
+ * Integer index indicating which unit in the imported library contains the
+ * definition of the entity. As with indices into [LinkedLibrary.units],
+ * zero represents the defining compilation unit, and nonzero values
+ * represent parts in the order of the corresponding `part` declarations.
+ *
+ * Zero if this entity is contained within another entity (e.g. a class
+ * member).
+ */
+ unit:uint (id: 0);
+}
+
+/**
+ * Linked summary of a compilation unit.
+ */
+table LinkedUnit {
+ /**
+ * Information about the resolution of references within the compilation
+ * unit. Each element of [UnlinkedUnit.references] has a corresponding
+ * element in this list (at the same index). If this list has additional
+ * elements beyond the number of elements in [UnlinkedUnit.references], those
+ * additional elements are references that are only referred to implicitly
+ * (e.g. elements involved in inferred or propagated types).
+ */
+ references:[LinkedReference] (id: 0);
+
+ /**
+ * List associating slot ids found inside the unlinked summary for the
+ * compilation unit with propagated and inferred types.
+ */
+ types:[EntityRef] (id: 1);
+}
+
+/**
+ * Summary information about a package.
+ */
+table PackageBundle {
+ /**
+ * Linked libraries.
+ */
+ linkedLibraries:[LinkedLibrary] (id: 0);
+
+ /**
+ * The list of URIs of items in [linkedLibraries], e.g. `dart:core` or
+ * `package:foo/bar.dart`.
+ */
+ linkedLibraryUris:[string] (id: 1);
+
+ /**
+ * Major version of the summary format. See
+ * [PackageBundleAssembler.currentMajorVersion].
+ */
+ majorVersion:uint (id: 5);
+
+ /**
+ * Minor version of the summary format. See
+ * [PackageBundleAssembler.currentMinorVersion].
+ */
+ minorVersion:uint (id: 6);
+
+ /**
+ * List of MD5 hashes of the files listed in [unlinkedUnitUris]. Each hash
+ * is encoded as a hexadecimal string using lower case letters.
+ */
+ unlinkedUnitHashes:[string] (id: 4);
+
+ /**
+ * Unlinked information for the compilation units constituting the package.
+ */
+ unlinkedUnits:[UnlinkedUnit] (id: 2);
+
+ /**
+ * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
+ */
+ unlinkedUnitUris:[string] (id: 3);
+}
+
+/**
+ * Index information about a package.
+ */
+table PackageIndex {
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the kind of the synthetic element.
+ */
+ elementKinds:[IndexSyntheticElementKind] (id: 5);
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the offset of the element name relative to the beginning of the file. The
+ * list is sorted in ascending order, so that the client can quickly check
+ * whether an element is referenced in this [PackageIndex].
+ */
+ elementOffsets:[uint] (id: 1);
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the index into [unitLibraryUris] and [unitUnitUris] for the library
+ * specific unit where the element is declared.
+ */
+ elementUnits:[uint] (id: 0);
+
+ /**
+ * List of unique element strings used in this [PackageIndex].
+ */
+ strings:[string] (id: 6);
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique library
+ * specific unit referenced in the [PackageIndex]. It is an index into
+ * [strings] list.
+ */
+ unitLibraryUris:[uint] (id: 2);
+
+ /**
+ * List of indexes of each unit in this [PackageIndex].
+ */
+ units:[UnitIndex] (id: 4);
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique library
+ * specific unit referenced in the [PackageIndex]. It is an index into
+ * [strings] list.
+ */
+ unitUnitUris:[uint] (id: 3);
+}
+
+/**
+ * Index information about a unit in a [PackageIndex].
+ */
+table UnitIndex {
+ /**
+ * Each item of this list is the kind of an element defined in this unit.
+ */
+ definedNameKinds:[IndexNameKind] (id: 6);
+
+ /**
+ * Each item of this list is the name offset of an element defined in this
+ * unit relative to the beginning of the file.
+ */
+ definedNameOffsets:[uint] (id: 7);
+
+ /**
+ * Each item of this list corresponds to an element defined in this unit. It
+ * is an index into [PackageIndex.strings] list. The list is sorted in
+ * ascending order, so that the client can quickly find name definitions in
+ * this [UnitIndex].
+ */
+ definedNames:[uint] (id: 5);
+
+ /**
+ * Index into [PackageIndex.unitLibraryUris] and [PackageIndex.unitUnitUris]
+ * for the library specific unit that corresponds to this [UnitIndex].
+ */
+ unit:uint (id: 0);
+
+ /**
+ * Each item of this list is the `true` if the corresponding element usage
+ * is qualified with some prefix.
+ */
+ usedElementIsQualifiedFlags:[ubyte] (id: 11);
+
+ /**
+ * Each item of this list is the kind of the element usage.
+ */
+ usedElementKinds:[IndexRelationKind] (id: 4);
+
+ /**
+ * Each item of this list is the length of the element usage.
+ */
+ usedElementLengths:[uint] (id: 1);
+
+ /**
+ * Each item of this list is the offset of the element usage relative to the
+ * beginning of the file.
+ */
+ usedElementOffsets:[uint] (id: 2);
+
+ /**
+ * Each item of this list is the index into [PackageIndex.elementUnits] and
+ * [PackageIndex.elementOffsets]. The list is sorted in ascending order, so
+ * that the client can quickly find element references in this [UnitIndex].
+ */
+ usedElements:[uint] (id: 3);
+
+ /**
+ * Each item of this list is the kind of the name usage.
+ */
+ usedNameKinds:[IndexRelationKind] (id: 10);
+
+ /**
+ * Each item of this list is the offset of the name usage relative to the
+ * beginning of the file.
+ */
+ usedNameOffsets:[uint] (id: 9);
+
+ /**
+ * Each item of this list is the index into [PackageIndex.strings] for a
+ * used name. The list is sorted in ascending order, so that the client can
+ * quickly find name uses in this [UnitIndex].
+ */
+ usedNames:[uint] (id: 8);
+}
+
+/**
+ * Unlinked summary information about a class declaration.
+ */
+table UnlinkedClass {
+ /**
+ * Annotations for this class.
+ */
+ annotations:[UnlinkedConst] (id: 5);
+
+ /**
+ * Documentation comment for the class, or `null` if there is no
+ * documentation comment.
+ */
+ documentationComment:UnlinkedDocumentationComment (id: 6);
+
+ /**
+ * Executable objects (methods, getters, and setters) contained in the class.
+ */
+ executables:[UnlinkedExecutable] (id: 2);
+
+ /**
+ * Field declarations contained in the class.
+ */
+ fields:[UnlinkedVariable] (id: 4);
+
+ /**
+ * Indicates whether this class is the core "Object" class (and hence has no
+ * supertype)
+ */
+ hasNoSupertype:bool (id: 12);
+
+ /**
+ * Interfaces appearing in an `implements` clause, if any.
+ */
+ interfaces:[EntityRef] (id: 7);
+
+ /**
+ * Indicates whether the class is declared with the `abstract` keyword.
+ */
+ isAbstract:bool (id: 8);
+
+ /**
+ * Indicates whether the class is declared using mixin application syntax.
+ */
+ isMixinApplication:bool (id: 11);
+
+ /**
+ * Mixins appearing in a `with` clause, if any.
+ */
+ mixins:[EntityRef] (id: 10);
+
+ /**
+ * Name of the class.
+ */
+ name:string (id: 0);
+
+ /**
+ * Offset of the class name relative to the beginning of the file.
+ */
+ nameOffset:uint (id: 1);
+
+ /**
+ * Supertype of the class, or `null` if either (a) the class doesn't
+ * explicitly declare a supertype (and hence has supertype `Object`), or (b)
+ * the class *is* `Object` (and hence has no supertype).
+ */
+ supertype:EntityRef (id: 3);
+
+ /**
+ * Type parameters of the class, if any.
+ */
+ typeParameters:[UnlinkedTypeParam] (id: 9);
+}
+
+/**
+ * Unlinked summary information about a `show` or `hide` combinator in an
+ * import or export declaration.
+ */
+table UnlinkedCombinator {
+ /**
+ * If this is a `show` combinator, offset of the end of the list of shown
+ * names. Otherwise zero.
+ */
+ end:uint (id: 3);
+
+ /**
+ * List of names which are hidden. Empty if this is a `show` combinator.
+ */
+ hides:[string] (id: 1);
+
+ /**
+ * If this is a `show` combinator, offset of the `show` keyword. Otherwise
+ * zero.
+ */
+ offset:uint (id: 2);
+
+ /**
+ * List of names which are shown. Empty if this is a `hide` combinator.
+ */
+ shows:[string] (id: 0);
+}
+
+/**
+ * Unlinked summary information about a compile-time constant expression, or a
+ * potentially constant expression.
+ *
+ * Constant expressions are represented using a simple stack-based language
+ * where [operations] is a sequence of operations to execute starting with an
+ * empty stack. Once all operations have been executed, the stack should
+ * contain a single value which is the value of the constant. Note that some
+ * operations consume additional data from the other fields of this class.
+ */
+table UnlinkedConst {
+ /**
+ * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+ */
+ doubles:[double] (id: 4);
+
+ /**
+ * Sequence of unsigned 32-bit integers consumed by the operations
+ * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+ * `makeList`, and `makeMap`.
+ */
+ ints:[uint] (id: 1);
+
+ /**
+ * Indicates whether the expression is not a valid potentially constant
+ * expression.
+ */
+ isInvalid:bool (id: 5);
+
+ /**
+ * Sequence of operations to execute (starting with an empty stack) to form
+ * the constant value.
+ */
+ operations:[UnlinkedConstOperation] (id: 0);
+
+ /**
+ * Sequence of language constructs consumed by the operations
+ * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`. Note
+ * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+ * actual entity being referred to may be something other than a type.
+ */
+ references:[EntityRef] (id: 2);
+
+ /**
+ * Sequence of strings consumed by the operations `pushString` and
+ * `invokeConstructor`.
+ */
+ strings:[string] (id: 3);
+}
+
+/**
+ * Unlinked summary information about a constructor initializer.
+ */
+table UnlinkedConstructorInitializer {
+ /**
+ * If [kind] is `thisInvocation` or `superInvocation`, the arguments of the
+ * invocation. Otherwise empty.
+ */
+ arguments:[UnlinkedConst] (id: 3);
+
+ /**
+ * If [kind] is `field`, the expression of the field initializer.
+ * Otherwise `null`.
+ */
+ expression:UnlinkedConst (id: 1);
+
+ /**
+ * The kind of the constructor initializer (field, redirect, super).
+ */
+ kind:UnlinkedConstructorInitializerKind (id: 2);
+
+ /**
+ * If [kind] is `field`, the name of the field declared in the class. If
+ * [kind] is `thisInvocation`, the name of the constructor, declared in this
+ * class, to redirect to. If [kind] is `superInvocation`, the name of the
+ * constructor, declared in the superclass, to invoke.
+ */
+ name:string (id: 0);
+}
+
+/**
+ * Unlinked summary information about a documentation comment.
+ */
+table UnlinkedDocumentationComment {
+ /**
+ * Length of the documentation comment (prior to replacing '\r\n' with '\n').
+ */
+ length:uint (id: 0);
+
+ /**
+ * Offset of the beginning of the documentation comment relative to the
+ * beginning of the file.
+ */
+ offset:uint (id: 2);
+
+ /**
+ * Text of the documentation comment, with '\r\n' replaced by '\n'.
+ *
+ * References appearing within the doc comment in square brackets are not
+ * specially encoded.
+ */
+ text:string (id: 1);
+}
+
+/**
+ * Unlinked summary information about an enum declaration.
+ */
+table UnlinkedEnum {
+ /**
+ * Annotations for this enum.
+ */
+ annotations:[UnlinkedConst] (id: 4);
+
+ /**
+ * Documentation comment for the enum, or `null` if there is no documentation
+ * comment.
+ */
+ documentationComment:UnlinkedDocumentationComment (id: 3);
+
+ /**
+ * Name of the enum type.
+ */
+ name:string (id: 0);
+
+ /**
+ * Offset of the enum name relative to the beginning of the file.
+ */
+ nameOffset:uint (id: 1);
+
+ /**
+ * Values listed in the enum declaration, in declaration order.
+ */
+ values:[UnlinkedEnumValue] (id: 2);
+}
+
+/**
+ * Unlinked summary information about a single enumerated value in an enum
+ * declaration.
+ */
+table UnlinkedEnumValue {
+ /**
+ * Documentation comment for the enum value, or `null` if there is no
+ * documentation comment.
+ */
+ documentationComment:UnlinkedDocumentationComment (id: 2);
+
+ /**
+ * Name of the enumerated value.
+ */
+ name:string (id: 0);
+
+ /**
+ * Offset of the enum value name relative to the beginning of the file.
+ */
+ nameOffset:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a function, method, getter, or setter
+ * declaration.
+ */
+table UnlinkedExecutable {
+ /**
+ * Annotations for this executable.
+ */
+ annotations:[UnlinkedConst] (id: 6);
+
+ /**
+ * If a constant [UnlinkedExecutableKind.constructor], the constructor
+ * initializers. Otherwise empty.
+ */
+ constantInitializers:[UnlinkedConstructorInitializer] (id: 14);
+
+ /**
+ * Documentation comment for the executable, or `null` if there is no
+ * documentation comment.
+ */
+ documentationComment:UnlinkedDocumentationComment (id: 7);
+
+ /**
+ * If this executable's return type is inferable, nonzero slot id
+ * identifying which entry in [LinkedUnit.types] contains the inferred
+ * return type. If there is no matching entry in [LinkedUnit.types], then
+ * no return type was inferred for this variable, so its static type is
+ * `dynamic`.
+ */
+ inferredReturnTypeSlot:uint (id: 5);
+
+ /**
+ * Indicates whether the executable is declared using the `abstract` keyword.
+ */
+ isAbstract:bool (id: 10);
+
+ /**
+ * Indicates whether the executable is declared using the `const` keyword.
+ */
+ isConst:bool (id: 12);
+
+ /**
+ * Indicates whether the executable is declared using the `external` keyword.
+ */
+ isExternal:bool (id: 11);
+
+ /**
+ * Indicates whether the executable is declared using the `factory` keyword.
+ */
+ isFactory:bool (id: 8);
+
+ /**
+ * Indicates whether the executable is a redirected constructor.
+ */
+ isRedirectedConstructor:bool (id: 13);
+
+ /**
+ * Indicates whether the executable is declared using the `static` keyword.
+ *
+ * Note that for top level executables, this flag is false, since they are
+ * not declared using the `static` keyword (even though they are considered
+ * static for semantic purposes).
+ */
+ isStatic:bool (id: 9);
+
+ /**
+ * The kind of the executable (function/method, getter, setter, or
+ * constructor).
+ */
+ kind:UnlinkedExecutableKind (id: 4);
+
+ /**
+ * The list of local functions.
+ */
+ localFunctions:[UnlinkedExecutable] (id: 18);
+
+ /**
+ * The list of local labels.
+ */
+ localLabels:[UnlinkedLabel] (id: 22);
+
+ /**
+ * The list of local variables.
+ */
+ localVariables:[UnlinkedVariable] (id: 19);
+
+ /**
+ * Name of the executable. For setters, this includes the trailing "=". For
+ * named constructors, this excludes the class name and excludes the ".".
+ * For unnamed constructors, this is the empty string.
+ */
+ name:string (id: 1);
+
+ /**
+ * If [kind] is [UnlinkedExecutableKind.constructor] and [name] is not empty,
+ * the offset of the end of the constructor name. Otherwise zero.
+ */
+ nameEnd:uint (id: 23);
+
+ /**
+ * Offset of the executable name relative to the beginning of the file. For
+ * named constructors, this excludes the class name and excludes the ".".
+ * For unnamed constructors, this is the offset of the class name (i.e. the
+ * offset of the second "C" in "class C { C(); }").
+ */
+ nameOffset:uint (id: 0);
+
+ /**
+ * Parameters of the executable, if any. Note that getters have no
+ * parameters (hence this will be the empty list), and setters have a single
+ * parameter.
+ */
+ parameters:[UnlinkedParam] (id: 2);
+
+ /**
+ * If [kind] is [UnlinkedExecutableKind.constructor] and [name] is not empty,
+ * the offset of the period before the constructor name. Otherwise zero.
+ */
+ periodOffset:uint (id: 24);
+
+ /**
+ * If [isRedirectedConstructor] and [isFactory] are both `true`, the
+ * constructor to which this constructor redirects; otherwise empty.
+ */
+ redirectedConstructor:EntityRef (id: 15);
+
+ /**
+ * If [isRedirectedConstructor] is `true` and [isFactory] is `false`, the
+ * name of the constructor that this constructor redirects to; otherwise
+ * empty.
+ */
+ redirectedConstructorName:string (id: 17);
+
+ /**
+ * Declared return type of the executable. Absent if the executable is a
+ * constructor or the return type is implicit. Absent for executables
+ * associated with variable initializers and closures, since these
+ * executables may have return types that are not accessible via direct
+ * imports.
+ */
+ returnType:EntityRef (id: 3);
+
+ /**
+ * Type parameters of the executable, if any. Empty if support for generic
+ * method syntax is disabled.
+ */
+ typeParameters:[UnlinkedTypeParam] (id: 16);
+
+ /**
+ * If a local function, the length of the visible range; zero otherwise.
+ */
+ visibleLength:uint (id: 20);
+
+ /**
+ * If a local function, the beginning of the visible range; zero otherwise.
+ */
+ visibleOffset:uint (id: 21);
+}
+
+/**
+ * Unlinked summary information about an export declaration (stored outside
+ * [UnlinkedPublicNamespace]).
+ */
+table UnlinkedExportNonPublic {
+ /**
+ * Annotations for this export directive.
+ */
+ annotations:[UnlinkedConst] (id: 3);
+
+ /**
+ * Offset of the "export" keyword.
+ */
+ offset:uint (id: 0);
+
+ /**
+ * End of the URI string (including quotes) relative to the beginning of the
+ * file.
+ */
+ uriEnd:uint (id: 1);
+
+ /**
+ * Offset of the URI string (including quotes) relative to the beginning of
+ * the file.
+ */
+ uriOffset:uint (id: 2);
+}
+
+/**
+ * Unlinked summary information about an export declaration (stored inside
+ * [UnlinkedPublicNamespace]).
+ */
+table UnlinkedExportPublic {
+ /**
+ * Combinators contained in this import declaration.
+ */
+ combinators:[UnlinkedCombinator] (id: 1);
+
+ /**
+ * URI used in the source code to reference the exported library.
+ */
+ uri:string (id: 0);
+}
+
+/**
+ * Unlinked summary information about an import declaration.
+ */
+table UnlinkedImport {
+ /**
+ * Annotations for this import declaration.
+ */
+ annotations:[UnlinkedConst] (id: 8);
+
+ /**
+ * Combinators contained in this import declaration.
+ */
+ combinators:[UnlinkedCombinator] (id: 4);
+
+ /**
+ * Indicates whether the import declaration uses the `deferred` keyword.
+ */
+ isDeferred:bool (id: 9);
+
+ /**
+ * Indicates whether the import declaration is implicit.
+ */
+ isImplicit:bool (id: 5);
+
+ /**
+ * If [isImplicit] is false, offset of the "import" keyword. If [isImplicit]
+ * is true, zero.
+ */
+ offset:uint (id: 0);
+
+ /**
+ * Offset of the prefix name relative to the beginning of the file, or zero
+ * if there is no prefix.
+ */
+ prefixOffset:uint (id: 6);
+
+ /**
+ * Index into [UnlinkedUnit.references] of the prefix declared by this
+ * import declaration, or zero if this import declaration declares no prefix.
+ *
+ * Note that multiple imports can declare the same prefix.
+ */
+ prefixReference:uint (id: 7);
+
+ /**
+ * URI used in the source code to reference the imported library.
+ */
+ uri:string (id: 1);
+
+ /**
+ * End of the URI string (including quotes) relative to the beginning of the
+ * file. If [isImplicit] is true, zero.
+ */
+ uriEnd:uint (id: 2);
+
+ /**
+ * Offset of the URI string (including quotes) relative to the beginning of
+ * the file. If [isImplicit] is true, zero.
+ */
+ uriOffset:uint (id: 3);
+}
+
+/**
+ * Unlinked summary information about a label.
+ */
+table UnlinkedLabel {
+ /**
+ * Return `true` if this label is associated with a `switch` member (`case` or
+ * `default`).
+ */
+ isOnSwitchMember:bool (id: 2);
+
+ /**
+ * Return `true` if this label is associated with a `switch` statement.
+ */
+ isOnSwitchStatement:bool (id: 3);
+
+ /**
+ * Name of the label.
+ */
+ name:string (id: 0);
+
+ /**
+ * Offset of the label relative to the beginning of the file.
+ */
+ nameOffset:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a function parameter.
+ */
+table UnlinkedParam {
+ /**
+ * Annotations for this parameter.
+ */
+ annotations:[UnlinkedConst] (id: 9);
+
+ /**
+ * If the parameter has a default value, the constant expression in the
+ * default value. Note that the presence of this expression does not mean
+ * that it is a valid, check [UnlinkedConst.isInvalid].
+ */
+ defaultValue:UnlinkedConst (id: 7);
+
+ /**
+ * If the parameter has a default value, the source text of the constant
+ * expression in the default value. Otherwise the empty string.
+ */
+ defaultValueCode:string (id: 13);
+
+ /**
+ * If this parameter's type is inferable, nonzero slot id identifying which
+ * entry in [LinkedLibrary.types] contains the inferred type. If there is no
+ * matching entry in [LinkedLibrary.types], then no type was inferred for
+ * this variable, so its static type is `dynamic`.
+ *
+ * Note that although strong mode considers initializing formals to be
+ * inferable, they are not marked as such in the summary; if their type is
+ * not specified, they always inherit the static type of the corresponding
+ * field.
+ */
+ inferredTypeSlot:uint (id: 2);
+
+ /**
+ * The synthetic initializer function of the parameter. Absent if the variable
+ * does not have an initializer.
+ */
+ initializer:UnlinkedExecutable (id: 12);
+
+ /**
+ * Indicates whether this is a function-typed parameter.
+ */
+ isFunctionTyped:bool (id: 5);
+
+ /**
+ * Indicates whether this is an initializing formal parameter (i.e. it is
+ * declared using `this.` syntax).
+ */
+ isInitializingFormal:bool (id: 6);
+
+ /**
+ * Kind of the parameter.
+ */
+ kind:UnlinkedParamKind (id: 4);
+
+ /**
+ * Name of the parameter.
+ */
+ name:string (id: 0);
+
+ /**
+ * Offset of the parameter name relative to the beginning of the file.
+ */
+ nameOffset:uint (id: 1);
+
+ /**
+ * If [isFunctionTyped] is `true`, the parameters of the function type.
+ */
+ parameters:[UnlinkedParam] (id: 8);
+
+ /**
+ * If [isFunctionTyped] is `true`, the declared return type. If
+ * [isFunctionTyped] is `false`, the declared type. Absent if the type is
+ * implicit.
+ */
+ type:EntityRef (id: 3);
+
+ /**
+ * The length of the visible range.
+ */
+ visibleLength:uint (id: 10);
+
+ /**
+ * The beginning of the visible range.
+ */
+ visibleOffset:uint (id: 11);
+}
+
+/**
+ * Unlinked summary information about a part declaration.
+ */
+table UnlinkedPart {
+ /**
+ * Annotations for this part declaration.
+ */
+ annotations:[UnlinkedConst] (id: 2);
+
+ /**
+ * End of the URI string (including quotes) relative to the beginning of the
+ * file.
+ */
+ uriEnd:uint (id: 0);
+
+ /**
+ * Offset of the URI string (including quotes) relative to the beginning of
+ * the file.
+ */
+ uriOffset:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a specific name contributed by a
+ * compilation unit to a library's public namespace.
+ *
+ * TODO(paulberry): some of this information is redundant with information
+ * elsewhere in the summary. Consider reducing the redundancy to reduce
+ * summary size.
+ */
+table UnlinkedPublicName {
+ /**
+ * The kind of object referred to by the name.
+ */
+ kind:ReferenceKind (id: 1);
+
+ /**
+ * If this [UnlinkedPublicName] is a class, the list of members which can be
+ * referenced from constants or factory redirects - static constant fields,
+ * static methods, and constructors. Otherwise empty.
+ *
+ * Unnamed constructors are not included since they do not constitute a
+ * separate name added to any namespace.
+ */
+ members:[UnlinkedPublicName] (id: 2);
+
+ /**
+ * The name itself.
+ */
+ name:string (id: 0);
+
+ /**
+ * If the entity being referred to is generic, the number of type parameters
+ * it accepts. Otherwise zero.
+ */
+ numTypeParameters:uint (id: 3);
+}
+
+/**
+ * Unlinked summary information about what a compilation unit contributes to a
+ * library's public namespace. This is the subset of [UnlinkedUnit] that is
+ * required from dependent libraries in order to perform prelinking.
+ */
+table UnlinkedPublicNamespace {
+ /**
+ * Export declarations in the compilation unit.
+ */
+ exports:[UnlinkedExportPublic] (id: 2);
+
+ /**
+ * Public names defined in the compilation unit.
+ *
+ * TODO(paulberry): consider sorting these names to reduce unnecessary
+ * relinking.
+ */
+ names:[UnlinkedPublicName] (id: 0);
+
+ /**
+ * URIs referenced by part declarations in the compilation unit.
+ */
+ parts:[string] (id: 1);
+}
+
+/**
+ * Unlinked summary information about a name referred to in one library that
+ * might be defined in another.
+ */
+table UnlinkedReference {
+ /**
+ * Name of the entity being referred to. For the pseudo-type `dynamic`, the
+ * string is "dynamic". For the pseudo-type `void`, the string is "void".
+ * For the pseudo-type `bottom`, the string is "*bottom*".
+ */
+ name:string (id: 0);
+
+ /**
+ * Prefix used to refer to the entity, or zero if no prefix is used. This is
+ * an index into [UnlinkedUnit.references].
+ *
+ * Prefix references must always point backward; that is, for all i, if
+ * UnlinkedUnit.references[i].prefixReference != 0, then
+ * UnlinkedUnit.references[i].prefixReference < i.
+ */
+ prefixReference:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a typedef declaration.
+ */
+table UnlinkedTypedef {
+ /**
+ * Annotations for this typedef.
+ */
+ annotations:[UnlinkedConst] (id: 4);
+
+ /**
+ * Documentation comment for the typedef, or `null` if there is no
+ * documentation comment.
+ */
+ documentationComment:UnlinkedDocumentationComment (id: 6);
+
+ /**
+ * Name of the typedef.
+ */
+ name:string (id: 0);
+
+ /**
+ * Offset of the typedef name relative to the beginning of the file.
+ */
+ nameOffset:uint (id: 1);
+
+ /**
+ * Parameters of the executable, if any.
+ */
+ parameters:[UnlinkedParam] (id: 3);
+
+ /**
+ * Return type of the typedef.
+ */
+ returnType:EntityRef (id: 2);
+
+ /**
+ * Type parameters of the typedef, if any.
+ */
+ typeParameters:[UnlinkedTypeParam] (id: 5);
+}
+
+/**
+ * Unlinked summary information about a type parameter declaration.
+ */
+table UnlinkedTypeParam {
+ /**
+ * Annotations for this type parameter.
+ */
+ annotations:[UnlinkedConst] (id: 3);
+
+ /**
+ * Bound of the type parameter, if a bound is explicitly declared. Otherwise
+ * null.
+ */
+ bound:EntityRef (id: 2);
+
+ /**
+ * Name of the type parameter.
+ */
+ name:string (id: 0);
+
+ /**
+ * Offset of the type parameter name relative to the beginning of the file.
+ */
+ nameOffset:uint (id: 1);
+}
+
+/**
+ * Unlinked summary information about a compilation unit ("part file").
+ */
+table UnlinkedUnit {
+ /**
+ * Classes declared in the compilation unit.
+ */
+ classes:[UnlinkedClass] (id: 2);
+
+ /**
+ * Enums declared in the compilation unit.
+ */
+ enums:[UnlinkedEnum] (id: 12);
+
+ /**
+ * Top level executable objects (functions, getters, and setters) declared in
+ * the compilation unit.
+ */
+ executables:[UnlinkedExecutable] (id: 4);
+
+ /**
+ * Export declarations in the compilation unit.
+ */
+ exports:[UnlinkedExportNonPublic] (id: 13);
+
+ /**
+ * Import declarations in the compilation unit.
+ */
+ imports:[UnlinkedImport] (id: 5);
+
+ /**
+ * Annotations for the library declaration, or the empty list if there is no
+ * library declaration.
+ */
+ libraryAnnotations:[UnlinkedConst] (id: 14);
+
+ /**
+ * Documentation comment for the library, or `null` if there is no
+ * documentation comment.
+ */
+ libraryDocumentationComment:UnlinkedDocumentationComment (id: 9);
+
+ /**
+ * Name of the library (from a "library" declaration, if present).
+ */
+ libraryName:string (id: 6);
+
+ /**
+ * Length of the library name as it appears in the source code (or 0 if the
+ * library has no name).
+ */
+ libraryNameLength:uint (id: 7);
+
+ /**
+ * Offset of the library name relative to the beginning of the file (or 0 if
+ * the library has no name).
+ */
+ libraryNameOffset:uint (id: 8);
+
+ /**
+ * Part declarations in the compilation unit.
+ */
+ parts:[UnlinkedPart] (id: 11);
+
+ /**
+ * Unlinked public namespace of this compilation unit.
+ */
+ publicNamespace:UnlinkedPublicNamespace (id: 0);
+
+ /**
+ * Top level and prefixed names referred to by this compilation unit. The
+ * zeroth element of this array is always populated and is used to represent
+ * the absence of a reference in places where a reference is optional (for
+ * example [UnlinkedReference.prefixReference or
+ * UnlinkedImport.prefixReference]).
+ */
+ references:[UnlinkedReference] (id: 1);
+
+ /**
+ * Typedefs declared in the compilation unit.
+ */
+ typedefs:[UnlinkedTypedef] (id: 10);
+
+ /**
+ * Top level variables declared in the compilation unit.
+ */
+ variables:[UnlinkedVariable] (id: 3);
+}
+
+/**
+ * Unlinked summary information about a top level variable, local variable, or
+ * a field.
+ */
+table UnlinkedVariable {
+ /**
+ * Annotations for this variable.
+ */
+ annotations:[UnlinkedConst] (id: 8);
+
+ /**
+ * If [isConst] is true, and the variable has an initializer, the constant
+ * expression in the initializer. Note that the presence of this expression
+ * does not mean that it is a valid, check [UnlinkedConst.isInvalid].
+ */
+ constExpr:UnlinkedConst (id: 5);
+
+ /**
+ * Documentation comment for the variable, or `null` if there is no
+ * documentation comment.
+ */
+ documentationComment:UnlinkedDocumentationComment (id: 10);
+
+ /**
+ * If this variable is inferable, nonzero slot id identifying which entry in
+ * [LinkedLibrary.types] contains the inferred type for this variable. If
+ * there is no matching entry in [LinkedLibrary.types], then no type was
+ * inferred for this variable, so its static type is `dynamic`.
+ */
+ inferredTypeSlot:uint (id: 9);
+
+ /**
+ * The synthetic initializer function of the variable. Absent if the variable
+ * does not have an initializer.
+ */
+ initializer:UnlinkedExecutable (id: 13);
+
+ /**
+ * Indicates whether the variable is declared using the `const` keyword.
+ */
+ isConst:bool (id: 6);
+
+ /**
+ * Indicates whether the variable is declared using the `final` keyword.
+ */
+ isFinal:bool (id: 7);
+
+ /**
+ * Indicates whether the variable is declared using the `static` keyword.
+ *
+ * Note that for top level variables, this flag is false, since they are not
+ * declared using the `static` keyword (even though they are considered
+ * static for semantic purposes).
+ */
+ isStatic:bool (id: 4);
+
+ /**
+ * Name of the variable.
+ */
+ name:string (id: 0);
+
+ /**
+ * Offset of the variable name relative to the beginning of the file.
+ */
+ nameOffset:uint (id: 1);
+
+ /**
+ * If this variable is propagable, nonzero slot id identifying which entry in
+ * [LinkedLibrary.types] contains the propagated type for this variable. If
+ * there is no matching entry in [LinkedLibrary.types], then this variable's
+ * propagated type is the same as its declared type.
+ *
+ * Non-propagable variables have a [propagatedTypeSlot] of zero.
+ */
+ propagatedTypeSlot:uint (id: 2);
+
+ /**
+ * Declared type of the variable. Absent if the type is implicit.
+ */
+ type:EntityRef (id: 3);
+
+ /**
+ * If a local variable, the length of the visible range; zero otherwise.
+ */
+ visibleLength:uint (id: 11);
+
+ /**
+ * If a local variable, the beginning of the visible range; zero otherwise.
+ */
+ visibleOffset:uint (id: 12);
+}
+
+root_type PackageBundle;
+
+file_identifier "PBdl";
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 9d840b9..21473a2 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -42,7 +42,7 @@
library analyzer.tool.summary.idl;
import 'base.dart' as base;
-import 'base.dart' show Id;
+import 'base.dart' show Id, TopLevel;
import 'format.dart' as generated;
/**
@@ -53,12 +53,6 @@
const informative = null;
/**
- * Annotation describing a class which can be the top level object in an
- * encoded summary.
- */
-const topLevel = null;
-
-/**
* Summary information about a reference to a an entity such as a type, top
* level executable, or executable within a class.
*/
@@ -128,6 +122,24 @@
int get slot;
/**
+ * If this [EntityRef] is a reference to a function type whose
+ * [FunctionElement] is not in any library (e.g. a function type that was
+ * synthesized by a LUB computation), the function parameters. Otherwise
+ * empty.
+ */
+ @Id(6)
+ List<UnlinkedParam> get syntheticParams;
+
+ /**
+ * If this [EntityRef] is a reference to a function type whose
+ * [FunctionElement] is not in any library (e.g. a function type that was
+ * synthesized by a LUB computation), the return type of the function.
+ * Otherwise `null`.
+ */
+ @Id(5)
+ EntityRef get syntheticReturnType;
+
+ /**
* If this is an instantiation of a generic type or generic executable, the
* type arguments used to instantiate it. Trailing type arguments of type
* `dynamic` are omitted.
@@ -137,6 +149,88 @@
}
/**
+ * Enum used to indicate the kind of a name in index.
+ */
+enum IndexNameKind {
+ /**
+ * A top-level element.
+ */
+ topLevel,
+
+ /**
+ * A class member.
+ */
+ classMember
+}
+
+/**
+ * Enum used to indicate the kind of an index relation.
+ */
+enum IndexRelationKind {
+ /**
+ * Left: class.
+ * Is extended by.
+ * Right: other class declaration.
+ */
+ IS_EXTENDED_BY,
+
+ /**
+ * Left: class.
+ * Is implemented by.
+ * Right: other class declaration.
+ */
+ IS_IMPLEMENTED_BY,
+
+ /**
+ * Left: class.
+ * Is mixed into.
+ * Right: other class declaration.
+ */
+ IS_MIXED_IN_BY,
+
+ /**
+ * Left: method, property accessor, function, variable.
+ * Is invoked at.
+ * Right: location.
+ */
+ IS_INVOKED_BY,
+
+ /**
+ * Left: any element.
+ * Is referenced (and not invoked, read/written) at.
+ * Right: location.
+ */
+ IS_REFERENCED_BY
+}
+
+/**
+ * When we need to reference a synthetic element in [PackageIndex] we use a
+ * value of this enum to specify which kind of the synthetic element we
+ * actually reference.
+ */
+enum IndexSyntheticElementKind {
+ /**
+ * Not a synthetic element.
+ */
+ notSynthetic,
+
+ /**
+ * The unnamed synthetic constructor a class element.
+ */
+ constructor,
+
+ /**
+ * The synthetic getter of a property introducing element.
+ */
+ getter,
+
+ /**
+ * The synthetic setter of a property introducing element.
+ */
+ setter
+}
+
+/**
* Information about a dependency that exists between one library and another
* due to an "import" declaration.
*/
@@ -197,7 +291,7 @@
/**
* Linked summary of a library.
*/
-@topLevel
+@TopLevel('LLib')
abstract class LinkedLibrary extends base.SummaryClass {
factory LinkedLibrary.fromBuffer(List<int> buffer) =>
generated.readLinkedLibrary(buffer);
@@ -356,7 +450,7 @@
/**
* Summary information about a package.
*/
-@topLevel
+@TopLevel('PBdl')
abstract class PackageBundle extends base.SummaryClass {
factory PackageBundle.fromBuffer(List<int> buffer) =>
generated.readPackageBundle(buffer);
@@ -375,6 +469,20 @@
List<String> get linkedLibraryUris;
/**
+ * Major version of the summary format. See
+ * [PackageBundleAssembler.currentMajorVersion].
+ */
+ @Id(5)
+ int get majorVersion;
+
+ /**
+ * Minor version of the summary format. See
+ * [PackageBundleAssembler.currentMinorVersion].
+ */
+ @Id(6)
+ int get minorVersion;
+
+ /**
* List of MD5 hashes of the files listed in [unlinkedUnitUris]. Each hash
* is encoded as a hexadecimal string using lower case letters.
*/
@@ -395,6 +503,67 @@
}
/**
+ * Index information about a package.
+ */
+@TopLevel('Indx')
+abstract class PackageIndex extends base.SummaryClass {
+ factory PackageIndex.fromBuffer(List<int> buffer) =>
+ generated.readPackageIndex(buffer);
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the kind of the synthetic element.
+ */
+ @Id(5)
+ List<IndexSyntheticElementKind> get elementKinds;
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the offset of the element name relative to the beginning of the file. The
+ * list is sorted in ascending order, so that the client can quickly check
+ * whether an element is referenced in this [PackageIndex].
+ */
+ @Id(1)
+ List<int> get elementOffsets;
+
+ /**
+ * Each item of this list corresponds to a unique referenced element. It is
+ * the index into [unitLibraryUris] and [unitUnitUris] for the library
+ * specific unit where the element is declared.
+ */
+ @Id(0)
+ List<int> get elementUnits;
+
+ /**
+ * List of unique element strings used in this [PackageIndex].
+ */
+ @Id(6)
+ List<String> get strings;
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique library
+ * specific unit referenced in the [PackageIndex]. It is an index into
+ * [strings] list.
+ */
+ @Id(2)
+ List<int> get unitLibraryUris;
+
+ /**
+ * List of indexes of each unit in this [PackageIndex].
+ */
+ @Id(4)
+ List<UnitIndex> get units;
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique library
+ * specific unit referenced in the [PackageIndex]. It is an index into
+ * [strings] list.
+ */
+ @Id(3)
+ List<int> get unitUnitUris;
+}
+
+/**
* Enum used to indicate the kind of entity referred to by a
* [LinkedReference].
*/
@@ -463,6 +632,95 @@
}
/**
+ * Index information about a unit in a [PackageIndex].
+ */
+abstract class UnitIndex extends base.SummaryClass {
+ /**
+ * Each item of this list is the kind of an element defined in this unit.
+ */
+ @Id(6)
+ List<IndexNameKind> get definedNameKinds;
+
+ /**
+ * Each item of this list is the name offset of an element defined in this
+ * unit relative to the beginning of the file.
+ */
+ @Id(7)
+ List<int> get definedNameOffsets;
+
+ /**
+ * Each item of this list corresponds to an element defined in this unit. It
+ * is an index into [PackageIndex.strings] list. The list is sorted in
+ * ascending order, so that the client can quickly find name definitions in
+ * this [UnitIndex].
+ */
+ @Id(5)
+ List<int> get definedNames;
+
+ /**
+ * Index into [PackageIndex.unitLibraryUris] and [PackageIndex.unitUnitUris]
+ * for the library specific unit that corresponds to this [UnitIndex].
+ */
+ @Id(0)
+ int get unit;
+
+ /**
+ * Each item of this list is the `true` if the corresponding element usage
+ * is qualified with some prefix.
+ */
+ @Id(11)
+ List<bool> get usedElementIsQualifiedFlags;
+
+ /**
+ * Each item of this list is the kind of the element usage.
+ */
+ @Id(4)
+ List<IndexRelationKind> get usedElementKinds;
+
+ /**
+ * Each item of this list is the length of the element usage.
+ */
+ @Id(1)
+ List<int> get usedElementLengths;
+
+ /**
+ * Each item of this list is the offset of the element usage relative to the
+ * beginning of the file.
+ */
+ @Id(2)
+ List<int> get usedElementOffsets;
+
+ /**
+ * Each item of this list is the index into [PackageIndex.elementUnits] and
+ * [PackageIndex.elementOffsets]. The list is sorted in ascending order, so
+ * that the client can quickly find element references in this [UnitIndex].
+ */
+ @Id(3)
+ List<int> get usedElements;
+
+ /**
+ * Each item of this list is the kind of the name usage.
+ */
+ @Id(10)
+ List<IndexRelationKind> get usedNameKinds;
+
+ /**
+ * Each item of this list is the offset of the name usage relative to the
+ * beginning of the file.
+ */
+ @Id(9)
+ List<int> get usedNameOffsets;
+
+ /**
+ * Each item of this list is the index into [PackageIndex.strings] for a
+ * used name. The list is sorted in ascending order, so that the client can
+ * quickly find name uses in this [UnitIndex].
+ */
+ @Id(8)
+ List<int> get usedNames;
+}
+
+/**
* Unlinked summary information about a class declaration.
*/
abstract class UnlinkedClass extends base.SummaryClass {
@@ -1648,7 +1906,7 @@
* library's public namespace. This is the subset of [UnlinkedUnit] that is
* required from dependent libraries in order to perform prelinking.
*/
-@topLevel
+@TopLevel('UPNS')
abstract class UnlinkedPublicNamespace extends base.SummaryClass {
factory UnlinkedPublicNamespace.fromBuffer(List<int> buffer) =>
generated.readUnlinkedPublicNamespace(buffer);
@@ -1784,7 +2042,7 @@
/**
* Unlinked summary information about a compilation unit ("part file").
*/
-@topLevel
+@TopLevel('UUnt')
abstract class UnlinkedUnit extends base.SummaryClass {
factory UnlinkedUnit.fromBuffer(List<int> buffer) =>
generated.readUnlinkedUnit(buffer);
diff --git a/pkg/analyzer/lib/src/summary/index_unit.dart b/pkg/analyzer/lib/src/summary/index_unit.dart
new file mode 100644
index 0000000..db659c7
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/index_unit.dart
@@ -0,0 +1,676 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+
+/**
+ * Object that gathers information about the whole package index and then uses
+ * it to assemble a new [PackageIndexBuilder]. Call [index] on each compilation
+ * unit to be indexed, then call [assemble] to retrieve the complete index for
+ * the package.
+ */
+class PackageIndexAssembler {
+ /**
+ * Map associating referenced elements with their [_ElementInfo]s.
+ */
+ final Map<Element, _ElementInfo> _elementMap = <Element, _ElementInfo>{};
+
+ /**
+ * Map associating [CompilationUnitElement]s with their identifiers, which
+ * are indices into [_unitLibraryUris] and [_unitUnitUris].
+ */
+ final Map<CompilationUnitElement, int> _unitMap =
+ <CompilationUnitElement, int>{};
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique
+ * [CompilationUnitElement]. It is an index into [_strings].
+ */
+ final List<int> _unitLibraryUris = <int>[];
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique
+ * [CompilationUnitElement]. It is an index into [_strings].
+ */
+ final List<int> _unitUnitUris = <int>[];
+
+ /**
+ * Map associating strings with their identifiers, which are indices
+ * into [_strings].
+ */
+ final Map<String, int> _stringMap = <String, int>{};
+
+ /**
+ * List of unique strings used in this index.
+ */
+ final List<String> _strings = <String>[];
+
+ /**
+ * List of information about each unit indexed in this index.
+ */
+ final List<_UnitIndexAssembler> _units = <_UnitIndexAssembler>[];
+
+ /**
+ * Assemble a new [PackageIndexBuilder] using the information gathered by
+ * [index].
+ */
+ PackageIndexBuilder assemble() {
+ List<_ElementInfo> elementInfoList = _elementMap.values.toList();
+ elementInfoList.sort((a, b) {
+ return a.offset - b.offset;
+ });
+ for (int i = 0; i < elementInfoList.length; i++) {
+ elementInfoList[i].id = i;
+ }
+ return new PackageIndexBuilder(
+ unitLibraryUris: _unitLibraryUris,
+ unitUnitUris: _unitUnitUris,
+ elementUnits: elementInfoList.map((e) => e.unitId).toList(),
+ elementOffsets: elementInfoList.map((e) => e.offset).toList(),
+ elementKinds: elementInfoList.map((e) => e.kind).toList(),
+ strings: _strings,
+ units: _units.map((unit) => unit.assemble()).toList());
+ }
+
+ /**
+ * Index the given fully resolved [unit].
+ */
+ void index(CompilationUnit unit) {
+ int unitId = _getUnitId(unit.element);
+ _UnitIndexAssembler assembler = new _UnitIndexAssembler(this, unitId);
+ _units.add(assembler);
+ unit.accept(new _IndexContributor(assembler));
+ }
+
+ /**
+ * Return the unique [_ElementInfo] corresponding the [element]. The field
+ * [_ElementInfo.id] is filled by [assemble] during final sorting.
+ */
+ _ElementInfo _getElementInfo(Element element) {
+ if (element is Member) {
+ element = (element as Member).baseElement;
+ }
+ return _elementMap.putIfAbsent(element, () {
+ CompilationUnitElement unitElement = getUnitElement(element);
+ int unitId = _getUnitId(unitElement);
+ int offset = element.nameOffset;
+ if (element is LibraryElement || element is CompilationUnitElement) {
+ offset = 0;
+ }
+ IndexSyntheticElementKind kind = getIndexElementKind(element);
+ return new _ElementInfo(unitId, offset, kind);
+ });
+ }
+
+ /**
+ * Add information about [str] to [_strings] if necessary, and return the
+ * location in this array representing [str].
+ */
+ int _getStringId(String str) {
+ return _stringMap.putIfAbsent(str, () {
+ int id = _strings.length;
+ _strings.add(str);
+ return id;
+ });
+ }
+
+ /**
+ * Add information about [unitElement] to [_unitUnitUris] and
+ * [_unitLibraryUris] if necessary, and return the location in those
+ * arrays representing [unitElement].
+ */
+ int _getUnitId(CompilationUnitElement unitElement) {
+ return _unitMap.putIfAbsent(unitElement, () {
+ assert(_unitLibraryUris.length == _unitUnitUris.length);
+ int id = _unitUnitUris.length;
+ _unitLibraryUris.add(_getUriId(unitElement.library.source.uri));
+ _unitUnitUris.add(_getUriId(unitElement.source.uri));
+ return id;
+ });
+ }
+
+ /**
+ * Return the identifier corresponding to [uri].
+ */
+ int _getUriId(Uri uri) {
+ String str = uri.toString();
+ return _getStringId(str);
+ }
+
+ /**
+ * Return the kind of the given [element].
+ */
+ static IndexSyntheticElementKind getIndexElementKind(Element element) {
+ if (element.isSynthetic) {
+ if (element is ConstructorElement) {
+ return IndexSyntheticElementKind.constructor;
+ }
+ if (element is PropertyAccessorElement) {
+ return element.isGetter
+ ? IndexSyntheticElementKind.getter
+ : IndexSyntheticElementKind.setter;
+ }
+ }
+ return IndexSyntheticElementKind.notSynthetic;
+ }
+
+ /**
+ * Return the [CompilationUnitElement] that should be used for [element].
+ * Throw [StateError] if the [element] is not linked into a unit.
+ */
+ static CompilationUnitElement getUnitElement(Element element) {
+ for (Element e = element; e != null; e = e.enclosingElement) {
+ if (e is CompilationUnitElement) {
+ return e;
+ }
+ if (e is LibraryElement) {
+ return e.definingCompilationUnit;
+ }
+ }
+ throw new StateError(element.toString());
+ }
+}
+
+/**
+ * Information about a single defined name. Any [_DefinedNameInfo] is always
+ * part of a [_UnitIndexAssembler], so [offset] should be understood within the
+ * context of the compilation unit pointed to by the [_UnitIndexAssembler].
+ */
+class _DefinedNameInfo {
+ /**
+ * The identifier of the name returned [PackageIndexAssembler._getStringId].
+ */
+ final int nameId;
+
+ /**
+ * The coarse-grained kind of the defined name.
+ */
+ final IndexNameKind kind;
+
+ /**
+ * The name offset of the defined element.
+ */
+ final int offset;
+
+ _DefinedNameInfo(this.nameId, this.kind, this.offset);
+}
+
+/**
+ * Information about an element referenced in index.
+ */
+class _ElementInfo {
+ /**
+ * The identifier of the [CompilationUnitElement] containing this element.
+ */
+ final int unitId;
+
+ /**
+ * The name offset of the element.
+ */
+ final int offset;
+
+ /**
+ * The kind of the element.
+ */
+ final IndexSyntheticElementKind kind;
+
+ /**
+ * The unique id of the element. It is set after indexing of the whole
+ * package is done and we are assembling the full package index.
+ */
+ int id;
+
+ _ElementInfo(this.unitId, this.offset, this.kind);
+}
+
+/**
+ * Information about a single relation. Any [_ElementRelationInfo] is always
+ * part of a [_UnitIndexAssembler], so [offset] and [length] should be
+ * understood within the context of the compilation unit pointed to by the
+ * [_UnitIndexAssembler].
+ */
+class _ElementRelationInfo {
+ final _ElementInfo elementInfo;
+ final IndexRelationKind kind;
+ final int offset;
+ final int length;
+ final bool isQualified;
+
+ _ElementRelationInfo(
+ this.elementInfo, this.kind, this.offset, this.length, this.isQualified);
+}
+
+/**
+ * Visits a resolved AST and adds relationships into [_UnitIndexAssembler].
+ */
+class _IndexContributor extends GeneralizingAstVisitor {
+ final _UnitIndexAssembler assembler;
+
+ _IndexContributor(this.assembler);
+
+ /**
+ * Record definition of the given [element].
+ */
+ void recordDefinedElement(Element element) {
+ if (element != null) {
+ String name = element.displayName;
+ int offset = element.nameOffset;
+ Element enclosing = element.enclosingElement;
+ if (enclosing is CompilationUnitElement) {
+ assembler.defineName(name, IndexNameKind.topLevel, offset);
+ } else if (enclosing is ClassElement) {
+ assembler.defineName(name, IndexNameKind.classMember, offset);
+ }
+ }
+ }
+
+ /**
+ * Record that the name [node] has a relation of the given [kind].
+ */
+ void recordNameRelation(SimpleIdentifier node, IndexRelationKind kind) {
+ if (node != null) {
+ assembler.addNameRelation(node.name, kind, node.offset);
+ }
+ }
+
+ /**
+ * Record reference to the given operator [Element].
+ */
+ void recordOperatorReference(Token operator, Element element) {
+ recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the location
+ * of the given [node]. The flag [isQualified] is `true` if [node] has an
+ * explicit or implicit qualifier, so cannot be shadowed by a local
+ * declaration.
+ */
+ void recordRelation(
+ Element element, IndexRelationKind kind, AstNode node, bool isQualified) {
+ if (element != null && node != null) {
+ recordRelationOffset(
+ element, kind, node.offset, node.length, isQualified);
+ }
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the given
+ * [offset] and [length]. The flag [isQualified] is `true` if the relation
+ * has an explicit or implicit qualifier, so [element] cannot be shadowed by
+ * a local declaration.
+ */
+ void recordRelationOffset(Element element, IndexRelationKind kind, int offset,
+ int length, bool isQualified) {
+ // Ignore elements that can't be referenced outside of the unit.
+ if (element == null ||
+ element is FunctionElement &&
+ element.enclosingElement is ExecutableElement ||
+ element is LabelElement ||
+ element is LocalVariableElement ||
+ element is ParameterElement &&
+ element.parameterKind != ParameterKind.NAMED ||
+ element is PrefixElement ||
+ element is TypeParameterElement) {
+ return;
+ }
+ // Add the relation.
+ assembler.addElementRelation(element, kind, offset, length, isQualified);
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the location
+ * of the given [token].
+ */
+ void recordRelationToken(
+ Element element, IndexRelationKind kind, Token token) {
+ if (element != null && token != null) {
+ recordRelationOffset(element, kind, token.offset, token.length, true);
+ }
+ }
+
+ /**
+ * Record a relation between a super [typeName] and its [Element].
+ */
+ void recordSuperType(TypeName typeName, IndexRelationKind kind) {
+ Identifier name = typeName?.name;
+ if (name != null) {
+ Element element = name.staticElement;
+ SimpleIdentifier relNode =
+ name is PrefixedIdentifier ? name.identifier : name;
+ recordRelation(element, kind, relNode, true);
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, relNode, true);
+ typeName.typeArguments?.accept(this);
+ }
+ }
+
+ void recordUriReference(Element element, UriBasedDirective directive) {
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, directive.uri, true);
+ }
+
+ @override
+ visitAssignmentExpression(AssignmentExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitAssignmentExpression(node);
+ }
+
+ @override
+ visitBinaryExpression(BinaryExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitBinaryExpression(node);
+ }
+
+ @override
+ visitClassDeclaration(ClassDeclaration node) {
+ if (node.extendsClause == null) {
+ ClassElement objectElement = node.element.supertype?.element;
+ recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY,
+ node.name.offset, 0, true);
+ }
+ super.visitClassDeclaration(node);
+ }
+
+ @override
+ visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+ SimpleIdentifier fieldName = node.fieldName;
+ if (fieldName != null) {
+ Element element = fieldName.staticElement;
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, fieldName, true);
+ }
+ node.expression?.accept(this);
+ }
+
+ @override
+ visitConstructorName(ConstructorName node) {
+ ConstructorElement element = node.staticElement;
+ element = _getActualConstructorElement(element);
+ // record relation
+ if (node.name != null) {
+ int offset = node.period.offset;
+ int length = node.name.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.type.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ super.visitConstructorName(node);
+ }
+
+ @override
+ visitExportDirective(ExportDirective node) {
+ ExportElement element = node.element;
+ recordUriReference(element?.exportedLibrary, node);
+ super.visitExportDirective(node);
+ }
+
+ @override
+ visitExtendsClause(ExtendsClause node) {
+ recordSuperType(node.superclass, IndexRelationKind.IS_EXTENDED_BY);
+ }
+
+ @override
+ visitImplementsClause(ImplementsClause node) {
+ for (TypeName typeName in node.interfaces) {
+ recordSuperType(typeName, IndexRelationKind.IS_IMPLEMENTED_BY);
+ }
+ }
+
+ @override
+ visitImportDirective(ImportDirective node) {
+ ImportElement element = node.element;
+ recordUriReference(element?.importedLibrary, node);
+ super.visitImportDirective(node);
+ }
+
+ @override
+ visitIndexExpression(IndexExpression node) {
+ MethodElement element = node.bestElement;
+ if (element is MethodElement) {
+ Token operator = node.leftBracket;
+ recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+ }
+ super.visitIndexExpression(node);
+ }
+
+ @override
+ visitMethodInvocation(MethodInvocation node) {
+ SimpleIdentifier name = node.methodName;
+ Element element = name.bestElement;
+ // qualified unresolved name invocation
+ bool isQualified = node.realTarget != null;
+ if (isQualified && element == null) {
+ recordNameRelation(name, IndexRelationKind.IS_INVOKED_BY);
+ }
+ // element invocation
+ IndexRelationKind kind = element is ClassElement
+ ? IndexRelationKind.IS_REFERENCED_BY
+ : IndexRelationKind.IS_INVOKED_BY;
+ recordRelation(element, kind, name, isQualified);
+ node.target?.accept(this);
+ node.argumentList?.accept(this);
+ }
+
+ @override
+ visitPartDirective(PartDirective node) {
+ Element element = node.element;
+ recordUriReference(element, node);
+ super.visitPartDirective(node);
+ }
+
+ @override
+ visitPostfixExpression(PostfixExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitPostfixExpression(node);
+ }
+
+ @override
+ visitPrefixExpression(PrefixExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitPrefixExpression(node);
+ }
+
+ @override
+ visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+ ConstructorElement element = node.staticElement;
+ if (node.constructorName != null) {
+ int offset = node.period.offset;
+ int length = node.constructorName.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.thisKeyword.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ super.visitRedirectingConstructorInvocation(node);
+ }
+
+ @override
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ Element element = node.bestElement;
+ // name in declaration
+ if (node.inDeclarationContext()) {
+ recordDefinedElement(element);
+ return;
+ }
+ // record qualified unresolved name reference
+ bool isQualified = _isQualified(node);
+ if (isQualified && element == null) {
+ recordNameRelation(node, IndexRelationKind.IS_REFERENCED_BY);
+ }
+ // this.field parameter
+ if (element is FieldFormalParameterElement) {
+ recordRelation(
+ element.field, IndexRelationKind.IS_REFERENCED_BY, node, true);
+ return;
+ }
+ // record specific relations
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, node, isQualified);
+ }
+
+ @override
+ visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+ ConstructorElement element = node.staticElement;
+ if (node.constructorName != null) {
+ int offset = node.period.offset;
+ int length = node.constructorName.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.superKeyword.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ super.visitSuperConstructorInvocation(node);
+ }
+
+ @override
+ visitTypeName(TypeName node) {
+ AstNode parent = node.parent;
+ if (parent is ClassTypeAlias && parent.superclass == node) {
+ recordSuperType(node, IndexRelationKind.IS_EXTENDED_BY);
+ } else {
+ super.visitTypeName(node);
+ }
+ }
+
+ @override
+ visitWithClause(WithClause node) {
+ for (TypeName typeName in node.mixinTypes) {
+ recordSuperType(typeName, IndexRelationKind.IS_MIXED_IN_BY);
+ }
+ }
+
+ /**
+ * If the given [constructor] is a synthetic constructor created for a
+ * [ClassTypeAlias], return the actual constructor of a [ClassDeclaration]
+ * which is invoked. Return `null` if a redirection cycle is detected.
+ */
+ ConstructorElement _getActualConstructorElement(
+ ConstructorElement constructor) {
+ Set<ConstructorElement> seenConstructors = new Set<ConstructorElement>();
+ while (constructor != null &&
+ constructor.isSynthetic &&
+ constructor.redirectedConstructor != null) {
+ constructor = constructor.redirectedConstructor;
+ // fail if a cycle is detected
+ if (!seenConstructors.add(constructor)) {
+ return null;
+ }
+ }
+ return constructor;
+ }
+
+ /**
+ * Return `true` if [node] has an explicit or implicit qualifier, so that it
+ * cannot be shadowed by a local declaration.
+ */
+ bool _isQualified(SimpleIdentifier node) {
+ if (node.isQualified) {
+ return true;
+ }
+ AstNode parent = node.parent;
+ return parent is Combinator || parent is Label;
+ }
+}
+
+/**
+ * Information about a single name relation. Any [_NameRelationInfo] is always
+ * part of a [_UnitIndexAssembler], so [offset] should be understood within the
+ * context of the compilation unit pointed to by the [_UnitIndexAssembler].
+ */
+class _NameRelationInfo {
+ /**
+ * The identifier of the name returned [PackageIndexAssembler._getStringId].
+ */
+ final int nameId;
+ final IndexRelationKind kind;
+ final int offset;
+
+ _NameRelationInfo(this.nameId, this.kind, this.offset);
+}
+
+/**
+ * Assembler of a single [CompilationUnit] index. The intended usage sequence:
+ *
+ * - Call [defineName] for each name defined in the compilation unit.
+ * - Call [addElementRelation] for each element relation found in the
+ * compilation unit.
+ * - Call [addNameRelation] for each name relation found in the
+ * compilation unit.
+ * - Assign ids to all the [_ElementInfo] objects reachable from
+ * [elementRelations].
+ * - Call [assemble] to produce the final unit index.
+ */
+class _UnitIndexAssembler {
+ final PackageIndexAssembler pkg;
+ final int unitId;
+ final List<_DefinedNameInfo> definedNames = <_DefinedNameInfo>[];
+ final List<_ElementRelationInfo> elementRelations = <_ElementRelationInfo>[];
+ final List<_NameRelationInfo> nameRelations = <_NameRelationInfo>[];
+
+ _UnitIndexAssembler(this.pkg, this.unitId);
+
+ void addElementRelation(Element element, IndexRelationKind kind, int offset,
+ int length, bool isQualified) {
+ try {
+ _ElementInfo elementInfo = pkg._getElementInfo(element);
+ elementRelations.add(new _ElementRelationInfo(
+ elementInfo, kind, offset, length, isQualified));
+ } on StateError {}
+ }
+
+ void addNameRelation(String name, IndexRelationKind kind, int offset) {
+ int nameId = pkg._getStringId(name);
+ nameRelations.add(new _NameRelationInfo(nameId, kind, offset));
+ }
+
+ /**
+ * Assemble a new [UnitIndexBuilder] using the information gathered
+ * by [addElementRelation] and [defineName].
+ */
+ UnitIndexBuilder assemble() {
+ definedNames.sort((a, b) {
+ return a.nameId - b.nameId;
+ });
+ elementRelations.sort((a, b) {
+ return a.elementInfo.id - b.elementInfo.id;
+ });
+ nameRelations.sort((a, b) {
+ return a.nameId - b.nameId;
+ });
+ return new UnitIndexBuilder(
+ unit: unitId,
+ definedNames: definedNames.map((n) => n.nameId).toList(),
+ definedNameKinds: definedNames.map((n) => n.kind).toList(),
+ definedNameOffsets: definedNames.map((n) => n.offset).toList(),
+ usedElements: elementRelations.map((r) => r.elementInfo.id).toList(),
+ usedElementKinds: elementRelations.map((r) => r.kind).toList(),
+ usedElementOffsets: elementRelations.map((r) => r.offset).toList(),
+ usedElementLengths: elementRelations.map((r) => r.length).toList(),
+ usedElementIsQualifiedFlags:
+ elementRelations.map((r) => r.isQualified).toList(),
+ usedNames: nameRelations.map((r) => r.nameId).toList(),
+ usedNameKinds: nameRelations.map((r) => r.kind).toList(),
+ usedNameOffsets: nameRelations.map((r) => r.offset).toList());
+ }
+
+ void defineName(String name, IndexNameKind kind, int offset) {
+ int nameId = pkg._getStringId(name);
+ definedNames.add(new _DefinedNameInfo(nameId, kind, offset));
+ }
+}
diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
new file mode 100644
index 0000000..a58bfd3
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
@@ -0,0 +1,224 @@
+import 'dart:io' as io;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/resynthesize.dart';
+import 'package:analyzer/src/summary/summary_sdk.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/model.dart';
+import 'package:path/path.dart' as pathos;
+
+/**
+ * If [uri] has the `package` scheme in form of `package:pkg/file.dart`,
+ * return the `pkg` name. Otherwise return `null`.
+ */
+String _getPackageName(Uri uri) {
+ if (uri.scheme != 'package') {
+ return null;
+ }
+ String path = uri.path;
+ int index = path.indexOf('/');
+ if (index == -1) {
+ return null;
+ }
+ return path.substring(0, index);
+}
+
+/**
+ * The [ResultProvider] that provides results from input package summaries.
+ */
+class InputPackagesResultProvider extends ResultProvider {
+ final InternalAnalysisContext _context;
+ final Map<String, String> _packageSummaryInputs;
+
+ _FileBasedSummaryResynthesizer _resynthesizer;
+ SummaryResultProvider _sdkProvider;
+
+ InputPackagesResultProvider(this._context, this._packageSummaryInputs) {
+ InternalAnalysisContext sdkContext = _context.sourceFactory.dartSdk.context;
+ _sdkProvider = sdkContext.resultProvider;
+ // Set the type provider to prevent the context from computing it.
+ _context.typeProvider = sdkContext.typeProvider;
+ // Create a chained resynthesizer.
+ _resynthesizer = new _FileBasedSummaryResynthesizer(
+ _sdkProvider.resynthesizer,
+ _context,
+ _context.typeProvider,
+ _context.sourceFactory,
+ _context.analysisOptions.strongMode,
+ _packageSummaryInputs.values.toList());
+ }
+
+ @override
+ bool compute(CacheEntry entry, ResultDescriptor result) {
+ if (_sdkProvider.compute(entry, result)) {
+ return true;
+ }
+ AnalysisTarget target = entry.target;
+ // Only library results are supported for now.
+ if (target is Source) {
+ Uri uri = target.uri;
+ // We know how to server results to input packages.
+ String sourcePackageName = _getPackageName(uri);
+ if (!_packageSummaryInputs.containsKey(sourcePackageName)) {
+ return false;
+ }
+ // Provide known results.
+ String uriString = uri.toString();
+ if (result == LIBRARY_ELEMENT1 ||
+ result == LIBRARY_ELEMENT2 ||
+ result == LIBRARY_ELEMENT3 ||
+ result == LIBRARY_ELEMENT4 ||
+ result == LIBRARY_ELEMENT5 ||
+ result == LIBRARY_ELEMENT6 ||
+ result == LIBRARY_ELEMENT7 ||
+ result == LIBRARY_ELEMENT8 ||
+ result == LIBRARY_ELEMENT ||
+ false) {
+ LibraryElement libraryElement =
+ _resynthesizer.getLibraryElement(uriString);
+ entry.setValue(result, libraryElement, TargetedResult.EMPTY_LIST);
+ return true;
+ } else if (result == READY_LIBRARY_ELEMENT2 ||
+ result == READY_LIBRARY_ELEMENT5 ||
+ result == READY_LIBRARY_ELEMENT6) {
+ entry.setValue(result, true, TargetedResult.EMPTY_LIST);
+ return true;
+ } else if (result == SOURCE_KIND) {
+ if (_resynthesizer.linkedMap.containsKey(uriString)) {
+ entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST);
+ return true;
+ }
+ if (_resynthesizer.unlinkedMap.containsKey(uriString)) {
+ entry.setValue(result, SourceKind.PART, TargetedResult.EMPTY_LIST);
+ return true;
+ }
+ return false;
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * The [UriResolver] that knows about sources that are parts of packages which
+ * are served from their summaries.
+ */
+class InSummaryPackageUriResolver extends UriResolver {
+ final Map<String, String> _packageSummaryInputs;
+
+ InSummaryPackageUriResolver(this._packageSummaryInputs);
+
+ @override
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+ actualUri ??= uri;
+ String packageName = _getPackageName(actualUri);
+ if (_packageSummaryInputs.containsKey(packageName)) {
+ return new _InSummarySource(actualUri);
+ }
+ return null;
+ }
+}
+
+/**
+ * A concrete resynthesizer that serves summaries from given file paths.
+ */
+class _FileBasedSummaryResynthesizer extends SummaryResynthesizer {
+ final Map<String, UnlinkedUnit> unlinkedMap = <String, UnlinkedUnit>{};
+ final Map<String, LinkedLibrary> linkedMap = <String, LinkedLibrary>{};
+
+ _FileBasedSummaryResynthesizer(
+ SummaryResynthesizer parent,
+ AnalysisContext context,
+ TypeProvider typeProvider,
+ SourceFactory sourceFactory,
+ bool strongMode,
+ List<String> summaryPaths)
+ : super(parent, context, typeProvider, sourceFactory, strongMode) {
+ summaryPaths.forEach(_fillMaps);
+ }
+
+ @override
+ LinkedLibrary getLinkedSummary(String uri) {
+ return linkedMap[uri];
+ }
+
+ @override
+ UnlinkedUnit getUnlinkedSummary(String uri) {
+ return unlinkedMap[uri];
+ }
+
+ @override
+ bool hasLibrarySummary(String uri) {
+ return linkedMap.containsKey(uri);
+ }
+
+ void _fillMaps(String path) {
+ io.File file = new io.File(path);
+ List<int> buffer = file.readAsBytesSync();
+ PackageBundle bundle = new PackageBundle.fromBuffer(buffer);
+ for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
+ unlinkedMap[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
+ }
+ for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
+ linkedMap[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
+ }
+ }
+}
+
+/**
+ * A placeholder of a source that is part of a package whose analysis results
+ * are served from its summary. This source uses its URI as [fullName] and has
+ * empty contents.
+ */
+class _InSummarySource extends Source {
+ final Uri uri;
+
+ _InSummarySource(this.uri);
+
+ @override
+ TimestampedData<String> get contents => new TimestampedData<String>(0, '');
+
+ @override
+ String get encoding => uri.toString();
+
+ @override
+ String get fullName => encoding;
+
+ @override
+ int get hashCode => uri.hashCode;
+
+ @override
+ bool get isInSystemLibrary => false;
+
+ @override
+ int get modificationStamp => 0;
+
+ @override
+ String get shortName => pathos.basename(fullName);
+
+ @override
+ UriKind get uriKind => UriKind.PACKAGE_URI;
+
+ @override
+ bool operator ==(Object object) =>
+ object is _InSummarySource && object.uri == uri;
+
+ @override
+ bool exists() => true;
+
+ @override
+ Uri resolveRelativeUri(Uri relativeUri) {
+ Uri baseUri = uri;
+ return baseUri.resolveUri(relativeUri);
+ }
+
+ @override
+ String toString() => uri.toString();
+}
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 4f6eb20..214861a 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -949,6 +949,7 @@
void buildClass(UnlinkedClass serializedClass) {
ClassElementImpl classElement =
new ClassElementImpl(serializedClass.name, serializedClass.nameOffset);
+ classElement.hasBeenInferred = summaryResynthesizer.strongMode;
classElement.typeParameters =
buildTypeParameters(serializedClass.typeParameters);
classElement.abstract = serializedClass.isAbstract;
@@ -1656,17 +1657,19 @@
/**
* Resynthesize a [ParameterElement].
*/
- ParameterElement buildParameter(UnlinkedParam serializedParameter) {
+ ParameterElement buildParameter(UnlinkedParam serializedParameter,
+ {bool synthetic: false}) {
ParameterElementImpl parameterElement;
+ int nameOffset = synthetic ? -1 : serializedParameter.nameOffset;
if (serializedParameter.isInitializingFormal) {
FieldFormalParameterElementImpl initializingParameter;
if (serializedParameter.kind == UnlinkedParamKind.required) {
initializingParameter = new FieldFormalParameterElementImpl(
- serializedParameter.name, serializedParameter.nameOffset);
+ serializedParameter.name, nameOffset);
} else {
DefaultFieldFormalParameterElementImpl defaultParameter =
new DefaultFieldFormalParameterElementImpl(
- serializedParameter.name, serializedParameter.nameOffset);
+ serializedParameter.name, nameOffset);
initializingParameter = defaultParameter;
if (serializedParameter.defaultValue != null) {
defaultParameter.constantInitializer =
@@ -1679,12 +1682,12 @@
initializingParameter.field = fields[serializedParameter.name];
} else {
if (serializedParameter.kind == UnlinkedParamKind.required) {
- parameterElement = new ParameterElementImpl(
- serializedParameter.name, serializedParameter.nameOffset);
+ parameterElement =
+ new ParameterElementImpl(serializedParameter.name, nameOffset);
} else {
DefaultParameterElementImpl defaultParameter =
new DefaultParameterElementImpl(
- serializedParameter.name, serializedParameter.nameOffset);
+ serializedParameter.name, nameOffset);
parameterElement = defaultParameter;
if (serializedParameter.defaultValue != null) {
defaultParameter.constantInitializer =
@@ -1694,6 +1697,7 @@
}
}
}
+ parameterElement.synthetic = synthetic;
buildAnnotations(parameterElement, serializedParameter.annotations);
if (serializedParameter.isFunctionTyped) {
FunctionElementImpl parameterTypeElement =
@@ -1784,6 +1788,17 @@
}
if (type.paramReference != 0) {
return getTypeParameterFromScope(type.paramReference);
+ } else if (type.syntheticReturnType != null) {
+ FunctionElementImpl element = new FunctionElementImpl('', -1);
+ element.synthetic = true;
+ element.parameters = type.syntheticParams
+ .map((UnlinkedParam param) => buildParameter(param, synthetic: true))
+ .toList();
+ element.returnType = buildType(type.syntheticReturnType);
+ FunctionTypeImpl result = new FunctionTypeImpl.elementWithNameAndArgs(
+ element, null, null, false);
+ element.type = result;
+ return result;
} else {
DartType getTypeArgument(int i) {
if (i < type.typeArguments.length) {
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index afd3ab1..3d9896b 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -4,6 +4,8 @@
library serialization.elements;
+import 'dart:convert';
+
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
@@ -17,6 +19,7 @@
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/name_filter.dart';
import 'package:analyzer/src/summary/summarize_const_expr.dart';
+import 'package:crypto/crypto.dart';
/**
* Serialize all the elements in [lib] to a summary using [ctx] as the context
@@ -24,7 +27,8 @@
*/
LibrarySerializationResult serializeLibrary(
LibraryElement lib, TypeProvider typeProvider, bool strongMode) {
- var serializer = new _LibrarySerializer(lib, typeProvider, strongMode);
+ _LibrarySerializer serializer =
+ new _LibrarySerializer(lib, typeProvider, strongMode);
LinkedLibraryBuilder linked = serializer.serializeLibrary();
return new LibrarySerializationResult(linked, serializer.unlinkedUnits,
serializer.unitUris, serializer.unitSources);
@@ -106,6 +110,76 @@
}
/**
+ * Object that gathers information uses it to assemble a new
+ * [PackageBundleBuilder].
+ */
+class PackageBundleAssembler {
+ /**
+ * Value that will be stored in [PackageBundle.majorVersion] for any summaries
+ * created by this code. When making a breaking change to the summary format,
+ * this value should be incremented by 1 and [currentMinorVersion] should be
+ * reset to zero.
+ */
+ static const int currentMajorVersion = 1;
+
+ /**
+ * Value that will be stored in [PackageBundle.minorVersion] for any summaries
+ * created by this code. When making a non-breaking change to the summary
+ * format that clients might need to be aware of (such as adding a kind of
+ * data that was previously not summarized), this value should be incremented
+ * by 1.
+ */
+ static const int currentMinorVersion = 0;
+
+ final List<String> _linkedLibraryUris = <String>[];
+ final List<LinkedLibraryBuilder> _linkedLibraries = <LinkedLibraryBuilder>[];
+ final List<String> _unlinkedUnitUris = <String>[];
+ final List<UnlinkedUnitBuilder> _unlinkedUnits = <UnlinkedUnitBuilder>[];
+ final List<String> _unlinkedUnitHashes = <String>[];
+
+ /**
+ * Assemble a new [PackageBundleBuilder] using the gathered information.
+ */
+ PackageBundleBuilder assemble() {
+ return new PackageBundleBuilder(
+ linkedLibraryUris: _linkedLibraryUris,
+ linkedLibraries: _linkedLibraries,
+ unlinkedUnitUris: _unlinkedUnitUris,
+ unlinkedUnits: _unlinkedUnits,
+ unlinkedUnitHashes: _unlinkedUnitHashes,
+ majorVersion: currentMajorVersion,
+ minorVersion: currentMinorVersion);
+ }
+
+ /**
+ * Serialize the library with the given [element].
+ */
+ void serializeLibraryElement(LibraryElement element) {
+ String uri = element.source.uri.toString();
+ LibrarySerializationResult libraryResult = serializeLibrary(
+ element,
+ element.context.typeProvider,
+ element.context.analysisOptions.strongMode);
+ _linkedLibraryUris.add(uri);
+ _linkedLibraries.add(libraryResult.linked);
+ _unlinkedUnitUris.addAll(libraryResult.unitUris);
+ _unlinkedUnits.addAll(libraryResult.unlinkedUnits);
+ for (Source source in libraryResult.unitSources) {
+ _unlinkedUnitHashes.add(_hash(source.contents.data));
+ }
+ }
+
+ /**
+ * Compute a hash of the given file contents.
+ */
+ String _hash(String contents) {
+ MD5 md5 = new MD5();
+ md5.add(UTF8.encode(contents));
+ return CryptoUtils.bytesToHex(md5.close());
+ }
+}
+
+/**
* Instances of this class keep track of intermediate state during
* serialization of a single compilation unit.
*/
@@ -185,6 +259,12 @@
*/
int bottomReferenceIndex = null;
+ /**
+ * If `true`, we are currently generating linked references, so new
+ * references will be not stored in [unlinkedReferences].
+ */
+ bool buildingLinkedReferences = false;
+
_CompilationUnitSerializer(
this.librarySerializer, this.compilationUnit, this.unitNum);
@@ -317,9 +397,11 @@
* found during [addCompilationUnitElements].
*/
void createLinkedTypes() {
+ buildingLinkedReferences = true;
linkedUnit.types = deferredLinkedTypes
.map((_SerializeTypeRef closure) => closure())
.toList();
+ buildingLinkedReferences = false;
}
/**
@@ -728,7 +810,7 @@
context ??= parameter;
UnlinkedParamBuilder b = new UnlinkedParamBuilder();
b.name = parameter.name;
- b.nameOffset = parameter.nameOffset;
+ b.nameOffset = parameter.nameOffset >= 0 ? parameter.nameOffset : 0;
switch (parameter.parameterKind) {
case ParameterKind.REQUIRED:
b.kind = UnlinkedParamKind.required;
@@ -794,11 +876,8 @@
/**
* Compute the reference index which should be stored in a [EntityRef].
- *
- * If [linked] is true, and a new reference has to be created, the reference
- * will only be stored in [linkedReferences].
*/
- int serializeReferenceForType(DartType type, bool linked) {
+ int serializeReferenceForType(DartType type) {
Element element = type.element;
LibraryElement dependentLibrary = element?.library;
if (dependentLibrary == null) {
@@ -806,7 +885,7 @@
// References to the "bottom" type are always implicit, since there is
// no way to explicitly refer to the "bottom" type. Therefore they
// should always be linked.
- assert(linked);
+ assert(buildingLinkedReferences);
return serializeBottomReference();
}
assert(type.isDynamic || type.isVoid);
@@ -816,7 +895,7 @@
// Note: for a type which is truly `dynamic` or `void`, fall through to
// use [_getElementReferenceId].
}
- return _getElementReferenceId(element, linked: linked);
+ return _getElementReferenceId(element);
}
/**
@@ -853,26 +932,36 @@
/**
* Serialize the given [type] into a [EntityRef]. If [slot] is provided,
- * it should be included in the [EntityRef]. If [linked] is true, any
- * references that are created will be populated into [linkedReferences] but
- * not [unlinkedReferences].
+ * it should be included in the [EntityRef].
*
* [context] is the element within which the [EntityRef] will be
* interpreted; this is used to serialize type parameters.
*/
EntityRefBuilder serializeTypeRef(DartType type, Element context,
- {bool linked: false, int slot}) {
+ {int slot}) {
+ if (slot != null) {
+ assert(buildingLinkedReferences);
+ }
EntityRefBuilder b = new EntityRefBuilder(slot: slot);
+ Element typeElement = type.element;
if (type is TypeParameterType) {
b.paramReference = findTypeParameterIndex(type, context);
+ } else if (type is FunctionType &&
+ typeElement is FunctionElement &&
+ typeElement.enclosingElement == null) {
+ b.syntheticReturnType =
+ serializeTypeRef(typeElement.returnType, typeElement);
+ b.syntheticParams = typeElement.parameters
+ .map((ParameterElement param) => serializeParam(param, context))
+ .toList();
} else {
if (type is FunctionType &&
- type.element.enclosingElement is ParameterElement) {
+ typeElement.enclosingElement is ParameterElement) {
// Code cannot refer to function types implicitly defined by parameters
// directly, so if we get here, we must be serializing a linked
// reference from type inference.
- assert(linked);
- ParameterElement parameterElement = type.element.enclosingElement;
+ assert(buildingLinkedReferences);
+ ParameterElement parameterElement = typeElement.enclosingElement;
while (true) {
Element parent = parameterElement.enclosingElement;
if (parent is ExecutableElement) {
@@ -885,7 +974,7 @@
continue;
} else {
// Function-typed parameter inside a top level function or method.
- b.reference = _getElementReferenceId(parent, linked: linked);
+ b.reference = _getElementReferenceId(parent);
break;
}
} else {
@@ -894,7 +983,7 @@
}
}
} else {
- b.reference = serializeReferenceForType(type, linked);
+ b.reference = serializeReferenceForType(type);
}
List<DartType> typeArguments = getTypeArguments(type);
if (typeArguments != null) {
@@ -907,8 +996,8 @@
if (numArgsToSerialize > 0) {
List<EntityRefBuilder> serializedArguments = <EntityRefBuilder>[];
for (int i = 0; i < numArgsToSerialize; i++) {
- serializedArguments.add(
- serializeTypeRef(typeArguments[i], context, linked: linked));
+ serializedArguments
+ .add(serializeTypeRef(typeArguments[i], context));
}
b.typeArguments = serializedArguments;
}
@@ -1027,12 +1116,12 @@
int slot = ++numSlots;
if (type != null) {
deferredLinkedTypes
- .add(() => serializeTypeRef(type, context, linked: true, slot: slot));
+ .add(() => serializeTypeRef(type, context, slot: slot));
}
return slot;
}
- int _getElementReferenceId(Element element, {bool linked: false}) {
+ int _getElementReferenceId(Element element) {
return referenceMap.putIfAbsent(element, () {
LibraryElement dependentLibrary = librarySerializer.libraryElement;
int unit = 0;
@@ -1049,13 +1138,13 @@
String name = element == null ? 'void' : element.name;
int index;
LinkedReferenceBuilder linkedReference;
- if (linked) {
+ if (buildingLinkedReferences) {
linkedReference =
new LinkedReferenceBuilder(kind: kind, unit: unit, name: name);
if (enclosingElement != null &&
enclosingElement is! CompilationUnitElement) {
linkedReference.containingReference =
- _getElementReferenceId(enclosingElement, linked: linked);
+ _getElementReferenceId(enclosingElement);
if (enclosingElement is ClassElement) {
// Nothing to do.
} else if (enclosingElement is ExecutableElement) {
@@ -1095,7 +1184,7 @@
prefixReference = serializePrefix(prefix);
}
} else {
- prefixReference = _getElementReferenceId(enclosing, linked: linked);
+ prefixReference = _getElementReferenceId(enclosing);
}
index = serializeUnlinkedReference(name, kind,
prefixReference: prefixReference, unit: unit);
@@ -1331,7 +1420,7 @@
/**
* Retrieve a list of the Sources for the compilation units in the library.
*/
- List<String> get unitSources => compilationUnitSerializers
+ List<Source> get unitSources => compilationUnitSerializers
.map((_CompilationUnitSerializer s) => s.unitSource)
.toList();
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index d21914c..b94806d 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -29,7 +29,6 @@
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:analyzer/src/generated/visitors.dart';
import 'package:analyzer/src/plugin/engine_plugin.dart';
import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/task/driver.dart';
@@ -1939,7 +1938,7 @@
// and the invalidation code (invalidateLibraryCycles) will ensure that
// element model results will be re-used here only if they are still valid.
if (context.analysisOptions.strongMode) {
- LibraryElementImpl library = getRequiredInput(LIBRARY_ELEMENT_INPUT);
+ LibraryElement library = getRequiredInput(LIBRARY_ELEMENT_INPUT);
List<LibraryElement> component = library.libraryCycle;
Set<LibraryElement> filter = new Set<LibraryElement>.from(component);
Set<CompilationUnitElement> deps = new Set<CompilationUnitElement>();
@@ -2266,7 +2265,7 @@
static const String PARSED_UNIT_INPUT = 'PARSED_UNIT_INPUT';
// Prefix for comments ignoring error codes.
- static const String _normalizedIgnorePrefix = '//#ignore:';
+ static const String _normalizedIgnorePrefix = '//ignore:';
DartErrorsTask(InternalAnalysisContext context, AnalysisTarget target)
: super(context, target);
@@ -3365,6 +3364,7 @@
parser.parseAsync = options.enableAsync;
parser.parseFunctionBodies = options.analyzeFunctionBodiesPredicate(source);
parser.parseGenericMethods = options.enableGenericMethods;
+ parser.parseConditionalDirectives = options.enableConditionalDirectives;
parser.parseGenericMethodComments = options.strongMode;
CompilationUnit unit = parser.parseCompilationUnit(tokenStream);
unit.lineInfo = lineInfo;
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 9b96c6a..e598910 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -47,6 +47,8 @@
static const String enableAsync = 'enableAsync';
static const String enableGenericMethods = 'enableGenericMethods';
static const String enableSuperMixins = 'enableSuperMixins';
+ static const String enableConditionalDirectives =
+ "enableConditionalDirectives";
static const String errors = 'errors';
static const String exclude = 'exclude';
static const String language = 'language';
@@ -79,7 +81,8 @@
static const List<String> languageOptions = const [
enableAsync,
enableGenericMethods,
- enableSuperMixins
+ enableSuperMixins,
+ enableConditionalDirectives,
];
}
@@ -490,6 +493,14 @@
context.analysisOptions = options;
}
}
+ if (feature == AnalyzerOptions.enableConditionalDirectives) {
+ if (isTrue(value)) {
+ AnalysisOptionsImpl options =
+ new AnalysisOptionsImpl.from(context.analysisOptions);
+ options.enableConditionalDirectives = true;
+ context.analysisOptions = options;
+ }
+ }
}
void setLanguageOptions(AnalysisContext context, Object configs) {
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index bb328c2..fb6756b 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.27.2
+version: 0.27.3-alpha.0
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 5d74e2c..b7ed4b3 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -660,6 +660,7 @@
AstFactory.classDeclaration(null, className, null, null, null, null);
classDeclaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ classDeclaration.endToken.offset = 80;
classDeclaration.accept(builder);
List<ClassElement> types = holder.types;
expect(types, hasLength(1));
@@ -673,6 +674,7 @@
expect(type.isSynthetic, isFalse);
expect(type.documentationComment, '/// aaa');
_assertHasDocRange(type, 50, 7);
+ _assertHasCodeRange(type, 50, 31);
}
void test_visitClassDeclaration_parameterized() {
@@ -837,6 +839,26 @@
expect(type.typeParameters[0].name, equals('T'));
}
+ void test_visitCompilationUnit_codeRange() {
+ TopLevelVariableDeclaration topLevelVariableDeclaration = AstFactory
+ .topLevelVariableDeclaration(null, AstFactory.typeName4('int'),
+ [AstFactory.variableDeclaration('V')]);
+ CompilationUnit unit = new CompilationUnit(
+ topLevelVariableDeclaration.beginToken,
+ null,
+ [],
+ [topLevelVariableDeclaration],
+ topLevelVariableDeclaration.endToken);
+ ElementHolder holder = new ElementHolder();
+ ElementBuilder builder = _makeBuilder(holder);
+ unit.beginToken.offset = 10;
+ unit.endToken.offset = 40;
+ unit.accept(builder);
+
+ CompilationUnitElement element = builder.compilationUnitElement;
+ _assertHasCodeRange(element, 0, 41);
+ }
+
void test_visitConstructorDeclaration_external() {
ElementHolder holder = new ElementHolder();
ElementBuilder builder = _makeBuilder(holder);
@@ -909,12 +931,14 @@
constructorDeclaration.documentationComment = AstFactory
.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ constructorDeclaration.endToken.offset = 80;
constructorDeclaration.accept(builder);
List<ConstructorElement> constructors = holder.constructors;
expect(constructors, hasLength(1));
ConstructorElement constructor = constructors[0];
expect(constructor, isNotNull);
+ _assertHasCodeRange(constructor, 50, 31);
expect(constructor.documentationComment, '/// aaa');
_assertHasDocRange(constructor, 50, 7);
expect(constructor.isExternal, isFalse);
@@ -993,11 +1017,14 @@
AstFactory.declaredIdentifier3(variableName);
AstFactory.forEachStatement(
identifier, AstFactory.nullLiteral(), AstFactory.emptyStatement());
+ identifier.beginToken.offset = 50;
+ identifier.endToken.offset = 80;
identifier.accept(builder);
List<LocalVariableElement> variables = holder.localVariables;
expect(variables, hasLength(1));
LocalVariableElement variable = variables[0];
+ _assertHasCodeRange(variable, 50, 31);
expect(variable, isNotNull);
expect(variable.hasImplicitType, isTrue);
expect(variable.isConst, isFalse);
@@ -1019,12 +1046,15 @@
AstFactory.declaredIdentifier4(AstFactory.typeName4('E'), variableName);
AstFactory.forEachStatement(
identifier, AstFactory.nullLiteral(), AstFactory.emptyStatement());
+ identifier.beginToken.offset = 50;
+ identifier.endToken.offset = 80;
identifier.accept(builder);
List<LocalVariableElement> variables = holder.localVariables;
expect(variables, hasLength(1));
LocalVariableElement variable = variables[0];
expect(variable, isNotNull);
+ _assertHasCodeRange(variable, 50, 31);
expect(variable.hasImplicitType, isFalse);
expect(variable.isConst, isFalse);
expect(variable.isDeprecated, isFalse);
@@ -1045,11 +1075,14 @@
AstFactory.positionalFormalParameter(
AstFactory.simpleFormalParameter3(parameterName),
AstFactory.integer(0));
+ formalParameter.beginToken.offset = 50;
+ formalParameter.endToken.offset = 80;
formalParameter.accept(builder);
List<ParameterElement> parameters = holder.parameters;
expect(parameters, hasLength(1));
ParameterElement parameter = parameters[0];
+ _assertHasCodeRange(parameter, 50, 31);
expect(parameter.hasImplicitType, isTrue);
expect(parameter.initializer, isNotNull);
expect(parameter.initializer.type, isNotNull);
@@ -1102,11 +1135,13 @@
AstFactory.enumDeclaration2(enumName, ["ONE"]);
enumDeclaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ enumDeclaration.endToken.offset = 80;
enumDeclaration.accept(builder);
List<ClassElement> enums = holder.enums;
expect(enums, hasLength(1));
ClassElement enumElement = enums[0];
expect(enumElement, isNotNull);
+ _assertHasCodeRange(enumElement, 50, 31);
expect(enumElement.documentationComment, '/// aaa');
_assertHasDocRange(enumElement, 50, 7);
expect(enumElement.name, enumName);
@@ -1124,6 +1159,7 @@
]);
fieldDeclaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ fieldDeclaration.endToken.offset = 110;
fieldDeclaration.accept(builder);
List<FieldElement> fields = holder.fields;
@@ -1131,6 +1167,7 @@
FieldElement firstField = fields[0];
expect(firstField, isNotNull);
+ _assertHasCodeRange(firstField, 50, 61);
expect(firstField.documentationComment, '/// aaa');
_assertHasDocRange(firstField, 50, 7);
expect(firstField.name, firstFieldName);
@@ -1141,6 +1178,7 @@
FieldElement secondField = fields[1];
expect(secondField, isNotNull);
+ _assertHasCodeRange(secondField, 50, 61);
expect(secondField.documentationComment, '/// aaa');
_assertHasDocRange(secondField, 50, 7);
expect(secondField.name, secondFieldName);
@@ -1156,11 +1194,14 @@
String parameterName = "p";
FieldFormalParameter formalParameter =
AstFactory.fieldFormalParameter(null, null, parameterName);
+ formalParameter.beginToken.offset = 50;
+ formalParameter.endToken.offset = 80;
formalParameter.accept(builder);
List<ParameterElement> parameters = holder.parameters;
expect(parameters, hasLength(1));
ParameterElement parameter = parameters[0];
expect(parameter, isNotNull);
+ _assertHasCodeRange(parameter, 50, 31);
expect(parameter.name, parameterName);
expect(parameter.initializer, isNull);
expect(parameter.isConst, isFalse);
@@ -1251,12 +1292,14 @@
AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
declaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ declaration.endToken.offset = 80;
declaration.accept(builder);
List<PropertyAccessorElement> accessors = holder.accessors;
expect(accessors, hasLength(1));
PropertyAccessorElement accessor = accessors[0];
expect(accessor, isNotNull);
+ _assertHasCodeRange(accessor, 50, 31);
expect(accessor.documentationComment, '/// aaa');
_assertHasDocRange(accessor, 50, 7);
expect(accessor.name, functionName);
@@ -1287,12 +1330,14 @@
AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
declaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ declaration.endToken.offset = 80;
declaration.accept(builder);
List<FunctionElement> functions = holder.functions;
expect(functions, hasLength(1));
FunctionElement function = functions[0];
expect(function, isNotNull);
+ _assertHasCodeRange(function, 50, 31);
expect(function.documentationComment, '/// aaa');
_assertHasDocRange(function, 50, 7);
expect(function.hasImplicitReturnType, isFalse);
@@ -1317,12 +1362,14 @@
AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
declaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ declaration.endToken.offset = 80;
declaration.accept(builder);
List<PropertyAccessorElement> accessors = holder.accessors;
expect(accessors, hasLength(1));
PropertyAccessorElement accessor = accessors[0];
expect(accessor, isNotNull);
+ _assertHasCodeRange(accessor, 50, 31);
expect(accessor.documentationComment, '/// aaa');
_assertHasDocRange(accessor, 50, 7);
expect(accessor.hasImplicitReturnType, isTrue);
@@ -1396,12 +1443,14 @@
null, aliasName, AstFactory.typeParameterList([parameterName]), null);
aliasNode.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ aliasNode.endToken.offset = 80;
aliasNode.accept(builder);
List<FunctionTypeAliasElement> aliases = holder.typeAliases;
expect(aliases, hasLength(1));
FunctionTypeAliasElement alias = aliases[0];
expect(alias, isNotNull);
+ _assertHasCodeRange(alias, 50, 31);
expect(alias.documentationComment, '/// aaa');
_assertHasDocRange(alias, 50, 7);
expect(alias.name, aliasName);
@@ -1557,6 +1606,7 @@
AstFactory.blockFunctionBody2());
methodDeclaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ methodDeclaration.endToken.offset = 80;
methodDeclaration.accept(builder);
List<FieldElement> fields = holder.fields;
@@ -1568,6 +1618,7 @@
expect(field.setter, isNull);
PropertyAccessorElement getter = field.getter;
expect(getter, isNotNull);
+ _assertHasCodeRange(getter, 50, 31);
expect(getter.documentationComment, '/// aaa');
_assertHasDocRange(getter, 50, 7);
expect(getter.hasImplicitReturnType, isTrue);
@@ -1673,12 +1724,14 @@
AstFactory.blockFunctionBody2());
methodDeclaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ methodDeclaration.endToken.offset = 80;
methodDeclaration.accept(builder);
List<MethodElement> methods = holder.methods;
expect(methods, hasLength(1));
MethodElement method = methods[0];
expect(method, isNotNull);
+ _assertHasCodeRange(method, 50, 31);
expect(method.documentationComment, '/// aaa');
_assertHasDocRange(method, 50, 7);
expect(method.hasImplicitReturnType, isFalse);
@@ -1742,6 +1795,7 @@
AstFactory.blockFunctionBody2());
methodDeclaration.documentationComment = AstFactory.documentationComment(
[TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+ methodDeclaration.endToken.offset = 80;
methodDeclaration.accept(builder);
List<FieldElement> fields = holder.fields;
@@ -1754,6 +1808,7 @@
PropertyAccessorElement setter = field.setter;
expect(setter, isNotNull);
+ _assertHasCodeRange(setter, 50, 31);
expect(setter.documentationComment, '/// aaa');
_assertHasDocRange(setter, 50, 7);
expect(setter.hasImplicitReturnType, isTrue);
@@ -1983,11 +2038,14 @@
AstFactory.simpleFormalParameter3(parameterName),
AstFactory.identifier3("42"));
_useParameterInMethod(formalParameter, 100, 110);
+ formalParameter.beginToken.offset = 50;
+ formalParameter.endToken.offset = 80;
formalParameter.accept(builder);
List<ParameterElement> parameters = holder.parameters;
expect(parameters, hasLength(1));
ParameterElement parameter = parameters[0];
expect(parameter, isNotNull);
+ _assertHasCodeRange(parameter, 50, 32);
expect(parameter.name, parameterName);
expect(parameter.isConst, isFalse);
expect(parameter.isFinal, isFalse);
@@ -2088,11 +2146,14 @@
AstFactory.simpleFormalParameter3(firstParameterName),
AstFactory.simpleFormalParameter3(secondParameterName)
]));
+ typeAlias.beginToken.offset = 50;
+ typeAlias.endToken.offset = 80;
typeAlias.accept(builder);
List<FunctionTypeAliasElement> aliases = holder.typeAliases;
expect(aliases, hasLength(1));
FunctionTypeAliasElement alias = aliases[0];
expect(alias, isNotNull);
+ _assertHasCodeRange(alias, 50, 31);
expect(alias.name, aliasName);
expect(alias.type, isNotNull);
expect(alias.isSynthetic, isFalse);
@@ -2139,11 +2200,13 @@
ElementBuilder builder = _makeBuilder(holder);
String parameterName = "E";
TypeParameter typeParameter = AstFactory.typeParameter(parameterName);
+ typeParameter.beginToken.offset = 50;
typeParameter.accept(builder);
List<TypeParameterElement> typeParameters = holder.typeParameters;
expect(typeParameters, hasLength(1));
TypeParameterElement typeParameterElement = typeParameters[0];
expect(typeParameterElement, isNotNull);
+ _assertHasCodeRange(typeParameterElement, 50, 1);
expect(typeParameterElement.name, parameterName);
expect(typeParameterElement.bound, isNull);
expect(typeParameterElement.isSynthetic, isFalse);
@@ -2158,8 +2221,8 @@
String variableName = "v";
VariableDeclaration variable =
AstFactory.variableDeclaration2(variableName, null);
- Statement statement =
- AstFactory.variableDeclarationStatement2(null, [variable]);
+ VariableDeclarationStatement statement =
+ AstFactory.variableDeclarationStatement2(Keyword.VAR, [variable]);
ConstructorDeclaration constructor = AstFactory.constructorDeclaration2(
null,
null,
@@ -2168,6 +2231,8 @@
AstFactory.formalParameterList(),
null,
AstFactory.blockFunctionBody2([statement]));
+ statement.beginToken.offset = 50;
+ statement.endToken.offset = 80;
constructor.accept(builder);
List<ConstructorElement> constructors = holder.constructors;
@@ -2176,6 +2241,7 @@
constructors[0].localVariables;
expect(variableElements, hasLength(1));
LocalVariableElement variableElement = variableElements[0];
+ _assertHasCodeRange(variableElement, 50, 31);
expect(variableElement.hasImplicitType, isTrue);
expect(variableElement.name, variableName);
}
@@ -2354,6 +2420,12 @@
expect(variable.setter, isNull);
}
+ void _assertHasCodeRange(Element element, int offset, int length) {
+ ElementImpl elementImpl = element;
+ expect(elementImpl.codeOffset, offset);
+ expect(elementImpl.codeLength, length);
+ }
+
void _assertHasDocRange(
Element element, int expectedOffset, int expectedLength) {
// Cast to dynamic here to avoid a hint about @deprecated docRange.
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 7c0c15a..09485aa 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -7,10 +7,12 @@
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:analyzer/src/generated/source_io.dart';
+import 'package:unittest/unittest.dart' show expect;
import '../reflective_tests.dart';
import '../utils.dart';
import 'resolver_test.dart';
+import 'package:analyzer/src/generated/engine.dart';
main() {
initializeTestEnvironment();
@@ -6043,6 +6045,41 @@
assertErrors(source, [CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
}
+ void test_uriDoesNotExist_import_disappears_when_fixed() {
+ Source source = addSource("import 'target.dart';");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
+
+ // Check that the file is represented as missing.
+ Source target =
+ analysisContext2.getSourcesWithFullName("/target.dart").first;
+ expect(analysisContext2.getModificationStamp(target), -1);
+
+ // Add an overlay in the same way as AnalysisServer.
+ analysisContext2
+ ..setContents(target, "")
+ ..handleContentsChanged(target, null, "", true);
+
+ // Make sure the error goes away.
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_IMPORT]);
+ }
+
+ void test_uriDoesNotExist_import_appears_after_deleting_target() {
+ Source test = addSource("import 'target.dart';");
+ Source target = addNamedSource("/target.dart", "");
+ computeLibrarySourceErrors(test);
+ assertErrors(test, [HintCode.UNUSED_IMPORT]);
+
+ // Remove the overlay in the same way as AnalysisServer.
+ analysisContext2.setContents(target, null);
+ ChangeSet changeSet = new ChangeSet()..removedSource(target);
+ analysisContext2.applyChanges(changeSet);
+
+ computeLibrarySourceErrors(test);
+ assertErrors(test, [CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
+ }
+
void test_uriDoesNotExist_part() {
Source source = addSource(r'''
library lib;
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
index 0f1112d..4f0b214 100644
--- a/pkg/analyzer/test/generated/declaration_resolver_test.dart
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -302,6 +302,26 @@
expect(setterName.staticElement, same(setterElement));
}
+ void test_visitExportDirective_notExistingSource() {
+ String code = r'''
+export 'foo.dart';
+''';
+ CompilationUnit unit = resolveSource(code);
+ // re-resolve
+ _cloneResolveUnit(unit);
+ // no other validations than built into DeclarationResolver
+ }
+
+ void test_visitExportDirective_unresolvedUri() {
+ String code = r'''
+export 'package:foo/bar.dart';
+''';
+ CompilationUnit unit = resolveSource(code);
+ // re-resolve
+ _cloneResolveUnit(unit);
+ // no other validations than built into DeclarationResolver
+ }
+
void test_visitFunctionExpression() {
String code = r'''
main(List<String> items) {
@@ -314,12 +334,19 @@
// no other validations than built into DeclarationResolver
}
- void test_visitMethodDeclaration_unaryMinus() {
+ void test_visitImportDirective_notExistingSource() {
String code = r'''
-class C {
- C operator -() => null;
- C operator -(C other) => null;
-}
+import 'foo.dart';
+''';
+ CompilationUnit unit = resolveSource(code);
+ // re-resolve
+ _cloneResolveUnit(unit);
+ // no other validations than built into DeclarationResolver
+ }
+
+ void test_visitImportDirective_unresolvedUri() {
+ String code = r'''
+import 'package:foo/bar.dart';
''';
CompilationUnit unit = resolveSource(code);
// re-resolve
@@ -409,6 +436,29 @@
expect(firstName.staticElement, same(firstElement));
expect(secondName.staticElement, same(secondElement));
}
+
+ void test_visitMethodDeclaration_unaryMinus() {
+ String code = r'''
+class C {
+ C operator -() => null;
+ C operator -(C other) => null;
+}
+''';
+ CompilationUnit unit = resolveSource(code);
+ // re-resolve
+ _cloneResolveUnit(unit);
+ // no other validations than built into DeclarationResolver
+ }
+
+ void test_visitPartDirective_notExistingSource() {
+ String code = r'''
+part 'foo.bar';
+''';
+ CompilationUnit unit = resolveSource(code);
+ // re-resolve
+ _cloneResolveUnit(unit);
+ // no other validations than built into DeclarationResolver
+ }
}
/**
diff --git a/pkg/analyzer/test/generated/error_suppression_test.dart b/pkg/analyzer/test/generated/error_suppression_test.dart
index 560a2c2..da6c49d 100644
--- a/pkg/analyzer/test/generated/error_suppression_test.dart
+++ b/pkg/analyzer/test/generated/error_suppression_test.dart
@@ -19,7 +19,7 @@
class ErrorSuppressionTest extends ResolverTestCase {
void test_error_code_mismatch() {
Source source = addSource('''
-//# ignore: const_initialized_with_non_constant_value
+// ignore: const_initialized_with_non_constant_value
int x = '';
const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
@@ -32,7 +32,7 @@
void test_ignore_first() {
Source source = addSource('''
-//# ignore: invalid_assignment
+// ignore: invalid_assignment
int x = '';
// ... but no ignore here ...
const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
@@ -46,7 +46,7 @@
Source source = addSource('''
//INVALID_ASSIGNMENT
int x = '';
-//# ignore: const_initialized_with_non_constant_value
+// ignore: const_initialized_with_non_constant_value
const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
computeLibrarySourceErrors(source);
@@ -55,7 +55,7 @@
void test_invalid_error_code() {
Source source = addSource('''
-//# ignore: right_format_wrong_code
+// ignore: right_format_wrong_code
int x = '';
const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
@@ -69,7 +69,7 @@
void test_missing_error_codes() {
Source source = addSource('''
int x = 3;
-//# ignore:
+// ignore:
const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
computeLibrarySourceErrors(source);
@@ -79,9 +79,9 @@
]);
}
- void test_missing_metadata_prefix() {
+ void test_missing_metadata_suffix() {
Source source = addSource('''
-// ignore: invalid_assignment
+// ignore invalid_assignment
String y = 3; //INVALID_ASSIGNMENT
''');
computeLibrarySourceErrors(source);
@@ -91,7 +91,7 @@
void test_multiple_comments() {
Source source = addSource('''
int x = ''; //This is the first comment...
-//# ignore: const_initialized_with_non_constant_value
+// ignore: const_initialized_with_non_constant_value
const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
computeLibrarySourceErrors(source);
@@ -101,7 +101,7 @@
void test_multiple_ignores() {
Source source = addSource('''
int x = 3;
-//# ignore: invalid_assignment, const_initialized_with_non_constant_value
+// ignore: invalid_assignment, const_initialized_with_non_constant_value
const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
computeLibrarySourceErrors(source);
@@ -111,7 +111,7 @@
void test_multiple_ignores_whitespace_variant_1() {
Source source = addSource('''
int x = 3;
-//#ignore:invalid_assignment,const_initialized_with_non_constant_value
+//ignore:invalid_assignment,const_initialized_with_non_constant_value
const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
computeLibrarySourceErrors(source);
@@ -121,7 +121,7 @@
void test_multiple_ignores_whitespace_variant_2() {
Source source = addSource('''
int x = 3;
-//#ignore: invalid_assignment,const_initialized_with_non_constant_value
+//ignore: invalid_assignment,const_initialized_with_non_constant_value
const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
computeLibrarySourceErrors(source);
@@ -131,7 +131,7 @@
void test_multiple_ignores_whitespace_variant_3() {
Source source = addSource('''
int x = 3;
-//# ignore: invalid_assignment,const_initialized_with_non_constant_value
+// ignore: invalid_assignment,const_initialized_with_non_constant_value
const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
''');
computeLibrarySourceErrors(source);
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 710be9b..19a2a89 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4016,6 +4016,33 @@
expect(metadata[0].name.name, "override");
}
+ void test_missingSemicolon_varialeDeclarationList() {
+ void verify(CompilationUnitMember member, String expectedTypeName,
+ String expectedName, String expectedSemicolon) {
+ expect(member, new isInstanceOf<TopLevelVariableDeclaration>());
+ TopLevelVariableDeclaration declaration = member;
+ VariableDeclarationList variableList = declaration.variables;
+ expect(variableList, isNotNull);
+ NodeList<VariableDeclaration> variables = variableList.variables;
+ expect(variables, hasLength(1));
+ VariableDeclaration variable = variables[0];
+ expect(variableList.type.toString(), expectedTypeName);
+ expect(variable.name.name, expectedName);
+ expect(declaration.semicolon.lexeme, expectedSemicolon);
+ }
+
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+ 'String n x = "";', [
+ ParserErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
+ ]);
+ expect(unit, isNotNull);
+ NodeList<CompilationUnitMember> declarations = unit.declarations;
+ expect(declarations, hasLength(2));
+ verify(declarations[0], 'String', 'n', '');
+ verify(declarations[1], 'null', 'x', ';');
+ }
+
void test_multiplicativeExpression_missing_LHS() {
BinaryExpression expression =
parseExpression("* y", [ParserErrorCode.MISSING_IDENTIFIER]);
@@ -4222,6 +4249,24 @@
@reflectiveTest
class ResolutionCopierTest extends EngineTestCase {
+ void test_visitAdjacentStrings() {
+ AdjacentStrings createNode() => new AdjacentStrings([
+ new SimpleStringLiteral(null, 'hello'),
+ new SimpleStringLiteral(null, 'world')
+ ]);
+
+ AdjacentStrings fromNode = createNode();
+ DartType propagatedType = ElementFactory.classElement2("A").type;
+ fromNode.propagatedType = propagatedType;
+ DartType staticType = ElementFactory.classElement2("B").type;
+ fromNode.staticType = staticType;
+
+ AdjacentStrings toNode = createNode();
+ ResolutionCopier.copyResolutionData(fromNode, toNode);
+ expect(toNode.propagatedType, same(propagatedType));
+ expect(toNode.staticType, same(staticType));
+ }
+
void test_visitAnnotation() {
String annotationName = "proxy";
Annotation fromNode =
@@ -4429,20 +4474,16 @@
MethodElement propagatedElement = ElementFactory.methodElement(
"m", ElementFactory.classElement2("C").type);
fromNode.propagatedElement = propagatedElement;
- DartType propagatedType = ElementFactory.classElement2("C").type;
- fromNode.propagatedType = propagatedType;
MethodElement staticElement = ElementFactory.methodElement(
"m", ElementFactory.classElement2("C").type);
fromNode.staticElement = staticElement;
- DartType staticType = ElementFactory.classElement2("C").type;
- fromNode.staticType = staticType;
FunctionExpressionInvocation toNode =
AstFactory.functionExpressionInvocation(AstFactory.identifier3("f"));
- ResolutionCopier.copyResolutionData(fromNode, toNode);
+
+ _copyAndVerifyInvocation(fromNode, toNode);
+
expect(toNode.propagatedElement, same(propagatedElement));
- expect(toNode.propagatedType, same(propagatedType));
expect(toNode.staticElement, same(staticElement));
- expect(toNode.staticType, same(staticType));
}
void test_visitImportDirective() {
@@ -4564,14 +4605,8 @@
void test_visitMethodInvocation() {
MethodInvocation fromNode = AstFactory.methodInvocation2("m");
- DartType propagatedType = ElementFactory.classElement2("C").type;
- fromNode.propagatedType = propagatedType;
- DartType staticType = ElementFactory.classElement2("C").type;
- fromNode.staticType = staticType;
MethodInvocation toNode = AstFactory.methodInvocation2("m");
- ResolutionCopier.copyResolutionData(fromNode, toNode);
- expect(toNode.propagatedType, same(propagatedType));
- expect(toNode.staticType, same(staticType));
+ _copyAndVerifyInvocation(fromNode, toNode);
}
void test_visitNamedExpression() {
@@ -4848,6 +4883,25 @@
ResolutionCopier.copyResolutionData(fromNode, toNode);
expect(toNode.type, same(type));
}
+
+ void _copyAndVerifyInvocation(
+ InvocationExpression fromNode, InvocationExpression toNode) {
+ DartType propagatedType = ElementFactory.classElement2("C").type;
+ fromNode.propagatedType = propagatedType;
+ DartType staticType = ElementFactory.classElement2("C").type;
+ fromNode.staticType = staticType;
+
+ DartType propagatedInvokeType = ElementFactory.classElement2("C").type;
+ fromNode.propagatedInvokeType = propagatedInvokeType;
+ DartType staticInvokeType = ElementFactory.classElement2("C").type;
+ fromNode.staticInvokeType = staticInvokeType;
+
+ ResolutionCopier.copyResolutionData(fromNode, toNode);
+ expect(toNode.propagatedType, same(propagatedType));
+ expect(toNode.staticType, same(staticType));
+ expect(toNode.propagatedInvokeType, same(propagatedInvokeType));
+ expect(toNode.staticInvokeType, same(staticInvokeType));
+ }
}
/**
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 339d4d1..41d96a5 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -12,6 +12,8 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/ast/ast.dart'
+ show SimpleIdentifierImpl, PrefixedIdentifierImpl;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
@@ -33,6 +35,7 @@
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/string_source.dart';
import 'package:unittest/unittest.dart';
import '../reflective_tests.dart';
@@ -100,6 +103,12 @@
return initContextWithCore(context);
}
+ static InternalAnalysisContext contextWithCoreAndPackages(
+ Map<String, String> packages) {
+ AnalysisContextForTests context = new AnalysisContextForTests();
+ return initContextWithCore(context, new TestPackageUriResolver(packages));
+ }
+
/**
* Initialize the given analysis context with a fake core library already resolved.
*
@@ -107,12 +116,19 @@
* @return the analysis context that was created
*/
static InternalAnalysisContext initContextWithCore(
- InternalAnalysisContext context) {
+ InternalAnalysisContext context,
+ [UriResolver contributedResolver]) {
DirectoryBasedDartSdk sdk = new _AnalysisContextFactory_initContextWithCore(
new JavaFile("/fake/sdk"),
enableAsync: context.analysisOptions.enableAsync);
- SourceFactory sourceFactory =
- new SourceFactory([new DartUriResolver(sdk), new FileUriResolver()]);
+ List<UriResolver> resolvers = <UriResolver>[
+ new DartUriResolver(sdk),
+ new FileUriResolver()
+ ];
+ if (contributedResolver != null) {
+ resolvers.add(contributedResolver);
+ }
+ SourceFactory sourceFactory = new SourceFactory(resolvers);
context.sourceFactory = sourceFactory;
AnalysisContext coreContext = sdk.context;
(coreContext.analysisOptions as AnalysisOptionsImpl).strongMode =
@@ -2467,6 +2483,21 @@
verify([source, source2, source3]);
}
+ @override
+ void reset() {
+ analysisContext2 = AnalysisContextFactory.contextWithCoreAndPackages({
+ 'package:meta/meta.dart': r'''
+library meta;
+
+const _Protected protected = const _Protected();
+
+class _Protected {
+ const _Protected();
+}
+'''
+ });
+ }
+
void test_argumentTypeNotAssignable_functionType() {
Source source = addSource(r'''
m() {
@@ -3303,6 +3334,241 @@
verify([source]);
}
+ void test_invalidUseOfProtectedMember_field() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ int a;
+}
+abstract class B implements A {
+ int b() => a;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_function() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(){ }
+}
+main() {
+ new A().a();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_getter() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ int get a => 42;
+}
+abstract class B implements A {
+ int b() => a;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_message() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(){ }
+}
+class B {
+ void b() => new A().a();
+}''');
+ List<AnalysisError> errors = analysisContext2.computeErrors(source);
+ expect(errors, hasLength(1));
+ expect(errors[0].message,
+ "The member 'a' can only be used within instance members of subclasses of 'A'");
+ }
+
+ void test_invalidUseOfProtectedMember_method_1() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(){ }
+}
+class B {
+ void b() => new A().a();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_method_2() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(){ }
+}
+abstract class B implements A {
+ void b() => a();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_OK_1() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(){ }
+}
+class B extends A {
+ void b() => a();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_OK_2() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(){ }
+}
+class B extends Object with A {
+ void b() => a();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_OK_3() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected m1() {}
+}
+class B extends A {
+ static m2(A a) => a.m1();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_OK_4() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(){ }
+}
+class B extends A {
+ void a() => a();
+}
+main() {
+ new B().a();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_OK_field() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ int a = 42;
+}
+class B extends A {
+ int b() => a;
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_OK_getter() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ int get a => 42;
+}
+class B extends A {
+ int b() => a;
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_OK_setter() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void set a(int i) { }
+}
+class B extends A {
+ void b(int i) {
+ a = i;
+ }
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, []);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_setter() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void set a(int i) { }
+}
+abstract class B implements A {
+ b(int i) {
+ a = i;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+ verify([source]);
+ }
+
+ void test_invalidUseOfProtectedMember_topLevelVariable() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+@protected
+int x = 0;
+main() {
+ print(x);
+}''');
+ computeLibrarySourceErrors(source);
+ // TODO(brianwilkerson) This should produce a hint because the annotation is
+ // being applied to the wrong kind of declaration.
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_isDouble() {
AnalysisOptionsImpl options = new AnalysisOptionsImpl();
options.dart2jsHint = true;
@@ -8006,6 +8272,7 @@
[List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
GatheringErrorListener errorListener = new GatheringErrorListener();
for (AnalysisError error in analysisContext2.computeErrors(source)) {
+ expect(error.source, source);
ErrorCode errorCode = error.errorCode;
if (!enableUnusedElement &&
(errorCode == HintCode.UNUSED_ELEMENT ||
@@ -8230,6 +8497,7 @@
@override
void setUp() {
+ ElementFactory.flushStaticState();
super.setUp();
reset();
}
@@ -14410,6 +14678,23 @@
}
}
+class TestPackageUriResolver extends UriResolver {
+ Map<Uri, Source> sourceMap = new HashMap<Uri, Source>();
+
+ TestPackageUriResolver(Map<String, String> map) {
+ map.forEach((String uri, String contents) {
+ sourceMap[Uri.parse(uri)] =
+ new StringSource(contents, '/test_pkg_source.dart');
+ });
+ }
+
+ @override
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) => sourceMap[uri];
+
+ @override
+ Uri restoreAbsolute(Source source) => throw new UnimplementedError();
+}
+
@reflectiveTest
class TypeOverrideManagerTest extends EngineTestCase {
void test_exitScope_noScopes() {
@@ -16792,6 +17077,30 @@
_listener.assertNoErrors();
}
+ void test_visitTypeName_noParameters_noArguments_undefined() {
+ SimpleIdentifier id = AstFactory.identifier3("unknown")
+ ..staticElement = new _StaleElement();
+ TypeName typeName = new TypeName(id, null);
+ _resolveNode(typeName, []);
+ expect(typeName.type, UndefinedTypeImpl.instance);
+ expect(typeName.name.staticElement, null);
+ _listener.assertErrorsWithCodes([StaticWarningCode.UNDEFINED_CLASS]);
+ }
+
+ void test_visitTypeName_prefixed_noParameters_noArguments_undefined() {
+ SimpleIdentifier prefix = AstFactory.identifier3("unknownPrefix")
+ ..staticElement = new _StaleElement();
+ SimpleIdentifier suffix = AstFactory.identifier3("unknownSuffix")
+ ..staticElement = new _StaleElement();
+ TypeName typeName =
+ new TypeName(AstFactory.identifier(prefix, suffix), null);
+ _resolveNode(typeName, []);
+ expect(typeName.type, UndefinedTypeImpl.instance);
+ expect(prefix.staticElement, null);
+ expect(suffix.staticElement, null);
+ _listener.assertErrorsWithCodes([StaticWarningCode.UNDEFINED_CLASS]);
+ }
+
void test_visitTypeName_parameters_arguments() {
ClassElement classA = ElementFactory.classElement2("A", ["E"]);
ClassElement classB = ElementFactory.classElement2("B");
@@ -16952,6 +17261,21 @@
}
/**
+ * Represents an element left over from a previous resolver run.
+ *
+ * A _StaleElement should always be replaced with either null or a new Element.
+ */
+class _StaleElement extends ElementImpl {
+ _StaleElement() : super("_StaleElement", -1);
+
+ @override
+ accept(_) => throw "_StaleElement shouldn't be visited";
+
+ @override
+ get kind => throw "_StaleElement's kind shouldn't be accessed";
+}
+
+/**
* Shared infrastructure for [StaticTypeAnalyzer2Test] and
* [StrongModeStaticTypeAnalyzer2Test].
*/
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 51f5fcd..239c42b 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -580,9 +580,7 @@
return new TimestampedData<String>(0, _contents);
}
- String get encoding {
- throw new UnsupportedOperationException();
- }
+ String get encoding => _name;
String get fullName {
return _name;
diff --git a/pkg/analyzer/test/src/abstract_single_unit.dart b/pkg/analyzer/test/src/abstract_single_unit.dart
new file mode 100644
index 0000000..48ba251
--- /dev/null
+++ b/pkg/analyzer/test/src/abstract_single_unit.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2014, 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 test.services.src.index.abstract_single_file;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:unittest/unittest.dart';
+
+import 'context/abstract_context.dart';
+
+class AbstractSingleUnitTest extends AbstractContextTest {
+ bool verifyNoTestUnitErrors = true;
+
+ String testCode;
+ String testFile = '/test.dart';
+ Source testSource;
+ CompilationUnit testUnit;
+ CompilationUnitElement testUnitElement;
+ LibraryElement testLibraryElement;
+
+ void addTestSource(String code, [Uri uri]) {
+ testCode = code;
+ testSource = addSource(testFile, code);
+ }
+
+ void assertNoErrorsInSource(Source source) {
+ List<AnalysisError> errors = context.getErrors(source).errors;
+ expect(errors, isEmpty);
+ }
+
+ Element findElement(String name, [ElementKind kind]) {
+ return findChildElement(testUnitElement, name, kind);
+ }
+
+ int findEnd(String search) {
+ return findOffset(search) + search.length;
+ }
+
+ /**
+ * Returns the [SimpleIdentifier] at the given search pattern.
+ */
+ SimpleIdentifier findIdentifier(String search) {
+ return findNodeAtString(search, (node) => node is SimpleIdentifier);
+ }
+
+ AstNode findNodeAtOffset(int offset, [Predicate<AstNode> predicate]) {
+ AstNode result = new NodeLocator(offset).searchWithin(testUnit);
+ if (result != null && predicate != null) {
+ result = result.getAncestor(predicate);
+ }
+ return result;
+ }
+
+ AstNode findNodeAtString(String search, [Predicate<AstNode> predicate]) {
+ int offset = findOffset(search);
+ return findNodeAtOffset(offset, predicate);
+ }
+
+ Element findNodeElementAtString(String search,
+ [Predicate<AstNode> predicate]) {
+ AstNode node = findNodeAtString(search, predicate);
+ if (node == null) {
+ return null;
+ }
+ return ElementLocator.locate(node);
+ }
+
+ int findOffset(String search) {
+ int offset = testCode.indexOf(search);
+ expect(offset, isNonNegative, reason: "Not found '$search' in\n$testCode");
+ return offset;
+ }
+
+ int getLeadingIdentifierLength(String search) {
+ int length = 0;
+ while (length < search.length) {
+ int c = search.codeUnitAt(length);
+ if (c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0)) {
+ length++;
+ continue;
+ }
+ if (c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0)) {
+ length++;
+ continue;
+ }
+ if (c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0)) {
+ length++;
+ continue;
+ }
+ break;
+ }
+ return length;
+ }
+
+ void resolveTestUnit(String code) {
+ addTestSource(code);
+ testUnit = resolveLibraryUnit(testSource);
+ if (verifyNoTestUnitErrors) {
+ assertNoErrorsInSource(testSource);
+ }
+ testUnitElement = testUnit.element;
+ testLibraryElement = testUnitElement.library;
+ }
+}
diff --git a/pkg/analyzer/test/src/context/abstract_context.dart b/pkg/analyzer/test/src/context/abstract_context.dart
index 18bde46..b0b7a01 100644
--- a/pkg/analyzer/test/src/context/abstract_context.dart
+++ b/pkg/analyzer/test/src/context/abstract_context.dart
@@ -4,7 +4,9 @@
library analyzer.test.src.context.abstract_context;
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/context/cache.dart';
@@ -20,6 +22,28 @@
import 'mock_sdk.dart';
+/**
+ * Finds an [Element] with the given [name].
+ */
+Element findChildElement(Element root, String name, [ElementKind kind]) {
+ Element result = null;
+ root.accept(new _ElementVisitorFunctionWrapper((Element element) {
+ if (element.name != name) {
+ return;
+ }
+ if (kind != null && element.kind != kind) {
+ return;
+ }
+ result = element;
+ }));
+ return result;
+}
+
+/**
+ * A function to be called for every [Element].
+ */
+typedef void _ElementVisitorFunction(Element element);
+
class AbstractContextTest {
MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
@@ -124,6 +148,10 @@
analysisDriver = context.driver;
}
+ CompilationUnit resolveLibraryUnit(Source source) {
+ return context.resolveCompilationUnit2(source, source);
+ }
+
void setUp() {
List<Plugin> plugins = <Plugin>[];
plugins.addAll(AnalysisEngine.instance.requiredPlugins);
@@ -138,3 +166,18 @@
void tearDown() {}
}
+
+/**
+ * Wraps the given [_ElementVisitorFunction] into an instance of
+ * [GeneralizingElementVisitor].
+ */
+class _ElementVisitorFunctionWrapper extends GeneralizingElementVisitor {
+ final _ElementVisitorFunction function;
+
+ _ElementVisitorFunctionWrapper(this.function);
+
+ visitElement(Element element) {
+ function(element);
+ super.visitElement(element);
+ }
+}
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index cbcfacf..d7e0a58 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -2548,7 +2548,7 @@
expect(unitA.element, same(unitElementA));
expect(unitElementA.library, same(libraryElementA));
}
- // Update a.dart, rename A to A2, invalidates b.dart, so
+ // Add method to a.dart. This invalidates b.dart, so
// we know that the previous update did not damage dependencies.
context.setContents(
sourceA,
@@ -2760,8 +2760,10 @@
}
void _assertInvalid(AnalysisTarget target, ResultDescriptor descriptor) {
- CacheState state = analysisCache.getState(target, descriptor);
- expect(state, CacheState.INVALID);
+ CacheState actual = analysisCache.getState(target, descriptor);
+ if (actual != CacheState.INVALID) {
+ fail("cache state of $target $descriptor: wanted INVALID, got: $actual");
+ }
}
void _assertValid(AnalysisTarget target, ResultDescriptor descriptor) {
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index 7d85c4f..5466949 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -36,7 +36,9 @@
const <String, String>{
'/lib/async/stream.dart': r'''
part of dart.async;
-class Stream<T> {}
+class Stream<T> {
+ Future<T> get first;
+}
abstract class StreamTransformer<S, T> {}
'''
});
@@ -112,6 +114,7 @@
num operator *(num other);
num operator /(num other);
int toInt();
+ double toDouble();
num abs();
int round();
}
@@ -140,6 +143,7 @@
abstract class Iterable<E> {
Iterator<E> get iterator;
bool get isEmpty;
+ E get first;
Iterable/*<R>*/ map/*<R>*/(/*=R*/ f(E e));
diff --git a/pkg/analyzer/test/src/summary/flat_buffers_test.dart b/pkg/analyzer/test/src/summary/flat_buffers_test.dart
index 361973b..076df23 100644
--- a/pkg/analyzer/test/src/summary/flat_buffers_test.dart
+++ b/pkg/analyzer/test/src/summary/flat_buffers_test.dart
@@ -55,6 +55,34 @@
}, throwsStateError);
}
+ void test_file_identifier() {
+ Uint8List byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ builder.startTable();
+ Offset offset = builder.endTable();
+ byteList = builder.finish(offset, 'Az~ÿ');
+ }
+ // Convert byteList to a ByteData so that we can read data from it.
+ ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
+ // First 4 bytes are an offset to the table data.
+ int tableDataLoc = byteData.getUint32(0, Endianness.LITTLE_ENDIAN);
+ // Next 4 bytes are the file identifier.
+ expect(byteData.getUint8(4), 65); // 'a'
+ expect(byteData.getUint8(5), 122); // 'z'
+ expect(byteData.getUint8(6), 126); // '~'
+ expect(byteData.getUint8(7), 255); // 'ÿ'
+ // First 4 bytes of the table data are a backwards offset to the vtable.
+ int vTableLoc = tableDataLoc -
+ byteData.getInt32(tableDataLoc, Endianness.LITTLE_ENDIAN);
+ // First 2 bytes of the vtable are the size of the vtable in bytes, which
+ // should be 4.
+ expect(byteData.getUint16(vTableLoc, Endianness.LITTLE_ENDIAN), 4);
+ // Next 2 bytes are the size of the object in bytes (including the vtable
+ // pointer), which should be 4.
+ expect(byteData.getUint16(vTableLoc + 2, Endianness.LITTLE_ENDIAN), 4);
+ }
+
void test_low() {
Builder builder = new Builder(initialSize: 0);
builder.lowReset();
@@ -164,6 +192,47 @@
expect(items, orderedEquals(values));
}
+ void test_writeList_ofBool() {
+ void verifyListBooleans(int len, List<int> trueBits) {
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ List<bool> values = new List<bool>.filled(len, false);
+ for (int bit in trueBits) {
+ values[bit] = true;
+ }
+ Offset offset = builder.writeListBool(values);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferPointer root = new BufferPointer.fromBytes(byteList);
+ List<bool> items = const BoolListReader().read(root);
+ expect(items, hasLength(len));
+ for (int i = 0; i < items.length; i++) {
+ expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
+ }
+ }
+ verifyListBooleans(0, <int>[]);
+ verifyListBooleans(1, <int>[]);
+ verifyListBooleans(1, <int>[0]);
+ verifyListBooleans(31, <int>[0, 1]);
+ verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
+ verifyListBooleans(31, <int>[0, 30]);
+ verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
+ verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
+ verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
+ verifyListBooleans(63, <int>[]);
+ verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
+ verifyListBooleans(63, new List<int>.generate(63, (i) => i));
+ verifyListBooleans(64, <int>[]);
+ verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
+ verifyListBooleans(64, <int>[1, 2, 62]);
+ verifyListBooleans(64, <int>[0, 1, 2, 63]);
+ verifyListBooleans(64, new List<int>.generate(64, (i) => i));
+ verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
+ }
+
void test_writeList_ofFloat64() {
List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
// write
diff --git a/pkg/analyzer/test/src/summary/index_unit_test.dart b/pkg/analyzer/test/src/summary/index_unit_test.dart
new file mode 100644
index 0000000..bfa331f
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/index_unit_test.dart
@@ -0,0 +1,936 @@
+// 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 'dart:convert';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/index_unit.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import '../abstract_single_unit.dart';
+
+main() {
+ groupSep = ' | ';
+ runReflectiveTests(PackageIndexAssemblerTest);
+}
+
+class ExpectedLocation {
+ final CompilationUnitElement unitElement;
+ final int offset;
+ final int length;
+ final bool isQualified;
+
+ ExpectedLocation(
+ this.unitElement, this.offset, this.length, this.isQualified);
+
+ @override
+ String toString() {
+ return '(unit=$unitElement; offset=$offset; length=$length;'
+ ' isQualified=$isQualified)';
+ }
+}
+
+@reflectiveTest
+class PackageIndexAssemblerTest extends AbstractSingleUnitTest {
+ PackageIndex packageIndex;
+ UnitIndex unitIndex;
+
+ _ElementIndexAssert assertThat(Element element) {
+ return new _ElementIndexAssert(this, element);
+ }
+
+ _NameIndexAssert assertThatName(String name) {
+ return new _NameIndexAssert(this, name);
+ }
+
+ CompilationUnitElement importedUnit({int index: 0}) {
+ List<ImportElement> imports = testLibraryElement.imports;
+ return imports[index].importedLibrary.definingCompilationUnit;
+ }
+
+ void test_definedName_classMember_field() {
+ _indexTestUnit('''
+class A {
+ int f;
+}''');
+ _assertDefinedName('f', IndexNameKind.classMember, 'f;');
+ }
+
+ void test_definedName_classMember_getter() {
+ _indexTestUnit('''
+class A {
+ int get g => 0;
+}''');
+ _assertDefinedName('g', IndexNameKind.classMember, 'g => 0;');
+ }
+
+ void test_definedName_classMember_method() {
+ _indexTestUnit('''
+class A {
+ m() {}
+}''');
+ _assertDefinedName('m', IndexNameKind.classMember, 'm() {}');
+ }
+
+ void test_definedName_classMember_operator() {
+ _indexTestUnit('''
+class A {
+ operator +(o) {}
+}''');
+ _assertDefinedName('+', IndexNameKind.classMember, '+(o) {}');
+ }
+
+ void test_definedName_classMember_setter() {
+ _indexTestUnit('''
+class A {
+ int set s (_) {}
+}''');
+ _assertDefinedName('s', IndexNameKind.classMember, 's (_) {}');
+ }
+
+ void test_definedName_topLevel_class() {
+ _indexTestUnit('class A {}');
+ _assertDefinedName('A', IndexNameKind.topLevel, 'A {}');
+ }
+
+ void test_definedName_topLevel_classAlias() {
+ _indexTestUnit('''
+class M {}
+class C = Object with M;''');
+ _assertDefinedName('C', IndexNameKind.topLevel, 'C =');
+ }
+
+ void test_definedName_topLevel_enum() {
+ _indexTestUnit('enum E {a, b, c}');
+ _assertDefinedName('E', IndexNameKind.topLevel, 'E {');
+ }
+
+ void test_definedName_topLevel_function() {
+ _indexTestUnit('foo() {}');
+ _assertDefinedName('foo', IndexNameKind.topLevel, 'foo() {}');
+ }
+
+ void test_definedName_topLevel_functionTypeAlias() {
+ _indexTestUnit('typedef F(int p);');
+ _assertDefinedName('F', IndexNameKind.topLevel, 'F(int p);');
+ }
+
+ void test_definedName_topLevel_getter() {
+ _indexTestUnit('''
+int get g => 0;
+''');
+ _assertDefinedName('g', IndexNameKind.topLevel, 'g => 0;');
+ }
+
+ void test_definedName_topLevel_setter() {
+ _indexTestUnit('''
+int set s (_) {}
+''');
+ _assertDefinedName('s', IndexNameKind.topLevel, 's (_) {}');
+ }
+
+ void test_definedName_topLevel_topLevelVariable() {
+ _indexTestUnit('var V = 42;');
+ _assertDefinedName('V', IndexNameKind.topLevel, 'V = 42;');
+ }
+
+ void test_isExtendedBy_ClassDeclaration() {
+ _indexTestUnit('''
+class A {} // 1
+class B extends A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isExtendedAt('A {} // 2', true)
+ ..isReferencedAt('A {} // 2', true);
+ }
+
+ void test_isExtendedBy_ClassDeclaration_isQualified() {
+ addSource(
+ '/lib.dart',
+ '''
+class A {}
+''');
+ _indexTestUnit('''
+import 'lib.dart' as p;
+class B extends p.A {} // 2
+''');
+ ClassElement elementA = importedUnit().getType('A');
+ assertThat(elementA).isExtendedAt('A {} // 2', true);
+ }
+
+ void test_isExtendedBy_ClassDeclaration_Object() {
+ _indexTestUnit('''
+class A {}
+''');
+ ClassElement elementA = findElement('A');
+ ClassElement elementObject = elementA.supertype.element;
+ assertThat(elementObject).isExtendedAt('A {}', true, length: 0);
+ }
+
+ void test_isExtendedBy_ClassTypeAlias() {
+ _indexTestUnit('''
+class A {}
+class B {}
+class C = A with B;
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isExtendedAt('A with', true)
+ ..isReferencedAt('A with', true);
+ }
+
+ void test_isImplementedBy_ClassDeclaration() {
+ _indexTestUnit('''
+class A {} // 1
+class B implements A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isImplementedAt('A {} // 2', true)
+ ..isReferencedAt('A {} // 2', true);
+ }
+
+ void test_isImplementedBy_ClassDeclaration_isQualified() {
+ addSource(
+ '/lib.dart',
+ '''
+class A {}
+''');
+ _indexTestUnit('''
+import 'lib.dart' as p;
+class B implements p.A {} // 2
+''');
+ ClassElement elementA = importedUnit().getType('A');
+ assertThat(elementA)
+ ..isImplementedAt('A {} // 2', true)
+ ..isReferencedAt('A {} // 2', true);
+ }
+
+ void test_isImplementedBy_ClassTypeAlias() {
+ _indexTestUnit('''
+class A {} // 1
+class B {} // 2
+class C = Object with A implements B; // 3
+''');
+ ClassElement elementB = findElement('B');
+ assertThat(elementB)
+ ..isImplementedAt('B; // 3', true)
+ ..isReferencedAt('B; // 3', true);
+ }
+
+ void test_isInvokedBy_FieldElement() {
+ _indexTestUnit('''
+class A {
+ var field;
+ main() {
+ this.field(); // q
+ field(); // nq
+ }
+}''');
+ FieldElement field = findElement('field');
+ assertThat(field.getter)
+ ..isInvokedAt('field(); // q', true)
+ ..isInvokedAt('field(); // nq', false);
+ }
+
+ void test_isInvokedBy_FunctionElement() {
+ addSource(
+ '/lib.dart',
+ '''
+library lib;
+foo() {}
+''');
+ _indexTestUnit('''
+import 'lib.dart';
+import 'lib.dart' as pref;
+main() {
+ pref.foo(); // q
+ foo(); // nq
+}''');
+ FunctionElement element = importedUnit().functions[0];
+ assertThat(element)
+ ..isInvokedAt('foo(); // q', true)
+ ..isInvokedAt('foo(); // nq', false);
+ }
+
+ void test_isInvokedBy_MethodElement() {
+ _indexTestUnit('''
+class A {
+ foo() {}
+ main() {
+ this.foo(); // q
+ foo(); // nq
+ }
+}''');
+ Element element = findElement('foo');
+ assertThat(element)
+ ..isInvokedAt('foo(); // q', true)
+ ..isInvokedAt('foo(); // nq', false);
+ }
+
+ void test_isInvokedBy_MethodElement_propagatedType() {
+ _indexTestUnit('''
+class A {
+ foo() {}
+}
+main() {
+ var a = new A();
+ a.foo();
+}
+''');
+ Element element = findElement('foo');
+ assertThat(element).isInvokedAt('foo();', true);
+ }
+
+ void test_isInvokedBy_operator_binary() {
+ _indexTestUnit('''
+class A {
+ operator +(other) => this;
+}
+main(A a) {
+ print(a + 1);
+ a += 2;
+ ++a;
+ a++;
+}
+''');
+ MethodElement element = findElement('+');
+ assertThat(element)
+ ..isInvokedAt('+ 1', true, length: 1)
+ ..isInvokedAt('+= 2', true, length: 2)
+ ..isInvokedAt('++a', true, length: 2)
+ ..isInvokedAt('++;', true, length: 2);
+ }
+
+ void test_isInvokedBy_operator_index() {
+ _indexTestUnit('''
+class A {
+ operator [](i) => null;
+ operator []=(i, v) {}
+}
+main(A a) {
+ print(a[0]);
+ a[1] = 42;
+}
+''');
+ MethodElement readElement = findElement('[]');
+ MethodElement writeElement = findElement('[]=');
+ assertThat(readElement).isInvokedAt('[0]', true, length: 1);
+ assertThat(writeElement).isInvokedAt('[1]', true, length: 1);
+ }
+
+ void test_isInvokedBy_operator_prefix() {
+ _indexTestUnit('''
+class A {
+ A operator ~() => this;
+}
+main(A a) {
+ print(~a);
+}
+''');
+ MethodElement element = findElement('~');
+ assertThat(element).isInvokedAt('~a', true, length: 1);
+ }
+
+ void test_isMixedInBy_ClassDeclaration() {
+ _indexTestUnit('''
+class A {} // 1
+class B extends Object with A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isMixedInAt('A {} // 2', true)
+ ..isReferencedAt('A {} // 2', true);
+ }
+
+ void test_isMixedInBy_ClassDeclaration_isQualified() {
+ addSource(
+ '/lib.dart',
+ '''
+class A {}
+''');
+ _indexTestUnit('''
+import 'lib.dart' as p;
+class B extends Object with p.A {} // 2
+''');
+ ClassElement elementA = importedUnit().getType('A');
+ assertThat(elementA).isMixedInAt('A {} // 2', true);
+ }
+
+ void test_isMixedInBy_ClassTypeAlias() {
+ _indexTestUnit('''
+class A {} // 1
+class B = Object with A; // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA).isMixedInAt('A; // 2', true);
+ }
+
+ void test_isReferencedBy_ClassElement() {
+ _indexTestUnit('''
+class A {
+ static var field;
+}
+main(A p) {
+ A v;
+ new A(); // 2
+ A.field = 1;
+ print(A.field); // 3
+}
+''');
+ ClassElement element = findElement('A');
+ assertThat(element)
+ ..isReferencedAt('A p) {', false)
+ ..isReferencedAt('A v;', false)
+ ..isReferencedAt('A(); // 2', false)
+ ..isReferencedAt('A.field = 1;', false)
+ ..isReferencedAt('A.field); // 3', false);
+ }
+
+ void test_isReferencedBy_ClassElement_invocation() {
+ verifyNoTestUnitErrors = false;
+ _indexTestUnit('''
+class A {}
+main() {
+ A(); // invalid code, but still a reference
+}''');
+ Element element = findElement('A');
+ assertThat(element).isReferencedAt('A();', false);
+ }
+
+ void test_isReferencedBy_ClassElement_invocation_isQualified() {
+ verifyNoTestUnitErrors = false;
+ addSource(
+ '/lib.dart',
+ '''
+class A {}
+''');
+ _indexTestUnit('''
+import 'lib.dart' as p;
+main() {
+ p.A(); // invalid code, but still a reference
+}''');
+ Element element = importedUnit().getType('A');
+ assertThat(element).isReferencedAt('A();', true);
+ }
+
+ void test_isReferencedBy_ClassTypeAlias() {
+ _indexTestUnit('''
+class A {}
+class B = Object with A;
+main(B p) {
+ B v;
+}
+''');
+ ClassElement element = findElement('B');
+ assertThat(element)
+ ..isReferencedAt('B p) {', false)
+ ..isReferencedAt('B v;', false);
+ }
+
+ void test_isReferencedBy_CompilationUnitElement_export() {
+ addSource(
+ '/lib.dart',
+ '''
+library lib;
+''');
+ _indexTestUnit('''
+export 'lib.dart';
+''');
+ LibraryElement element = testLibraryElement.exports[0].exportedLibrary;
+ assertThat(element)..isReferencedAt("'lib.dart'", true, length: 10);
+ }
+
+ void test_isReferencedBy_CompilationUnitElement_import() {
+ addSource(
+ '/lib.dart',
+ '''
+library lib;
+''');
+ _indexTestUnit('''
+import 'lib.dart';
+''');
+ LibraryElement element = testLibraryElement.imports[0].importedLibrary;
+ assertThat(element)..isReferencedAt("'lib.dart'", true, length: 10);
+ }
+
+ void test_isReferencedBy_CompilationUnitElement_part() {
+ addSource('/my_unit.dart', 'part of my_lib;');
+ _indexTestUnit('''
+library my_lib;
+part 'my_unit.dart';
+''');
+ CompilationUnitElement element = testLibraryElement.parts[0];
+ assertThat(element)..isReferencedAt("'my_unit.dart';", true, length: 14);
+ }
+
+ void test_isReferencedBy_ConstructorElement() {
+ _indexTestUnit('''
+class A implements B {
+ A() {}
+ A.foo() {}
+}
+class B extends A {
+ B() : super(); // 1
+ B.foo() : super.foo(); // 2
+ factory B.bar() = A.foo; // 3
+}
+main() {
+ new A(); // 4
+ new A.foo(); // 5
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_foo = classA.constructors[1];
+ // A()
+ assertThat(constA)
+ ..isReferencedAt('(); // 1', true, length: 0)
+ ..isReferencedAt('(); // 4', true, length: 0);
+ // A.foo()
+ assertThat(constA_foo)
+ ..isReferencedAt('.foo(); // 2', true, length: 4)
+ ..isReferencedAt('.foo; // 3', true, length: 4)
+ ..isReferencedAt('.foo(); // 5', true, length: 4);
+ }
+
+ void test_isReferencedBy_ConstructorElement_classTypeAlias() {
+ _indexTestUnit('''
+class M {}
+class A implements B {
+ A() {}
+ A.named() {}
+}
+class B = A with M;
+class C = B with M;
+main() {
+ new B(); // B1
+ new B.named(); // B2
+ new C(); // C1
+ new C.named(); // C2
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_named = classA.constructors[1];
+ assertThat(constA)
+ ..isReferencedAt('(); // B1', true, length: 0)
+ ..isReferencedAt('(); // C1', true, length: 0);
+ assertThat(constA_named)
+ ..isReferencedAt('.named(); // B2', true, length: 6)
+ ..isReferencedAt('.named(); // C2', true, length: 6);
+ }
+
+ void test_isReferencedBy_ConstructorElement_classTypeAlias_cycle() {
+ _indexTestUnit('''
+class M {}
+class A = B with M;
+class B = A with M;
+main() {
+ new A();
+ new B();
+}
+''');
+ // No additional validation, but it should not fail with stack overflow.
+ }
+
+ void test_isReferencedBy_ConstructorElement_redirection() {
+ _indexTestUnit('''
+class A {
+ A() : this.bar(); // 1
+ A.foo() : this(); // 2
+ A.bar();
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_bar = classA.constructors[2];
+ assertThat(constA).isReferencedAt('(); // 2', true, length: 0);
+ assertThat(constA_bar).isReferencedAt('.bar(); // 1', true, length: 4);
+ }
+
+ void test_isReferencedBy_ConstructorFieldInitializer() {
+ _indexTestUnit('''
+class A {
+ int field;
+ A() : field = 5;
+}
+''');
+ FieldElement element = findElement('field');
+ assertThat(element).isReferencedAt('field = 5', true);
+ }
+
+ void test_isReferencedBy_FieldElement() {
+ _indexTestUnit('''
+class A {
+ var field;
+ A({this.field});
+ m() {
+ field = 1; // nq
+ print(field); // nq
+ }
+}
+main(A a) {
+ a.field = 2; // q
+ print(a.field); // q
+ new A(field: 3);
+}
+''');
+ FieldElement field = findElement('field');
+ PropertyAccessorElement getter = field.getter;
+ PropertyAccessorElement setter = field.setter;
+ // A()
+ assertThat(field)..isReferencedAt('field});', true);
+ // m()
+ assertThat(setter)..isReferencedAt('field = 1; // nq', false);
+ assertThat(getter)..isReferencedAt('field); // nq', false);
+ // main()
+ assertThat(setter)..isReferencedAt('field = 2; // q', true);
+ assertThat(getter)..isReferencedAt('field); // q', true);
+ assertThat(field)..isReferencedAt('field: 3', true);
+ }
+
+ void test_isReferencedBy_FunctionElement() {
+ _indexTestUnit('''
+foo() {}
+main() {
+ print(foo);
+ print(foo());
+}
+''');
+ FunctionElement element = findElement('foo');
+ assertThat(element)
+ ..isReferencedAt('foo);', false)
+ ..isInvokedAt('foo());', false);
+ }
+
+ void test_isReferencedBy_FunctionTypeAliasElement() {
+ _indexTestUnit('''
+typedef A();
+main(A p) {
+}
+''');
+ Element element = findElement('A');
+ assertThat(element)..isReferencedAt('A p) {', false);
+ }
+
+ /**
+ * There was a bug in the AST structure, when single [Comment] was cloned and
+ * assigned to both [FieldDeclaration] and [VariableDeclaration].
+ *
+ * This caused duplicate indexing.
+ * Here we test that the problem is fixed one way or another.
+ */
+ void test_isReferencedBy_identifierInComment() {
+ _indexTestUnit('''
+class A {}
+/// [A] text
+var myVariable = null;
+''');
+ Element element = findElement('A');
+ assertThat(element)..isReferencedAt('A] text', false);
+ }
+
+ void test_isReferencedBy_MethodElement() {
+ _indexTestUnit('''
+class A {
+ method() {}
+ main() {
+ print(this.method); // q
+ print(method); // nq
+ }
+}''');
+ MethodElement element = findElement('method');
+ assertThat(element)
+ ..isReferencedAt('method); // q', true)
+ ..isReferencedAt('method); // nq', false);
+ }
+
+ void test_isReferencedBy_ParameterElement() {
+ _indexTestUnit('''
+foo({var p}) {}
+main() {
+ foo(p: 1);
+}
+''');
+ Element element = findElement('p');
+ assertThat(element)..isReferencedAt('p: 1', true);
+ }
+
+ void test_isReferencedBy_TopLevelVariableElement() {
+ addSource(
+ '/lib.dart',
+ '''
+library lib;
+var V;
+''');
+ _indexTestUnit('''
+import 'lib.dart' show V; // imp
+import 'lib.dart' as pref;
+main() {
+ pref.V = 5; // q
+ print(pref.V); // q
+ V = 5; // nq
+ print(V); // nq
+}''');
+ TopLevelVariableElement variable = importedUnit().topLevelVariables[0];
+ assertThat(variable)..isReferencedAt('V; // imp', true);
+ assertThat(variable.getter)
+ ..isReferencedAt('V); // q', true)
+ ..isReferencedAt('V); // nq', false);
+ assertThat(variable.setter)
+ ..isReferencedAt('V = 5; // q', true)
+ ..isReferencedAt('V = 5; // nq', false);
+ }
+
+ void test_isReferencedBy_typeInVariableList() {
+ _indexTestUnit('''
+class A {}
+A myVariable = null;
+''');
+ Element element = findElement('A');
+ assertThat(element).isReferencedAt('A myVariable', false);
+ }
+
+ void test_usedName_isInvokedBy() {
+ verifyNoTestUnitErrors = false;
+ _indexTestUnit('''
+class C {
+ x() {}
+}
+main(C c) {
+ x(); // nq
+ c.x(); // q
+ y(); // nq
+ c.y(); // q
+}
+''');
+ assertThatName('x')
+ ..isNotInvokedAt('x(); // nq')
+ ..isNotInvokedAt('x(); // q');
+ assertThatName('y')
+ ..isNotInvokedAt('y(); // nq')
+ ..isInvokedAt('y(); // q');
+ }
+
+ void test_usedName_isReferencedBy() {
+ verifyNoTestUnitErrors = false;
+ _indexTestUnit('''
+class C {
+ int x;
+}
+main(C c) {
+ x; // nq
+ c.x; // q
+ y; // nq
+ c.y; // q
+}
+''');
+ assertThatName('x')
+ ..isNotReferencedAt('x; // nq')
+ ..isNotReferencedAt('x; // q');
+ assertThatName('y')
+ ..isNotReferencedAt('y; // nq')
+ ..isReferencedAt('y; // q');
+ }
+
+ void _assertDefinedName(String name, IndexNameKind kind, String search) {
+ int offset = findOffset(search);
+ int nameId = _getStringId(name);
+ for (int i = 0; i < unitIndex.definedNames.length; i++) {
+ if (unitIndex.definedNames[i] == nameId &&
+ unitIndex.definedNameKinds[i] == kind &&
+ unitIndex.definedNameOffsets[i] == offset) {
+ return;
+ }
+ }
+ _failWithIndexDump('Not found $name $kind at $offset');
+ }
+
+ /**
+ * Asserts that [unitIndex] has an item with the expected properties.
+ */
+ void _assertHasRelation(
+ Element element,
+ IndexRelationKind expectedRelationKind,
+ ExpectedLocation expectedLocation) {
+ int elementId = _findElementId(element);
+ for (int i = 0; i < unitIndex.usedElementOffsets.length; i++) {
+ if (unitIndex.usedElements[i] == elementId &&
+ unitIndex.usedElementKinds[i] == expectedRelationKind &&
+ unitIndex.usedElementOffsets[i] == expectedLocation.offset &&
+ unitIndex.usedElementLengths[i] == expectedLocation.length &&
+ unitIndex.usedElementIsQualifiedFlags[i] ==
+ expectedLocation.isQualified) {
+ return;
+ }
+ }
+ _failWithIndexDump(
+ 'not found\n$element $expectedRelationKind at $expectedLocation');
+ }
+
+ void _assertUsedName(String name, IndexRelationKind kind,
+ ExpectedLocation expectedLocation, bool isNot) {
+ int nameId = _getStringId(name);
+ for (int i = 0; i < unitIndex.usedNames.length; i++) {
+ if (unitIndex.usedNames[i] == nameId &&
+ unitIndex.usedNameKinds[i] == kind &&
+ unitIndex.usedNameOffsets[i] == expectedLocation.offset) {
+ if (isNot) {
+ _failWithIndexDump('Unexpected $name $kind at $expectedLocation');
+ }
+ return;
+ }
+ }
+ if (isNot) {
+ return;
+ }
+ _failWithIndexDump('Not found $name $kind at $expectedLocation');
+ }
+
+ ExpectedLocation _expectedLocation(String search, bool isQualified,
+ {int length}) {
+ int offset = findOffset(search);
+ if (length == null) {
+ length = getLeadingIdentifierLength(search);
+ }
+ return new ExpectedLocation(testUnitElement, offset, length, isQualified);
+ }
+
+ void _failWithIndexDump(String msg) {
+ String packageIndexJsonString =
+ new JsonEncoder.withIndent(' ').convert(packageIndex.toJson());
+ fail('$msg in\n' + packageIndexJsonString);
+ }
+
+ /**
+ * Return the [element] identifier in [packageIndex] or fail.
+ */
+ int _findElementId(Element element) {
+ int unitId = _getUnitId(element);
+ int offset = element.nameOffset;
+ if (element is LibraryElement || element is CompilationUnitElement) {
+ offset = 0;
+ }
+ IndexSyntheticElementKind kind =
+ PackageIndexAssembler.getIndexElementKind(element);
+ for (int elementId = 0;
+ elementId < packageIndex.elementUnits.length;
+ elementId++) {
+ if (packageIndex.elementUnits[elementId] == unitId &&
+ packageIndex.elementOffsets[elementId] == offset &&
+ packageIndex.elementKinds[elementId] == kind) {
+ return elementId;
+ }
+ }
+ _failWithIndexDump('Element $element is not referenced');
+ return 0;
+ }
+
+ int _getStringId(String str) {
+ int id = packageIndex.strings.indexOf(str);
+ expect(id, isNonNegative);
+ return id;
+ }
+
+ int _getUnitId(Element element) {
+ CompilationUnitElement unitElement =
+ PackageIndexAssembler.getUnitElement(element);
+ int libraryUriId = _getUriId(unitElement.library.source.uri);
+ int unitUriId = _getUriId(unitElement.source.uri);
+ expect(packageIndex.unitLibraryUris,
+ hasLength(packageIndex.unitUnitUris.length));
+ for (int i = 0; i < packageIndex.unitLibraryUris.length; i++) {
+ if (packageIndex.unitLibraryUris[i] == libraryUriId &&
+ packageIndex.unitUnitUris[i] == unitUriId) {
+ return i;
+ }
+ }
+ _failWithIndexDump('Unit $unitElement of $element is not referenced');
+ return -1;
+ }
+
+ int _getUriId(Uri uri) {
+ String str = uri.toString();
+ return _getStringId(str);
+ }
+
+ void _indexTestUnit(String code) {
+ resolveTestUnit(code);
+ PackageIndexAssembler assembler = new PackageIndexAssembler();
+ assembler.index(testUnit);
+ // assemble, write and read
+ PackageIndexBuilder indexBuilder = assembler.assemble();
+ List<int> indexBytes = indexBuilder.toBuffer();
+ packageIndex = new PackageIndex.fromBuffer(indexBytes);
+ // prepare the only unit index
+ expect(packageIndex.units, hasLength(1));
+ unitIndex = packageIndex.units[0];
+ expect(unitIndex.unit, _getUnitId(testUnitElement));
+ }
+}
+
+class _ElementIndexAssert {
+ final PackageIndexAssemblerTest test;
+ final Element element;
+
+ _ElementIndexAssert(this.test, this.element);
+
+ void isExtendedAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(element, IndexRelationKind.IS_EXTENDED_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isImplementedAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(element, IndexRelationKind.IS_IMPLEMENTED_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isInvokedAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(element, IndexRelationKind.IS_INVOKED_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isMixedInAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(element, IndexRelationKind.IS_MIXED_IN_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+
+ void isReferencedAt(String search, bool isQualified, {int length}) {
+ test._assertHasRelation(element, IndexRelationKind.IS_REFERENCED_BY,
+ test._expectedLocation(search, isQualified, length: length));
+ }
+}
+
+class _NameIndexAssert {
+ final PackageIndexAssemblerTest test;
+ final String name;
+
+ _NameIndexAssert(this.test, this.name);
+
+ void isInvokedAt(String search, {int length}) {
+ test._assertUsedName(name, IndexRelationKind.IS_INVOKED_BY,
+ test._expectedLocation(search, true, length: length), false);
+ }
+
+ void isNotInvokedAt(String search, {int length}) {
+ test._assertUsedName(name, IndexRelationKind.IS_INVOKED_BY,
+ test._expectedLocation(search, true, length: length), true);
+ }
+
+ void isNotReferencedAt(String search, {int length}) {
+ test._assertUsedName(name, IndexRelationKind.IS_REFERENCED_BY,
+ test._expectedLocation(search, true, length: length), true);
+ }
+
+ void isReferencedAt(String search, {int length}) {
+ test._assertUsedName(name, IndexRelationKind.IS_REFERENCED_BY,
+ test._expectedLocation(search, true, length: length), false);
+ }
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
index b6a9258..37c2f4a 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
@@ -18,5 +18,6 @@
@reflectiveTest
class ResynthStrongTest extends ResynthTest {
@override
- AnalysisOptionsImpl get options => super.options..strongMode = true;
+ AnalysisOptionsImpl createOptions() =>
+ super.createOptions()..strongMode = true;
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index 8b1e4dd..e163d04 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -42,7 +42,7 @@
/**
* Determine the analysis options that should be used for this test.
*/
- AnalysisOptionsImpl get options =>
+ AnalysisOptionsImpl createOptions() =>
new AnalysisOptionsImpl()..enableGenericMethods = true;
void addLibrary(String uri) {
@@ -119,6 +119,7 @@
original.loadLibraryFunction as ExecutableElementImpl,
'(loadLibraryFunction)');
}
+ expect(resynthesized.libraryCycle.toSet(), original.libraryCycle.toSet());
}
/**
@@ -233,6 +234,8 @@
'$desc.${original.methods[i].name}');
}
compareTypes(resynthesized.type, original.type, desc);
+ expect(resynthesized.hasBeenInferred, original.hasBeenInferred,
+ reason: desc);
}
void compareCompilationUnitElements(CompilationUnitElementImpl resynthesized,
@@ -642,14 +645,17 @@
}
}
- void compareExecutableElements(ExecutableElement resynthesized,
- ExecutableElement original, String desc) {
+ void compareExecutableElements(
+ ExecutableElement resynthesized, ExecutableElement original, String desc,
+ {bool shallow: false}) {
compareElements(resynthesized, original, desc);
compareParameterElementLists(
resynthesized.parameters, original.parameters, desc);
compareTypes(
resynthesized.returnType, original.returnType, '$desc return type');
- compareTypes(resynthesized.type, original.type, desc);
+ if (!shallow) {
+ compareTypes(resynthesized.type, original.type, desc);
+ }
expect(resynthesized.typeParameters.length, original.typeParameters.length);
for (int i = 0; i < resynthesized.typeParameters.length; i++) {
compareTypeParameterElements(
@@ -704,12 +710,13 @@
}
void compareFunctionElements(
- FunctionElement resynthesized, FunctionElement original, String desc) {
+ FunctionElement resynthesized, FunctionElement original, String desc,
+ {bool shallow: false}) {
if (original == null && resynthesized == null) {
return;
}
expect(resynthesized, isNotNull, reason: desc);
- compareExecutableElements(resynthesized, original, desc);
+ compareExecutableElements(resynthesized, original, desc, shallow: shallow);
checkPossibleLocalElements(resynthesized, original);
}
@@ -937,6 +944,15 @@
compareFunctionTypeAliasElements(
resynthesized.element, original.element, desc);
}
+ if (original.element.enclosingElement == null &&
+ original.element is FunctionElement) {
+ expect(resynthesized.element, new isInstanceOf<FunctionElement>());
+ expect(resynthesized.element.enclosingElement, isNull, reason: desc);
+ compareFunctionElements(
+ resynthesized.element, original.element, '$desc element',
+ shallow: true);
+ expect(resynthesized.element.type, same(resynthesized));
+ }
expect(resynthesized.typeArguments.length, original.typeArguments.length,
reason: desc);
for (int i = 0; i < resynthesized.typeArguments.length; i++) {
@@ -993,8 +1009,8 @@
VariableElementImpl resynthesizedActual =
getActualElement(resynthesized, desc);
VariableElementImpl originalActual = getActualElement(original, desc);
- compareFunctionElements(
- resynthesizedActual.initializer, originalActual.initializer, desc);
+ compareFunctionElements(resynthesizedActual.initializer,
+ originalActual.initializer, '$desc initializer');
if (originalActual is ConstVariableElement) {
Element oEnclosing = original.enclosingElement;
if (oEnclosing is ClassElement && oEnclosing.isEnum) {
@@ -1072,7 +1088,7 @@
analysisContext.sourceFactory,
unlinkedSummaries,
linkedSummaries,
- options.strongMode);
+ createOptions().strongMode);
}
fail_library_hasExtUri() {
@@ -1117,7 +1133,7 @@
@override
void setUp() {
super.setUp();
- resetWithOptions(options);
+ resetWithOptions(createOptions());
}
test_class_abstract() {
@@ -2498,6 +2514,11 @@
}
test_core() {
+ if (createOptions().strongMode) {
+ // The fake `dart:core` library is always in spec mode, so don't bother
+ // trying to check that it resynthesizes properly; it won't.
+ return;
+ }
String uri = 'dart:core';
LibraryElementImpl original =
resolve2(analysisContext2.sourceFactory.forUri(uri));
@@ -2756,12 +2777,12 @@
}
test_function_type_parameter() {
- resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+ resetWithOptions(createOptions()..enableGenericMethods = true);
checkLibrary('T f<T, U>(U u) => null;');
}
test_function_type_parameter_with_function_typed_parameter() {
- resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+ resetWithOptions(createOptions()..enableGenericMethods = true);
checkLibrary('void f<T, U>(T x(U u)) {}');
}
@@ -2770,7 +2791,7 @@
}
test_generic_gClass_gMethodStatic() {
- resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+ resetWithOptions(createOptions()..enableGenericMethods = true);
checkLibrary('''
class C<T, U> {
static void m<V, W>(V v, W w) {
@@ -2970,7 +2991,7 @@
}
test_inferred_function_type_in_generic_closure() {
- if (!options.strongMode) {
+ if (!createOptions().strongMode) {
// The test below uses generic comment syntax because proper generic
// method syntax doesn't support generic closures. So it can only run in
// strong mode.
@@ -2989,7 +3010,7 @@
}
test_inferred_generic_function_type_in_generic_closure() {
- if (!options.strongMode) {
+ if (!createOptions().strongMode) {
// The test below uses generic comment syntax because proper generic
// method syntax doesn't support generic closures. So it can only run in
// strong mode.
@@ -3445,17 +3466,17 @@
}
test_method_type_parameter() {
- resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+ resetWithOptions(createOptions()..enableGenericMethods = true);
checkLibrary('class C { T f<T, U>(U u) => null; }');
}
test_method_type_parameter_in_generic_class() {
- resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+ resetWithOptions(createOptions()..enableGenericMethods = true);
checkLibrary('class C<T, U> { V f<V, W>(T t, U u, W w) => null; }');
}
test_method_type_parameter_with_function_typed_parameter() {
- resetWithOptions(new AnalysisOptionsImpl()..enableGenericMethods = true);
+ resetWithOptions(createOptions()..enableGenericMethods = true);
checkLibrary('class C { void f<T, U>(T x(U u)) {} }');
}
@@ -3632,6 +3653,70 @@
checkLibrary('void set x(int value) {} set y(value) {}');
}
+ test_syntheticFunctionType_genericClosure() {
+ if (!createOptions().strongMode) {
+ // The test below uses generic comment syntax because proper generic
+ // method syntax doesn't support generic closures. So it can only run in
+ // strong mode.
+ // TODO(paulberry): once proper generic method syntax supports generic
+ // closures, rewrite the test below without using generic comment syntax,
+ // and remove this hack. See dartbug.com/25819
+ return;
+ }
+ checkLibrary('''
+final v = f() ? /*<T>*/(T t) => 0 : /*<T>*/(T t) => 1;
+bool f() => true;
+''');
+ }
+
+ test_syntheticFunctionType_genericClosure_inGenericFunction() {
+ if (!createOptions().strongMode) {
+ // The test below uses generic comment syntax because proper generic
+ // method syntax doesn't support generic closures. So it can only run in
+ // strong mode.
+ // TODO(paulberry): once proper generic method syntax supports generic
+ // closures, rewrite the test below without using generic comment syntax,
+ // and remove this hack. See dartbug.com/25819
+ return;
+ }
+ checkLibrary('''
+void f<T, U>(bool b) {
+ final v = b ? /*<V>*/(T t, U u, V v) => 0 : /*<V>*/(T t, U u, V v) => 1;
+}
+''');
+ }
+
+ test_syntheticFunctionType_inGenericClass() {
+ checkLibrary('''
+class C<T, U> {
+ var v = f() ? (T t, U u) => 0 : (T t, U u) => 1;
+}
+bool f() => false;
+''');
+ }
+
+ test_syntheticFunctionType_inGenericFunction() {
+ checkLibrary('''
+void f<T, U>(bool b) {
+ var v = b ? (T t, U u) => 0 : (T t, U u) => 1;
+}
+''');
+ }
+
+ test_syntheticFunctionType_noArguments() {
+ checkLibrary('''
+final v = f() ? () => 0 : () => 1;
+bool f() => true;
+''');
+ }
+
+ test_syntheticFunctionType_withArguments() {
+ checkLibrary('''
+final v = f() ? (int x, String y) => 0 : (int x, String y) => 1;
+bool f() => true;
+''');
+ }
+
test_type_arguments_explicit_dynamic_dynamic() {
checkLibrary('Map<dynamic, dynamic> m;');
}
@@ -3893,7 +3978,7 @@
}
test_variable_propagatedType_final_dep_inLib() {
- addNamedSource('/a.dart', 'final a = 1;');
+ addLibrarySource('/a.dart', 'final a = 1;');
checkLibrary('import "a.dart"; final b = a / 2;');
}
@@ -3908,8 +3993,8 @@
test_variable_propagatedType_implicit_dep() {
// The propagated type is defined in a library that is not imported.
- addNamedSource('/a.dart', 'class C {}');
- addNamedSource('/b.dart', 'import "a.dart"; C f() => null;');
+ addLibrarySource('/a.dart', 'class C {}');
+ addLibrarySource('/b.dart', 'import "a.dart"; C f() => null;');
checkLibrary('import "b.dart"; final x = f();');
}
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 6356d47..9427cd6 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -6525,6 +6525,130 @@
expect(unlinkedUnits[1].variables[0].propagatedTypeSlot, 1);
}
+ test_syntheticFunctionType_genericClosure() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ if (!strongMode) {
+ // The test below uses generic comment syntax because proper generic
+ // method syntax doesn't support generic closures. So it can only run in
+ // strong mode.
+ // TODO(paulberry): once proper generic method syntax supports generic
+ // closures, rewrite the test below without using generic comment syntax,
+ // and remove this hack. See dartbug.com/25819
+ return;
+ }
+ UnlinkedVariable variable = serializeVariableText('''
+final v = f() ? /*<T>*/(T t) => 0 : /*<T>*/(T t) => 1;
+bool f() => true;
+''');
+ // The inferred type of `v` is currently `(Object) -> int` due to
+ // dartbug.com/25802. TODO(paulberry): fix this test when the bug is fixed.
+ EntityRef inferredType = getTypeRefForSlot(variable.inferredTypeSlot);
+ checkLinkedTypeRef(
+ inferredType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+ expect(inferredType.syntheticParams, hasLength(1));
+ checkLinkedTypeRef(inferredType.syntheticParams[0].type, 'dart:core',
+ 'dart:core', 'Object');
+ }
+
+ test_syntheticFunctionType_genericClosure_inGenericFunction() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ if (!strongMode) {
+ // The test below uses generic comment syntax because proper generic
+ // method syntax doesn't support generic closures. So it can only run in
+ // strong mode.
+ // TODO(paulberry): once proper generic method syntax supports generic
+ // closures, rewrite the test below without using generic comment syntax,
+ // and remove this hack. See dartbug.com/25819
+ return;
+ }
+ UnlinkedVariable variable = serializeExecutableText('''
+void f<T, U>(bool b) {
+ final v = b ? /*<V>*/(T t, U u, V v) => 0 : /*<V>*/(T t, U u, V v) => 1;
+}
+''').localVariables[0];
+ // The inferred type of `v` is currently `(T, U, Object) -> int` due to
+ // dartbug.com/25802. TODO(paulberry): fix this test when the bug is fixed.
+ EntityRef inferredType = getTypeRefForSlot(variable.inferredTypeSlot);
+ checkLinkedTypeRef(
+ inferredType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+ expect(inferredType.syntheticParams, hasLength(3));
+ checkParamTypeRef(inferredType.syntheticParams[0].type, 2);
+ checkParamTypeRef(inferredType.syntheticParams[1].type, 1);
+ checkLinkedTypeRef(inferredType.syntheticParams[2].type, 'dart:core',
+ 'dart:core', 'Object');
+ }
+
+ test_syntheticFunctionType_inGenericClass() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedVariable variable = serializeClassText('''
+class C<T, U> {
+ var v = f() ? (T t, U u) => 0 : (T t, U u) => 1;
+}
+bool f() => false;
+''').fields[0];
+ EntityRef inferredType =
+ getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
+ checkLinkedTypeRef(
+ inferredType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+ checkParamTypeRef(inferredType.syntheticParams[0].type, 2);
+ checkParamTypeRef(inferredType.syntheticParams[1].type, 1);
+ }
+
+ test_syntheticFunctionType_inGenericFunction() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedVariable variable = serializeExecutableText('''
+void f<T, U>(bool b) {
+ var v = b ? (T t, U u) => 0 : (T t, U u) => 1;
+}
+''').localVariables[0];
+ EntityRef inferredType =
+ getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
+ checkLinkedTypeRef(
+ inferredType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+ checkParamTypeRef(inferredType.syntheticParams[0].type, 2);
+ checkParamTypeRef(inferredType.syntheticParams[1].type, 1);
+ }
+
+ test_syntheticFunctionType_noArguments() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedVariable variable = serializeVariableText('''
+final v = f() ? () => 0 : () => 1;
+bool f() => true;
+''');
+ EntityRef propagatedType = getTypeRefForSlot(variable.propagatedTypeSlot);
+ checkLinkedTypeRef(
+ propagatedType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+ expect(propagatedType.syntheticParams, isEmpty);
+ }
+
+ test_syntheticFunctionType_withArguments() {
+ if (skipFullyLinkedData) {
+ return;
+ }
+ UnlinkedVariable variable = serializeVariableText('''
+final v = f() ? (int x, String y) => 0 : (int x, String y) => 1;
+bool f() => true;
+''');
+ EntityRef propagatedType = getTypeRefForSlot(variable.propagatedTypeSlot);
+ checkTypeRef(
+ propagatedType.syntheticReturnType, 'dart:core', 'dart:core', 'int');
+ expect(propagatedType.syntheticParams, hasLength(2));
+ checkTypeRef(propagatedType.syntheticParams[0].type, 'dart:core',
+ 'dart:core', 'int');
+ checkTypeRef(propagatedType.syntheticParams[1].type, 'dart:core',
+ 'dart:core', 'String');
+ }
+
test_type_arguments_explicit() {
EntityRef typeRef = serializeTypeText('List<int>');
checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
@@ -7076,8 +7200,7 @@
}
test_variable_initializer_withLocals() {
- String text =
- 'var v = <dynamic, dynamic>{"1": () { f1() {} var v1; }, '
+ String text = 'var v = <dynamic, dynamic>{"1": () { f1() {} var v1; }, '
'"2": () { f2() {} var v2; }};';
UnlinkedVariable variable = serializeVariableText(text);
UnlinkedExecutable initializer = variable.initializer;
diff --git a/pkg/analyzer/test/src/summary/test_all.dart b/pkg/analyzer/test/src/summary/test_all.dart
index d24342f..fe80a5a 100644
--- a/pkg/analyzer/test/src/summary/test_all.dart
+++ b/pkg/analyzer/test/src/summary/test_all.dart
@@ -8,6 +8,7 @@
import '../../utils.dart';
import 'flat_buffers_test.dart' as flat_buffers_test;
+import 'index_unit_test.dart' as index_unit_test;
import 'name_filter_test.dart' as name_filter_test;
import 'prelinker_test.dart' as prelinker_test;
import 'resynthesize_strong_test.dart' as resynthesize_strong_test;
@@ -21,6 +22,7 @@
initializeTestEnvironment();
group('summary tests', () {
flat_buffers_test.main();
+ index_unit_test.main();
name_filter_test.main();
prelinker_test.main();
resynthesize_strong_test.main();
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index ebdca70..105ed8b 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -77,6 +77,16 @@
expect(analysisOptions.enableGenericMethods, true);
}
+ test_configure_enableConditionalDirectives() {
+ expect(analysisOptions.enableConditionalDirectives, false);
+ configureContext('''
+analyzer:
+ language:
+ enableConditionalDirectives: true
+''');
+ expect(analysisOptions.enableConditionalDirectives, true);
+ }
+
test_configure_enableSuperMixins() {
configureContext('''
analyzer:
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index ba964d8..4bfe3521 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1903,8 +1903,10 @@
void foo(int f(Object _)) {}
main() {
- var f = (x) => null;
- f = (x) => 'hello';
+ var f = (Object x) => null;
+ String y = /*info:DYNAMIC_CAST*/f(42);
+
+ f = /*info:INFERRED_TYPE_CLOSURE*/(x) => 'hello';
var g = null;
g = 'hello';
@@ -1960,4 +1962,233 @@
}
''');
});
+
+
+ group('block bodied lambdas', () {
+ // Original feature request: https://github.com/dart-lang/sdk/issues/25487
+
+ test('basic', () {
+ checkFile(r'''
+ test1() {
+ List<int> o;
+ var y = o.map(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { return x + 1; });
+ Iterable<int> z = y;
+ }
+ ''');
+ });
+
+ test('no return', () {
+ var mainUnit = checkFile(r'''
+ test1() {
+ List<int> o;
+ var y = o.map(/*info:INFERRED_TYPE_CLOSURE*/(x) { });
+ Iterable<int> z = /*warning:DOWN_CAST_COMPOSITE*/y;
+ }
+ ''');
+ var f = mainUnit.element.functions[0].localVariables[1];
+ expect(f.type.toString(), 'Iterable<dynamic>');
+ });
+
+ test('LUB', () {
+ checkFile(r'''
+ import 'dart:math' show Random;
+ test2() {
+ List<num> o;
+ var y = o.map(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) {
+ if (new Random().nextBool()) {
+ return x.toInt() + 1;
+ } else {
+ return x.toDouble();
+ }
+ });
+ Iterable<num> w = y;
+ Iterable<int> z = /*info:ASSIGNMENT_CAST*/y;
+ }
+ ''');
+ });
+
+ group('does not infer bottom', () {
+ test('sync', () {
+ var mainUnit = checkFile(r'''
+ var h = null;
+ void foo(int f(Object _)) {}
+
+ main() {
+ var f = (Object x) { return null; };
+ String y = /*info:DYNAMIC_CAST*/f(42);
+
+ f = /*info:INFERRED_TYPE_CLOSURE*/(x) => 'hello';
+
+ foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { return null; });
+ foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) { throw "not implemented"; });
+ }
+ ''');
+
+ var f = mainUnit.element.functions[1].localVariables[0];
+ expect(f.type.toString(), '(Object) → dynamic');
+ });
+
+ test('sync*', () {
+ var mainUnit = checkFile(r'''
+ main() {
+ var f = () sync* { yield null; };
+ Iterable y = f();
+ Iterable<String> z = /*warning:DOWN_CAST_COMPOSITE*/f();
+ String s = /*info:DYNAMIC_CAST*/f().first;
+ }
+ ''');
+
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → Iterable<dynamic>');
+ });
+
+ test('async', () {
+ var mainUnit = checkFile(r'''
+ import 'dart:async';
+ main() async {
+ var f = () async { return null; };
+ Future y = f();
+ Future<String> z = /*warning:DOWN_CAST_COMPOSITE*/f();
+ String s = /*info:DYNAMIC_CAST*/await f();
+ }
+ ''');
+
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → Future<dynamic>');
+ });
+
+ test('async*', () {
+ var mainUnit = checkFile(r'''
+ import 'dart:async';
+ main() async {
+ var f = () async* { yield null; };
+ Stream y = f();
+ Stream<String> z = /*warning:DOWN_CAST_COMPOSITE*/f();
+ String s = /*info:DYNAMIC_CAST*/await f().first;
+ }
+ ''');
+
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → Stream<dynamic>');
+ });
+ });
+
+ group('async', () {
+ test('all returns are values', () {
+ var mainUnit = checkFile(r'''
+ import 'dart:async';
+ import 'dart:math' show Random;
+ main() {
+ var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+ if (new Random().nextBool()) {
+ return 1;
+ } else {
+ return 2.0;
+ }
+ };
+ Future<num> g = f();
+ Future<int> h = /*info:ASSIGNMENT_CAST*/f();
+ }
+ ''');
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → Future<num>');
+ });
+
+ test('all returns are futures', () {
+ var mainUnit = checkFile(r'''
+ import 'dart:async';
+ import 'dart:math' show Random;
+ main() {
+ var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+ if (new Random().nextBool()) {
+ return new Future<int>.value(1);
+ } else {
+ return new Future<double>.value(2.0);
+ }
+ };
+ Future<num> g = f();
+ Future<int> h = /*info:ASSIGNMENT_CAST*/f();
+ }
+ ''');
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → Future<num>');
+ });
+
+ test('mix of values and futures', () {
+ var mainUnit = checkFile(r'''
+ import 'dart:async';
+ import 'dart:math' show Random;
+ main() {
+ var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+ if (new Random().nextBool()) {
+ return new Future<int>.value(1);
+ } else {
+ return 2.0;
+ }
+ };
+ Future<num> g = f();
+ Future<int> h = /*info:ASSIGNMENT_CAST*/f();
+ }
+ ''');
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → Future<num>');
+ });
+ });
+
+ test('sync*', () {
+ var mainUnit = checkFile(r'''
+ main() {
+ var f = /*info:INFERRED_TYPE_CLOSURE*/() sync* {
+ yield 1;
+ yield* [3, 4.0];
+ };
+ Iterable<num> g = f();
+ Iterable<int> h = /*info:ASSIGNMENT_CAST*/f();
+ }
+ ''');
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → Iterable<num>');
+ });
+
+ test('async*', () {
+ var mainUnit = checkFile(r'''
+ import 'dart:async';
+ main() {
+ var f = /*info:INFERRED_TYPE_CLOSURE*/() async* {
+ yield 1;
+ Stream<double> s;
+ yield* s;
+ };
+ Stream<num> g = f();
+ Stream<int> h = /*info:ASSIGNMENT_CAST*/f();
+ }
+ ''');
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → Stream<num>');
+ });
+
+ test('downwards incompatible with upwards inference', () {
+ var mainUnit = checkFile(r'''
+ main() {
+ String f() => null;
+ var g = f;
+ g = /*info:INFERRED_TYPE_CLOSURE*/() { return /*severe:STATIC_TYPE_ERROR*/1; };
+ }
+ ''');
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → String');
+ });
+
+ test('nested lambdas', () {
+ var mainUnit = checkFile(r'''
+ main() {
+ var f = /*info:INFERRED_TYPE_CLOSURE*/() {
+ return /*info:INFERRED_TYPE_CLOSURE*/(int x) { return 2.0 * x; };
+ };
+ }
+ ''');
+ var f = mainUnit.element.functions[0].localVariables[0];
+ expect(f.type.toString(), '() → (int) → num');
+ });
+ });
}
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index 19ed5b3..e04fb30 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -52,7 +52,9 @@
///
/// See [addFile] for more information about how to encode expectations in
/// the file text.
-void check() {
+///
+/// Returns the main resolved library. This can be used for further checks.
+CompilationUnit check() {
_checkCalled = true;
expect(files.getFile('/main.dart').exists, true,
@@ -93,12 +95,16 @@
_expectErrors(resolved, errors);
}
}
+
+ return initialLibrary;
}
/// Adds a file using [addFile] and calls [check].
-void checkFile(String content) {
+///
+/// Also returns the resolved compilation unit.
+CompilationUnit checkFile(String content) {
addFile(content);
- check();
+ return check();
}
SourceSpanWithContext _createSpanHelper(
diff --git a/pkg/analyzer/tool/summary/build_sdk_summaries.dart b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
index 176f7c6..29f49db 100644
--- a/pkg/analyzer/tool/summary/build_sdk_summaries.dart
+++ b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
@@ -1,6 +1,6 @@
-import 'dart:convert';
import 'dart:io';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
@@ -8,8 +8,8 @@
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/index_unit.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:crypto/crypto.dart';
import 'package:path/path.dart';
main(List<String> args) {
@@ -71,11 +71,8 @@
AnalysisContext context;
final Set<Source> processedSources = new Set<Source>();
- final List<String> linkedLibraryUris = <String>[];
- final List<LinkedLibraryBuilder> linkedLibraries = <LinkedLibraryBuilder>[];
- final List<String> unlinkedUnitUris = <String>[];
- final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
- final List<String> unlinkedUnitHashes = <String>[];
+ final PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
+ final PackageIndexAssembler indexAssembler = new PackageIndexAssembler();
_Builder(this.sdkPath, this.outputDirectoryPath, this.strongMode);
@@ -83,7 +80,8 @@
* Build a strong or spec mode summary for the Dart SDK at [sdkPath].
*/
void build() {
- print('Generating ${strongMode ? 'strong' : 'spec'} mode summary.');
+ String modeName = strongMode ? 'strong' : 'spec';
+ print('Generating $modeName mode summary and index.');
Stopwatch sw = new Stopwatch()..start();
//
// Prepare SDK.
@@ -111,16 +109,21 @@
//
// Write the whole SDK bundle.
//
- PackageBundleBuilder sdkBundle = new PackageBundleBuilder(
- linkedLibraryUris: linkedLibraryUris,
- linkedLibraries: linkedLibraries,
- unlinkedUnitUris: unlinkedUnitUris,
- unlinkedUnits: unlinkedUnits,
- unlinkedUnitHashes: unlinkedUnitHashes);
- String outputFilePath =
- join(outputDirectoryPath, strongMode ? 'strong.sum' : 'spec.sum');
- File file = new File(outputFilePath);
- file.writeAsBytesSync(sdkBundle.toBuffer(), mode: FileMode.WRITE_ONLY);
+ {
+ PackageBundleBuilder bundle = bundleAssembler.assemble();
+ String outputPath = join(outputDirectoryPath, '$modeName.sum');
+ File file = new File(outputPath);
+ file.writeAsBytesSync(bundle.toBuffer(), mode: FileMode.WRITE_ONLY);
+ }
+ //
+ // Write the whole SDK index.
+ //
+ {
+ PackageIndexBuilder index = indexAssembler.assemble();
+ String outputPath = join(outputDirectoryPath, '$modeName.index');
+ File file = new File(outputPath);
+ file.writeAsBytesSync(index.toBuffer(), mode: FileMode.WRITE_ONLY);
+ }
//
// Done.
//
@@ -128,15 +131,6 @@
}
/**
- * Compute a hash of the given file contents.
- */
- String _hash(String contents) {
- MD5 md5 = new MD5();
- md5.add(UTF8.encode(contents));
- return CryptoUtils.bytesToHex(md5.close());
- }
-
- /**
* Serialize the library with the given [source] and all its direct or
* indirect imports and exports.
*/
@@ -145,24 +139,15 @@
return;
}
LibraryElement element = context.computeLibraryElement(source);
- _serializeSingleLibrary(element);
+ bundleAssembler.serializeLibraryElement(element);
element.importedLibraries.forEach((e) => _serializeLibrary(e.source));
element.exportedLibraries.forEach((e) => _serializeLibrary(e.source));
- }
-
- /**
- * Serialize the library with the given [element].
- */
- void _serializeSingleLibrary(LibraryElement element) {
- String uri = element.source.uri.toString();
- LibrarySerializationResult libraryResult =
- serializeLibrary(element, context.typeProvider, strongMode);
- linkedLibraryUris.add(uri);
- linkedLibraries.add(libraryResult.linked);
- unlinkedUnitUris.addAll(libraryResult.unitUris);
- unlinkedUnits.addAll(libraryResult.unlinkedUnits);
- for (Source source in libraryResult.unitSources) {
- unlinkedUnitHashes.add(_hash(source.contents.data));
+ // Index every unit of the library.
+ for (CompilationUnitElement unitElement in element.units) {
+ Source unitSource = unitElement.source;
+ CompilationUnit unit =
+ context.resolveCompilationUnit2(unitSource, source);
+ indexAssembler.index(unit);
}
}
}
diff --git a/pkg/analyzer/tool/summary/check_test.dart b/pkg/analyzer/tool/summary/check_test.dart
index ac5f7bb..156dc19 100644
--- a/pkg/analyzer/tool/summary/check_test.dart
+++ b/pkg/analyzer/tool/summary/check_test.dart
@@ -19,5 +19,5 @@
String script = Platform.script.toFilePath(windows: Platform.isWindows);
String pkgPath = normalize(join(dirname(script), '..', '..'));
GeneratedContent.checkAll(
- pkgPath, 'tool/summary/generate.dart', <GeneratedContent>[target]);
+ pkgPath, 'tool/summary/generate.dart', allTargets);
}
diff --git a/pkg/analyzer/tool/summary/generate.dart b/pkg/analyzer/tool/summary/generate.dart
index 9d5fcb6..cfa14a0 100644
--- a/pkg/analyzer/tool/summary/generate.dart
+++ b/pkg/analyzer/tool/summary/generate.dart
@@ -38,33 +38,34 @@
main() {
String script = Platform.script.toFilePath(windows: Platform.isWindows);
String pkgPath = normalize(join(dirname(script), '..', '..'));
- GeneratedContent.generateAll(pkgPath, <GeneratedContent>[target]);
+ GeneratedContent.generateAll(pkgPath, allTargets);
}
-final GeneratedFile target =
+final List<GeneratedContent> allTargets = <GeneratedContent>[
+ formatTarget,
+ schemaTarget
+];
+
+final GeneratedFile formatTarget =
new GeneratedFile('lib/src/summary/format.dart', (String pkgPath) {
- // Parse the input "IDL" file and pass it to the [_CodeGenerator].
- PhysicalResourceProvider provider = new PhysicalResourceProvider(
- PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS);
- String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart');
- File idlFile = provider.getFile(idlPath);
- Source idlSource = provider.getFile(idlPath).createSource();
- String idlText = idlFile.readAsStringSync();
- BooleanErrorListener errorListener = new BooleanErrorListener();
- CharacterReader idlReader = new CharSequenceReader(idlText);
- Scanner scanner = new Scanner(idlSource, idlReader, errorListener);
- Token tokenStream = scanner.tokenize();
- LineInfo lineInfo = new LineInfo(scanner.lineStarts);
- Parser parser = new Parser(idlSource, new BooleanErrorListener());
- CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream);
- _CodeGenerator codeGenerator = new _CodeGenerator();
- codeGenerator.processCompilationUnit(lineInfo, idlParsed);
+ _CodeGenerator codeGenerator = new _CodeGenerator(pkgPath);
+ codeGenerator.generateFormatCode();
+ return codeGenerator._outBuffer.toString();
+});
+
+final GeneratedFile schemaTarget =
+ new GeneratedFile('lib/src/summary/format.fbs', (String pkgPath) {
+ _CodeGenerator codeGenerator = new _CodeGenerator(pkgPath);
+ codeGenerator.generateFlatBufferSchema();
return codeGenerator._outBuffer.toString();
});
typedef String _StringToString(String s);
class _CodeGenerator {
+ static const String _throwDeprecated =
+ "throw new UnimplementedError('attempt to access deprecated field')";
+
/**
* Buffer in which generated code is accumulated.
*/
@@ -80,12 +81,43 @@
*/
idlModel.Idl _idl;
+ _CodeGenerator(String pkgPath) {
+ // Parse the input "IDL" file.
+ PhysicalResourceProvider provider = new PhysicalResourceProvider(
+ PhysicalResourceProvider.NORMALIZE_EOL_ALWAYS);
+ String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart');
+ File idlFile = provider.getFile(idlPath);
+ Source idlSource = provider.getFile(idlPath).createSource();
+ String idlText = idlFile.readAsStringSync();
+ BooleanErrorListener errorListener = new BooleanErrorListener();
+ CharacterReader idlReader = new CharSequenceReader(idlText);
+ Scanner scanner = new Scanner(idlSource, idlReader, errorListener);
+ Token tokenStream = scanner.tokenize();
+ LineInfo lineInfo = new LineInfo(scanner.lineStarts);
+ Parser parser = new Parser(idlSource, new BooleanErrorListener());
+ CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream);
+ // Extract a description of the IDL and make sure it is valid.
+ extractIdl(lineInfo, idlParsed);
+ checkIdl();
+ }
+
/**
* Perform basic sanity checking of the IDL (over and above that done by
* [extractIdl]).
*/
void checkIdl() {
_idl.classes.forEach((String name, idlModel.ClassDeclaration cls) {
+ if (cls.fileIdentifier != null) {
+ if (cls.fileIdentifier.length != 4) {
+ throw new Exception('$name: file identifier must be 4 characters');
+ }
+ for (int i = 0; i < cls.fileIdentifier.length; i++) {
+ if (cls.fileIdentifier.codeUnitAt(i) >= 256) {
+ throw new Exception(
+ '$name: file identifier must be encodable as Latin-1');
+ }
+ }
+ }
Map<int, String> idsUsed = <int, String>{};
for (idlModel.FieldDeclaration field in cls.fields) {
String fieldName = field.name;
@@ -95,6 +127,8 @@
// List of classes is ok
} else if (_idl.enums.containsKey(type.typeName)) {
// List of enums is ok
+ } else if (type.typeName == 'bool') {
+ // List of booleans is ok
} else if (type.typeName == 'int') {
// List of ints is ok
} else if (type.typeName == 'double') {
@@ -190,25 +224,49 @@
for (CompilationUnitMember decl in idlParsed.declarations) {
if (decl is ClassDeclaration) {
bool isTopLevel = false;
+ String fileIdentifier;
+ String clsName = decl.name.name;
for (Annotation annotation in decl.metadata) {
- if (annotation.arguments == null &&
- annotation.name.name == 'topLevel') {
+ if (annotation.arguments != null &&
+ annotation.name.name == 'TopLevel' &&
+ annotation.constructorName == null) {
isTopLevel = true;
+ if (annotation.arguments == null) {
+ throw new Exception(
+ 'Class `$clsName`: TopLevel requires parenthesis');
+ }
+ if (annotation.constructorName != null) {
+ throw new Exception(
+ "Class `$clsName`: TopLevel doesn't have named constructors");
+ }
+ if (annotation.arguments.arguments.length == 1) {
+ Expression arg = annotation.arguments.arguments[0];
+ if (arg is StringLiteral) {
+ fileIdentifier = arg.stringValue;
+ } else {
+ throw new Exception(
+ 'Class `$clsName`: TopLevel argument must be a string'
+ ' literal');
+ }
+ } else if (annotation.arguments.arguments.length != 0) {
+ throw new Exception(
+ 'Class `$clsName`: TopLevel requires 0 or 1 arguments');
+ }
}
}
String doc = _getNodeDoc(lineInfo, decl);
- idlModel.ClassDeclaration cls =
- new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel);
- _idl.classes[cls.name] = cls;
+ idlModel.ClassDeclaration cls = new idlModel.ClassDeclaration(
+ doc, clsName, isTopLevel, fileIdentifier);
+ _idl.classes[clsName] = cls;
String expectedBase = 'base.SummaryClass';
if (decl.extendsClause == null ||
decl.extendsClause.superclass.name.name != expectedBase) {
throw new Exception(
- 'Class `${cls.name}` needs to extend `$expectedBase`');
+ 'Class `$clsName` needs to extend `$expectedBase`');
}
for (ClassMember classMember in decl.members) {
if (classMember is MethodDeclaration && classMember.isGetter) {
- String desc = '${cls.name}.${classMember.name.name}';
+ String desc = '$clsName.${classMember.name.name}';
TypeName type = classMember.returnType;
if (type == null) {
throw new Exception('Class member needs a type: $desc');
@@ -224,6 +282,7 @@
throw new Exception('Cannot handle type arguments in `$type`');
}
int id;
+ bool isDeprecated = false;
for (Annotation annotation in classMember.metadata) {
if (annotation.name.name == 'Id') {
if (id != null) {
@@ -241,6 +300,11 @@
throw new Exception(
'@Id parameter must be an integer literal ($desc)');
}
+ } else if (annotation.name.name == 'deprecated') {
+ if (annotation.arguments != null) {
+ throw new Exception('@deprecated does not take args ($desc)');
+ }
+ isDeprecated = true;
}
}
if (id == null) {
@@ -249,8 +313,8 @@
String doc = _getNodeDoc(lineInfo, classMember);
idlModel.FieldType fieldType =
new idlModel.FieldType(type.name.name, isList);
- cls.fields.add(new idlModel.FieldDeclaration(
- doc, classMember.name.name, fieldType, id));
+ cls.allFields.add(new idlModel.FieldDeclaration(
+ doc, classMember.name.name, fieldType, id, isDeprecated));
} else if (classMember is ConstructorDeclaration &&
classMember.name.name == 'fromBuffer') {
// Ignore `fromBuffer` declarations; they simply forward to the
@@ -279,6 +343,128 @@
}
/**
+ * Generate a string representing the FlatBuffer schema type which should be
+ * used to represent [type].
+ */
+ String fbsType(idlModel.FieldType type) {
+ String typeStr;
+ switch (type.typeName) {
+ case 'bool':
+ typeStr = 'bool';
+ break;
+ case 'double':
+ typeStr = 'double';
+ break;
+ case 'int':
+ typeStr = 'uint';
+ break;
+ case 'String':
+ typeStr = 'string';
+ break;
+ default:
+ typeStr = type.typeName;
+ break;
+ }
+ if (type.isList) {
+ // FlatBuffers don't natively support a packed list of booleans, so we
+ // treat it as a list of unsigned bytes, which is a compatible data
+ // structure.
+ if (typeStr == 'bool') {
+ typeStr = 'ubyte';
+ }
+ return '[$typeStr]';
+ } else {
+ return typeStr;
+ }
+ }
+
+ /**
+ * Entry point to the code generator when generating the "format.fbs" file.
+ */
+ void generateFlatBufferSchema() {
+ outputHeader();
+ for (idlModel.EnumDeclaration enm in _idl.enums.values) {
+ out();
+ outDoc(enm.documentation);
+ out('enum ${enm.name} : byte {');
+ indent(() {
+ for (int i = 0; i < enm.values.length; i++) {
+ idlModel.EnumValueDeclaration value = enm.values[i];
+ if (i != 0) {
+ out();
+ }
+ String suffix = i < enm.values.length - 1 ? ',' : '';
+ outDoc(value.documentation);
+ out('${value.name}$suffix');
+ }
+ });
+ out('}');
+ }
+ for (idlModel.ClassDeclaration cls in _idl.classes.values) {
+ out();
+ outDoc(cls.documentation);
+ out('table ${cls.name} {');
+ indent(() {
+ for (int i = 0; i < cls.allFields.length; i++) {
+ idlModel.FieldDeclaration field = cls.allFields[i];
+ if (i != 0) {
+ out();
+ }
+ outDoc(field.documentation);
+ List<String> attributes = <String>['id: ${field.id}'];
+ if (field.isDeprecated) {
+ attributes.add('deprecated');
+ }
+ String attrText = attributes.join(', ');
+ out('${field.name}:${fbsType(field.type)} ($attrText);');
+ }
+ });
+ out('}');
+ }
+ out();
+ // Standard flatbuffers only support one root type. We support multiple
+ // root types. For now work around this by forcing PackageBundle to be the
+ // root type. TODO(paulberry): come up with a better solution.
+ idlModel.ClassDeclaration rootType = _idl.classes['PackageBundle'];
+ out('root_type ${rootType.name};');
+ if (rootType.fileIdentifier != null) {
+ out();
+ out('file_identifier ${quoted(rootType.fileIdentifier)};');
+ }
+ }
+
+ /**
+ * Entry point to the code generator when generating the "format.dart" file.
+ */
+ void generateFormatCode() {
+ outputHeader();
+ out('library analyzer.src.summary.format;');
+ out();
+ out("import 'flat_buffers.dart' as fb;");
+ out("import 'idl.dart' as idl;");
+ out("import 'dart:convert' as convert;");
+ out();
+ for (idlModel.EnumDeclaration enm in _idl.enums.values) {
+ _generateEnumReader(enm);
+ out();
+ }
+ for (idlModel.ClassDeclaration cls in _idl.classes.values) {
+ _generateBuilder(cls);
+ out();
+ if (cls.isTopLevel) {
+ _generateReadFunction(cls);
+ out();
+ }
+ _generateReader(cls);
+ out();
+ _generateImpl(cls);
+ out();
+ _generateMixin(cls);
+ out();
+ }
+ }
+
+ /**
* Add the prefix `idl.` to a type name, unless that type name is the name of
* a built-in type.
*/
@@ -325,13 +511,7 @@
}
}
- /**
- * Entry point to the code generator. Interpret the AST in [idlParsed],
- * generate code, and output it to [_outBuffer].
- */
- void processCompilationUnit(LineInfo lineInfo, CompilationUnit idlParsed) {
- extractIdl(lineInfo, idlParsed);
- checkIdl();
+ void outputHeader() {
out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file');
out('// for details. All rights reserved. Use of this source code is governed by a');
out('// BSD-style license that can be found in the LICENSE file.');
@@ -339,30 +519,6 @@
out('// This file has been automatically generated. Please do not edit it manually.');
out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_files".');
out();
- out('library analyzer.src.summary.format;');
- out();
- out("import 'flat_buffers.dart' as fb;");
- out("import 'idl.dart' as idl;");
- out("import 'dart:convert' as convert;");
- out();
- for (idlModel.EnumDeclaration enm in _idl.enums.values) {
- _generateEnumReader(enm);
- out();
- }
- for (idlModel.ClassDeclaration cls in _idl.classes.values) {
- _generateBuilder(cls);
- out();
- if (cls.isTopLevel) {
- _generateReadFunction(cls);
- out();
- }
- _generateReader(cls);
- out();
- _generateImpl(cls);
- out();
- _generateMixin(cls);
- out();
- }
}
/**
@@ -390,7 +546,7 @@
out('$typeStr _$fieldName;');
}
// Generate getters and setters.
- for (idlModel.FieldDeclaration field in cls.fields) {
+ for (idlModel.FieldDeclaration field in cls.allFields) {
String fieldName = field.name;
idlModel.FieldType fieldType = field.type;
String typeStr = encodedType(fieldType);
@@ -398,34 +554,39 @@
String defSuffix = def == null ? '' : ' ??= $def';
out();
out('@override');
- out('$typeStr get $fieldName => _$fieldName$defSuffix;');
- out();
- outDoc(field.documentation);
- constructorParams.add('$typeStr $fieldName');
- out('void set $fieldName($typeStr _value) {');
- indent(() {
- String stateFieldName = '_' + fieldName;
- out('assert(!_finished);');
- // Validate that int(s) are non-negative.
- if (fieldType.typeName == 'int') {
- if (!fieldType.isList) {
- out('assert(_value == null || _value >= 0);');
- } else {
- out('assert(_value == null || _value.every((e) => e >= 0));');
+ if (field.isDeprecated) {
+ out('$typeStr get $fieldName => $_throwDeprecated;');
+ } else {
+ out('$typeStr get $fieldName => _$fieldName$defSuffix;');
+ out();
+ outDoc(field.documentation);
+ constructorParams.add('$typeStr $fieldName');
+ out('void set $fieldName($typeStr _value) {');
+ indent(() {
+ String stateFieldName = '_' + fieldName;
+ out('assert(!_finished);');
+ // Validate that int(s) are non-negative.
+ if (fieldType.typeName == 'int') {
+ if (!fieldType.isList) {
+ out('assert(_value == null || _value >= 0);');
+ } else {
+ out('assert(_value == null || _value.every((e) => e >= 0));');
+ }
}
- }
- // Set the value.
- out('$stateFieldName = _value;');
- });
- out('}');
+ // Set the value.
+ out('$stateFieldName = _value;');
+ });
+ out('}');
+ }
}
// Generate constructor.
out();
out('$builderName({${constructorParams.join(', ')}})');
- for (int i = 0; i < cls.fields.length; i++) {
- idlModel.FieldDeclaration field = cls.fields[i];
+ List<idlModel.FieldDeclaration> fields = cls.fields.toList();
+ for (int i = 0; i < fields.length; i++) {
+ idlModel.FieldDeclaration field = fields[i];
String prefix = i == 0 ? ' : ' : ' ';
- String suffix = i == cls.fields.length - 1 ? ';' : ',';
+ String suffix = i == fields.length - 1 ? ';' : ',';
out('${prefix}_${field.name} = ${field.name}$suffix');
}
// Generate finish.
@@ -434,7 +595,10 @@
out('List<int> toBuffer() {');
indent(() {
out('fb.Builder fbBuilder = new fb.Builder();');
- out('return fbBuilder.finish(finish(fbBuilder));');
+ String fileId = cls.fileIdentifier == null
+ ? ''
+ : ', ${quoted(cls.fileIdentifier)}';
+ out('return fbBuilder.finish(finish(fbBuilder)$fileId);');
});
out('}');
}
@@ -469,6 +633,8 @@
String itemCode = 'b.index';
String listCode = '$valueName.map((b) => $itemCode).toList()';
writeCode = '$offsetName = fbBuilder.writeListUint8($listCode);';
+ } else if (fieldType.typeName == 'bool') {
+ writeCode = '$offsetName = fbBuilder.writeListBool($valueName);';
} else if (fieldType.typeName == 'int') {
writeCode =
'$offsetName = fbBuilder.writeListUint32($valueName);';
@@ -541,6 +707,8 @@
void _generateEnumReader(idlModel.EnumDeclaration enm) {
String name = enm.name;
String readerName = '_${name}Reader';
+ String count = '${idlPrefix(name)}.values.length';
+ String def = '${idlPrefix(name)}.${enm.values[0].name}';
out('class $readerName extends fb.Reader<${idlPrefix(name)}> {');
indent(() {
out('const $readerName() : super();');
@@ -552,7 +720,7 @@
out('${idlPrefix(name)} read(fb.BufferPointer bp) {');
indent(() {
out('int index = const fb.Uint8Reader().read(bp);');
- out('return ${idlPrefix(name)}.values[index];');
+ out('return index < $count ? ${idlPrefix(name)}.values[index] : $def;');
});
out('}');
});
@@ -577,7 +745,7 @@
out('$returnType _$fieldName;');
}
// Write getters.
- for (idlModel.FieldDeclaration field in cls.fields) {
+ for (idlModel.FieldDeclaration field in cls.allFields) {
int index = field.id;
String fieldName = field.name;
idlModel.FieldType type = field.type;
@@ -586,7 +754,9 @@
String readCode;
String def = defaultValue(type, false);
if (type.isList) {
- if (typeName == 'int') {
+ if (typeName == 'bool') {
+ readCode = 'const fb.BoolListReader()';
+ } else if (typeName == 'int') {
readCode = 'const fb.Uint32ListReader()';
} else if (typeName == 'double') {
readCode = 'const fb.Float64ListReader()';
@@ -617,13 +787,17 @@
out();
out('@override');
String returnType = dartType(type);
- out('$returnType get $fieldName {');
- indent(() {
- String readExpr = '$readCode.vTableGet(_bp, $index, $def)';
- out('_$fieldName ??= $readExpr;');
- out('return _$fieldName;');
- });
- out('}');
+ if (field.isDeprecated) {
+ out('$returnType get $fieldName => $_throwDeprecated;');
+ } else {
+ out('$returnType get $fieldName {');
+ indent(() {
+ String readExpr = '$readCode.vTableGet(_bp, $index, $def)';
+ out('_$fieldName ??= $readExpr;');
+ out('return _$fieldName;');
+ });
+ out('}');
+ }
}
});
out('}');
diff --git a/pkg/analyzer/tool/summary/idl_model.dart b/pkg/analyzer/tool/summary/idl_model.dart
index fca1054..9ec248f 100644
--- a/pkg/analyzer/tool/summary/idl_model.dart
+++ b/pkg/analyzer/tool/summary/idl_model.dart
@@ -14,17 +14,30 @@
*/
class ClassDeclaration extends Declaration {
/**
- * Fields defined in the class.
+ * All fields defined in the class, including deprecated ones.
*/
- final List<FieldDeclaration> fields = <FieldDeclaration>[];
+ final List<FieldDeclaration> allFields = <FieldDeclaration>[];
/**
* Indicates whether the class has the `topLevel` annotation.
*/
final bool isTopLevel;
- ClassDeclaration(String documentation, String name, this.isTopLevel)
+ /**
+ * If [isTopLevel] is `true` and a file identifier was specified for this
+ * class, the file identifier string. Otheswise `null`.
+ */
+ final String fileIdentifier;
+
+ ClassDeclaration(
+ String documentation, String name, this.isTopLevel, this.fileIdentifier)
: super(documentation, name);
+
+ /**
+ * Get the non-deprecated fields defined in the class.
+ */
+ Iterable<FieldDeclaration> get fields =>
+ allFields.where((FieldDeclaration field) => !field.isDeprecated);
}
/**
@@ -79,7 +92,13 @@
*/
final int id;
- FieldDeclaration(String documentation, String name, this.type, this.id)
+ /**
+ * Indicates whether the field is deprecated.
+ */
+ final bool isDeprecated;
+
+ FieldDeclaration(
+ String documentation, String name, this.type, this.id, this.isDeprecated)
: super(documentation, name);
}
diff --git a/pkg/analyzer_cli/lib/src/package_analyzer.dart b/pkg/analyzer_cli/lib/src/package_analyzer.dart
index 0bad260..746c77a 100644
--- a/pkg/analyzer_cli/lib/src/package_analyzer.dart
+++ b/pkg/analyzer_cli/lib/src/package_analyzer.dart
@@ -4,7 +4,6 @@
library analyzer_cli.src.package_analyzer;
-import 'dart:convert';
import 'dart:core' hide Resource;
import 'dart:io' as io;
@@ -12,231 +11,22 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/source/package_map_resolver.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary/resynthesize.dart';
+import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
-import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/task/dart.dart';
-import 'package:analyzer/task/model.dart';
import 'package:analyzer_cli/src/analyzer_impl.dart';
import 'package:analyzer_cli/src/driver.dart';
import 'package:analyzer_cli/src/error_formatter.dart';
import 'package:analyzer_cli/src/options.dart';
-import 'package:crypto/crypto.dart';
import 'package:path/path.dart' as pathos;
/**
- * If [uri] has the `package` scheme in form of `package:pkg/file.dart`,
- * return the `pkg` name. Otherwise return `null`.
- */
-String getPackageName(Uri uri) {
- if (uri.scheme != 'package') {
- return null;
- }
- String path = uri.path;
- int index = path.indexOf('/');
- if (index == -1) {
- return null;
- }
- return path.substring(0, index);
-}
-
-/**
- * A concrete resynthesizer that serves summaries from given file paths.
- */
-class FileBasedSummaryResynthesizer extends SummaryResynthesizer {
- final Map<String, UnlinkedUnit> unlinkedMap = <String, UnlinkedUnit>{};
- final Map<String, LinkedLibrary> linkedMap = <String, LinkedLibrary>{};
-
- FileBasedSummaryResynthesizer(
- SummaryResynthesizer parent,
- AnalysisContext context,
- TypeProvider typeProvider,
- SourceFactory sourceFactory,
- bool strongMode,
- List<String> summaryPaths)
- : super(parent, context, typeProvider, sourceFactory, strongMode) {
- summaryPaths.forEach(_fillMaps);
- }
-
- @override
- LinkedLibrary getLinkedSummary(String uri) {
- return linkedMap[uri];
- }
-
- @override
- UnlinkedUnit getUnlinkedSummary(String uri) {
- return unlinkedMap[uri];
- }
-
- @override
- bool hasLibrarySummary(String uri) {
- return linkedMap.containsKey(uri);
- }
-
- void _fillMaps(String path) {
- io.File file = new io.File(path);
- List<int> buffer = file.readAsBytesSync();
- PackageBundle bundle = new PackageBundle.fromBuffer(buffer);
- for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
- unlinkedMap[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
- }
- for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
- linkedMap[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
- }
- }
-}
-
-/**
- * The [ResultProvider] that provides results from input package summaries.
- */
-class InputPackagesResultProvider extends ResultProvider {
- final InternalAnalysisContext context;
- final Map<String, String> packageSummaryInputs;
-
- FileBasedSummaryResynthesizer resynthesizer;
- SummaryResultProvider sdkProvider;
-
- InputPackagesResultProvider(this.context, this.packageSummaryInputs) {
- InternalAnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
- sdkProvider = sdkContext.resultProvider;
- // Set the type provider to prevent the context from computing it.
- context.typeProvider = sdkContext.typeProvider;
- // Create a chained resynthesizer.
- resynthesizer = new FileBasedSummaryResynthesizer(
- sdkProvider.resynthesizer,
- context,
- context.typeProvider,
- context.sourceFactory,
- context.analysisOptions.strongMode,
- packageSummaryInputs.values.toList());
- }
-
- bool compute(CacheEntry entry, ResultDescriptor result) {
- if (sdkProvider.compute(entry, result)) {
- return true;
- }
- AnalysisTarget target = entry.target;
- // Only library results are supported for now.
- if (target is Source) {
- Uri uri = target.uri;
- // We know how to server results to input packages.
- String sourcePackageName = getPackageName(uri);
- if (!packageSummaryInputs.containsKey(sourcePackageName)) {
- return false;
- }
- // Provide known results.
- String uriString = uri.toString();
- if (result == LIBRARY_ELEMENT1 ||
- result == LIBRARY_ELEMENT2 ||
- result == LIBRARY_ELEMENT3 ||
- result == LIBRARY_ELEMENT4 ||
- result == LIBRARY_ELEMENT5 ||
- result == LIBRARY_ELEMENT6 ||
- result == LIBRARY_ELEMENT7 ||
- result == LIBRARY_ELEMENT8 ||
- result == LIBRARY_ELEMENT ||
- false) {
- LibraryElement libraryElement =
- resynthesizer.getLibraryElement(uriString);
- entry.setValue(result, libraryElement, TargetedResult.EMPTY_LIST);
- return true;
- } else if (result == READY_LIBRARY_ELEMENT2 ||
- result == READY_LIBRARY_ELEMENT5 ||
- result == READY_LIBRARY_ELEMENT6) {
- entry.setValue(result, true, TargetedResult.EMPTY_LIST);
- return true;
- } else if (result == SOURCE_KIND) {
- if (resynthesizer.linkedMap.containsKey(uriString)) {
- entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST);
- return true;
- }
- if (resynthesizer.unlinkedMap.containsKey(uriString)) {
- entry.setValue(result, SourceKind.PART, TargetedResult.EMPTY_LIST);
- return true;
- }
- return false;
- }
- }
- return false;
- }
-}
-
-/**
- * The [UriResolver] that knows about sources that are parts of packages which
- * are served from their summaries.
- */
-class InSummaryPackageUriResolver extends UriResolver {
- final Map<String, String> packageSummaryInputs;
-
- InSummaryPackageUriResolver(this.packageSummaryInputs);
-
- @override
- Source resolveAbsolute(Uri uri, [Uri actualUri]) {
- actualUri ??= uri;
- String packageName = getPackageName(actualUri);
- if (packageSummaryInputs.containsKey(packageName)) {
- return new InSummarySource(actualUri);
- }
- return null;
- }
-}
-
-/**
- * A placeholder of a source that is part of a package whose analysis results
- * are served from its summary. This source uses its URI as [fullName] and has
- * empty contents.
- */
-class InSummarySource extends Source {
- final Uri uri;
-
- InSummarySource(this.uri);
-
- @override
- TimestampedData<String> get contents => new TimestampedData<String>(0, '');
-
- @override
- String get encoding => uri.toString();
-
- @override
- String get fullName => encoding;
-
- @override
- bool get isInSystemLibrary => false;
-
- @override
- int get modificationStamp => 0;
-
- @override
- String get shortName => pathos.basename(fullName);
-
- @override
- UriKind get uriKind => UriKind.PACKAGE_URI;
-
- @override
- bool exists() => true;
-
- @override
- Uri resolveRelativeUri(Uri relativeUri) {
- Uri baseUri = uri;
- return baseUri.resolveUri(relativeUri);
- }
-
- @override
- String toString() => uri.toString();
-}
-
-/**
* The hermetic whole package analyzer.
*/
class PackageAnalyzer {
@@ -249,12 +39,6 @@
InternalAnalysisContext context;
final List<Source> explicitSources = <Source>[];
- final List<String> linkedLibraryUris = <String>[];
- final List<LinkedLibraryBuilder> linkedLibraries = <LinkedLibraryBuilder>[];
- final List<String> unlinkedUnitUris = <String>[];
- final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
- final List<String> unlinkedUnitHashes = <String>[];
-
PackageAnalyzer(this.options);
/**
@@ -306,21 +90,17 @@
// Write summary for Dart libraries.
if (options.packageSummaryOutput != null) {
+ PackageBundleAssembler assembler = new PackageBundleAssembler();
for (Source source in context.librarySources) {
if (pathos.isWithin(packageLibPath, source.fullName)) {
LibraryElement libraryElement = context.getLibraryElement(source);
if (libraryElement != null) {
- _serializeSingleLibrary(libraryElement);
+ assembler.serializeLibraryElement(libraryElement);
}
}
}
// Write the whole package bundle.
- PackageBundleBuilder sdkBundle = new PackageBundleBuilder(
- linkedLibraryUris: linkedLibraryUris,
- linkedLibraries: linkedLibraries,
- unlinkedUnitUris: unlinkedUnitUris,
- unlinkedUnits: unlinkedUnits,
- unlinkedUnitHashes: unlinkedUnitHashes);
+ PackageBundleBuilder sdkBundle = assembler.assemble();
io.File file = new io.File(options.packageSummaryOutput);
file.writeAsBytesSync(sdkBundle.toBuffer(), mode: io.FileMode.WRITE_ONLY);
}
@@ -346,12 +126,11 @@
}
void _createContext() {
- DirectoryBasedDartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
- sdk.useSummary = true;
+ DirectoryBasedDartSdk sdk =
+ new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
// Create the context.
context = AnalysisEngine.instance.createAnalysisContext();
- context.typeProvider = sdk.context.typeProvider;
context.sourceFactory = new SourceFactory(<UriResolver>[
new DartUriResolver(sdk),
new InSummaryPackageUriResolver(options.packageSummaryInputs),
@@ -367,7 +146,9 @@
Driver.setAnalysisContextOptions(
context, options, (AnalysisOptionsImpl contextOptions) {});
- // Set the result provider.
+ // Configure using summaries.
+ sdk.useSummary = true;
+ context.typeProvider = sdk.context.typeProvider;
context.resultProvider =
new InputPackagesResultProvider(context, options.packageSummaryInputs);
}
@@ -385,15 +166,6 @@
}
/**
- * Compute a hash of the given file contents.
- */
- String _hash(String contents) {
- MD5 md5 = new MD5();
- md5.add(UTF8.encode(contents));
- return CryptoUtils.bytesToHex(md5.close());
- }
-
- /**
* Print errors for all explicit sources.
*/
void _printErrors() {
@@ -408,20 +180,4 @@
formatter.formatErrors([errorInfo]);
}
}
-
- /**
- * Serialize the library with the given [element].
- */
- void _serializeSingleLibrary(LibraryElement element) {
- String uri = element.source.uri.toString();
- LibrarySerializationResult libraryResult =
- serializeLibrary(element, context.typeProvider, options.strongMode);
- linkedLibraryUris.add(uri);
- linkedLibraries.add(libraryResult.linked);
- unlinkedUnitUris.addAll(libraryResult.unitUris);
- unlinkedUnits.addAll(libraryResult.unlinkedUnits);
- for (Source source in libraryResult.unitSources) {
- unlinkedUnitHashes.add(_hash(source.contents.data));
- }
- }
}
diff --git a/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart b/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
index 6a2c16f..de027ec 100644
--- a/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
+++ b/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
@@ -50,9 +50,8 @@
BlockVisitor.traverseInPostOrder(node, this);
}
- /// Returns a reference to an operand of [prim], where [prim] throws if null
- /// is passed into that operand.
- Reference<Primitive> getNullCheckedOperand(Primitive prim) {
+ /// Returns an operand of [prim] that throws if null is passed into it.
+ Primitive getNullCheckedOperand(Primitive prim) {
if (prim is ReceiverCheck) return prim.value;
if (prim is GetLength) return prim.object;
if (prim is GetField) return prim.object;
@@ -60,10 +59,10 @@
if (prim is SetField) return prim.object;
if (prim is SetIndex) return prim.object;
if (prim is InvokeMethod && !selectorsOnNull.contains(prim.selector)) {
- return prim.dartReceiverReference;
+ return prim.dartReceiver;
}
if (prim is ForeignCode) {
- return prim.isNullGuardOnNullFirstArgument() ? prim.arguments[0] : null;
+ return prim.isNullGuardOnNullFirstArgument() ? prim.argument(0) : null;
}
return null;
}
@@ -72,7 +71,7 @@
/// [newNullCheck]. Eliminate [prim] if it is not needed any more.
void tryEliminateRedundantNullCheck(Primitive prim, Primitive newNullCheck) {
if (prim is ReceiverCheck && prim.isNullCheck) {
- Primitive value = prim.value.definition;
+ Primitive value = prim.value;
LetPrim let = prim.parent;
prim..replaceUsesWith(value)..destroy();
let.remove();
@@ -99,7 +98,7 @@
void visitLetPrim(LetPrim node) {
Primitive prim = node.primitive;
- Primitive receiver = getNullCheckedOperand(prim)?.definition;
+ Primitive receiver = getNullCheckedOperand(prim);
if (receiver != null) {
if (nullCheckedValue != null && receiver.sameValue(nullCheckedValue)) {
tryEliminateRedundantNullCheck(prim, nullCheckedValue);
@@ -123,7 +122,7 @@
visitInvokeContinuation(InvokeContinuation node) {
if (!node.isRecursive) {
- nullCheckedValue = nullCheckedValueAt[node.continuation.definition];
+ nullCheckedValue = nullCheckedValueAt[node.continuation];
}
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
index 798875f..b357c99 100644
--- a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
+++ b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
@@ -14,6 +14,7 @@
import '../world.dart';
import '../elements/elements.dart';
import 'loop_effects.dart';
+import 'effects.dart';
/// Eliminates bounds checks when they can be proven safe.
///
@@ -268,9 +269,9 @@
@override
void visitBranch(Branch node) {
- Primitive condition = node.condition.definition;
- Continuation trueCont = node.trueContinuation.definition;
- Continuation falseCont = node.falseContinuation.definition;
+ Primitive condition = node.condition;
+ Continuation trueCont = node.trueContinuation;
+ Continuation falseCont = node.falseContinuation;
effectNumberAt[trueCont] = currentEffectNumber;
effectNumberAt[falseCont] = currentEffectNumber;
pushAction(() {
@@ -300,11 +301,11 @@
});
}
if (condition is ApplyBuiltinOperator &&
- condition.arguments.length == 2 &&
- isInt(condition.arguments[0].definition) &&
- isInt(condition.arguments[1].definition)) {
- SignedVariable v1 = getValue(condition.arguments[0].definition);
- SignedVariable v2 = getValue(condition.arguments[1].definition);
+ condition.argumentRefs.length == 2 &&
+ isInt(condition.argument(0)) &&
+ isInt(condition.argument(1))) {
+ SignedVariable v1 = getValue(condition.argument(0));
+ SignedVariable v2 = getValue(condition.argument(1));
switch (condition.operator) {
case BuiltinOperator.NumLe:
pushTrue(() => makeLessThanOrEqual(v1, v2));
@@ -351,16 +352,16 @@
@override
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
if (!isInt(node)) return;
- if (node.arguments.length == 1) {
+ if (node.argumentRefs.length == 1) {
applyUnaryOperator(node);
- } else if (node.arguments.length == 2) {
+ } else if (node.argumentRefs.length == 2) {
applyBinaryOperator(node);
}
}
void applyBinaryOperator(ApplyBuiltinOperator node) {
- Primitive left = node.arguments[0].definition;
- Primitive right = node.arguments[1].definition;
+ Primitive left = node.argument(0);
+ Primitive right = node.argument(1);
if (!isInt(left) || !isInt(right)) {
return;
}
@@ -461,7 +462,7 @@
}
void applyUnaryOperator(ApplyBuiltinOperator node) {
- Primitive argument = node.arguments[0].definition;
+ Primitive argument = node.argument(0);
if (!isInt(argument)) return;
if (node.operator == BuiltinOperator.NumNegate) {
valueOf[node] = getValue(argument).negated;
@@ -486,17 +487,17 @@
@override
void visitGetLength(GetLength node) {
- valueOf[node] = getLength(node.object.definition, currentEffectNumber);
+ valueOf[node] = getLength(node.object, currentEffectNumber);
}
@override
void visitBoundsCheck(BoundsCheck node) {
if (node.checks == BoundsCheck.NONE) return;
- assert(node.index != null); // Because there is at least one check.
- SignedVariable length = node.length == null
+ assert(node.indexRef != null); // Because there is at least one check.
+ SignedVariable length = node.lengthRef == null
? null
- : getValue(node.length.definition);
- SignedVariable index = getValue(node.index.definition);
+ : getValue(node.length);
+ SignedVariable index = getValue(node.index);
if (node.hasUpperBoundCheck) {
if (isDefinitelyLessThan(index, length)) {
node.checks &= ~BoundsCheck.UPPER_BOUND;
@@ -518,24 +519,24 @@
makeGreaterThanOrEqualToConstant(length, 1);
}
}
- if (!node.lengthUsedInCheck && node.length != null) {
- node..length.unlink()..length = null;
+ if (!node.lengthUsedInCheck && node.lengthRef != null) {
+ node..lengthRef.unlink()..lengthRef = null;
}
if (node.checks == BoundsCheck.NONE) {
// We can't remove the bounds check node because it may still be used to
// restrict code motion. But the index is no longer needed.
- node..index.unlink()..index = null;
+ node..indexRef.unlink()..indexRef = null;
}
}
void analyzeLoopEntry(InvokeContinuation node) {
foundLoop = true;
- Continuation cont = node.continuation.definition;
+ Continuation cont = node.continuation;
if (isStrongLoopPass) {
- for (int i = 0; i < node.arguments.length; ++i) {
+ for (int i = 0; i < node.argumentRefs.length; ++i) {
Parameter param = cont.parameters[i];
if (!isInt(param)) continue;
- Primitive initialValue = node.arguments[i].definition;
+ Primitive initialValue = node.argument(i);
SignedVariable initialVariable = getValue(initialValue);
Monotonicity mono = monotonicity[param];
if (mono == null) {
@@ -548,14 +549,14 @@
}
}
}
- if (loopEffects.loopChangesLength(cont)) {
+ if (loopEffects.changesIndexableLength(cont)) {
currentEffectNumber = effectNumberAt[cont] = makeNewEffect();
}
push(cont);
}
void analyzeLoopContinue(InvokeContinuation node) {
- Continuation cont = node.continuation.definition;
+ Continuation cont = node.continuation;
// During the strong loop phase, there is no need to compute monotonicity,
// and we already put bounds on the loop variables when we went into the
@@ -565,10 +566,10 @@
// For each loop parameter, try to prove that the new value is definitely
// less/greater than its old value. When we fail to prove this, update the
// monotonicity flag accordingly.
- for (int i = 0; i < node.arguments.length; ++i) {
+ for (int i = 0; i < node.argumentRefs.length; ++i) {
Parameter param = cont.parameters[i];
if (!isInt(param)) continue;
- SignedVariable arg = getValue(node.arguments[i].definition);
+ SignedVariable arg = getValue(node.argument(i));
SignedVariable paramVar = getValue(param);
if (!isDefinitelyLessThanOrEqualTo(arg, paramVar)) {
// We couldn't prove that the value does not increase, so assume
@@ -594,7 +595,7 @@
@override
void visitInvokeContinuation(InvokeContinuation node) {
- Continuation cont = node.continuation.definition;
+ Continuation cont = node.continuation;
if (node.isRecursive) {
analyzeLoopContinue(node);
} else if (cont.isRecursive) {
@@ -613,6 +614,18 @@
// ---------------- PRIMITIVES --------------------
@override
+ Expression traverseLetPrim(LetPrim node) {
+ visit(node.primitive);
+ // visitApplyBuiltinMethod updates the effect number.
+ if (node.primitive is! ApplyBuiltinMethod) {
+ if (node.primitive.effects & Effects.changesIndexableLength != 0) {
+ currentEffectNumber = makeNewEffect();
+ }
+ }
+ return node.body;
+ }
+
+ @override
void visitInvokeMethod(InvokeMethod node) {
if (node.selector.isGetter && node.selector.name == 'length') {
// If the receiver type is not known to be indexable, the length call
@@ -624,70 +637,11 @@
valueOf[node] = getLength(node.dartReceiver, currentEffectNumber);
}
}
- // TODO(asgerf): What we really need is a "changes length" side effect flag.
- if (world
- .getSideEffectsOfSelector(node.selector, node.mask)
- .changesIndex()) {
- currentEffectNumber = makeNewEffect();
- }
- }
-
- @override
- void visitInvokeStatic(InvokeStatic node) {
- if (world.getSideEffectsOfElement(node.target).changesIndex()) {
- currentEffectNumber = makeNewEffect();
- }
- }
-
- @override
- void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- FunctionElement target = node.target;
- if (target is ConstructorBodyElement) {
- ConstructorBodyElement body = target;
- target = body.constructor;
- }
- if (world.getSideEffectsOfElement(target).changesIndex()) {
- currentEffectNumber = makeNewEffect();
- }
- }
-
- @override
- void visitInvokeConstructor(InvokeConstructor node) {
- if (world.getSideEffectsOfElement(node.target).changesIndex()) {
- currentEffectNumber = makeNewEffect();
- }
- }
-
- @override
- void visitTypeCast(TypeCast node) {
- }
-
- @override
- void visitGetLazyStatic(GetLazyStatic node) {
- // TODO(asgerf): How do we get the side effects of a lazy field initializer?
- currentEffectNumber = makeNewEffect();
- }
-
- @override
- void visitForeignCode(ForeignCode node) {
- if (node.nativeBehavior.sideEffects.changesIndex()) {
- currentEffectNumber = makeNewEffect();
- }
- }
-
- @override
- void visitAwait(Await node) {
- currentEffectNumber = makeNewEffect();
- }
-
- @override
- void visitYield(Yield node) {
- currentEffectNumber = makeNewEffect();
}
@override
void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- Primitive receiver = node.receiver.definition;
+ Primitive receiver = node.receiver;
int effectBefore = currentEffectNumber;
currentEffectNumber = makeNewEffect();
int effectAfter = currentEffectNumber;
@@ -696,7 +650,7 @@
switch (node.method) {
case BuiltinMethod.Push:
// after = before + count
- int count = node.arguments.length;
+ int count = node.argumentRefs.length;
makeExactSum(lengthAfter, lengthBefore, count);
break;
@@ -704,12 +658,16 @@
// after = before - 1
makeExactSum(lengthAfter, lengthBefore, -1);
break;
+
+ case BuiltinMethod.SetLength:
+ makeEqual(lengthAfter, getValue(node.argument(0)));
+ break;
}
}
@override
void visitLiteralList(LiteralList node) {
- makeConstant(getLength(node, currentEffectNumber), node.values.length);
+ makeConstant(getLength(node, currentEffectNumber), node.valueRefs.length);
}
// ---------------- INTERIOR EXPRESSIONS --------------------
diff --git a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
index 7992821..5751644 100644
--- a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
+++ b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
@@ -5,6 +5,8 @@
// This is shared by the CPS and Tree IRs.
// Both cps_ir_nodes and tree_ir_nodes import and re-export this file.
+import 'effects.dart';
+
/// An operator supported natively in the CPS and Tree IRs using the
/// `ApplyBuiltinOperator` instructions.
///
@@ -187,7 +189,7 @@
/// but may not depend on or mutate any other state. An exception is thrown
/// if the object is null, but otherwise they cannot throw or diverge.
enum BuiltinMethod {
- /// Add an item to a native list.
+ /// Add an item to an array.
///
/// Takes any number of arguments, each argument will be added to the
/// list on the order given (as per the JS `push` method).
@@ -195,12 +197,17 @@
/// Compiles to `object.push(x1, ..., xN)`.
Push,
- /// Remove and return the last item from a native list.
+ /// Remove and return the last item from an array.
///
/// Takes no arguments.
///
/// Compiles to `object.pop()`.
Pop,
+
+ /// Sets the length of the array.
+ ///
+ /// Compiles to `object.length = x1`.
+ SetLength,
}
/// True for the built-in operators that may be used in a compound assignment.
@@ -217,3 +224,17 @@
return false;
}
}
+
+int getEffectsOfBuiltinMethod(BuiltinMethod method) {
+ switch (method) {
+ case BuiltinMethod.Push:
+ return Effects.changesIndexableContent |
+ Effects.changesIndexableLength;
+ case BuiltinMethod.Pop:
+ return Effects.dependsOnIndexableContent |
+ Effects.dependsOnIndexableLength |
+ Effects.changesIndexableLength;
+ case BuiltinMethod.SetLength:
+ return Effects.changesIndexableLength;
+ }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
index 7e62fa5..f30375a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -124,7 +124,6 @@
{bool receiverIsNotNull: false}) {
ApplyBuiltinMethod apply =
new ApplyBuiltinMethod(method, receiver, arguments, sourceInformation);
- apply.receiverIsNotNull = receiverIsNotNull;
return letPrim(apply);
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index 8ec5743..95fa11a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -343,8 +343,8 @@
arguments.add(new ir.Reference(invocationEnvironment[varIndex]));
}
ir.InvokeContinuation invocation = _invocations[jumpIndex];
- invocation.continuation = new ir.Reference(_continuation);
- invocation.arguments = arguments;
+ invocation.continuationRef = new ir.Reference(_continuation);
+ invocation.argumentRefs = arguments;
}
}
}
@@ -2588,7 +2588,8 @@
}
ir.Primitive buildFieldGet(ir.Primitive receiver, FieldElement target) {
- return addPrimitive(new ir.GetField(receiver, target));
+ return addPrimitive(new ir.GetField(receiver, target,
+ isFinal: program.fieldNeverChanges(target)));
}
void buildFieldSet(ir.Primitive receiver,
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index 629bfac..cfea55a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -878,9 +878,13 @@
typeMaskSystem.associateConstantValueWithElement(constant, field);
return irBuilder.buildConstant(constant, sourceInformation: src);
} else if (backend.constants.lazyStatics.contains(field)) {
- return irBuilder.addPrimitive(new ir.GetLazyStatic(field, src));
+ return irBuilder.addPrimitive(new ir.GetLazyStatic(field,
+ sourceInformation: src,
+ isFinal: compiler.world.fieldNeverChanges(field)));
} else {
- return irBuilder.addPrimitive(new ir.GetStatic(field, src));
+ return irBuilder.addPrimitive(new ir.GetStatic(field,
+ sourceInformation: src,
+ isFinal: compiler.world.fieldNeverChanges(field)));
}
}
@@ -1936,7 +1940,7 @@
ast.Send node,
MethodElement function,
_) {
- return irBuilder.addPrimitive(new ir.GetStatic(function));
+ return irBuilder.addPrimitive(new ir.GetStatic(function, isFinal: true));
}
@override
@@ -2902,7 +2906,8 @@
case CompoundGetter.GETTER:
return buildStaticGetterGet(getter, node);
case CompoundGetter.METHOD:
- return irBuilder.addPrimitive(new ir.GetStatic(getter));
+ return irBuilder.addPrimitive(new ir.GetStatic(getter,
+ isFinal: true));
case CompoundGetter.UNRESOLVED:
return irBuilder.buildStaticNoSuchMethod(
new Selector.getter(new Name(getter.name, getter.library)),
@@ -2942,7 +2947,8 @@
case CompoundGetter.GETTER:
return buildStaticGetterGet(getter, node);
case CompoundGetter.METHOD:
- return irBuilder.addPrimitive(new ir.GetStatic(getter));
+ return irBuilder.addPrimitive(new ir.GetStatic(getter,
+ isFinal: true));
case CompoundGetter.UNRESOLVED:
return irBuilder.buildStaticNoSuchMethod(
new Selector.getter(new Name(getter.name, getter.library)),
@@ -4014,6 +4020,10 @@
return _compiler.world.locateSingleField(selector, type);
}
+ bool fieldNeverChanges(FieldElement field) {
+ return _compiler.world.fieldNeverChanges(field);
+ }
+
Element get closureConverter {
return _backend.helpers.closureConverter;
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
index a295902..8fb65a2 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
@@ -110,7 +110,7 @@
@override
Expression traverseLetMutable(LetMutable node) {
handleDeclaration(node.variable);
- processReference(node.value);
+ processReference(node.valueRef);
// Put the primitive in scope when visiting the body.
enterScope([node.variable]);
@@ -166,7 +166,7 @@
@override
processInvokeContinuation(InvokeContinuation node) {
- Continuation target = node.continuation.definition;
+ Continuation target = node.continuation;
if (node.isRecursive && inScope[target] == ScopeType.InScope) {
error('Non-recursive InvokeContinuation marked as recursive', node);
}
@@ -176,7 +176,7 @@
if (node.isRecursive && !target.isRecursive) {
error('Recursive Continuation was not marked as recursive', node);
}
- if (node.arguments.length != target.parameters.length) {
+ if (node.argumentRefs.length != target.parameters.length) {
error('Arity mismatch in InvokeContinuation', node);
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index 1562262..61a5ddd 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -12,10 +12,13 @@
import '../io/source_information.dart' show SourceInformation;
import '../types/types.dart' show TypeMask;
import '../universe/selector.dart' show Selector;
+import '../universe/side_effects.dart';
import 'builtin_operator.dart';
export 'builtin_operator.dart';
+import 'effects.dart';
+
// These imports are only used for the JavaScript specific nodes. If we want to
// support more than one native backend, we should probably create better
// abstractions for native code and its type and effect system.
@@ -64,7 +67,8 @@
/// same node.
String debugString([Map annotations]) {
return new SExpressionStringifier()
- .withAnnotations(annotations).visit(this);
+ .withAnnotations(annotations)
+ .visit(this);
}
/// Prints the result of [debugString].
@@ -115,70 +119,17 @@
accept(BlockVisitor visitor);
}
-/// An expression that creates new bindings and continues evaluation in
-/// a subexpression.
-///
-/// The interior expressions are [LetPrim], [LetCont], [LetHandler], and
-/// [LetMutable].
-abstract class InteriorExpression extends Expression implements InteriorNode {
- Expression get next => body;
-
- /// Removes this expression from its current position in the IR.
- ///
- /// The node can be re-inserted elsewhere or remain orphaned.
- ///
- /// If orphaned, the caller is responsible for unlinking all references in
- /// the orphaned node. Use [Reference.unlink] or [Primitive.destroy] for this.
- void remove() {
- assert(parent != null);
- assert(parent.body == this);
- assert(body.parent == this);
- parent.body = body;
- body.parent = parent;
- parent = null;
- body = null;
- }
-
- /// Inserts this above [node].
- ///
- /// This node must be orphaned first.
- void insertAbove(Expression node) {
- insertBelow(node.parent);
- }
-
- /// Inserts this below [node].
- ///
- /// This node must be orphaned first.
- void insertBelow(InteriorNode newParent) {
- assert(parent == null);
- assert(body == null);
- Expression child = newParent.body;
- newParent.body = this;
- this.body = child;
- child.parent = this;
- this.parent = newParent;
- }
-}
-
-/// An expression without a continuation or a subexpression body.
-///
-/// These break straight-line control flow and can be thought of as ending a
-/// basic block.
-abstract class TailExpression extends Expression {
- Expression get next => null;
-}
-
/// The base class of things that variables can refer to: primitives,
/// continuations, function and continuation parameters, etc.
abstract class Definition<T extends Definition<T>> extends Node {
// The head of a linked-list of occurrences, in no particular order.
Reference<T> firstRef;
- bool get hasAtMostOneUse => firstRef == null || firstRef.next == null;
+ bool get hasAtMostOneUse => firstRef == null || firstRef.next == null;
bool get hasExactlyOneUse => firstRef != null && firstRef.next == null;
bool get hasNoUses => firstRef == null;
bool get hasAtLeastOneUse => firstRef != null;
- bool get hasMultipleUses => !hasAtMostOneUse;
+ bool get hasMultipleUses => !hasAtMostOneUse;
void replaceUsesWith(Definition<T> newDefinition) {
if (newDefinition == this) return;
@@ -198,6 +149,45 @@
}
}
+/// Operands to invocations and primitives are always variables. They point to
+/// their definition and are doubly-linked into a list of occurrences.
+class Reference<T extends Definition<T>> {
+ T definition;
+ Reference<T> previous;
+ Reference<T> next;
+
+ /// A pointer to the parent node. Is null until set by optimization passes.
+ Node parent;
+
+ Reference(this.definition) {
+ next = definition.firstRef;
+ if (next != null) next.previous = this;
+ definition.firstRef = this;
+ }
+
+ /// Unlinks this reference from the list of occurrences.
+ void unlink() {
+ if (previous == null) {
+ assert(definition.firstRef == this);
+ definition.firstRef = next;
+ } else {
+ previous.next = next;
+ }
+ if (next != null) next.previous = previous;
+ }
+
+ /// Changes the definition referenced by this object and updates
+ /// the reference chains accordingly.
+ void changeTo(Definition<T> newDefinition) {
+ unlink();
+ previous = null;
+ definition = newDefinition;
+ next = definition.firstRef;
+ if (next != null) next.previous = this;
+ definition.firstRef = this;
+ }
+}
+
class EffectiveUseIterator extends Iterator<Reference<Primitive>> {
Reference<Primitive> current;
Reference<Primitive> next;
@@ -242,6 +232,10 @@
abstract class Primitive extends Variable<Primitive> {
Primitive() : super(null);
+ /// Returns a bitmask with the non-local side effects and dependencies of
+ /// this primitive, as defined by [Effects].
+ int get effects => Effects.none;
+
/// True if this primitive has a value that can be used by other expressions.
bool get hasValue;
@@ -260,8 +254,8 @@
// TODO(johnniwinther): Require source information for all primitives.
SourceInformation get sourceInformation => null;
- /// If this is a [Refinement], [BoundsCheck] or [ReceiverCheck] node, returns the
- /// value being refined, the indexable object being checked, or the value
+ /// If this is a [Refinement], [BoundsCheck] or [ReceiverCheck] node, returns
+ /// the value being refined, the indexable object being checked, or the value
/// that was checked to be non-null, respectively.
///
/// Those instructions all return the corresponding operand directly, and
@@ -343,1374 +337,6 @@
}
}
-/// A primitive that is generally not safe for elimination, but may be marked
-/// as safe by type propagation
-//
-// TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this
-// class.
-abstract class UnsafePrimitive extends Primitive {
- bool isSafeForElimination = false;
- bool isSafeForReordering = false;
-}
-
-/// Operands to invocations and primitives are always variables. They point to
-/// their definition and are doubly-linked into a list of occurrences.
-class Reference<T extends Definition<T>> {
- T definition;
- Reference<T> previous;
- Reference<T> next;
-
- /// A pointer to the parent node. Is null until set by optimization passes.
- Node parent;
-
- Reference(this.definition) {
- next = definition.firstRef;
- if (next != null) next.previous = this;
- definition.firstRef = this;
- }
-
- /// Unlinks this reference from the list of occurrences.
- void unlink() {
- if (previous == null) {
- assert(definition.firstRef == this);
- definition.firstRef = next;
- } else {
- previous.next = next;
- }
- if (next != null) next.previous = previous;
- }
-
- /// Changes the definition referenced by this object and updates
- /// the reference chains accordingly.
- void changeTo(Definition<T> newDefinition) {
- unlink();
- previous = null;
- definition = newDefinition;
- next = definition.firstRef;
- if (next != null) next.previous = this;
- definition.firstRef = this;
- }
-}
-
-/// Evaluates a primitive and binds it to variable: `let val x = V in E`.
-///
-/// The bound value is in scope in the body.
-///
-/// During one-pass construction a LetPrim with an empty body is used to
-/// represent the one-hole context `let val x = V in []`.
-class LetPrim extends InteriorExpression {
- Primitive primitive;
- Expression body;
-
- LetPrim(this.primitive, [this.body = null]);
-
- Expression plug(Expression expr) {
- assert(body == null);
- return body = expr;
- }
-
- accept(BlockVisitor visitor) => visitor.visitLetPrim(this);
-
- void setParentPointers() {
- primitive.parent = this;
- if (body != null) body.parent = this;
- }
-}
-
-/// Binding continuations.
-///
-/// let cont k0(v0 ...) = E0
-/// k1(v1 ...) = E1
-/// ...
-/// in E
-///
-/// The bound continuations are in scope in the body and the continuation
-/// parameters are in scope in the respective continuation bodies.
-///
-/// During one-pass construction a LetCont whose first continuation has an empty
-/// body is used to represent the one-hole context
-/// `let cont ... k(v) = [] ... in E`.
-class LetCont extends InteriorExpression {
- List<Continuation> continuations;
- Expression body;
-
- LetCont(Continuation continuation, this.body)
- : continuations = <Continuation>[continuation];
-
- LetCont.two(Continuation first, Continuation second, this.body)
- : continuations = <Continuation>[first, second];
-
- LetCont.many(this.continuations, this.body);
-
- Expression plug(Expression expr) {
- assert(continuations != null &&
- continuations.isNotEmpty &&
- continuations.first.body == null);
- return continuations.first.body = expr;
- }
-
- accept(BlockVisitor visitor) => visitor.visitLetCont(this);
-
- void setParentPointers() {
- _setParentsOnNodes(continuations, this);
- if (body != null) body.parent = this;
- }
-}
-
-// Binding an exception handler.
-//
-// let handler h(v0, v1) = E0 in E1
-//
-// The handler is a two-argument (exception, stack trace) continuation which
-// is implicitly the error continuation of all the code in its body E1.
-// [LetHandler] differs from a [LetCont] binding in that it (1) has the
-// runtime semantics of pushing/popping a handler from the dynamic exception
-// handler stack and (2) it does not have any explicit invocations.
-class LetHandler extends InteriorExpression {
- Continuation handler;
- Expression body;
-
- LetHandler(this.handler, this.body);
-
- accept(BlockVisitor visitor) => visitor.visitLetHandler(this);
-
- void setParentPointers() {
- handler.parent = this;
- if (body != null) body.parent = this;
- }
-}
-
-/// Binding mutable variables.
-///
-/// let mutable v = P in E
-///
-/// [MutableVariable]s can be seen as ref cells that are not first-class
-/// values. They are therefore not [Primitive]s and not bound by [LetPrim]
-/// to prevent unrestricted use of references to them. During one-pass
-/// construction, a [LetMutable] with an empty body is use to represent the
-/// one-hole context 'let mutable v = P in []'.
-class LetMutable extends InteriorExpression {
- final MutableVariable variable;
- final Reference<Primitive> value;
- Expression body;
-
- LetMutable(this.variable, Primitive value)
- : this.value = new Reference<Primitive>(value);
-
- Expression plug(Expression expr) {
- return body = expr;
- }
-
- accept(BlockVisitor visitor) => visitor.visitLetMutable(this);
-
- void setParentPointers() {
- variable.parent = this;
- value.parent = this;
- if (body != null) body.parent = this;
- }
-}
-
-enum CallingConvention {
- /// JS receiver is the Dart receiver, there are no extra arguments.
- ///
- /// This includes cases (e.g., static functions, constructors) where there
- /// is no receiver.
- ///
- /// For example: `foo.bar$1(x)`
- Normal,
-
- /// JS receiver is an interceptor, the first argument is the Dart receiver.
- ///
- /// For example: `getInterceptor(foo).bar$1(foo, x)`
- Intercepted,
-
- /// JS receiver is the Dart receiver, the first argument is a dummy value.
- ///
- /// For example: `foo.bar$1(0, x)`
- DummyIntercepted,
-
- /// JS receiver is the Dart receiver, there are no extra arguments.
- ///
- /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)`
- OneShotIntercepted,
-}
-
-/// Base class of function invocations.
-///
-/// This class defines the common interface of function invocations.
-abstract class InvocationPrimitive extends UnsafePrimitive {
- Reference<Primitive> get receiver => null;
- List<Reference<Primitive>> get arguments;
- SourceInformation get sourceInformation;
-
- Reference<Primitive> get dartReceiverReference => null;
- Primitive get dartReceiver => dartReceiverReference.definition;
-
- CallingConvention get callingConvention => CallingConvention.Normal;
-
- Reference<Primitive> dartArgumentReference(int n) {
- switch (callingConvention) {
- case CallingConvention.Normal:
- case CallingConvention.OneShotIntercepted:
- return arguments[n];
-
- case CallingConvention.Intercepted:
- case CallingConvention.DummyIntercepted:
- return arguments[n + 1];
- }
- }
-
- Primitive dartArgument(int n) => dartArgumentReference(n).definition;
-
- int get dartArgumentsLength =>
- arguments.length -
- (callingConvention == CallingConvention.Intercepted ||
- callingConvention == CallingConvention.DummyIntercepted ? 1 : 0);
-}
-
-/// Invoke a static function.
-///
-/// All optional arguments declared by [target] are passed in explicitly, and
-/// occur at the end of [arguments] list, in normalized order.
-///
-/// Discussion:
-/// All information in the [selector] is technically redundant; it will likely
-/// be removed.
-class InvokeStatic extends InvocationPrimitive {
- final FunctionElement target;
- final Selector selector;
- final List<Reference<Primitive>> arguments;
- final SourceInformation sourceInformation;
-
- InvokeStatic(this.target,
- this.selector,
- List<Primitive> args,
- [this.sourceInformation])
- : arguments = _referenceList(args);
-
- InvokeStatic.byReference(this.target,
- this.selector,
- this.arguments,
- [this.sourceInformation]);
-
- accept(Visitor visitor) => visitor.visitInvokeStatic(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {
- _setParentsOnList(arguments, this);
- }
-}
-
-/// Invoke a method on an object.
-///
-/// This includes getters, setters, operators, and index getter/setters.
-///
-/// Tearing off a method is treated like a getter invocation (getters and
-/// tear-offs cannot be distinguished at compile-time).
-///
-/// The [selector] records the names of named arguments. The value of named
-/// arguments occur at the end of the [arguments] list, in normalized order.
-class InvokeMethod extends InvocationPrimitive {
- Reference<Primitive> receiver;
- Selector selector;
- TypeMask mask;
- final List<Reference<Primitive>> arguments;
- final SourceInformation sourceInformation;
-
- CallingConvention callingConvention = CallingConvention.Normal;
-
- Reference<Primitive> get dartReceiverReference {
- return callingConvention == CallingConvention.Intercepted
- ? arguments[0]
- : receiver;
- }
-
- /// If true, it is known that the receiver cannot be `null`.
- bool receiverIsNotNull = false;
-
- InvokeMethod(Primitive receiver,
- this.selector,
- this.mask,
- List<Primitive> arguments,
- {this.sourceInformation,
- this.callingConvention: CallingConvention.Normal})
- : this.receiver = new Reference<Primitive>(receiver),
- this.arguments = _referenceList(arguments);
-
- accept(Visitor visitor) => visitor.visitInvokeMethod(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {
- receiver.parent = this;
- _setParentsOnList(arguments, this);
- }
-}
-
-/// Invoke [target] on [receiver], bypassing dispatch and override semantics.
-///
-/// That is, if [receiver] is an instance of a class that overrides [target]
-/// with a different implementation, the overriding implementation is bypassed
-/// and [target]'s implementation is invoked.
-///
-/// As with [InvokeMethod], this can be used to invoke a method, operator,
-/// getter, setter, or index getter/setter.
-///
-/// If it is known that [target] does not use its receiver argument, then
-/// [receiver] may refer to a null constant primitive. This happens for direct
-/// invocations to intercepted methods, where the effective receiver is instead
-/// passed as a formal parameter.
-///
-/// TODO(sra): Review. A direct call to a method that is mixed into a native
-/// class will still require an explicit argument.
-///
-/// All optional arguments declared by [target] are passed in explicitly, and
-/// occur at the end of [arguments] list, in normalized order.
-class InvokeMethodDirectly extends InvocationPrimitive {
- Reference<Primitive> receiver;
- final FunctionElement target;
- final Selector selector;
- final List<Reference<Primitive>> arguments;
- final SourceInformation sourceInformation;
-
- CallingConvention callingConvention;
-
- Reference<Primitive> get dartReceiverReference {
- return callingConvention == CallingConvention.Intercepted
- ? arguments[0]
- : receiver;
- }
-
- InvokeMethodDirectly(Primitive receiver,
- this.target,
- this.selector,
- List<Primitive> arguments,
- this.sourceInformation,
- {this.callingConvention: CallingConvention.Normal})
- : this.receiver = new Reference<Primitive>(receiver),
- this.arguments = _referenceList(arguments);
-
- accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {
- receiver.parent = this;
- _setParentsOnList(arguments, this);
- }
-
- bool get isConstructorBodyCall => target is ConstructorBodyElement;
- bool get isTearOff => selector.isGetter && !target.isGetter;
-}
-
-/// Non-const call to a constructor.
-///
-/// The [target] may be a generative constructor (forwarding or normal)
-/// or a non-redirecting factory.
-///
-/// All optional arguments declared by [target] are passed in explicitly, and
-/// occur in the [arguments] list, in normalized order.
-///
-/// Last in the [arguments] list, after the mandatory and optional arguments,
-/// the internal representation of each type argument occurs, unless it could
-/// be determined at build-time that the constructed class has no need for its
-/// runtime type information.
-///
-/// Note that [InvokeConstructor] does it itself allocate an object.
-/// The invoked constructor will do that using [CreateInstance].
-class InvokeConstructor extends InvocationPrimitive {
- final DartType dartType;
- final ConstructorElement target;
- final List<Reference<Primitive>> arguments;
- final Selector selector;
- final SourceInformation sourceInformation;
-
- /// If non-null, this is an allocation site-specific type that is potentially
- /// better than the inferred return type of [target].
- ///
- /// In particular, container type masks depend on the allocation site and
- /// can therefore not be inferred solely based on the call target.
- TypeMask allocationSiteType;
-
- InvokeConstructor(this.dartType,
- this.target,
- this.selector,
- List<Primitive> args,
- this.sourceInformation,
- {this.allocationSiteType})
- : arguments = _referenceList(args);
-
- accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {
- _setParentsOnList(arguments, this);
- }
-}
-
-/// An alias for [value] in a context where the value is known to satisfy
-/// [type].
-///
-/// Refinement nodes are inserted before the type propagator pass and removed
-/// afterwards, so as not to complicate passes that don't reason about types,
-/// but need to reason about value references being identical (i.e. referring
-/// to the same primitive).
-class Refinement extends Primitive {
- Reference<Primitive> value;
- final TypeMask refineType;
-
- Refinement(Primitive value, this.refineType)
- : value = new Reference<Primitive>(value);
-
- bool get hasValue => true;
- bool get isSafeForElimination => false;
- bool get isSafeForReordering => false;
-
- accept(Visitor visitor) => visitor.visitRefinement(this);
-
- Primitive get effectiveDefinition => value.definition.effectiveDefinition;
-
- Primitive get unrefined => value.definition.unrefined;
-
- void setParentPointers() {
- value.parent = this;
- }
-}
-
-/// Checks that [index] is a valid index on a given indexable [object].
-///
-/// In the simplest form, compiles to the following:
-///
-/// if (index < 0 || index >= object.length)
-/// ThrowIndexOutOfRangeException(object, index);
-///
-/// In the general form, any of the following conditions can be checked:
-///
-/// Lower bound: `index >= 0`
-/// Upper bound: `index < object.length`
-/// Emptiness: `object.length !== 0`
-/// Integerness: `index >>> 0 === index`
-///
-/// [index] must be an integer unless integerness is checked, and [object] must
-/// refer to null or an indexable object, and [length] must be the length of
-/// [object] at the time of the check.
-///
-/// Returns [object] so the bounds check can be used to restrict code motion.
-/// It is possible to have a bounds check node that performs no checks but
-/// is retained to restrict code motion.
-///
-/// The [index] reference may be null if there are no checks to perform,
-/// and the [length] reference may be null if there is no upper bound or
-/// emptiness check.
-///
-/// If a separate code motion guard for the index is required, e.g. because it
-/// must be known to be non-negative in an operator that does not involve
-/// [object], a [Refinement] can be created for it with the non-negative integer
-/// type.
-class BoundsCheck extends Primitive {
- final Reference<Primitive> object;
- Reference<Primitive> index;
- Reference<Primitive> length;
- int checks;
- final SourceInformation sourceInformation;
-
- /// If true, check that `index >= 0`.
- bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0;
-
- /// If true, check that `index < object.length`.
- bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0;
-
- /// If true, check that `object.length !== 0`.
- ///
- /// Equivalent to a lower bound check with `object.length - 1` as the index,
- /// but this check is faster.
- ///
- /// Although [index] is not used in the condition, it is used to generate
- /// the thrown error. Currently it is always `-1` for emptiness checks,
- /// because that corresponds to `object.length - 1` in the error case.
- bool get hasEmptinessCheck => checks & EMPTINESS != 0;
-
- /// If true, check that `index` is an integer.
- bool get hasIntegerCheck => checks & INTEGER != 0;
-
- /// True if the [length] is needed to perform the check.
- bool get lengthUsedInCheck => checks & (UPPER_BOUND | EMPTINESS) != 0;
-
- bool get hasNoChecks => checks == NONE;
-
- static const int UPPER_BOUND = 1 << 0;
- static const int LOWER_BOUND = 1 << 1;
- static const int EMPTINESS = 1 << 2; // See [hasEmptinessCheck].
- static const int INTEGER = 1 << 3; // Check if index is an int.
- static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND;
- static const int NONE = 0;
-
- BoundsCheck(Primitive object, Primitive index, Primitive length,
- [this.checks = BOTH_BOUNDS, this.sourceInformation])
- : this.object = new Reference<Primitive>(object),
- this.index = new Reference<Primitive>(index),
- this.length = length == null ? null : new Reference<Primitive>(length);
-
- BoundsCheck.noCheck(Primitive object, [this.sourceInformation])
- : this.object = new Reference<Primitive>(object),
- this.checks = NONE;
-
- accept(Visitor visitor) => visitor.visitBoundsCheck(this);
-
- void setParentPointers() {
- object.parent = this;
- if (index != null) {
- index.parent = this;
- }
- if (length != null) {
- length.parent = this;
- }
- }
-
- String get checkString {
- if (hasNoChecks) return 'no-check';
- return [hasUpperBoundCheck ? 'upper' : null,
- hasLowerBoundCheck ? 'lower' : null,
- hasEmptinessCheck ? 'emptiness' : null,
- hasIntegerCheck ? 'integer' : null,
- 'check']
- .where((x) => x != null).join('-');
- }
-
- bool get isSafeForElimination => checks == NONE;
- bool get isSafeForReordering => false;
- bool get hasValue => true; // Can be referenced to restrict code motion.
-
- Primitive get effectiveDefinition => object.definition.effectiveDefinition;
-}
-
-/// Throw a [NoSuchMethodError] if [value] cannot respond to [selector].
-///
-/// Returns [value] so this can be used to restrict code motion.
-///
-/// The check can take one of three forms:
-///
-/// value.toString;
-/// value.selectorName;
-/// value.selectorName(); (should only be used if check always fails)
-///
-/// The first two forms are used when it is known that only null fails the
-/// check. Additionally, the check may be guarded by a [condition], allowing
-/// for three more forms:
-///
-/// if (condition) value.toString; (this form is valid but unused)
-/// if (condition) value.selectorName;
-/// if (condition) value.selectorName();
-///
-/// The condition must be true if and only if the check should fail. It should
-/// ideally be of a form understood by JS engines, e.g. a `typeof` test.
-///
-/// If [useSelector] is false, the first form instead becomes `value.toString;`.
-/// This form is faster when the value is non-null and the accessed property has
-/// been removed by tree shaking.
-///
-/// [selector] may not be one of the selectors implemented by the null object.
-class ReceiverCheck extends Primitive {
- final Reference<Primitive> value;
- final Selector selector;
- final SourceInformation sourceInformation;
- final Reference<Primitive> condition;
- final int _flags;
-
- static const int _USE_SELECTOR = 1 << 0;
- static const int _NULL_CHECK = 1 << 1;
-
- /// True if the selector name should be used in the check; otherwise
- /// `toString` will be used.
- bool get useSelector => _flags & _USE_SELECTOR != 0;
-
- /// True if null is the only possible input that cannot respond to [selector].
- bool get isNullCheck => _flags & _NULL_CHECK != 0;
-
-
- /// Constructor for creating checks in arbitrary configurations.
- ///
- /// Consider using one of the named constructors instead.
- ///
- /// [useSelector] and [isNullCheck] are mandatory named arguments.
- ReceiverCheck(Primitive value, this.selector, this.sourceInformation,
- {Primitive condition, bool useSelector, bool isNullCheck})
- : value = new Reference<Primitive>(value),
- condition = _optionalReference(condition),
- _flags = (useSelector ? _USE_SELECTOR : 0) |
- (isNullCheck ? _NULL_CHECK : 0);
-
- /// Simplified constructor for building null checks.
- ///
- /// Null must be the only possible input value that does not respond to
- /// [selector].
- ReceiverCheck.nullCheck(
- Primitive value,
- Selector selector,
- SourceInformation sourceInformation,
- {Primitive condition})
- : this(value,
- selector,
- sourceInformation,
- condition: condition,
- useSelector: condition != null,
- isNullCheck: true);
-
- /// Simplified constructor for building the general check of form:
- ///
- /// if (condition) value.selectorName();
- ///
- ReceiverCheck.generalCheck(
- Primitive value,
- Selector selector,
- SourceInformation sourceInformation,
- Primitive condition)
- : this(value,
- selector,
- sourceInformation,
- condition: condition,
- useSelector: true,
- isNullCheck: false);
-
- bool get isSafeForElimination => false;
- bool get isSafeForReordering => false;
- bool get hasValue => true;
-
- accept(Visitor visitor) => visitor.visitReceiverCheck(this);
-
- void setParentPointers() {
- value.parent = this;
- if (condition != null) {
- condition.parent = this;
- }
- }
-
- Primitive get effectiveDefinition => value.definition.effectiveDefinition;
-
- String get nullCheckString => isNullCheck ? 'null-check' : 'general-check';
- String get useSelectorString => useSelector ? 'use-selector' : 'no-selector';
- String get flagString => '$nullCheckString $useSelectorString';
-}
-
-/// An "is" type test.
-///
-/// Returns `true` if [value] is an instance of [dartType].
-///
-/// [type] must not be the [Object], `dynamic` or [Null] types (though it might
-/// be a type variable containing one of these types). This design is chosen
-/// to simplify code generation for type tests.
-class TypeTest extends Primitive {
- Reference<Primitive> value;
- final DartType dartType;
-
- /// If [dartType] is an [InterfaceType], this holds the internal
- /// representation of the type arguments to [dartType]. Since these may
- /// reference type variables from the enclosing class, they are not constant.
- ///
- /// If [dartType] is a [TypeVariableType], this is a singleton list with the
- /// internal representation of the type held in that type variable.
- ///
- /// If [dartType] is a [FunctionType], this is a singleton list with the
- /// internal representation of that type,
- ///
- /// Otherwise the list is empty.
- final List<Reference<Primitive>> typeArguments;
-
- TypeTest(Primitive value,
- this.dartType,
- List<Primitive> typeArguments)
- : this.value = new Reference<Primitive>(value),
- this.typeArguments = _referenceList(typeArguments);
-
- accept(Visitor visitor) => visitor.visitTypeTest(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- value.parent = this;
- _setParentsOnList(typeArguments, this);
- }
-}
-
-/// An "is" type test for a raw type, performed by testing a flag property.
-///
-/// Returns `true` if [interceptor] is for [dartType].
-class TypeTestViaFlag extends Primitive {
- Reference<Primitive> interceptor;
- final DartType dartType;
-
- TypeTestViaFlag(Primitive interceptor, this.dartType)
- : this.interceptor = new Reference<Primitive>(interceptor);
-
- accept(Visitor visitor) => visitor.visitTypeTestViaFlag(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- interceptor.parent = this;
- }
-}
-
-/// An "as" type cast.
-///
-/// If [value] is `null` or is an instance of [type], [continuation] is invoked
-/// with [value] as argument. Otherwise, a [CastError] is thrown.
-///
-/// Discussion:
-/// The parameter to [continuation] is redundant since it will always equal
-/// [value], which is typically in scope in the continuation. However, it might
-/// simplify type propagation, since a better type can be computed for the
-/// continuation parameter without needing flow-sensitive analysis.
-class TypeCast extends UnsafePrimitive {
- Reference<Primitive> value;
- final DartType dartType;
-
- /// See the corresponding field on [TypeTest].
- final List<Reference<Primitive>> typeArguments;
-
- TypeCast(Primitive value,
- this.dartType,
- List<Primitive> typeArguments)
- : this.value = new Reference<Primitive>(value),
- this.typeArguments = _referenceList(typeArguments);
-
- accept(Visitor visitor) => visitor.visitTypeCast(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {
- value.parent = this;
- _setParentsOnList(typeArguments, this);
- }
-}
-
-/// Apply a built-in operator.
-///
-/// It must be known that the arguments have the proper types.
-class ApplyBuiltinOperator extends Primitive {
- BuiltinOperator operator;
- List<Reference<Primitive>> arguments;
- final SourceInformation sourceInformation;
-
- ApplyBuiltinOperator(this.operator,
- List<Primitive> arguments,
- this.sourceInformation)
- : this.arguments = _referenceList(arguments);
-
- accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- _setParentsOnList(arguments, this);
- }
-}
-
-/// Apply a built-in method.
-///
-/// It must be known that the arguments have the proper types.
-class ApplyBuiltinMethod extends Primitive {
- BuiltinMethod method;
- Reference<Primitive> receiver;
- List<Reference<Primitive>> arguments;
- final SourceInformation sourceInformation;
-
- bool receiverIsNotNull;
-
- ApplyBuiltinMethod(this.method,
- Primitive receiver,
- List<Primitive> arguments,
- this.sourceInformation,
- {this.receiverIsNotNull: false})
- : this.receiver = new Reference<Primitive>(receiver),
- this.arguments = _referenceList(arguments);
-
- accept(Visitor visitor) => visitor.visitApplyBuiltinMethod(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => false;
- bool get isSafeForReordering => false;
-
- void setParentPointers() {
- receiver.parent = this;
- _setParentsOnList(arguments, this);
- }
-}
-
-/// Throw a value.
-///
-/// Throw is an expression, i.e., it always occurs in tail position with
-/// respect to a body or expression.
-class Throw extends TailExpression {
- Reference<Primitive> value;
-
- Throw(Primitive value) : value = new Reference<Primitive>(value);
-
- accept(BlockVisitor visitor) => visitor.visitThrow(this);
-
- void setParentPointers() {
- value.parent = this;
- }
-}
-
-/// Rethrow
-///
-/// Rethrow can only occur inside a continuation bound by [LetHandler]. It
-/// implicitly throws the exception parameter of the enclosing handler with
-/// the same stack trace as the enclosing handler.
-class Rethrow extends TailExpression {
- accept(BlockVisitor visitor) => visitor.visitRethrow(this);
- void setParentPointers() {}
-}
-
-/// An expression that is known to be unreachable.
-///
-/// This can be placed as the body of a call continuation, when the caller is
-/// known never to invoke it, e.g. because the calling expression always throws.
-class Unreachable extends TailExpression {
- accept(BlockVisitor visitor) => visitor.visitUnreachable(this);
- void setParentPointers() {}
-}
-
-/// Gets the value from a [MutableVariable].
-///
-/// [MutableVariable]s can be seen as ref cells that are not first-class
-/// values. A [LetPrim] with a [GetMutable] can then be seen as:
-///
-/// let prim p = ![variable] in [body]
-///
-class GetMutable extends Primitive {
- final Reference<MutableVariable> variable;
-
- GetMutable(MutableVariable variable)
- : this.variable = new Reference<MutableVariable>(variable);
-
- accept(Visitor visitor) => visitor.visitGetMutable(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => false;
-
- void setParentPointers() {
- variable.parent = this;
- }
-}
-
-/// Assign a [MutableVariable].
-///
-/// [MutableVariable]s can be seen as ref cells that are not first-class
-/// values. This can be seen as a dereferencing assignment:
-///
-/// { [variable] := [value]; [body] }
-class SetMutable extends Primitive {
- final Reference<MutableVariable> variable;
- final Reference<Primitive> value;
-
- SetMutable(MutableVariable variable, Primitive value)
- : this.variable = new Reference<MutableVariable>(variable),
- this.value = new Reference<Primitive>(value);
-
- accept(Visitor visitor) => visitor.visitSetMutable(this);
-
- bool get hasValue => false;
- bool get isSafeForElimination => false;
- bool get isSafeForReordering => false;
-
- void setParentPointers() {
- variable.parent = this;
- value.parent = this;
- }
-}
-
-/// Invoke a continuation in tail position.
-class InvokeContinuation extends TailExpression {
- Reference<Continuation> continuation;
- List<Reference<Primitive>> arguments;
- SourceInformation sourceInformation;
-
- // An invocation of a continuation is recursive if it occurs in the body of
- // the continuation itself.
- bool isRecursive;
-
- /// True if this invocation escapes from the body of a [LetHandler]
- /// (i.e. a try block). Notably, such an invocation cannot be inlined.
- bool isEscapingTry;
-
- InvokeContinuation(Continuation cont, List<Primitive> args,
- {this.isRecursive: false,
- this.isEscapingTry: false,
- this.sourceInformation})
- : continuation = new Reference<Continuation>(cont),
- arguments = _referenceList(args) {
- assert(cont.parameters == null || cont.parameters.length == args.length);
- if (isRecursive) cont.isRecursive = true;
- }
-
- /// A continuation invocation whose target and arguments will be filled
- /// in later.
- ///
- /// Used as a placeholder for a jump whose target is not yet created
- /// (e.g., in the translation of break and continue).
- InvokeContinuation.uninitialized({this.isRecursive: false,
- this.isEscapingTry: false})
- : continuation = null,
- arguments = null,
- sourceInformation = null;
-
- accept(BlockVisitor visitor) => visitor.visitInvokeContinuation(this);
-
- void setParentPointers() {
- if (continuation != null) continuation.parent = this;
- if (arguments != null) _setParentsOnList(arguments, this);
- }
-}
-
-/// Choose between a pair of continuations based on a condition value.
-///
-/// The two continuations must not declare any parameters.
-class Branch extends TailExpression {
- final Reference<Primitive> condition;
- final Reference<Continuation> trueContinuation;
- final Reference<Continuation> falseContinuation;
-
- /// If true, only the value `true` satisfies the condition. Otherwise, any
- /// truthy value satisfies the check.
- ///
- /// Non-strict checks are preferable when the condition is known to be a
- /// boolean.
- bool isStrictCheck;
-
- Branch(Primitive condition,
- Continuation trueCont,
- Continuation falseCont,
- {bool strict})
- : this.condition = new Reference<Primitive>(condition),
- trueContinuation = new Reference<Continuation>(trueCont),
- falseContinuation = new Reference<Continuation>(falseCont),
- isStrictCheck = strict {
- assert(strict != null);
- }
-
- Branch.strict(Primitive condition,
- Continuation trueCont,
- Continuation falseCont)
- : this(condition, trueCont, falseCont, strict: true);
-
- Branch.loose(Primitive condition,
- Continuation trueCont,
- Continuation falseCont)
- : this(condition, trueCont, falseCont, strict: false);
-
- accept(BlockVisitor visitor) => visitor.visitBranch(this);
-
- void setParentPointers() {
- condition.parent = this;
- trueContinuation.parent = this;
- falseContinuation.parent = this;
- }
-}
-
-/// Directly assigns to a field on a given object.
-class SetField extends Primitive {
- final Reference<Primitive> object;
- FieldElement field;
- final Reference<Primitive> value;
-
- SetField(Primitive object, this.field, Primitive value)
- : this.object = new Reference<Primitive>(object),
- this.value = new Reference<Primitive>(value);
-
- accept(Visitor visitor) => visitor.visitSetField(this);
-
- bool get hasValue => false;
- bool get isSafeForElimination => false;
- bool get isSafeForReordering => false;
-
- void setParentPointers() {
- object.parent = this;
- value.parent = this;
- }
-}
-
-/// Directly reads from a field on a given object.
-///
-/// The [object] must either be `null` or an object that has [field].
-class GetField extends Primitive {
- final Reference<Primitive> object;
- FieldElement field;
-
- /// True if the object is known not to be null.
- // TODO(asgerf): This is a placeholder until we agree on how to track
- // side effects.
- bool objectIsNotNull = false;
-
- GetField(Primitive object, this.field)
- : this.object = new Reference<Primitive>(object);
-
- accept(Visitor visitor) => visitor.visitGetField(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => objectIsNotNull;
- bool get isSafeForReordering => false;
-
- toString() => 'GetField($field)';
-
- void setParentPointers() {
- object.parent = this;
- }
-}
-
-/// Get the length of a string or native list.
-class GetLength extends Primitive {
- final Reference<Primitive> object;
-
- /// True if the object is known not to be null.
- bool objectIsNotNull = false;
-
- GetLength(Primitive object) : this.object = new Reference<Primitive>(object);
-
- bool get hasValue => true;
- bool get isSafeForElimination => objectIsNotNull;
- bool get isSafeForReordering => false;
-
- accept(Visitor v) => v.visitGetLength(this);
-
- void setParentPointers() {
- object.parent = this;
- }
-}
-
-/// Read an entry from an indexable object.
-///
-/// [object] must be null or an indexable object, and [index] must be
-/// an integer where `0 <= index < object.length`.
-class GetIndex extends Primitive {
- final Reference<Primitive> object;
- final Reference<Primitive> index;
-
- /// True if the object is known not to be null.
- bool objectIsNotNull = false;
-
- GetIndex(Primitive object, Primitive index)
- : this.object = new Reference<Primitive>(object),
- this.index = new Reference<Primitive>(index);
-
- bool get hasValue => true;
- bool get isSafeForElimination => objectIsNotNull;
- bool get isSafeForReordering => false;
-
- accept(Visitor v) => v.visitGetIndex(this);
-
- void setParentPointers() {
- object.parent = this;
- index.parent = this;
- }
-}
-
-/// Set an entry on a native list.
-///
-/// [object] must be null or a native list, and [index] must be an integer.
-///
-/// The primitive itself has no value and may not be referenced.
-class SetIndex extends Primitive {
- final Reference<Primitive> object;
- final Reference<Primitive> index;
- final Reference<Primitive> value;
-
- SetIndex(Primitive object, Primitive index, Primitive value)
- : this.object = new Reference<Primitive>(object),
- this.index = new Reference<Primitive>(index),
- this.value = new Reference<Primitive>(value);
-
- bool get hasValue => false;
- bool get isSafeForElimination => false;
- bool get isSafeForReordering => false;
-
- accept(Visitor v) => v.visitSetIndex(this);
-
- void setParentPointers() {
- object.parent = this;
- index.parent = this;
- value.parent = this;
- }
-}
-
-/// Reads the value of a static field or tears off a static method.
-///
-/// If [GetStatic] is used to load a lazily initialized static field, it must
-/// have been initialized beforehand, and a [witness] must be set to restrict
-/// code motion.
-class GetStatic extends Primitive {
- /// Can be [FieldElement] or [FunctionElement].
- final Element element;
- final SourceInformation sourceInformation;
-
- /// If reading a lazily initialized field, [witness] must refer to a node
- /// that initializes the field or always occurs after the field initializer.
- ///
- /// The value of the witness is not used.
- Reference<Primitive> witness;
-
- GetStatic(this.element, [this.sourceInformation]);
-
- /// Read a lazily initialized static field that is known to have been
- /// initialized by [witness] or earlier.
- GetStatic.witnessed(this.element, Primitive witness, [this.sourceInformation])
- : witness = witness == null ? null : new Reference<Primitive>(witness);
-
- accept(Visitor visitor) => visitor.visitGetStatic(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering {
- return element is FunctionElement || element.isFinal;
- }
-
- void setParentPointers() {
- if (witness != null) {
- witness.parent = this;
- }
- }
-}
-
-/// Sets the value of a static field.
-class SetStatic extends Primitive {
- final FieldElement element;
- final Reference<Primitive> value;
- final SourceInformation sourceInformation;
-
- SetStatic(this.element, Primitive value, [this.sourceInformation])
- : this.value = new Reference<Primitive>(value);
-
- accept(Visitor visitor) => visitor.visitSetStatic(this);
-
- bool get hasValue => false;
- bool get isSafeForElimination => false;
- bool get isSafeForReordering => false;
-
- void setParentPointers() {
- value.parent = this;
- }
-}
-
-/// Reads the value of a lazily initialized static field.
-///
-/// If the field has not yet been initialized, its initializer is evaluated
-/// and assigned to the field.
-class GetLazyStatic extends UnsafePrimitive {
- final FieldElement element;
- final SourceInformation sourceInformation;
-
- GetLazyStatic(this.element, [this.sourceInformation]);
-
- accept(Visitor visitor) => visitor.visitGetLazyStatic(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {}
-}
-
-/// Creates an object for holding boxed variables captured by a closure.
-class CreateBox extends Primitive {
- accept(Visitor visitor) => visitor.visitCreateBox(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {}
-}
-
-/// Creates an instance of a class and initializes its fields and runtime type
-/// information.
-class CreateInstance extends Primitive {
- final ClassElement classElement;
-
- /// Initial values for the fields on the class.
- /// The order corresponds to the order of fields on the class.
- final List<Reference<Primitive>> arguments;
-
- /// The runtime type information structure which contains the type arguments.
- ///
- /// May be `null` to indicate that no type information is needed because the
- /// compiler determined that the type information for instances of this class
- /// is not needed at runtime.
- final Reference<Primitive> typeInformation;
-
- final SourceInformation sourceInformation;
-
- CreateInstance(this.classElement, List<Primitive> arguments,
- Primitive typeInformation,
- this.sourceInformation)
- : this.arguments = _referenceList(arguments),
- this.typeInformation = typeInformation == null
- ? null
- : new Reference<Primitive>(typeInformation);
-
- accept(Visitor visitor) => visitor.visitCreateInstance(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- toString() => 'CreateInstance($classElement)';
-
- void setParentPointers() {
- _setParentsOnList(arguments, this);
- if (typeInformation != null) typeInformation.parent = this;
- }
-}
-
-/// Obtains the interceptor for the given value. This is a method table
-/// corresponding to the Dart class of the value.
-///
-/// All values are either intercepted or self-intercepted. The interceptor for
-/// an "intercepted value" is one of the subclasses of Interceptor.
-/// The interceptor for a "self-intercepted value" is the value itself.
-///
-/// If the input is an intercepted value, and any of its superclasses is in
-/// [interceptedClasses], the method table for the input is returned.
-/// Otherwise, the input itself is returned.
-///
-/// There are thus three significant cases:
-/// - the input is a self-interceptor
-/// - the input is an intercepted value and is caught by [interceptedClasses]
-/// - the input is an intercepted value but is bypassed by [interceptedClasses]
-///
-/// The [flags] field indicates which of the above cases may happen, with
-/// additional special cases for null (which can either by intercepted or
-/// bypassed).
-class Interceptor extends Primitive {
- final Reference<Primitive> input;
- final Set<ClassElement> interceptedClasses = new Set<ClassElement>();
- final SourceInformation sourceInformation;
-
- Interceptor(Primitive input, this.sourceInformation)
- : this.input = new Reference<Primitive>(input);
-
- accept(Visitor visitor) => visitor.visitInterceptor(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- input.parent = this;
- }
-}
-
-/// Create an instance of [Invocation] for use in a call to `noSuchMethod`.
-class CreateInvocationMirror extends Primitive {
- final Selector selector;
- final List<Reference<Primitive>> arguments;
-
- CreateInvocationMirror(this.selector, List<Primitive> arguments)
- : this.arguments = _referenceList(arguments);
-
- accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- _setParentsOnList(arguments, this);
- }
-}
-
-class ForeignCode extends UnsafePrimitive {
- final js.Template codeTemplate;
- final TypeMask storedType;
- final List<Reference<Primitive>> arguments;
- final native.NativeBehavior nativeBehavior;
- final FunctionElement dependency;
-
- ForeignCode(this.codeTemplate, this.storedType, List<Primitive> arguments,
- this.nativeBehavior, {this.dependency})
- : this.arguments = _referenceList(arguments);
-
- accept(Visitor visitor) => visitor.visitForeignCode(this);
-
- bool get hasValue => true;
-
- void setParentPointers() {
- _setParentsOnList(arguments, this);
- }
-
- bool isNullGuardOnNullFirstArgument() {
- if (arguments.length < 1) return false;
- // TODO(sra): Fix NativeThrowBehavior to distinguish MAY from
- // throws-nsm-on-null-followed-by-MAY and remove
- // [isNullGuardForFirstArgument].
- if (nativeBehavior.throwBehavior.isNullNSMGuard) return true;
- return js.isNullGuardOnFirstArgument(codeTemplate);
- }
-}
-
-class Constant extends Primitive {
- final values.ConstantValue value;
- final SourceInformation sourceInformation;
-
- Constant(this.value, {this.sourceInformation}) {
- assert(value != null);
- }
-
- accept(Visitor visitor) => visitor.visitConstant(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {}
-}
-
-class LiteralList extends Primitive {
- /// The List type being created; this is not the type argument.
- final InterfaceType dartType;
- final List<Reference<Primitive>> values;
-
- /// If non-null, this is an allocation site-specific type for the list
- /// created here.
- TypeMask allocationSiteType;
-
- LiteralList(this.dartType, List<Primitive> values, {this.allocationSiteType})
- : this.values = _referenceList(values);
-
- accept(Visitor visitor) => visitor.visitLiteralList(this);
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {
- _setParentsOnList(values, this);
- }
-}
-
-class Parameter extends Primitive {
- Parameter(Entity hint) {
- super.hint = hint;
- }
-
- accept(Visitor visitor) => visitor.visitParameter(this);
-
- String toString() => 'Parameter(${hint == null ? null : hint.name})';
-
- bool get hasValue => true;
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {}
-}
-
/// Continuations are normally bound by 'let cont'. A continuation with one
/// parameter and no body is used to represent a function's return continuation.
/// The return continuation is bound by the function, not by 'let cont'.
@@ -1736,15 +362,15 @@
/// [InvokeContinuation].
bool get isJoinContinuation {
return body != null &&
- parent is! LetHandler &&
- (firstRef == null || firstRef.parent is InvokeContinuation);
+ parent is! LetHandler &&
+ (firstRef == null || firstRef.parent is InvokeContinuation);
}
Continuation(this.parameters, {this.isRecursive: false});
Continuation.retrn()
- : parameters = <Parameter>[new Parameter(null)],
- isRecursive = false;
+ : parameters = <Parameter>[new Parameter(null)],
+ isRecursive = false;
accept(BlockVisitor visitor) => visitor.visitContinuation(this);
@@ -1795,11 +421,8 @@
final Continuation returnContinuation;
Expression body;
- FunctionDefinition(this.element,
- this.thisParameter,
- this.parameters,
- this.returnContinuation,
- this.body);
+ FunctionDefinition(this.element, this.thisParameter, this.parameters,
+ this.returnContinuation, this.body);
accept(BlockVisitor visitor) => visitor.visitFunctionDefinition(this);
@@ -1811,17 +434,1174 @@
}
}
+// ----------------------------------------------------------------------------
+// PRIMITIVES
+// ----------------------------------------------------------------------------
+
+class Parameter extends Primitive {
+ Parameter(Entity hint) {
+ super.hint = hint;
+ }
+
+ accept(Visitor visitor) => visitor.visitParameter(this);
+
+ String toString() => 'Parameter(${hint == null ? null : hint.name})';
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {}
+}
+
+/// A primitive that is generally not safe for elimination, but may be marked
+/// as safe by type propagation
+abstract class UnsafePrimitive extends Primitive {
+ int effects = Effects.all;
+ bool isSafeForElimination = false;
+ bool isSafeForReordering = false;
+}
+
+enum CallingConvention {
+ /// JS receiver is the Dart receiver, there are no extra arguments.
+ ///
+ /// This includes cases (e.g., static functions, constructors) where there
+ /// is no receiver.
+ ///
+ /// For example: `foo.bar$1(x)`
+ Normal,
+
+ /// JS receiver is an interceptor, the first argument is the Dart receiver.
+ ///
+ /// For example: `getInterceptor(foo).bar$1(foo, x)`
+ Intercepted,
+
+ /// JS receiver is the Dart receiver, the first argument is a dummy value.
+ ///
+ /// For example: `foo.bar$1(0, x)`
+ DummyIntercepted,
+
+ /// JS receiver is the Dart receiver, there are no extra arguments.
+ ///
+ /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)`
+ OneShotIntercepted,
+}
+
+/// Base class of function invocations.
+///
+/// This class defines the common interface of function invocations.
+abstract class InvocationPrimitive extends UnsafePrimitive {
+ Reference<Primitive> get receiverRef => null;
+ Primitive get receiver => receiverRef?.definition;
+
+ List<Reference<Primitive>> get argumentRefs;
+ Primitive argument(int n) => argumentRefs[n].definition;
+ Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+ Reference<Primitive> get dartReceiverRef => null;
+ Primitive get dartReceiver => dartReceiverRef?.definition;
+
+ CallingConvention get callingConvention => CallingConvention.Normal;
+
+ Reference<Primitive> dartArgumentReference(int n) {
+ switch (callingConvention) {
+ case CallingConvention.Normal:
+ case CallingConvention.OneShotIntercepted:
+ return argumentRefs[n];
+
+ case CallingConvention.Intercepted:
+ case CallingConvention.DummyIntercepted:
+ return argumentRefs[n + 1];
+ }
+ }
+
+ Primitive dartArgument(int n) => dartArgumentReference(n).definition;
+
+ int get dartArgumentsLength =>
+ argumentRefs.length -
+ (callingConvention == CallingConvention.Intercepted ||
+ callingConvention == CallingConvention.DummyIntercepted ? 1 : 0);
+
+ SourceInformation get sourceInformation;
+}
+
+/// Invoke a static function.
+///
+/// All optional arguments declared by [target] are passed in explicitly, and
+/// occur at the end of [arguments] list, in normalized order.
+///
+/// Discussion:
+/// All information in the [selector] is technically redundant; it will likely
+/// be removed.
+class InvokeStatic extends InvocationPrimitive {
+ final FunctionElement target;
+ final Selector selector;
+ final List<Reference<Primitive>> argumentRefs;
+ final SourceInformation sourceInformation;
+
+ InvokeStatic(this.target, this.selector, List<Primitive> args,
+ [this.sourceInformation])
+ : argumentRefs = _referenceList(args);
+
+ InvokeStatic.byReference(this.target, this.selector, this.argumentRefs,
+ [this.sourceInformation]);
+
+ accept(Visitor visitor) => visitor.visitInvokeStatic(this);
+
+ bool get hasValue => true;
+
+ void setParentPointers() {
+ _setParentsOnList(argumentRefs, this);
+ }
+}
+
+/// Invoke a method on an object.
+///
+/// This includes getters, setters, operators, and index getter/setters.
+///
+/// Tearing off a method is treated like a getter invocation (getters and
+/// tear-offs cannot be distinguished at compile-time).
+///
+/// The [selector] records the names of named arguments. The value of named
+/// arguments occur at the end of the [arguments] list, in normalized order.
+class InvokeMethod extends InvocationPrimitive {
+ Reference<Primitive> receiverRef;
+ Selector selector;
+ TypeMask mask;
+ final List<Reference<Primitive>> argumentRefs;
+ final SourceInformation sourceInformation;
+
+ CallingConvention callingConvention = CallingConvention.Normal;
+
+ Reference<Primitive> get dartReceiverRef {
+ return callingConvention == CallingConvention.Intercepted
+ ? argumentRefs[0]
+ : receiverRef;
+ }
+
+ InvokeMethod(
+ Primitive receiver, this.selector, this.mask, List<Primitive> arguments,
+ {this.sourceInformation,
+ this.callingConvention: CallingConvention.Normal})
+ : this.receiverRef = new Reference<Primitive>(receiver),
+ this.argumentRefs = _referenceList(arguments);
+
+ accept(Visitor visitor) => visitor.visitInvokeMethod(this);
+
+ bool get hasValue => true;
+
+ void setParentPointers() {
+ receiverRef.parent = this;
+ _setParentsOnList(argumentRefs, this);
+ }
+}
+
+/// Invoke [target] on [receiver], bypassing dispatch and override semantics.
+///
+/// That is, if [receiver] is an instance of a class that overrides [target]
+/// with a different implementation, the overriding implementation is bypassed
+/// and [target]'s implementation is invoked.
+///
+/// As with [InvokeMethod], this can be used to invoke a method, operator,
+/// getter, setter, or index getter/setter.
+///
+/// If it is known that [target] does not use its receiver argument, then
+/// [receiver] may refer to a null constant primitive. This happens for direct
+/// invocations to intercepted methods, where the effective receiver is instead
+/// passed as a formal parameter.
+///
+/// TODO(sra): Review. A direct call to a method that is mixed into a native
+/// class will still require an explicit argument.
+///
+/// All optional arguments declared by [target] are passed in explicitly, and
+/// occur at the end of [arguments] list, in normalized order.
+class InvokeMethodDirectly extends InvocationPrimitive {
+ Reference<Primitive> receiverRef;
+ final FunctionElement target;
+ final Selector selector;
+ final List<Reference<Primitive>> argumentRefs;
+ final SourceInformation sourceInformation;
+
+ CallingConvention callingConvention;
+
+ Reference<Primitive> get dartReceiverRef {
+ return callingConvention == CallingConvention.Intercepted
+ ? argumentRefs[0]
+ : receiverRef;
+ }
+
+ InvokeMethodDirectly(Primitive receiver, this.target, this.selector,
+ List<Primitive> arguments, this.sourceInformation,
+ {this.callingConvention: CallingConvention.Normal})
+ : this.receiverRef = new Reference<Primitive>(receiver),
+ this.argumentRefs = _referenceList(arguments);
+
+ accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this);
+
+ bool get hasValue => true;
+
+ void setParentPointers() {
+ receiverRef.parent = this;
+ _setParentsOnList(argumentRefs, this);
+ }
+
+ bool get isConstructorBodyCall => target is ConstructorBodyElement;
+ bool get isTearOff => selector.isGetter && !target.isGetter;
+}
+
+/// Non-const call to a constructor.
+///
+/// The [target] may be a generative constructor (forwarding or normal)
+/// or a non-redirecting factory.
+///
+/// All optional arguments declared by [target] are passed in explicitly, and
+/// occur in the [arguments] list, in normalized order.
+///
+/// Last in the [arguments] list, after the mandatory and optional arguments,
+/// the internal representation of each type argument occurs, unless it could
+/// be determined at build-time that the constructed class has no need for its
+/// runtime type information.
+///
+/// Note that [InvokeConstructor] does it itself allocate an object.
+/// The invoked constructor will do that using [CreateInstance].
+class InvokeConstructor extends InvocationPrimitive {
+ final DartType dartType;
+ final ConstructorElement target;
+ final List<Reference<Primitive>> argumentRefs;
+ final Selector selector;
+ final SourceInformation sourceInformation;
+
+ /// If non-null, this is an allocation site-specific type that is potentially
+ /// better than the inferred return type of [target].
+ ///
+ /// In particular, container type masks depend on the allocation site and
+ /// can therefore not be inferred solely based on the call target.
+ TypeMask allocationSiteType;
+
+ InvokeConstructor(this.dartType, this.target, this.selector,
+ List<Primitive> args, this.sourceInformation,
+ {this.allocationSiteType})
+ : argumentRefs = _referenceList(args);
+
+ accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
+
+ bool get hasValue => true;
+
+ void setParentPointers() {
+ _setParentsOnList(argumentRefs, this);
+ }
+}
+
+/// An alias for [value] in a context where the value is known to satisfy
+/// [type].
+///
+/// Refinement nodes are inserted before the type propagator pass and removed
+/// afterwards, so as not to complicate passes that don't reason about types,
+/// but need to reason about value references being identical (i.e. referring
+/// to the same primitive).
+class Refinement extends Primitive {
+ Reference<Primitive> value;
+ final TypeMask refineType;
+
+ Refinement(Primitive value, this.refineType)
+ : value = new Reference<Primitive>(value);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => false;
+ bool get isSafeForReordering => false;
+
+ accept(Visitor visitor) => visitor.visitRefinement(this);
+
+ Primitive get effectiveDefinition => value.definition.effectiveDefinition;
+
+ Primitive get unrefined => value.definition.unrefined;
+
+ void setParentPointers() {
+ value.parent = this;
+ }
+}
+
+/// Checks that [index] is a valid index on a given indexable [object].
+///
+/// In the simplest form, compiles to the following:
+///
+/// if (index < 0 || index >= object.length)
+/// ThrowIndexOutOfRangeException(object, index);
+///
+/// In the general form, any of the following conditions can be checked:
+///
+/// Lower bound: `index >= 0`
+/// Upper bound: `index < object.length`
+/// Emptiness: `object.length !== 0`
+/// Integerness: `index >>> 0 === index`
+///
+/// [index] must be an integer unless integerness is checked, and [object] must
+/// refer to null or an indexable object, and [length] must be the length of
+/// [object] at the time of the check.
+///
+/// Returns [object] so the bounds check can be used to restrict code motion.
+/// It is possible to have a bounds check node that performs no checks but
+/// is retained to restrict code motion.
+///
+/// The [index] reference may be null if there are no checks to perform,
+/// and the [length] reference may be null if there is no upper bound or
+/// emptiness check.
+///
+/// If a separate code motion guard for the index is required, e.g. because it
+/// must be known to be non-negative in an operator that does not involve
+/// [object], a [Refinement] can be created for it with the non-negative integer
+/// type.
+class BoundsCheck extends Primitive {
+ final Reference<Primitive> objectRef;
+ Reference<Primitive> indexRef;
+ Reference<Primitive> lengthRef;
+ int checks;
+ final SourceInformation sourceInformation;
+
+ Primitive get object => objectRef.definition;
+ Primitive get index => indexRef?.definition;
+ Primitive get length => lengthRef?.definition;
+
+ /// If true, check that `index >= 0`.
+ bool get hasLowerBoundCheck => checks & LOWER_BOUND != 0;
+
+ /// If true, check that `index < object.length`.
+ bool get hasUpperBoundCheck => checks & UPPER_BOUND != 0;
+
+ /// If true, check that `object.length !== 0`.
+ ///
+ /// Equivalent to a lower bound check with `object.length - 1` as the index,
+ /// but this check is faster.
+ ///
+ /// Although [index] is not used in the condition, it is used to generate
+ /// the thrown error. Currently it is always `-1` for emptiness checks,
+ /// because that corresponds to `object.length - 1` in the error case.
+ bool get hasEmptinessCheck => checks & EMPTINESS != 0;
+
+ /// If true, check that `index` is an integer.
+ bool get hasIntegerCheck => checks & INTEGER != 0;
+
+ /// True if the [length] is needed to perform the check.
+ bool get lengthUsedInCheck => checks & (UPPER_BOUND | EMPTINESS) != 0;
+
+ bool get hasNoChecks => checks == NONE;
+
+ static const int UPPER_BOUND = 1 << 0;
+ static const int LOWER_BOUND = 1 << 1;
+ static const int EMPTINESS = 1 << 2; // See [hasEmptinessCheck].
+ static const int INTEGER = 1 << 3; // Check if index is an int.
+ static const int BOTH_BOUNDS = UPPER_BOUND | LOWER_BOUND;
+ static const int NONE = 0;
+
+ BoundsCheck(Primitive object, Primitive index, Primitive length,
+ [this.checks = BOTH_BOUNDS, this.sourceInformation])
+ : this.objectRef = new Reference<Primitive>(object),
+ this.indexRef = new Reference<Primitive>(index),
+ this.lengthRef = _optionalReference(length);
+
+ BoundsCheck.noCheck(Primitive object, [this.sourceInformation])
+ : this.objectRef = new Reference<Primitive>(object),
+ this.checks = NONE;
+
+ accept(Visitor visitor) => visitor.visitBoundsCheck(this);
+
+ void setParentPointers() {
+ objectRef.parent = this;
+ if (indexRef != null) {
+ indexRef.parent = this;
+ }
+ if (lengthRef != null) {
+ lengthRef.parent = this;
+ }
+ }
+
+ String get checkString {
+ if (hasNoChecks) return 'no-check';
+ return [
+ hasUpperBoundCheck ? 'upper' : null,
+ hasLowerBoundCheck ? 'lower' : null,
+ hasEmptinessCheck ? 'emptiness' : null,
+ hasIntegerCheck ? 'integer' : null,
+ 'check'
+ ].where((x) => x != null).join('-');
+ }
+
+ bool get isSafeForElimination => checks == NONE;
+ bool get isSafeForReordering => false;
+ bool get hasValue => true; // Can be referenced to restrict code motion.
+
+ Primitive get effectiveDefinition => object.effectiveDefinition;
+}
+
+/// Throw a [NoSuchMethodError] if [value] cannot respond to [selector].
+///
+/// Returns [value] so this can be used to restrict code motion.
+///
+/// The check can take one of three forms:
+///
+/// value.toString;
+/// value.selectorName;
+/// value.selectorName(); (should only be used if check always fails)
+///
+/// The first two forms are used when it is known that only null fails the
+/// check. Additionally, the check may be guarded by a [condition], allowing
+/// for three more forms:
+///
+/// if (condition) value.toString; (this form is valid but unused)
+/// if (condition) value.selectorName;
+/// if (condition) value.selectorName();
+///
+/// The condition must be true if and only if the check should fail. It should
+/// ideally be of a form understood by JS engines, e.g. a `typeof` test.
+///
+/// If [useSelector] is false, the first form instead becomes `value.toString;`.
+/// This form is faster when the value is non-null and the accessed property has
+/// been removed by tree shaking.
+///
+/// [selector] may not be one of the selectors implemented by the null object.
+class ReceiverCheck extends Primitive {
+ final Reference<Primitive> valueRef;
+ final Selector selector;
+ final SourceInformation sourceInformation;
+ final Reference<Primitive> conditionRef;
+ final int _flags;
+
+ Primitive get value => valueRef.definition;
+ Primitive get condition => conditionRef?.definition;
+
+ static const int _USE_SELECTOR = 1 << 0;
+ static const int _NULL_CHECK = 1 << 1;
+
+ /// True if the selector name should be used in the check; otherwise
+ /// `toString` will be used.
+ bool get useSelector => _flags & _USE_SELECTOR != 0;
+
+ /// True if null is the only possible input that cannot respond to [selector].
+ bool get isNullCheck => _flags & _NULL_CHECK != 0;
+
+ /// Constructor for creating checks in arbitrary configurations.
+ ///
+ /// Consider using one of the named constructors instead.
+ ///
+ /// [useSelector] and [isNullCheck] are mandatory named arguments.
+ ReceiverCheck(Primitive value, this.selector, this.sourceInformation,
+ {Primitive condition, bool useSelector, bool isNullCheck})
+ : valueRef = new Reference<Primitive>(value),
+ conditionRef = _optionalReference(condition),
+ _flags =
+ (useSelector ? _USE_SELECTOR : 0) | (isNullCheck ? _NULL_CHECK : 0);
+
+ /// Simplified constructor for building null checks.
+ ///
+ /// Null must be the only possible input value that does not respond to
+ /// [selector].
+ ReceiverCheck.nullCheck(
+ Primitive value, Selector selector, SourceInformation sourceInformation,
+ {Primitive condition})
+ : this(value, selector, sourceInformation,
+ condition: condition,
+ useSelector: condition != null,
+ isNullCheck: true);
+
+ /// Simplified constructor for building the general check of form:
+ ///
+ /// if (condition) value.selectorName();
+ ///
+ ReceiverCheck.generalCheck(Primitive value, Selector selector,
+ SourceInformation sourceInformation, Primitive condition)
+ : this(value, selector, sourceInformation,
+ condition: condition, useSelector: true, isNullCheck: false);
+
+ bool get isSafeForElimination => false;
+ bool get isSafeForReordering => false;
+ bool get hasValue => true;
+
+ accept(Visitor visitor) => visitor.visitReceiverCheck(this);
+
+ void setParentPointers() {
+ valueRef.parent = this;
+ if (conditionRef != null) {
+ conditionRef.parent = this;
+ }
+ }
+
+ Primitive get effectiveDefinition => value.effectiveDefinition;
+
+ String get nullCheckString => isNullCheck ? 'null-check' : 'general-check';
+ String get useSelectorString => useSelector ? 'use-selector' : 'no-selector';
+ String get flagString => '$nullCheckString $useSelectorString';
+}
+
+/// An "is" type test.
+///
+/// Returns `true` if [value] is an instance of [dartType].
+///
+/// [type] must not be the [Object], `dynamic` or [Null] types (though it might
+/// be a type variable containing one of these types). This design is chosen
+/// to simplify code generation for type tests.
+class TypeTest extends Primitive {
+ Reference<Primitive> valueRef;
+ final DartType dartType;
+
+ /// If [dartType] is an [InterfaceType], this holds the internal
+ /// representation of the type arguments to [dartType]. Since these may
+ /// reference type variables from the enclosing class, they are not constant.
+ ///
+ /// If [dartType] is a [TypeVariableType], this is a singleton list with the
+ /// internal representation of the type held in that type variable.
+ ///
+ /// If [dartType] is a [FunctionType], this is a singleton list with the
+ /// internal representation of that type,
+ ///
+ /// Otherwise the list is empty.
+ final List<Reference<Primitive>> typeArgumentRefs;
+
+ Primitive get value => valueRef.definition;
+ Primitive typeArgument(int n) => typeArgumentRefs[n].definition;
+ Iterable<Primitive> get typeArguments => _dereferenceList(typeArgumentRefs);
+
+ TypeTest(Primitive value, this.dartType, List<Primitive> typeArguments)
+ : this.valueRef = new Reference<Primitive>(value),
+ this.typeArgumentRefs = _referenceList(typeArguments);
+
+ accept(Visitor visitor) => visitor.visitTypeTest(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {
+ valueRef.parent = this;
+ _setParentsOnList(typeArgumentRefs, this);
+ }
+}
+
+/// An "is" type test for a raw type, performed by testing a flag property.
+///
+/// Returns `true` if [interceptor] is for [dartType].
+class TypeTestViaFlag extends Primitive {
+ Reference<Primitive> interceptorRef;
+ final DartType dartType;
+
+ Primitive get interceptor => interceptorRef.definition;
+
+ TypeTestViaFlag(Primitive interceptor, this.dartType)
+ : this.interceptorRef = new Reference<Primitive>(interceptor);
+
+ accept(Visitor visitor) => visitor.visitTypeTestViaFlag(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {
+ interceptorRef.parent = this;
+ }
+}
+
+/// An "as" type cast.
+///
+/// If [value] is `null` or is an instance of [type], [continuation] is invoked
+/// with [value] as argument. Otherwise, a [CastError] is thrown.
+///
+/// Discussion:
+/// The parameter to [continuation] is redundant since it will always equal
+/// [value], which is typically in scope in the continuation. However, it might
+/// simplify type propagation, since a better type can be computed for the
+/// continuation parameter without needing flow-sensitive analysis.
+class TypeCast extends UnsafePrimitive {
+ Reference<Primitive> valueRef;
+ final DartType dartType;
+
+ /// See the corresponding field on [TypeTest].
+ final List<Reference<Primitive>> typeArgumentRefs;
+
+ Primitive get value => valueRef.definition;
+ Primitive typeArgument(int n) => typeArgumentRefs[n].definition;
+ Iterable<Primitive> get typeArguments => _dereferenceList(typeArgumentRefs);
+
+ TypeCast(Primitive value, this.dartType, List<Primitive> typeArguments)
+ : this.valueRef = new Reference<Primitive>(value),
+ this.typeArgumentRefs = _referenceList(typeArguments);
+
+ accept(Visitor visitor) => visitor.visitTypeCast(this);
+
+ bool get hasValue => true;
+
+ void setParentPointers() {
+ valueRef.parent = this;
+ _setParentsOnList(typeArgumentRefs, this);
+ }
+}
+
+/// Apply a built-in operator.
+///
+/// It must be known that the arguments have the proper types.
+class ApplyBuiltinOperator extends Primitive {
+ BuiltinOperator operator;
+ List<Reference<Primitive>> argumentRefs;
+ final SourceInformation sourceInformation;
+
+ Primitive argument(int n) => argumentRefs[n].definition;
+ Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+ ApplyBuiltinOperator(
+ this.operator, List<Primitive> arguments, this.sourceInformation)
+ : this.argumentRefs = _referenceList(arguments);
+
+ accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {
+ _setParentsOnList(argumentRefs, this);
+ }
+}
+
+/// Apply a built-in method.
+///
+/// It must be known that the arguments have the proper types.
+class ApplyBuiltinMethod extends Primitive {
+ BuiltinMethod method;
+ Reference<Primitive> receiverRef;
+ List<Reference<Primitive>> argumentRefs;
+ final SourceInformation sourceInformation;
+
+ Primitive get receiver => receiverRef.definition;
+ Primitive argument(int n) => argumentRefs[n].definition;
+ Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+ ApplyBuiltinMethod(this.method, Primitive receiver, List<Primitive> arguments,
+ this.sourceInformation)
+ : this.receiverRef = new Reference<Primitive>(receiver),
+ this.argumentRefs = _referenceList(arguments);
+
+ accept(Visitor visitor) => visitor.visitApplyBuiltinMethod(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => false;
+ bool get isSafeForReordering => false;
+
+ void setParentPointers() {
+ receiverRef.parent = this;
+ _setParentsOnList(argumentRefs, this);
+ }
+
+ int get effects => getEffectsOfBuiltinMethod(method);
+}
+
+/// Gets the value from a [MutableVariable].
+///
+/// [MutableVariable]s can be seen as ref cells that are not first-class
+/// values. A [LetPrim] with a [GetMutable] can then be seen as:
+///
+/// let prim p = ![variable] in [body]
+///
+class GetMutable extends Primitive {
+ final Reference<MutableVariable> variableRef;
+
+ MutableVariable get variable => variableRef.definition;
+
+ GetMutable(MutableVariable variable)
+ : this.variableRef = new Reference<MutableVariable>(variable);
+
+ accept(Visitor visitor) => visitor.visitGetMutable(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => false;
+
+ void setParentPointers() {
+ variableRef.parent = this;
+ }
+}
+
+/// Assign a [MutableVariable].
+///
+/// [MutableVariable]s can be seen as ref cells that are not first-class
+/// values. This can be seen as a dereferencing assignment:
+///
+/// { [variable] := [value]; [body] }
+class SetMutable extends Primitive {
+ final Reference<MutableVariable> variableRef;
+ final Reference<Primitive> valueRef;
+
+ MutableVariable get variable => variableRef.definition;
+ Primitive get value => valueRef.definition;
+
+ SetMutable(MutableVariable variable, Primitive value)
+ : this.variableRef = new Reference<MutableVariable>(variable),
+ this.valueRef = new Reference<Primitive>(value);
+
+ accept(Visitor visitor) => visitor.visitSetMutable(this);
+
+ bool get hasValue => false;
+ bool get isSafeForElimination => false;
+ bool get isSafeForReordering => false;
+
+ void setParentPointers() {
+ variableRef.parent = this;
+ valueRef.parent = this;
+ }
+}
+
+/// Directly reads from a field on a given object.
+///
+/// The [object] must either be `null` or an object that has [field].
+class GetField extends Primitive {
+ final Reference<Primitive> objectRef;
+ FieldElement field;
+
+ /// True if the field never changes value.
+ final bool isFinal;
+
+ /// True if the object is known not to be null.
+ // TODO(asgerf): This is a placeholder until we agree on how to track
+ // side effects.
+ bool objectIsNotNull = false;
+
+ Primitive get object => objectRef.definition;
+
+ GetField(Primitive object, this.field, {this.isFinal: false})
+ : this.objectRef = new Reference<Primitive>(object);
+
+ accept(Visitor visitor) => visitor.visitGetField(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => objectIsNotNull;
+ bool get isSafeForReordering => false;
+
+ toString() => 'GetField($field)';
+
+ void setParentPointers() {
+ objectRef.parent = this;
+ }
+
+ int get effects => isFinal ? 0 : Effects.dependsOnInstanceField;
+}
+
+/// Directly assigns to a field on a given object.
+class SetField extends Primitive {
+ final Reference<Primitive> objectRef;
+ FieldElement field;
+ final Reference<Primitive> valueRef;
+
+ Primitive get object => objectRef.definition;
+ Primitive get value => valueRef.definition;
+
+ SetField(Primitive object, this.field, Primitive value)
+ : this.objectRef = new Reference<Primitive>(object),
+ this.valueRef = new Reference<Primitive>(value);
+
+ accept(Visitor visitor) => visitor.visitSetField(this);
+
+ bool get hasValue => false;
+ bool get isSafeForElimination => false;
+ bool get isSafeForReordering => false;
+
+ void setParentPointers() {
+ objectRef.parent = this;
+ valueRef.parent = this;
+ }
+
+ int get effects => Effects.changesInstanceField;
+}
+
+/// Get the length of a string or native list.
+class GetLength extends Primitive {
+ final Reference<Primitive> objectRef;
+
+ /// True if the length of the given object can never change.
+ bool isFinal;
+
+ /// True if the object is known not to be null.
+ bool objectIsNotNull = false;
+
+ Primitive get object => objectRef.definition;
+
+ GetLength(Primitive object, {this.isFinal: false})
+ : this.objectRef = new Reference<Primitive>(object);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => objectIsNotNull;
+ bool get isSafeForReordering => false;
+
+ accept(Visitor v) => v.visitGetLength(this);
+
+ void setParentPointers() {
+ objectRef.parent = this;
+ }
+
+ int get effects => isFinal ? 0 : Effects.dependsOnIndexableLength;
+}
+
+/// Read an entry from an indexable object.
+///
+/// [object] must be null or an indexable object, and [index] must be
+/// an integer where `0 <= index < object.length`.
+class GetIndex extends Primitive {
+ final Reference<Primitive> objectRef;
+ final Reference<Primitive> indexRef;
+
+ /// True if the object is known not to be null.
+ bool objectIsNotNull = false;
+
+ Primitive get object => objectRef.definition;
+ Primitive get index => indexRef.definition;
+
+ GetIndex(Primitive object, Primitive index)
+ : this.objectRef = new Reference<Primitive>(object),
+ this.indexRef = new Reference<Primitive>(index);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => objectIsNotNull;
+ bool get isSafeForReordering => false;
+
+ accept(Visitor v) => v.visitGetIndex(this);
+
+ void setParentPointers() {
+ objectRef.parent = this;
+ indexRef.parent = this;
+ }
+
+ int get effects => Effects.dependsOnIndexableContent;
+}
+
+/// Set an entry on a native list.
+///
+/// [object] must be null or a native list, and [index] must be an integer
+/// within the bounds of the indexable object.
+///
+/// [SetIndex] may not be used to alter the length of a JS array.
+///
+/// The primitive itself has no value and may not be referenced.
+class SetIndex extends Primitive {
+ final Reference<Primitive> objectRef;
+ final Reference<Primitive> indexRef;
+ final Reference<Primitive> valueRef;
+
+ Primitive get object => objectRef.definition;
+ Primitive get index => indexRef.definition;
+ Primitive get value => valueRef.definition;
+
+ SetIndex(Primitive object, Primitive index, Primitive value)
+ : this.objectRef = new Reference<Primitive>(object),
+ this.indexRef = new Reference<Primitive>(index),
+ this.valueRef = new Reference<Primitive>(value);
+
+ bool get hasValue => false;
+ bool get isSafeForElimination => false;
+ bool get isSafeForReordering => false;
+
+ accept(Visitor v) => v.visitSetIndex(this);
+
+ void setParentPointers() {
+ objectRef.parent = this;
+ indexRef.parent = this;
+ valueRef.parent = this;
+ }
+
+ int get effects => Effects.changesIndexableContent;
+}
+
+/// Reads the value of a static field or tears off a static method.
+///
+/// If [GetStatic] is used to load a lazily initialized static field, it must
+/// have been initialized beforehand, and a [witness] must be set to restrict
+/// code motion.
+class GetStatic extends Primitive {
+ /// Can be [FieldElement] or [FunctionElement].
+ final Element element;
+ final SourceInformation sourceInformation;
+
+ /// True if the field never changes value.
+ final bool isFinal;
+
+ /// If reading a lazily initialized field, [witness] must refer to a node
+ /// that initializes the field or always occurs after the field initializer.
+ ///
+ /// The value of the witness is not used.
+ Reference<Primitive> witnessRef;
+
+ Primitive get witness => witnessRef.definition;
+
+ GetStatic(this.element, {this.isFinal: false, this.sourceInformation});
+
+ /// Read a lazily initialized static field that is known to have been
+ /// initialized by [witness] or earlier.
+ GetStatic.witnessed(this.element, Primitive witness, {this.sourceInformation})
+ : witnessRef = _optionalReference(witness),
+ isFinal = false;
+
+ accept(Visitor visitor) => visitor.visitGetStatic(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => isFinal;
+
+ void setParentPointers() {
+ if (witnessRef != null) {
+ witnessRef.parent = this;
+ }
+ }
+
+ int get effects => isFinal ? 0 : Effects.dependsOnStaticField;
+}
+
+/// Sets the value of a static field.
+class SetStatic extends Primitive {
+ final FieldElement element;
+ final Reference<Primitive> valueRef;
+ final SourceInformation sourceInformation;
+
+ Primitive get value => valueRef.definition;
+
+ SetStatic(this.element, Primitive value, [this.sourceInformation])
+ : this.valueRef = new Reference<Primitive>(value);
+
+ accept(Visitor visitor) => visitor.visitSetStatic(this);
+
+ bool get hasValue => false;
+ bool get isSafeForElimination => false;
+ bool get isSafeForReordering => false;
+
+ void setParentPointers() {
+ valueRef.parent = this;
+ }
+
+ int get effects => Effects.changesStaticField;
+}
+
+/// Reads the value of a lazily initialized static field.
+///
+/// If the field has not yet been initialized, its initializer is evaluated
+/// and assigned to the field.
+class GetLazyStatic extends UnsafePrimitive {
+ final FieldElement element;
+ final SourceInformation sourceInformation;
+
+ /// True if the field never changes value.
+ final bool isFinal;
+
+ GetLazyStatic(this.element, {this.isFinal: false, this.sourceInformation});
+
+ accept(Visitor visitor) => visitor.visitGetLazyStatic(this);
+
+ bool get hasValue => true;
+
+ void setParentPointers() {}
+
+ // TODO(asgerf): Track side effects of lazy field initializers.
+ int get effects => Effects.all;
+}
+
+/// Creates an object for holding boxed variables captured by a closure.
+class CreateBox extends Primitive {
+ accept(Visitor visitor) => visitor.visitCreateBox(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {}
+}
+
+/// Creates an instance of a class and initializes its fields and runtime type
+/// information.
+class CreateInstance extends Primitive {
+ final ClassElement classElement;
+
+ /// Initial values for the fields on the class.
+ /// The order corresponds to the order of fields on the class.
+ final List<Reference<Primitive>> argumentRefs;
+
+ /// The runtime type information structure which contains the type arguments.
+ ///
+ /// May be `null` to indicate that no type information is needed because the
+ /// compiler determined that the type information for instances of this class
+ /// is not needed at runtime.
+ final Reference<Primitive> typeInformationRef;
+
+ final SourceInformation sourceInformation;
+
+ Primitive argument(int n) => argumentRefs[n].definition;
+ Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+ Primitive get typeInformation => typeInformationRef?.definition;
+
+ CreateInstance(this.classElement, List<Primitive> arguments,
+ Primitive typeInformation, this.sourceInformation)
+ : this.argumentRefs = _referenceList(arguments),
+ this.typeInformationRef = _optionalReference(typeInformation);
+
+ accept(Visitor visitor) => visitor.visitCreateInstance(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ toString() => 'CreateInstance($classElement)';
+
+ void setParentPointers() {
+ _setParentsOnList(argumentRefs, this);
+ if (typeInformationRef != null) typeInformationRef.parent = this;
+ }
+}
+
+/// Obtains the interceptor for the given value. This is a method table
+/// corresponding to the Dart class of the value.
+///
+/// All values are either intercepted or self-intercepted. The interceptor for
+/// an "intercepted value" is one of the subclasses of Interceptor.
+/// The interceptor for a "self-intercepted value" is the value itself.
+///
+/// If the input is an intercepted value, and any of its superclasses is in
+/// [interceptedClasses], the method table for the input is returned.
+/// Otherwise, the input itself is returned.
+///
+/// There are thus three significant cases:
+/// - the input is a self-interceptor
+/// - the input is an intercepted value and is caught by [interceptedClasses]
+/// - the input is an intercepted value but is bypassed by [interceptedClasses]
+///
+/// The [flags] field indicates which of the above cases may happen, with
+/// additional special cases for null (which can either by intercepted or
+/// bypassed).
+class Interceptor extends Primitive {
+ final Reference<Primitive> inputRef;
+ final Set<ClassElement> interceptedClasses = new Set<ClassElement>();
+ final SourceInformation sourceInformation;
+
+ Primitive get input => inputRef.definition;
+
+ Interceptor(Primitive input, this.sourceInformation)
+ : this.inputRef = new Reference<Primitive>(input);
+
+ accept(Visitor visitor) => visitor.visitInterceptor(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {
+ inputRef.parent = this;
+ }
+}
+
+/// Create an instance of [Invocation] for use in a call to `noSuchMethod`.
+class CreateInvocationMirror extends Primitive {
+ final Selector selector;
+ final List<Reference<Primitive>> argumentRefs;
+
+ Primitive argument(int n) => argumentRefs[n].definition;
+ Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+ CreateInvocationMirror(this.selector, List<Primitive> arguments)
+ : this.argumentRefs = _referenceList(arguments);
+
+ accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {
+ _setParentsOnList(argumentRefs, this);
+ }
+}
+
+class ForeignCode extends UnsafePrimitive {
+ final js.Template codeTemplate;
+ final TypeMask storedType;
+ final List<Reference<Primitive>> argumentRefs;
+ final native.NativeBehavior nativeBehavior;
+ final FunctionElement dependency;
+
+ Primitive argument(int n) => argumentRefs[n].definition;
+ Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+ ForeignCode(this.codeTemplate, this.storedType, List<Primitive> arguments,
+ this.nativeBehavior,
+ {this.dependency})
+ : this.argumentRefs = _referenceList(arguments) {
+ effects = Effects.from(nativeBehavior.sideEffects);
+ }
+
+ accept(Visitor visitor) => visitor.visitForeignCode(this);
+
+ bool get hasValue => true;
+
+ void setParentPointers() {
+ _setParentsOnList(argumentRefs, this);
+ }
+
+ bool isNullGuardOnNullFirstArgument() {
+ if (argumentRefs.length < 1) return false;
+ // TODO(sra): Fix NativeThrowBehavior to distinguish MAY from
+ // throws-nsm-on-null-followed-by-MAY and remove
+ // [isNullGuardForFirstArgument].
+ if (nativeBehavior.throwBehavior.isNullNSMGuard) return true;
+ return js.isNullGuardOnFirstArgument(codeTemplate);
+ }
+}
+
+class Constant extends Primitive {
+ final values.ConstantValue value;
+ final SourceInformation sourceInformation;
+
+ Constant(this.value, {this.sourceInformation}) {
+ assert(value != null);
+ }
+
+ accept(Visitor visitor) => visitor.visitConstant(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {}
+}
+
+class LiteralList extends Primitive {
+ /// The List type being created; this is not the type argument.
+ final InterfaceType dartType;
+ final List<Reference<Primitive>> valueRefs;
+
+ /// If non-null, this is an allocation site-specific type for the list
+ /// created here.
+ TypeMask allocationSiteType;
+
+ Primitive value(int n) => valueRefs[n].definition;
+ Iterable<Primitive> get values => _dereferenceList(valueRefs);
+
+ LiteralList(this.dartType, List<Primitive> values, {this.allocationSiteType})
+ : this.valueRefs = _referenceList(values);
+
+ accept(Visitor visitor) => visitor.visitLiteralList(this);
+
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
+ bool get isSafeForReordering => true;
+
+ void setParentPointers() {
+ _setParentsOnList(valueRefs, this);
+ }
+}
+
/// Converts the internal representation of a type to a Dart object of type
/// [Type].
class ReifyRuntimeType extends Primitive {
/// Reference to the internal representation of a type (as produced, for
/// example, by [ReadTypeVariable]).
- final Reference<Primitive> value;
+ final Reference<Primitive> valueRef;
final SourceInformation sourceInformation;
+ Primitive get value => valueRef.definition;
+
ReifyRuntimeType(Primitive value, this.sourceInformation)
- : this.value = new Reference<Primitive>(value);
+ : this.valueRef = new Reference<Primitive>(value);
@override
accept(Visitor visitor) => visitor.visitReifyRuntimeType(this);
@@ -1831,7 +1611,7 @@
bool get isSafeForReordering => true;
void setParentPointers() {
- value.parent = this;
+ valueRef.parent = this;
}
}
@@ -1842,11 +1622,13 @@
/// used as a Dart value.
class ReadTypeVariable extends Primitive {
final TypeVariableType variable;
- final Reference<Primitive> target;
+ final Reference<Primitive> targetRef;
final SourceInformation sourceInformation;
+ Primitive get target => targetRef.definition;
+
ReadTypeVariable(this.variable, Primitive target, this.sourceInformation)
- : this.target = new Reference<Primitive>(target);
+ : this.targetRef = new Reference<Primitive>(target);
@override
accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
@@ -1856,14 +1638,11 @@
bool get isSafeForReordering => true;
void setParentPointers() {
- target.parent = this;
+ targetRef.parent = this;
}
}
-enum TypeExpressionKind {
- COMPLETE,
- INSTANCE
-}
+enum TypeExpressionKind { COMPLETE, INSTANCE }
/// Constructs a representation of a closed or ground-term type (that is, a type
/// without type variables).
@@ -1918,15 +1697,16 @@
class TypeExpression extends Primitive {
final TypeExpressionKind kind;
final DartType dartType;
- final List<Reference<Primitive>> arguments;
+ final List<Reference<Primitive>> argumentRefs;
- TypeExpression(this.kind,
- this.dartType,
- List<Primitive> arguments)
- : this.arguments = _referenceList(arguments) {
+ Primitive argument(int n) => argumentRefs[n].definition;
+ Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+ TypeExpression(this.kind, this.dartType, List<Primitive> arguments)
+ : this.argumentRefs = _referenceList(arguments) {
assert(kind == TypeExpressionKind.INSTANCE
- ? dartType == (dartType.element as ClassElement).thisType
- : true);
+ ? dartType == (dartType.element as ClassElement).thisType
+ : true);
}
@override
@@ -1939,22 +1719,25 @@
bool get isSafeForReordering => true;
void setParentPointers() {
- _setParentsOnList(arguments, this);
+ _setParentsOnList(argumentRefs, this);
}
String get kindAsString {
switch (kind) {
- case TypeExpressionKind.COMPLETE: return 'COMPLETE';
- case TypeExpressionKind.INSTANCE: return 'INSTANCE';
+ case TypeExpressionKind.COMPLETE:
+ return 'COMPLETE';
+ case TypeExpressionKind.INSTANCE:
+ return 'INSTANCE';
}
}
}
class Await extends UnsafePrimitive {
- final Reference<Primitive> input;
+ final Reference<Primitive> inputRef;
- Await(Primitive input)
- : this.input = new Reference<Primitive>(input);
+ Primitive get input => inputRef.definition;
+
+ Await(Primitive input) : this.inputRef = new Reference<Primitive>(input);
@override
accept(Visitor visitor) {
@@ -1964,16 +1747,18 @@
bool get hasValue => true;
void setParentPointers() {
- input.parent = this;
+ inputRef.parent = this;
}
}
class Yield extends UnsafePrimitive {
- final Reference<Primitive> input;
+ final Reference<Primitive> inputRef;
final bool hasStar;
+ Primitive get input => inputRef.definition;
+
Yield(Primitive input, this.hasStar)
- : this.input = new Reference<Primitive>(input);
+ : this.inputRef = new Reference<Primitive>(input);
@override
accept(Visitor visitor) {
@@ -1983,24 +1768,336 @@
bool get hasValue => true;
void setParentPointers() {
- input.parent = this;
+ inputRef.parent = this;
}
}
+// ---------------------------------------------------------------------------
+// EXPRESSIONS
+// ---------------------------------------------------------------------------
+
+/// An expression that creates new bindings and continues evaluation in
+/// a subexpression.
+///
+/// The interior expressions are [LetPrim], [LetCont], [LetHandler], and
+/// [LetMutable].
+abstract class InteriorExpression extends Expression implements InteriorNode {
+ Expression get next => body;
+
+ /// Removes this expression from its current position in the IR.
+ ///
+ /// The node can be re-inserted elsewhere or remain orphaned.
+ ///
+ /// If orphaned, the caller is responsible for unlinking all references in
+ /// the orphaned node. Use [Reference.unlink] or [Primitive.destroy] for this.
+ void remove() {
+ assert(parent != null);
+ assert(parent.body == this);
+ assert(body.parent == this);
+ parent.body = body;
+ body.parent = parent;
+ parent = null;
+ body = null;
+ }
+
+ /// Inserts this above [node].
+ ///
+ /// This node must be orphaned first.
+ void insertAbove(Expression node) {
+ insertBelow(node.parent);
+ }
+
+ /// Inserts this below [node].
+ ///
+ /// This node must be orphaned first.
+ void insertBelow(InteriorNode newParent) {
+ assert(parent == null);
+ assert(body == null);
+ Expression child = newParent.body;
+ newParent.body = this;
+ this.body = child;
+ child.parent = this;
+ this.parent = newParent;
+ }
+}
+
+/// An expression without a continuation or a subexpression body.
+///
+/// These break straight-line control flow and can be thought of as ending a
+/// basic block.
+abstract class TailExpression extends Expression {
+ Expression get next => null;
+}
+
+/// Evaluates a primitive and binds it to variable: `let val x = V in E`.
+///
+/// The bound value is in scope in the body.
+///
+/// During one-pass construction a LetPrim with an empty body is used to
+/// represent the one-hole context `let val x = V in []`.
+class LetPrim extends InteriorExpression {
+ Primitive primitive;
+ Expression body;
+
+ LetPrim(this.primitive, [this.body = null]);
+
+ Expression plug(Expression expr) {
+ assert(body == null);
+ return body = expr;
+ }
+
+ accept(BlockVisitor visitor) => visitor.visitLetPrim(this);
+
+ void setParentPointers() {
+ primitive.parent = this;
+ if (body != null) body.parent = this;
+ }
+}
+
+/// Binding continuations.
+///
+/// let cont k0(v0 ...) = E0
+/// k1(v1 ...) = E1
+/// ...
+/// in E
+///
+/// The bound continuations are in scope in the body and the continuation
+/// parameters are in scope in the respective continuation bodies.
+///
+/// During one-pass construction a LetCont whose first continuation has an empty
+/// body is used to represent the one-hole context
+/// `let cont ... k(v) = [] ... in E`.
+class LetCont extends InteriorExpression {
+ List<Continuation> continuations;
+ Expression body;
+
+ LetCont(Continuation continuation, this.body)
+ : continuations = <Continuation>[continuation];
+
+ LetCont.two(Continuation first, Continuation second, this.body)
+ : continuations = <Continuation>[first, second];
+
+ LetCont.many(this.continuations, this.body);
+
+ Expression plug(Expression expr) {
+ assert(continuations != null &&
+ continuations.isNotEmpty &&
+ continuations.first.body == null);
+ return continuations.first.body = expr;
+ }
+
+ accept(BlockVisitor visitor) => visitor.visitLetCont(this);
+
+ void setParentPointers() {
+ _setParentsOnNodes(continuations, this);
+ if (body != null) body.parent = this;
+ }
+}
+
+// Binding an exception handler.
+//
+// let handler h(v0, v1) = E0 in E1
+//
+// The handler is a two-argument (exception, stack trace) continuation which
+// is implicitly the error continuation of all the code in its body E1.
+// [LetHandler] differs from a [LetCont] binding in that it (1) has the
+// runtime semantics of pushing/popping a handler from the dynamic exception
+// handler stack and (2) it does not have any explicit invocations.
+class LetHandler extends InteriorExpression {
+ Continuation handler;
+ Expression body;
+
+ LetHandler(this.handler, this.body);
+
+ accept(BlockVisitor visitor) => visitor.visitLetHandler(this);
+
+ void setParentPointers() {
+ handler.parent = this;
+ if (body != null) body.parent = this;
+ }
+}
+
+/// Binding mutable variables.
+///
+/// let mutable v = P in E
+///
+/// [MutableVariable]s can be seen as ref cells that are not first-class
+/// values. They are therefore not [Primitive]s and not bound by [LetPrim]
+/// to prevent unrestricted use of references to them. During one-pass
+/// construction, a [LetMutable] with an empty body is use to represent the
+/// one-hole context 'let mutable v = P in []'.
+class LetMutable extends InteriorExpression {
+ final MutableVariable variable;
+ final Reference<Primitive> valueRef;
+ Expression body;
+
+ Primitive get value => valueRef.definition;
+
+ LetMutable(this.variable, Primitive value)
+ : this.valueRef = new Reference<Primitive>(value);
+
+ Expression plug(Expression expr) {
+ return body = expr;
+ }
+
+ accept(BlockVisitor visitor) => visitor.visitLetMutable(this);
+
+ void setParentPointers() {
+ variable.parent = this;
+ valueRef.parent = this;
+ if (body != null) body.parent = this;
+ }
+}
+
+/// Throw a value.
+///
+/// Throw is an expression, i.e., it always occurs in tail position with
+/// respect to a body or expression.
+class Throw extends TailExpression {
+ Reference<Primitive> valueRef;
+
+ Primitive get value => valueRef.definition;
+
+ Throw(Primitive value) : valueRef = new Reference<Primitive>(value);
+
+ accept(BlockVisitor visitor) => visitor.visitThrow(this);
+
+ void setParentPointers() {
+ valueRef.parent = this;
+ }
+}
+
+/// Rethrow
+///
+/// Rethrow can only occur inside a continuation bound by [LetHandler]. It
+/// implicitly throws the exception parameter of the enclosing handler with
+/// the same stack trace as the enclosing handler.
+class Rethrow extends TailExpression {
+ accept(BlockVisitor visitor) => visitor.visitRethrow(this);
+ void setParentPointers() {}
+}
+
+/// An expression that is known to be unreachable.
+///
+/// This can be placed as the body of a call continuation, when the caller is
+/// known never to invoke it, e.g. because the calling expression always throws.
+class Unreachable extends TailExpression {
+ accept(BlockVisitor visitor) => visitor.visitUnreachable(this);
+ void setParentPointers() {}
+}
+
+/// Invoke a continuation in tail position.
+class InvokeContinuation extends TailExpression {
+ Reference<Continuation> continuationRef;
+ List<Reference<Primitive>> argumentRefs;
+ SourceInformation sourceInformation;
+
+ Continuation get continuation => continuationRef.definition;
+ Primitive argument(int n) => argumentRefs[n].definition;
+ Iterable<Primitive> get arguments => _dereferenceList(argumentRefs);
+
+ // An invocation of a continuation is recursive if it occurs in the body of
+ // the continuation itself.
+ bool isRecursive;
+
+ /// True if this invocation escapes from the body of a [LetHandler]
+ /// (i.e. a try block). Notably, such an invocation cannot be inlined.
+ bool isEscapingTry;
+
+ InvokeContinuation(Continuation cont, List<Primitive> args,
+ {this.isRecursive: false,
+ this.isEscapingTry: false,
+ this.sourceInformation})
+ : continuationRef = new Reference<Continuation>(cont),
+ argumentRefs = _referenceList(args) {
+ assert(cont.parameters == null || cont.parameters.length == args.length);
+ if (isRecursive) cont.isRecursive = true;
+ }
+
+ /// A continuation invocation whose target and arguments will be filled
+ /// in later.
+ ///
+ /// Used as a placeholder for a jump whose target is not yet created
+ /// (e.g., in the translation of break and continue).
+ InvokeContinuation.uninitialized(
+ {this.isRecursive: false, this.isEscapingTry: false})
+ : continuationRef = null,
+ argumentRefs = null,
+ sourceInformation = null;
+
+ accept(BlockVisitor visitor) => visitor.visitInvokeContinuation(this);
+
+ void setParentPointers() {
+ if (continuationRef != null) continuationRef.parent = this;
+ if (argumentRefs != null) _setParentsOnList(argumentRefs, this);
+ }
+}
+
+/// Choose between a pair of continuations based on a condition value.
+///
+/// The two continuations must not declare any parameters.
+class Branch extends TailExpression {
+ final Reference<Primitive> conditionRef;
+ final Reference<Continuation> trueContinuationRef;
+ final Reference<Continuation> falseContinuationRef;
+
+ Primitive get condition => conditionRef.definition;
+ Continuation get trueContinuation => trueContinuationRef.definition;
+ Continuation get falseContinuation => falseContinuationRef.definition;
+
+ /// If true, only the value `true` satisfies the condition. Otherwise, any
+ /// truthy value satisfies the check.
+ ///
+ /// Non-strict checks are preferable when the condition is known to be a
+ /// boolean.
+ bool isStrictCheck;
+
+ Branch(Primitive condition, Continuation trueCont, Continuation falseCont,
+ {bool strict})
+ : this.conditionRef = new Reference<Primitive>(condition),
+ trueContinuationRef = new Reference<Continuation>(trueCont),
+ falseContinuationRef = new Reference<Continuation>(falseCont),
+ isStrictCheck = strict {
+ assert(strict != null);
+ }
+
+ Branch.strict(
+ Primitive condition, Continuation trueCont, Continuation falseCont)
+ : this(condition, trueCont, falseCont, strict: true);
+
+ Branch.loose(
+ Primitive condition, Continuation trueCont, Continuation falseCont)
+ : this(condition, trueCont, falseCont, strict: false);
+
+ accept(BlockVisitor visitor) => visitor.visitBranch(this);
+
+ void setParentPointers() {
+ conditionRef.parent = this;
+ trueContinuationRef.parent = this;
+ falseContinuationRef.parent = this;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// UTILITY STUFF
+// ----------------------------------------------------------------------------
+
Reference<Primitive> _reference(Primitive definition) {
return new Reference<Primitive>(definition);
}
Reference<Primitive> _optionalReference(Primitive definition) {
- return definition == null
- ? null
- : new Reference<Primitive>(definition);
+ return definition == null ? null : new Reference<Primitive>(definition);
}
List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) {
return definitions.map((e) => new Reference<Primitive>(e)).toList();
}
+Iterable<Primitive> _dereferenceList(List<Reference<Primitive>> references) {
+ return references.map((ref) => ref.definition);
+}
+
void _setParentsOnNodes(List<Node> nodes, Node parent) {
for (Node node in nodes) {
node.parent = parent;
@@ -2013,6 +2110,10 @@
}
}
+// ----------------------------------------------------------------------------
+// VISITORS
+// ----------------------------------------------------------------------------
+
/// Visitor for block-level traversals that do not need to dispatch on
/// primitives.
abstract class BlockVisitor<T> {
@@ -2210,47 +2311,47 @@
visitLetMutable(LetMutable node) {
processLetMutable(node);
visit(node.variable);
- processReference(node.value);
+ processReference(node.valueRef);
visit(node.body);
}
processInvokeStatic(InvokeStatic node) {}
visitInvokeStatic(InvokeStatic node) {
processInvokeStatic(node);
- node.arguments.forEach(processReference);
+ node.argumentRefs.forEach(processReference);
}
processInvokeContinuation(InvokeContinuation node) {}
visitInvokeContinuation(InvokeContinuation node) {
processInvokeContinuation(node);
- processReference(node.continuation);
- node.arguments.forEach(processReference);
+ processReference(node.continuationRef);
+ node.argumentRefs.forEach(processReference);
}
processInvokeMethod(InvokeMethod node) {}
visitInvokeMethod(InvokeMethod node) {
processInvokeMethod(node);
- processReference(node.receiver);
- node.arguments.forEach(processReference);
+ processReference(node.receiverRef);
+ node.argumentRefs.forEach(processReference);
}
processInvokeMethodDirectly(InvokeMethodDirectly node) {}
visitInvokeMethodDirectly(InvokeMethodDirectly node) {
processInvokeMethodDirectly(node);
- processReference(node.receiver);
- node.arguments.forEach(processReference);
+ processReference(node.receiverRef);
+ node.argumentRefs.forEach(processReference);
}
processInvokeConstructor(InvokeConstructor node) {}
visitInvokeConstructor(InvokeConstructor node) {
processInvokeConstructor(node);
- node.arguments.forEach(processReference);
+ node.argumentRefs.forEach(processReference);
}
processThrow(Throw node) {}
visitThrow(Throw node) {
processThrow(node);
- processReference(node.value);
+ processReference(node.valueRef);
}
processRethrow(Rethrow node) {}
@@ -2261,36 +2362,36 @@
processBranch(Branch node) {}
visitBranch(Branch node) {
processBranch(node);
- processReference(node.trueContinuation);
- processReference(node.falseContinuation);
- processReference(node.condition);
+ processReference(node.trueContinuationRef);
+ processReference(node.falseContinuationRef);
+ processReference(node.conditionRef);
}
processTypeCast(TypeCast node) {}
visitTypeCast(TypeCast node) {
processTypeCast(node);
- processReference(node.value);
- node.typeArguments.forEach(processReference);
+ processReference(node.valueRef);
+ node.typeArgumentRefs.forEach(processReference);
}
processTypeTest(TypeTest node) {}
visitTypeTest(TypeTest node) {
processTypeTest(node);
- processReference(node.value);
- node.typeArguments.forEach(processReference);
+ processReference(node.valueRef);
+ node.typeArgumentRefs.forEach(processReference);
}
processTypeTestViaFlag(TypeTestViaFlag node) {}
visitTypeTestViaFlag(TypeTestViaFlag node) {
processTypeTestViaFlag(node);
- processReference(node.interceptor);
+ processReference(node.interceptorRef);
}
processSetMutable(SetMutable node) {}
visitSetMutable(SetMutable node) {
processSetMutable(node);
- processReference(node.variable);
- processReference(node.value);
+ processReference(node.variableRef);
+ processReference(node.valueRef);
}
processGetLazyStatic(GetLazyStatic node) {}
@@ -2301,11 +2402,11 @@
processLiteralList(LiteralList node) {}
visitLiteralList(LiteralList node) {
processLiteralList(node);
- node.values.forEach(processReference);
+ node.valueRefs.forEach(processReference);
}
processConstant(Constant node) {}
- visitConstant(Constant node) {
+ visitConstant(Constant node) {
processConstant(node);
}
@@ -2317,7 +2418,7 @@
processGetMutable(GetMutable node) {}
visitGetMutable(GetMutable node) {
processGetMutable(node);
- processReference(node.variable);
+ processReference(node.variableRef);
}
processParameter(Parameter node) {}
@@ -2328,41 +2429,43 @@
processInterceptor(Interceptor node) {}
visitInterceptor(Interceptor node) {
processInterceptor(node);
- processReference(node.input);
+ processReference(node.inputRef);
}
processCreateInstance(CreateInstance node) {}
visitCreateInstance(CreateInstance node) {
processCreateInstance(node);
- node.arguments.forEach(processReference);
- if (node.typeInformation != null) processReference(node.typeInformation);
+ node.argumentRefs.forEach(processReference);
+ if (node.typeInformationRef != null) {
+ processReference(node.typeInformationRef);
+ }
}
processSetField(SetField node) {}
visitSetField(SetField node) {
processSetField(node);
- processReference(node.object);
- processReference(node.value);
+ processReference(node.objectRef);
+ processReference(node.valueRef);
}
processGetField(GetField node) {}
visitGetField(GetField node) {
processGetField(node);
- processReference(node.object);
+ processReference(node.objectRef);
}
processGetStatic(GetStatic node) {}
visitGetStatic(GetStatic node) {
processGetStatic(node);
- if (node.witness != null) {
- processReference(node.witness);
+ if (node.witnessRef != null) {
+ processReference(node.witnessRef);
}
}
processSetStatic(SetStatic node) {}
visitSetStatic(SetStatic node) {
processSetStatic(node);
- processReference(node.value);
+ processReference(node.valueRef);
}
processCreateBox(CreateBox node) {}
@@ -2373,44 +2476,44 @@
processReifyRuntimeType(ReifyRuntimeType node) {}
visitReifyRuntimeType(ReifyRuntimeType node) {
processReifyRuntimeType(node);
- processReference(node.value);
+ processReference(node.valueRef);
}
processReadTypeVariable(ReadTypeVariable node) {}
visitReadTypeVariable(ReadTypeVariable node) {
processReadTypeVariable(node);
- processReference(node.target);
+ processReference(node.targetRef);
}
processTypeExpression(TypeExpression node) {}
visitTypeExpression(TypeExpression node) {
processTypeExpression(node);
- node.arguments.forEach(processReference);
+ node.argumentRefs.forEach(processReference);
}
processCreateInvocationMirror(CreateInvocationMirror node) {}
visitCreateInvocationMirror(CreateInvocationMirror node) {
processCreateInvocationMirror(node);
- node.arguments.forEach(processReference);
+ node.argumentRefs.forEach(processReference);
}
processApplyBuiltinOperator(ApplyBuiltinOperator node) {}
visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
processApplyBuiltinOperator(node);
- node.arguments.forEach(processReference);
+ node.argumentRefs.forEach(processReference);
}
processApplyBuiltinMethod(ApplyBuiltinMethod node) {}
visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
processApplyBuiltinMethod(node);
- processReference(node.receiver);
- node.arguments.forEach(processReference);
+ processReference(node.receiverRef);
+ node.argumentRefs.forEach(processReference);
}
processForeignCode(ForeignCode node) {}
visitForeignCode(ForeignCode node) {
processForeignCode(node);
- node.arguments.forEach(processReference);
+ node.argumentRefs.forEach(processReference);
}
processUnreachable(Unreachable node) {}
@@ -2421,34 +2524,34 @@
processAwait(Await node) {}
visitAwait(Await node) {
processAwait(node);
- processReference(node.input);
+ processReference(node.inputRef);
}
processYield(Yield node) {}
visitYield(Yield node) {
processYield(node);
- processReference(node.input);
+ processReference(node.inputRef);
}
processGetLength(GetLength node) {}
visitGetLength(GetLength node) {
processGetLength(node);
- processReference(node.object);
+ processReference(node.objectRef);
}
processGetIndex(GetIndex node) {}
visitGetIndex(GetIndex node) {
processGetIndex(node);
- processReference(node.object);
- processReference(node.index);
+ processReference(node.objectRef);
+ processReference(node.indexRef);
}
processSetIndex(SetIndex node) {}
visitSetIndex(SetIndex node) {
processSetIndex(node);
- processReference(node.object);
- processReference(node.index);
- processReference(node.value);
+ processReference(node.objectRef);
+ processReference(node.indexRef);
+ processReference(node.valueRef);
}
processRefinement(Refinement node) {}
@@ -2460,21 +2563,21 @@
processBoundsCheck(BoundsCheck node) {}
visitBoundsCheck(BoundsCheck node) {
processBoundsCheck(node);
- processReference(node.object);
- if (node.index != null) {
- processReference(node.index);
+ processReference(node.objectRef);
+ if (node.indexRef != null) {
+ processReference(node.indexRef);
}
- if (node.length != null) {
- processReference(node.length);
+ if (node.lengthRef != null) {
+ processReference(node.lengthRef);
}
}
processNullCheck(ReceiverCheck node) {}
visitReceiverCheck(ReceiverCheck node) {
processNullCheck(node);
- processReference(node.value);
- if (node.condition != null) {
- processReference(node.condition);
+ processReference(node.valueRef);
+ if (node.conditionRef != null) {
+ processReference(node.conditionRef);
}
}
}
@@ -2570,7 +2673,7 @@
Expression traverseLetMutable(LetMutable node) {
processLetMutable(node);
visit(node.variable);
- processReference(node.value);
+ processReference(node.valueRef);
return node.body;
}
@@ -2636,12 +2739,16 @@
/// Get the copy of a [Reference]'s definition from the map.
Definition getCopy(Reference reference) => _copies[reference.definition];
+ /// Get the copy of a [Reference]'s definition from the map.
+ Definition getCopyOrNull(Reference reference) =>
+ reference == null ? null : getCopy(reference);
+
/// Map a list of [Reference]s to the list of their definition's copies.
List<Definition> getList(List<Reference> list) => list.map(getCopy).toList();
/// Copy a non-[Continuation] [Definition].
Definition copy(Definition node) {
- assert (node is! Continuation);
+ assert(node is! Continuation);
return putCopy(node, visit(node));
}
@@ -2660,65 +2767,67 @@
visitContinuation(Continuation node) {}
Definition visitInvokeStatic(InvokeStatic node) {
- return new InvokeStatic(node.target, node.selector, getList(node.arguments),
- node.sourceInformation);
+ return new InvokeStatic(node.target, node.selector,
+ getList(node.argumentRefs), node.sourceInformation);
}
Definition visitInvokeMethod(InvokeMethod node) {
- return new InvokeMethod(getCopy(node.receiver), node.selector, node.mask,
- getList(node.arguments),
+ return new InvokeMethod(getCopy(node.receiverRef), node.selector, node.mask,
+ getList(node.argumentRefs),
sourceInformation: node.sourceInformation,
callingConvention: node.callingConvention);
}
Definition visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- return new InvokeMethodDirectly(getCopy(node.receiver), node.target,
- node.selector,
- getList(node.arguments),
- node.sourceInformation,
+ return new InvokeMethodDirectly(getCopy(node.receiverRef), node.target,
+ node.selector, getList(node.argumentRefs), node.sourceInformation,
callingConvention: node.callingConvention);
}
Definition visitInvokeConstructor(InvokeConstructor node) {
- return new InvokeConstructor(node.dartType, node.target, node.selector,
- getList(node.arguments),
- node.sourceInformation)
- ..allocationSiteType = node.allocationSiteType;
+ return new InvokeConstructor(
+ node.dartType,
+ node.target,
+ node.selector,
+ getList(node.argumentRefs),
+ node.sourceInformation)..allocationSiteType = node.allocationSiteType;
}
Definition visitTypeCast(TypeCast node) {
- return new TypeCast(getCopy(node.value), node.dartType,
- getList(node.typeArguments));
+ return new TypeCast(
+ getCopy(node.valueRef), node.dartType, getList(node.typeArgumentRefs));
}
Definition visitSetMutable(SetMutable node) {
- return new SetMutable(getCopy(node.variable), getCopy(node.value));
+ return new SetMutable(getCopy(node.variableRef), getCopy(node.valueRef));
}
Definition visitSetStatic(SetStatic node) {
- return new SetStatic(node.element, getCopy(node.value),
- node.sourceInformation);
+ return new SetStatic(
+ node.element, getCopy(node.valueRef), node.sourceInformation);
}
Definition visitSetField(SetField node) {
- return new SetField(getCopy(node.object), node.field, getCopy(node.value));
+ return new SetField(
+ getCopy(node.objectRef), node.field, getCopy(node.valueRef));
}
Definition visitGetLazyStatic(GetLazyStatic node) {
- return new GetLazyStatic(node.element, node.sourceInformation);
+ return new GetLazyStatic(node.element,
+ isFinal: node.isFinal, sourceInformation: node.sourceInformation);
}
Definition visitAwait(Await node) {
- return new Await(getCopy(node.input));
+ return new Await(getCopy(node.inputRef));
}
Definition visitYield(Yield node) {
- return new Yield(getCopy(node.input), node.hasStar);
+ return new Yield(getCopy(node.inputRef), node.hasStar);
}
Definition visitLiteralList(LiteralList node) {
- return new LiteralList(node.dartType, getList(node.values))
- ..allocationSiteType = node.allocationSiteType;
+ return new LiteralList(node.dartType, getList(node.valueRefs))
+ ..allocationSiteType = node.allocationSiteType;
}
Definition visitConstant(Constant node) {
@@ -2726,7 +2835,7 @@
}
Definition visitGetMutable(GetMutable node) {
- return new GetMutable(getCopy(node.variable));
+ return new GetMutable(getCopy(node.variableRef));
}
Definition visitParameter(Parameter node) {
@@ -2738,24 +2847,28 @@
}
Definition visitGetStatic(GetStatic node) {
- return new GetStatic(node.element, node.sourceInformation);
+ if (node.witnessRef != null) {
+ return new GetStatic.witnessed(node.element, getCopy(node.witnessRef),
+ sourceInformation: node.sourceInformation);
+ } else {
+ return new GetStatic(node.element,
+ isFinal: node.isFinal, sourceInformation: node.sourceInformation);
+ }
}
Definition visitInterceptor(Interceptor node) {
- return new Interceptor(getCopy(node.input), node.sourceInformation)
- ..interceptedClasses.addAll(node.interceptedClasses);
+ return new Interceptor(getCopy(node.inputRef), node.sourceInformation)
+ ..interceptedClasses.addAll(node.interceptedClasses);
}
Definition visitCreateInstance(CreateInstance node) {
- return new CreateInstance(
- node.classElement,
- getList(node.arguments),
- node.typeInformation == null ? null : getCopy(node.typeInformation),
- node.sourceInformation);
+ return new CreateInstance(node.classElement, getList(node.argumentRefs),
+ getCopyOrNull(node.typeInformationRef), node.sourceInformation);
}
Definition visitGetField(GetField node) {
- return new GetField(getCopy(node.object), node.field);
+ return new GetField(getCopy(node.objectRef), node.field,
+ isFinal: node.isFinal);
}
Definition visitCreateBox(CreateBox node) {
@@ -2763,55 +2876,54 @@
}
Definition visitReifyRuntimeType(ReifyRuntimeType node) {
- return new ReifyRuntimeType(getCopy(node.value), node.sourceInformation);
+ return new ReifyRuntimeType(getCopy(node.valueRef), node.sourceInformation);
}
Definition visitReadTypeVariable(ReadTypeVariable node) {
- return new ReadTypeVariable(node.variable, getCopy(node.target),
- node.sourceInformation);
+ return new ReadTypeVariable(
+ node.variable, getCopy(node.targetRef), node.sourceInformation);
}
Definition visitTypeExpression(TypeExpression node) {
return new TypeExpression(
- node.kind, node.dartType, getList(node.arguments));
+ node.kind, node.dartType, getList(node.argumentRefs));
}
Definition visitCreateInvocationMirror(CreateInvocationMirror node) {
- return new CreateInvocationMirror(node.selector, getList(node.arguments));
+ return new CreateInvocationMirror(
+ node.selector, getList(node.argumentRefs));
}
Definition visitTypeTest(TypeTest node) {
- return new TypeTest(getCopy(node.value), node.dartType,
- getList(node.typeArguments));
+ return new TypeTest(
+ getCopy(node.valueRef), node.dartType, getList(node.typeArgumentRefs));
}
Definition visitTypeTestViaFlag(TypeTestViaFlag node) {
- return new TypeTestViaFlag(getCopy(node.interceptor), node.dartType);
+ return new TypeTestViaFlag(getCopy(node.interceptorRef), node.dartType);
}
Definition visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- return new ApplyBuiltinOperator(node.operator, getList(node.arguments),
- node.sourceInformation);
+ return new ApplyBuiltinOperator(
+ node.operator, getList(node.argumentRefs), node.sourceInformation);
}
Definition visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- return new ApplyBuiltinMethod(node.method, getCopy(node.receiver),
- getList(node.arguments),
- node.sourceInformation,
- receiverIsNotNull: node.receiverIsNotNull);
+ return new ApplyBuiltinMethod(node.method, getCopy(node.receiverRef),
+ getList(node.argumentRefs), node.sourceInformation);
}
Definition visitGetLength(GetLength node) {
- return new GetLength(getCopy(node.object));
+ return new GetLength(getCopy(node.objectRef), isFinal: node.isFinal);
}
Definition visitGetIndex(GetIndex node) {
- return new GetIndex(getCopy(node.object), getCopy(node.index));
+ return new GetIndex(getCopy(node.objectRef), getCopy(node.indexRef));
}
Definition visitSetIndex(SetIndex node) {
- return new SetIndex(getCopy(node.object), getCopy(node.index),
- getCopy(node.value));
+ return new SetIndex(getCopy(node.objectRef), getCopy(node.indexRef),
+ getCopy(node.valueRef));
}
Definition visitRefinement(Refinement node) {
@@ -2820,29 +2932,25 @@
Definition visitBoundsCheck(BoundsCheck node) {
if (node.hasNoChecks) {
- return new BoundsCheck.noCheck(getCopy(node.object),
- node.sourceInformation);
+ return new BoundsCheck.noCheck(
+ getCopy(node.objectRef), node.sourceInformation);
} else {
- return new BoundsCheck(getCopy(node.object), getCopy(node.index),
- node.length == null ? null : getCopy(node.length),
- node.checks,
- node.sourceInformation);
+ return new BoundsCheck(getCopy(node.objectRef), getCopy(node.indexRef),
+ getCopyOrNull(node.lengthRef), node.checks, node.sourceInformation);
}
}
Definition visitReceiverCheck(ReceiverCheck node) {
- return new ReceiverCheck(getCopy(node.value),
- node.selector,
- node.sourceInformation,
- condition: node.condition == null ? null : getCopy(node.condition),
+ return new ReceiverCheck(
+ getCopy(node.valueRef), node.selector, node.sourceInformation,
+ condition: getCopyOrNull(node.conditionRef),
useSelector: node.useSelector,
isNullCheck: node.isNullCheck);
}
Definition visitForeignCode(ForeignCode node) {
return new ForeignCode(node.codeTemplate, node.storedType,
- getList(node.arguments),
- node.nativeBehavior,
+ getList(node.argumentRefs), node.nativeBehavior,
dependency: node.dependency);
}
}
@@ -2909,15 +3017,12 @@
// copied.
Parameter returnParameter =
_definitions.copy(node.returnContinuation.parameters.first);
- Continuation returnContinuation = _copies[node.returnContinuation] =
- new Continuation([returnParameter]);
+ Continuation returnContinuation =
+ _copies[node.returnContinuation] = new Continuation([returnParameter]);
visit(node.body);
- FunctionDefinition copy = new FunctionDefinition(node.element,
- thisParameter,
- parameters,
- returnContinuation,
- _first);
+ FunctionDefinition copy = new FunctionDefinition(
+ node.element, thisParameter, parameters, returnContinuation, _first);
_first = _current = null;
return copy;
}
@@ -2940,9 +3045,8 @@
// Continuations are copied where they are bound, before processing
// expressions in the scope of their binding.
push(node.handler);
- Continuation handler = _copies[node.handler] =
- new Continuation(node.handler.parameters.map(_definitions.copy)
- .toList());
+ Continuation handler = _copies[node.handler] = new Continuation(
+ node.handler.parameters.map(_definitions.copy).toList());
plug(new LetHandler(handler, null));
return node.body;
}
@@ -2953,23 +3057,23 @@
}
Expression traverseLetMutable(LetMutable node) {
- plug(new LetMutable(_definitions.copy(node.variable),
- _definitions.getCopy(node.value)));
+ plug(new LetMutable(
+ _definitions.copy(node.variable), _definitions.getCopy(node.valueRef)));
return node.body;
}
// Tail expressions do not have references, so we do not need to map them
// to their copies.
visitInvokeContinuation(InvokeContinuation node) {
- plug(new InvokeContinuation(_copies[node.continuation.definition],
- _definitions.getList(node.arguments),
+ plug(new InvokeContinuation(
+ _copies[node.continuation], _definitions.getList(node.argumentRefs),
isRecursive: node.isRecursive,
isEscapingTry: node.isEscapingTry,
sourceInformation: node.sourceInformation));
}
visitThrow(Throw node) {
- plug(new Throw(_definitions.getCopy(node.value)));
+ plug(new Throw(_definitions.getCopy(node.valueRef)));
}
visitRethrow(Rethrow node) {
@@ -2977,10 +3081,10 @@
}
visitBranch(Branch node) {
- plug(new Branch.loose(_definitions.getCopy(node.condition),
- _copies[node.trueContinuation.definition],
- _copies[node.falseContinuation.definition])
- ..isStrictCheck = node.isStrictCheck);
+ plug(new Branch.loose(
+ _definitions.getCopy(node.conditionRef),
+ _copies[node.trueContinuation],
+ _copies[node.falseContinuation])..isStrictCheck = node.isStrictCheck);
}
visitUnreachable(Unreachable node) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index 952f881..4c39e16 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -170,7 +170,7 @@
String visitLetMutable(LetMutable node) {
String name = visit(node.variable);
- String value = access(node.value);
+ String value = access(node.valueRef);
String body = indentBlock(() => visit(node.body));
return '$indentation(LetMutable ($name $value)\n$body)';
}
@@ -200,22 +200,22 @@
String visitInvokeStatic(InvokeStatic node) {
String name = node.target.name;
- String args = formatArguments(node.selector.callStructure, node.arguments);
+ String args = formatArguments(node.selector.callStructure, node.argumentRefs);
return '(InvokeStatic $name $args)';
}
String visitInvokeMethod(InvokeMethod node) {
String name = node.selector.name;
- String rcv = access(node.receiver);
- String args = formatArguments(node.selector.callStructure, node.arguments,
+ String rcv = access(node.receiverRef);
+ String args = formatArguments(node.selector.callStructure, node.argumentRefs,
node.callingConvention);
return '(InvokeMethod $rcv $name $args)';
}
String visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- String receiver = access(node.receiver);
+ String receiver = access(node.receiverRef);
String name = node.selector.name;
- String args = formatArguments(node.selector.callStructure, node.arguments,
+ String args = formatArguments(node.selector.callStructure, node.argumentRefs,
node.callingConvention);
return '(InvokeMethodDirectly $receiver $name $args)';
}
@@ -231,22 +231,22 @@
if (!node.target.name.isEmpty) {
name = '${name}.${node.target.name}';
}
- String args = formatArguments(node.selector.callStructure, node.arguments);
+ String args = formatArguments(node.selector.callStructure, node.argumentRefs);
return '(InvokeConstructor $name $args)';
}
String visitInvokeContinuation(InvokeContinuation node) {
- String name = access(node.continuation);
+ String name = access(node.continuationRef);
if (node.isRecursive) name = 'rec $name';
- String args = node.arguments == null
+ String args = node.argumentRefs == null
? '**** NULL ****'
- : node.arguments.map(access).join(' ');
+ : node.argumentRefs.map(access).join(' ');
String escaping = node.isEscapingTry ? ' escape' : '';
return '$indentation(InvokeContinuation $name ($args)$escaping)';
}
String visitThrow(Throw node) {
- String value = access(node.value);
+ String value = access(node.valueRef);
return '$indentation(Throw $value)';
}
@@ -255,13 +255,13 @@
}
String visitBranch(Branch node) {
- String condition = access(node.condition);
- assert(isBranchTarget(node.trueContinuation.definition));
- assert(isBranchTarget(node.falseContinuation.definition));
+ String condition = access(node.conditionRef);
+ assert(isBranchTarget(node.trueContinuation));
+ assert(isBranchTarget(node.falseContinuation));
String trueCont =
- indentBlock(() => visit(node.trueContinuation.definition));
+ indentBlock(() => visit(node.trueContinuation));
String falseCont =
- indentBlock(() => visit(node.falseContinuation.definition));
+ indentBlock(() => visit(node.falseContinuation));
String strict = node.isStrictCheck ? 'Strict' : 'NonStrict';
return '$indentation(Branch $strict $condition\n$trueCont\n$falseCont)';
}
@@ -295,45 +295,45 @@
}
String visitGetMutable(GetMutable node) {
- return '(GetMutable ${access(node.variable)})';
+ return '(GetMutable ${access(node.variableRef)})';
}
String visitSetMutable(SetMutable node) {
- String value = access(node.value);
- return '(SetMutable ${access(node.variable)} $value)';
+ String value = access(node.valueRef);
+ return '(SetMutable ${access(node.variableRef)} $value)';
}
String visitTypeCast(TypeCast node) {
- String value = access(node.value);
- String typeArguments = node.typeArguments.map(access).join(' ');
+ String value = access(node.valueRef);
+ String typeArguments = node.typeArgumentRefs.map(access).join(' ');
return '(TypeCast $value ${node.dartType} ($typeArguments))';
}
String visitTypeTest(TypeTest node) {
- String value = access(node.value);
- String typeArguments = node.typeArguments.map(access).join(' ');
+ String value = access(node.valueRef);
+ String typeArguments = node.typeArgumentRefs.map(access).join(' ');
return '(TypeTest $value ${node.dartType} ($typeArguments))';
}
String visitTypeTestViaFlag(TypeTestViaFlag node) {
- String interceptor = access(node.interceptor);
+ String interceptor = access(node.interceptorRef);
return '(TypeTestViaFlag $interceptor ${node.dartType})';
}
String visitLiteralList(LiteralList node) {
- String values = node.values.map(access).join(' ');
+ String values = node.valueRefs.map(access).join(' ');
return '(LiteralList ($values))';
}
String visitSetField(SetField node) {
- String object = access(node.object);
+ String object = access(node.objectRef);
String field = node.field.name;
- String value = access(node.value);
+ String value = access(node.valueRef);
return '(SetField $object $field $value)';
}
String visitGetField(GetField node) {
- String object = access(node.object);
+ String object = access(node.objectRef);
String field = node.field.name;
return '(GetField $object $field)';
}
@@ -345,7 +345,7 @@
String visitSetStatic(SetStatic node) {
String element = node.element.name;
- String value = access(node.value);
+ String value = access(node.valueRef);
return '(SetStatic $element $value)';
}
@@ -360,79 +360,79 @@
String visitCreateInstance(CreateInstance node) {
String className = node.classElement.name;
- String arguments = node.arguments.map(access).join(' ');
- String typeInformation = optionalAccess(node.typeInformation);
+ String arguments = node.argumentRefs.map(access).join(' ');
+ String typeInformation = optionalAccess(node.typeInformationRef);
return '(CreateInstance $className ($arguments) ($typeInformation))';
}
String visitInterceptor(Interceptor node) {
- return '(Interceptor ${access(node.input)})';
+ return '(Interceptor ${access(node.inputRef)})';
}
String visitReifyRuntimeType(ReifyRuntimeType node) {
- return '(ReifyRuntimeType ${access(node.value)})';
+ return '(ReifyRuntimeType ${access(node.valueRef)})';
}
String visitReadTypeVariable(ReadTypeVariable node) {
- return '(ReadTypeVariable ${access(node.target)}.${node.variable})';
+ return '(ReadTypeVariable ${access(node.targetRef)}.${node.variable})';
}
String visitTypeExpression(TypeExpression node) {
- String args = node.arguments.map(access).join(' ');
+ String args = node.argumentRefs.map(access).join(' ');
return '(TypeExpression ${node.kindAsString} ${node.dartType} ($args))';
}
String visitCreateInvocationMirror(CreateInvocationMirror node) {
String selector = node.selector.name;
- String args = node.arguments.map(access).join(' ');
+ String args = node.argumentRefs.map(access).join(' ');
return '(CreateInvocationMirror $selector ($args))';
}
String visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
String operator = node.operator.toString();
- String args = node.arguments.map(access).join(' ');
+ String args = node.argumentRefs.map(access).join(' ');
return '(ApplyBuiltinOperator $operator ($args))';
}
String visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
String method = node.method.toString();
- String receiver = access(node.receiver);
- String args = node.arguments.map(access).join(' ');
+ String receiver = access(node.receiverRef);
+ String args = node.argumentRefs.map(access).join(' ');
return '(ApplyBuiltinMethod $method $receiver ($args))';
}
String visitForeignCode(ForeignCode node) {
- String arguments = node.arguments.map(access).join(' ');
+ String arguments = node.argumentRefs.map(access).join(' ');
return '(JS "${node.codeTemplate.source}" ($arguments))';
}
String visitGetLength(GetLength node) {
- String object = access(node.object);
+ String object = access(node.objectRef);
return '(GetLength $object)';
}
String visitGetIndex(GetIndex node) {
- String object = access(node.object);
- String index = access(node.index);
+ String object = access(node.objectRef);
+ String index = access(node.indexRef);
return '(GetIndex $object $index)';
}
String visitSetIndex(SetIndex node) {
- String object = access(node.object);
- String index = access(node.index);
- String value = access(node.value);
+ String object = access(node.objectRef);
+ String index = access(node.indexRef);
+ String value = access(node.valueRef);
return '(SetIndex $object $index $value)';
}
@override
String visitAwait(Await node) {
- String value = access(node.input);
+ String value = access(node.inputRef);
return '(Await $value)';
}
@override
String visitYield(Yield node) {
- String value = access(node.input);
+ String value = access(node.inputRef);
return '(Yield $value)';
}
@@ -442,15 +442,15 @@
}
String visitBoundsCheck(BoundsCheck node) {
- String object = access(node.object);
- String index = optionalAccess(node.index);
- String length = optionalAccess(node.length);
+ String object = access(node.objectRef);
+ String index = optionalAccess(node.indexRef);
+ String length = optionalAccess(node.lengthRef);
return '(BoundsCheck $object $index $length ${node.checkString})';
}
String visitReceiverCheck(ReceiverCheck node) {
- String value = access(node.value);
- String condition = optionalAccess(node.condition);
+ String value = access(node.valueRef);
+ String condition = optionalAccess(node.conditionRef);
return '(ReceiverCheck $value ${node.selector} $condition '
'${node.flagString}))';
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index dd69e3e..1c7779b 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -137,27 +137,27 @@
visitLetMutable(cps_ir.LetMutable node) {
String id = names.name(node.variable);
- printStmt(id, "LetMutable $id = ${formatReference(node.value)}");
+ printStmt(id, "LetMutable $id = ${formatReference(node.valueRef)}");
visit(node.body);
}
visitInvokeStatic(cps_ir.InvokeStatic node) {
String callName = node.selector.name;
- String args = node.arguments.map(formatReference).join(', ');
+ String args = node.argumentRefs.map(formatReference).join(', ');
return "InvokeStatic $callName ($args)";
}
visitInvokeMethod(cps_ir.InvokeMethod node) {
- String receiver = formatReference(node.receiver);
+ String receiver = formatReference(node.receiverRef);
String callName = node.selector.name;
- String args = node.arguments.map(formatReference).join(', ');
+ String args = node.argumentRefs.map(formatReference).join(', ');
return "InvokeMethod $receiver $callName ($args)";
}
visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
- String receiver = formatReference(node.receiver);
+ String receiver = formatReference(node.receiverRef);
String callName = node.selector.name;
- String args = node.arguments.map(formatReference).join(', ');
+ String args = node.argumentRefs.map(formatReference).join(', ');
return "InvokeMethodDirectly $receiver $callName ($args)";
}
@@ -169,13 +169,13 @@
} else {
callName = '${className}.${node.target.name}';
}
- String args = node.arguments.map(formatReference).join(', ');
+ String args = node.argumentRefs.map(formatReference).join(', ');
return "InvokeConstructor $callName ($args)";
}
visitThrow(cps_ir.Throw node) {
String dummy = names.name(node);
- String value = formatReference(node.value);
+ String value = formatReference(node.valueRef);
printStmt(dummy, "Throw $value");
}
@@ -190,46 +190,46 @@
}
visitLiteralList(cps_ir.LiteralList node) {
- String values = node.values.map(formatReference).join(', ');
+ String values = node.valueRefs.map(formatReference).join(', ');
return "LiteralList ($values)";
}
visitTypeCast(cps_ir.TypeCast node) {
- String value = formatReference(node.value);
- String args = node.typeArguments.map(formatReference).join(', ');
+ String value = formatReference(node.valueRef);
+ String args = node.typeArgumentRefs.map(formatReference).join(', ');
return "TypeCast ($value ${node.dartType} ($args))";
}
visitInvokeContinuation(cps_ir.InvokeContinuation node) {
String dummy = names.name(node);
- String kont = formatReference(node.continuation);
- String args = node.arguments.map(formatReference).join(', ');
+ String kont = formatReference(node.continuationRef);
+ String args = node.argumentRefs.map(formatReference).join(', ');
printStmt(dummy, "InvokeContinuation $kont ($args)");
}
visitBranch(cps_ir.Branch node) {
String dummy = names.name(node);
- String condition = formatReference(node.condition);
- String trueCont = formatReference(node.trueContinuation);
- String falseCont = formatReference(node.falseContinuation);
+ String condition = formatReference(node.conditionRef);
+ String trueCont = formatReference(node.trueContinuationRef);
+ String falseCont = formatReference(node.falseContinuationRef);
String strict = node.isStrictCheck ? "Strict" : "NonStrict";
printStmt(dummy, "Branch $condition ($trueCont, $falseCont) $strict");
}
visitAwait(cps_ir.Await node) {
- String value = formatReference(node.input);
+ String value = formatReference(node.inputRef);
return 'Await $value';
}
visitYield(cps_ir.Yield node) {
String name = node.hasStar ? 'YieldStar' : 'Yield';
- String value = formatReference(node.input);
+ String value = formatReference(node.inputRef);
return '$name $value';
}
visitSetMutable(cps_ir.SetMutable node) {
- String variable = names.name(node.variable.definition);
- String value = formatReference(node.value);
+ String variable = names.name(node.variable);
+ String value = formatReference(node.valueRef);
return 'SetMutable $variable := $value';
}
@@ -260,32 +260,35 @@
}
visitSetField(cps_ir.SetField node) {
- String object = formatReference(node.object);
+ String object = formatReference(node.objectRef);
String field = node.field.name;
- String value = formatReference(node.value);
+ String value = formatReference(node.valueRef);
return 'SetField $object.$field = $value';
}
visitGetField(cps_ir.GetField node) {
- String object = formatReference(node.object);
+ String object = formatReference(node.objectRef);
String field = node.field.name;
- return 'GetField($object.$field)';
+ String finalFlag = node.isFinal ? 'final' : 'non-final';
+ return 'GetField $object.$field $finalFlag';
}
visitGetStatic(cps_ir.GetStatic node) {
String element = node.element.name;
- return 'GetStatic($element)';
+ String finalFlag = node.isFinal ? 'final' : 'non-final';
+ return 'GetStatic $element $finalFlag';
}
visitSetStatic(cps_ir.SetStatic node) {
String element = node.element.name;
- String value = formatReference(node.value);
+ String value = formatReference(node.valueRef);
return 'SetStatic $element = $value';
}
visitGetLazyStatic(cps_ir.GetLazyStatic node) {
String element = node.element.name;
- return "GetLazyStatic $element";
+ String finalFlag = node.isFinal ? 'final' : 'non-final';
+ return "GetLazyStatic $element $finalFlag";
}
visitCreateBox(cps_ir.CreateBox node) {
@@ -294,86 +297,87 @@
visitCreateInstance(cps_ir.CreateInstance node) {
String className = node.classElement.name;
- String arguments = node.arguments.map(formatReference).join(', ');
- String typeInformation = formatReference(node.typeInformation);
+ String arguments = node.argumentRefs.map(formatReference).join(', ');
+ String typeInformation = formatReference(node.typeInformationRef);
return 'CreateInstance $className ($arguments) <$typeInformation>';
}
visitInterceptor(cps_ir.Interceptor node) {
- return 'Interceptor(${formatReference(node.input)}, '
+ return 'Interceptor(${formatReference(node.inputRef)}, '
'${node.interceptedClasses})';
}
visitGetMutable(cps_ir.GetMutable node) {
- String variable = names.name(node.variable.definition);
+ String variable = names.name(node.variable);
return 'GetMutable $variable';
}
visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
return "ReadTypeVariable ${node.variable.element} "
- "${formatReference(node.target)}";
+ "${formatReference(node.targetRef)}";
}
visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
- return "ReifyRuntimeType ${formatReference(node.value)}";
+ return "ReifyRuntimeType ${formatReference(node.valueRef)}";
}
visitTypeExpression(cps_ir.TypeExpression node) {
return "TypeExpression ${node.kindAsString} ${node.dartType}"
- "${node.arguments.map(formatReference).join(', ')}";
+ "${node.argumentRefs.map(formatReference).join(', ')}";
}
visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
- String args = node.arguments.map(formatReference).join(', ');
+ String args = node.argumentRefs.map(formatReference).join(', ');
return "CreateInvocationMirror(${node.selector.name}, $args)";
}
visitTypeTest(cps_ir.TypeTest node) {
- String value = formatReference(node.value);
- String args = node.typeArguments.map(formatReference).join(', ');
+ String value = formatReference(node.valueRef);
+ String args = node.typeArgumentRefs.map(formatReference).join(', ');
return "TypeTest ($value ${node.dartType} ($args))";
}
visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) {
- String interceptor = formatReference(node.interceptor);
+ String interceptor = formatReference(node.interceptorRef);
return "TypeTestViaFlag ($interceptor ${node.dartType})";
}
visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
String operator = node.operator.toString();
- String args = node.arguments.map(formatReference).join(', ');
+ String args = node.argumentRefs.map(formatReference).join(', ');
return 'ApplyBuiltinOperator $operator ($args)';
}
visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) {
String method = node.method.toString();
- String receiver = formatReference(node.receiver);
- String args = node.arguments.map(formatReference).join(', ');
+ String receiver = formatReference(node.receiverRef);
+ String args = node.argumentRefs.map(formatReference).join(', ');
return 'ApplyBuiltinMethod $method $receiver ($args)';
}
visitForeignCode(cps_ir.ForeignCode node) {
String id = names.name(node);
- String arguments = node.arguments.map(formatReference).join(', ');
+ String arguments = node.argumentRefs.map(formatReference).join(', ');
printStmt(id,
"ForeignCode ${node.type} ${node.codeTemplate.source} $arguments");
}
visitGetLength(cps_ir.GetLength node) {
- String object = formatReference(node.object);
- return 'GetLength $object';
+ String object = formatReference(node.objectRef);
+ String finalFlag = node.isFinal ? 'final' : 'non-final';
+ return 'GetLength $object $finalFlag';
}
visitGetIndex(cps_ir.GetIndex node) {
- String object = formatReference(node.object);
- String index = formatReference(node.index);
+ String object = formatReference(node.objectRef);
+ String index = formatReference(node.indexRef);
return 'GetIndex $object $index';
}
visitSetIndex(cps_ir.SetIndex node) {
- String object = formatReference(node.object);
- String index = formatReference(node.index);
- String value = formatReference(node.value);
+ String object = formatReference(node.objectRef);
+ String index = formatReference(node.indexRef);
+ String value = formatReference(node.valueRef);
return 'SetIndex $object $index $value';
}
@@ -383,19 +387,19 @@
}
visitBoundsCheck(cps_ir.BoundsCheck node) {
- String object = formatReference(node.object);
- String index = node.index == null
+ String object = formatReference(node.objectRef);
+ String index = node.indexRef == null
? 'no-index'
- : formatReference(node.index);
- String length = node.length == null
+ : formatReference(node.indexRef);
+ String length = node.lengthRef == null
? 'no-length'
- : formatReference(node.length);
+ : formatReference(node.lengthRef);
return 'BoundsCheck $object $index $length ${node.checkString}';
}
visitReceiverCheck(cps_ir.ReceiverCheck node) {
- String value = formatReference(node.value);
- String condition = formatReference(node.condition);
+ String value = formatReference(node.valueRef);
+ String condition = formatReference(node.conditionRef);
return 'ReceiverCheck $value $condition ${node.selector} '
'${node.flagString}';
}
@@ -506,7 +510,7 @@
}
visitInvokeContinuation(cps_ir.InvokeContinuation exp) {
- addEdgeToContinuation(exp.continuation);
+ addEdgeToContinuation(exp.continuationRef);
}
visitInvokeStatic(cps_ir.InvokeStatic node) {
@@ -539,11 +543,11 @@
}
visitBranch(cps_ir.Branch exp) {
- cps_ir.Continuation trueTarget = exp.trueContinuation.definition;
+ cps_ir.Continuation trueTarget = exp.trueContinuation;
if (!trueTarget.isReturnContinuation) {
currentBlock.addEdgeTo(getBlock(trueTarget));
}
- cps_ir.Continuation falseTarget = exp.falseContinuation.definition;
+ cps_ir.Continuation falseTarget = exp.falseContinuation;
if (!falseTarget.isReturnContinuation) {
currentBlock.addEdgeTo(getBlock(falseTarget));
}
diff --git a/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart b/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart
index 6f733e3..e03f9ca 100644
--- a/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart
+++ b/pkg/compiler/lib/src/cps_ir/eagerly_load_statics.dart
@@ -7,6 +7,7 @@
import 'cps_ir_nodes.dart';
import 'optimizers.dart' show Pass;
import '../elements/elements.dart';
+import 'cps_fragment.dart';
/// Replaces [GetLazyStatic] with [GetStatic] when the static field is known
/// to have been initialized.
@@ -30,6 +31,12 @@
visit(node.body);
}
+ Expression traverseLetPrim(LetPrim node) {
+ Expression next = node.body;
+ visit(node.primitive);
+ return next;
+ }
+
Expression traverseLetCont(LetCont node) {
for (Continuation cont in node.continuations) {
initializersAt[cont] = cloneFieldMap(initializerFor);
@@ -51,10 +58,13 @@
void visitGetLazyStatic(GetLazyStatic node) {
Primitive initializer = initializerFor[node.element];
- if (initializer != null) {
- GetStatic newNode = new GetStatic.witnessed(node.element, initializer,
- node.sourceInformation);
- newNode.type = node.type;
+ if (initializer is GetLazyStatic && initializer.isFinal) {
+ // No reason to create a GetStatic when the field is final.
+ node.replaceWithFragment(new CpsFragment(), initializer);
+ } else if (initializer != null) {
+ GetStatic newNode = new GetStatic.witnessed(node.element,
+ initializer, sourceInformation: node.sourceInformation)
+ ..type = node.type;
node.replaceWith(newNode);
} else {
initializerFor[node.element] = node;
diff --git a/pkg/compiler/lib/src/cps_ir/effects.dart b/pkg/compiler/lib/src/cps_ir/effects.dart
new file mode 100644
index 0000000..9ab55cd
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/effects.dart
@@ -0,0 +1,197 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library dart2js.cps_ir.effects;
+
+import 'dart:typed_data';
+import '../universe/side_effects.dart' show SideEffects;
+
+/// Bitmasks for tracking non-local side effects and dependencies.
+///
+/// All effects must be attributed to an effect area. The `other` area is a
+/// catch-all for any effect that does not belong to any of the specific areas;
+/// this includes external effects such as printing to the console.
+class Effects {
+ // Effect areas.
+ // These are bit positions, not bit masks. They are private because it is
+ // otherwise easy to mistake them for bitmasks.
+ static const int _staticField = 0;
+ static const int _instanceField = 1;
+ static const int _indexableContent = 2;
+ static const int _indexableLength = 3;
+ static const int _other = 4;
+ static const int numberOfEffectAreas = 5;
+
+ // Bitmasks for computation that modifies state in a given area.
+ static const int _changes = 1;
+ static const int changesStaticField = _changes << _staticField;
+ static const int changesInstanceField = _changes << _instanceField;
+ static const int changesIndexableContent = _changes << _indexableContent;
+ static const int changesIndexableLength = _changes << _indexableLength;
+ static const int changesOther = _changes << _other;
+
+ static const int changesAll =
+ changesStaticField |
+ changesInstanceField |
+ changesIndexableContent |
+ changesIndexableLength |
+ changesOther;
+
+ // Bitmasks for computation that depends on state in a given area.
+ static const int _depends = 1 << numberOfEffectAreas;
+ static const int dependsOnStaticField = _depends << _staticField;
+ static const int dependsOnInstanceField = _depends << _instanceField;
+ static const int dependsOnIndexableContent = _depends << _indexableContent;
+ static const int dependsOnIndexableLength = _depends << _indexableLength;
+ static const int dependsOnOther = _depends << _other;
+
+ static const int dependsOnAll =
+ dependsOnStaticField |
+ dependsOnInstanceField |
+ dependsOnIndexableContent |
+ dependsOnIndexableLength |
+ dependsOnOther;
+
+ static const int all = changesAll | dependsOnAll;
+ static const int none = 0;
+
+ static int _changesArea(int effectArea) => _changes << effectArea;
+
+ static int _dependsOnArea(int effectArea) => _depends << effectArea;
+
+ static int changesToDepends(int changesFlags) {
+ return (changesFlags & changesAll) << numberOfEffectAreas;
+ }
+
+ static int dependsToChanges(int dependsFlags) {
+ return (dependsFlags & dependsOnAll) >> numberOfEffectAreas;
+ }
+
+ /// Converts [SideEffects] from a JS annotation or type inference to the
+ /// more fine-grained flag set.
+ //
+ // TODO(asgerf): Once we finalize the set of flags to use, unify the two
+ // systems.
+ static int from(SideEffects fx) {
+ int result = 0;
+ if (fx.changesInstanceProperty()) {
+ result |= changesInstanceField;
+ }
+ if (fx.changesStaticProperty()) {
+ result |= changesStaticField;
+ }
+ if (fx.changesIndex()) {
+ result |= changesIndexableContent | changesIndexableLength;
+ }
+ if (fx.hasSideEffects()) {
+ result |= changesOther;
+ }
+ if (fx.dependsOnInstancePropertyStore()) {
+ result |= dependsOnInstanceField;
+ }
+ if (fx.dependsOnStaticPropertyStore()) {
+ result |= dependsOnStaticField;
+ }
+ if (fx.dependsOnIndexStore()) {
+ result |= dependsOnIndexableContent | dependsOnIndexableLength;
+ }
+ if (fx.dependsOnSomething()) {
+ result |= dependsOnOther;
+ }
+ return result;
+ }
+}
+
+/// Creates fresh IDs to ensure effect numbers do not clash with each other.
+class EffectNumberer {
+ int _id = 0;
+ int next() => ++_id;
+
+ /// Special effect number that can be used in place for an effect area that
+ /// is irrelevant for a computation.
+ ///
+ /// This value is never returned by [next].
+ static const int none = 0;
+}
+
+/// A mutable vector of effect numbers, one for each effect area.
+///
+/// Effect numbers are used to identify regions of code wherein the given
+/// effect area is unmodified.
+class EffectNumbers {
+ final Int32List _effectNumbers = new Int32List(Effects.numberOfEffectAreas);
+
+ EffectNumbers._zero();
+
+ EffectNumbers.fresh(EffectNumberer numberer) {
+ reset(numberer);
+ }
+
+ EffectNumbers copy() {
+ return new EffectNumbers._zero().._effectNumbers.setAll(0, _effectNumbers);
+ }
+
+ int operator[](int i) => _effectNumbers[i];
+
+ void operator[]=(int i, int value) {
+ _effectNumbers[i] = value;
+ }
+
+ int get staticField => _effectNumbers[Effects._staticField];
+ int get instanceField => _effectNumbers[Effects._instanceField];
+ int get indexableContent => _effectNumbers[Effects._indexableContent];
+ int get indexableLength => _effectNumbers[Effects._indexableLength];
+ int get other => _effectNumbers[Effects._other];
+
+ void set staticField(int n) {
+ _effectNumbers[Effects._staticField] = n;
+ }
+ void set instanceField(int n) {
+ _effectNumbers[Effects._instanceField] = n;
+ }
+ void set indexableContent(int n) {
+ _effectNumbers[Effects._indexableContent] = n;
+ }
+ void set indexableLength(int n) {
+ _effectNumbers[Effects._indexableLength] = n;
+ }
+ void set other(int n) {
+ _effectNumbers[Effects._other] = n;
+ }
+
+ void reset(EffectNumberer numberer) {
+ for (int i = 0; i < Effects.numberOfEffectAreas; ++i) {
+ _effectNumbers[i] = numberer.next();
+ }
+ }
+
+ void join(EffectNumberer numberer, EffectNumbers other) {
+ for (int i = 0; i < Effects.numberOfEffectAreas; ++i) {
+ if (_effectNumbers[i] != other._effectNumbers[i]) {
+ _effectNumbers[i] = numberer.next();
+ }
+ }
+ }
+
+ void change(EffectNumberer numberer, int changeFlags) {
+ for (int i = 0; i < Effects.numberOfEffectAreas; ++i) {
+ if (changeFlags & Effects._changesArea(i) != 0) {
+ _effectNumbers[i] = numberer.next();
+ }
+ }
+ }
+
+ /// Builds a vector where all entries that are not depended on are replaced
+ /// by [EffectNumberer.none].
+ //
+ // TODO(asgerf): Use this in GVN to simplify the dispatching code.
+ List<int> getDependencies(int dependsFlags) {
+ Int32List copy = new Int32List.fromList(_effectNumbers);
+ for (int i = 0; i < Effects.numberOfEffectAreas; ++i) {
+ if (dependsFlags & Effects._dependsOnArea(i) == 0) {
+ copy[i] = EffectNumberer.none;
+ }
+ }
+ return copy;
+ }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/finalize.dart b/pkg/compiler/lib/src/cps_ir/finalize.dart
index dad9e51..9376800 100644
--- a/pkg/compiler/lib/src/cps_ir/finalize.dart
+++ b/pkg/compiler/lib/src/cps_ir/finalize.dart
@@ -38,11 +38,11 @@
CpsFragment visitBoundsCheck(BoundsCheck node) {
CpsFragment cps = new CpsFragment(node.sourceInformation);
if (node.hasNoChecks) {
- node..replaceUsesWith(node.object.definition)..destroy();
+ node..replaceUsesWith(node.object)..destroy();
return cps;
}
Continuation fail = cps.letCont();
- Primitive index = node.index.definition;
+ Primitive index = node.index;
if (node.hasIntegerCheck) {
cps.ifTruthy(cps.applyBuiltin(BuiltinOperator.IsNotUnsigned32BitInteger,
[index, index]))
@@ -53,7 +53,7 @@
.invokeContinuation(fail);
}
if (node.hasUpperBoundCheck) {
- Primitive length = node.length.definition;
+ Primitive length = node.length;
if (length is GetLength &&
length.hasExactlyOneUse &&
areAdjacent(length, node)) {
@@ -69,19 +69,19 @@
}
if (node.hasEmptinessCheck) {
cps.ifTruthy(cps.applyBuiltin(BuiltinOperator.StrictEq,
- [node.length.definition, cps.makeZero()]))
+ [node.length, cps.makeZero()]))
.invokeContinuation(fail);
}
cps.insideContinuation(fail).invokeStaticThrower(
helpers.throwIndexOutOfRangeException,
- [node.object.definition, index]);
- node..replaceUsesWith(node.object.definition)..destroy();
+ [node.object, index]);
+ node..replaceUsesWith(node.object)..destroy();
return cps;
}
void visitGetStatic(GetStatic node) {
- if (node.witness != null) {
- node..witness.unlink()..witness = null;
+ if (node.witnessRef != null) {
+ node..witnessRef.unlink()..witnessRef = null;
}
}
@@ -92,9 +92,8 @@
// type of an object is immutable, but the type of an array can change
// after allocation. After the finalize pass, this assumption is no
// longer needed, so we can replace the remaining idenitity templates.
- Refinement refinement = new Refinement(
- node.arguments.single.definition,
- node.type)..type = node.type;
+ Refinement refinement = new Refinement(node.argument(0), node.type)
+ ..type = node.type;
node.replaceWith(refinement);
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/gvn.dart b/pkg/compiler/lib/src/cps_ir/gvn.dart
index 46f5d93..8bf896d 100644
--- a/pkg/compiler/lib/src/cps_ir/gvn.dart
+++ b/pkg/compiler/lib/src/cps_ir/gvn.dart
@@ -15,6 +15,7 @@
import '../js_backend/js_backend.dart' show JavaScriptBackend;
import '../constants/values.dart';
import 'type_mask_system.dart';
+import 'effects.dart';
/// Eliminates redundant primitives by reusing the value of another primitive
/// that is known to have the same result. Primitives are also hoisted out of
@@ -36,11 +37,6 @@
// - Since the new type may be worse, insert a refinement at the old
// definition site, so we do not degrade existing type information.
//
-// TODO(asgerf): Put this pass at a better place in the pipeline. We currently
-// cannot put it anywhere we want, because this pass relies on refinement
-// nodes being present (for safety), whereas other passes rely on refinement
-// nodes being absent (for simplicity & precision).
-//
class GVN extends TrampolineRecursiveVisitor implements Pass {
String get passName => 'GVN';
@@ -54,11 +50,13 @@
LoopHierarchy loopHierarchy;
LoopSideEffects loopEffects;
+ final EffectNumberer effectNumberer = new EffectNumberer();
+
/// Effect numbers at the given join point.
Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{};
/// The effect numbers at the current position (during traversal).
- EffectNumbers effectNumbers = new EffectNumbers();
+ EffectNumbers effectNumbers;
/// The loop currently enclosing the binding of a given primitive.
final Map<Primitive, Continuation> loopHeaderFor =
@@ -80,10 +78,8 @@
GVN(this.compiler, this.types);
- int _usedEffectNumbers = 0;
- int makeNewEffect() => ++_usedEffectNumbers;
-
void rewrite(FunctionDefinition node) {
+ effectNumbers = new EffectNumbers.fresh(effectNumberer);
gvnVectorBuilder = new GvnVectorBuilder(gvnFor, compiler, types);
loopHierarchy = new LoopHierarchy(node);
loopEffects =
@@ -125,7 +121,7 @@
// GetLazyStatic is GVN'ed like a GetStatic, but the effects of the static
// initializer occur before reading the field.
if (prim is GetLazyStatic) {
- visit(prim);
+ addSideEffectsOfPrimitive(prim);
}
// Compute the GVN vector for this computation.
@@ -135,7 +131,7 @@
// Do this after computing the GVN vector so the primitive's GVN is not
// influenced by its own side effects, except in the case of GetLazyStatic.
if (prim is! GetLazyStatic) {
- visit(prim);
+ addSideEffectsOfPrimitive(prim);
}
if (vector == null) {
@@ -347,18 +343,6 @@
return prim is Constant && (prim.value.isPrimitive || prim.value.isDummy);
}
- /// True if [element] is a final or constant field or a function.
- bool isImmutable(Element element) {
- if (element.isField && backend.isNative(element)) return false;
- return element.isField && world.fieldNeverChanges(element) ||
- element.isFunction;
- }
-
- bool isImmutableLength(GetLength length) {
- return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
- allowNull: true);
- }
-
/// Assuming [prim] has no side effects, returns true if it can safely
/// be hoisted out of [loop] without changing its value or changing the timing
/// of a thrown exception.
@@ -369,56 +353,26 @@
if (!prim.isSafeForElimination && loop != currentLoopHeader) {
return false;
}
- if (prim is GetLength && !isImmutableLength(prim)) {
- return !loopEffects.loopChangesLength(loop);
- } else if (prim is GetField && !isImmutable(prim.field)) {
- return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty();
- } else if (prim is GetStatic && !isImmutable(prim.element)) {
- return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty();
- } else if (prim is GetIndex) {
- return !loopEffects.getSideEffectsInLoop(loop).changesIndex();
- } else {
- return true;
- }
+ int effects = loopEffects.getSideEffectsInLoop(loop);
+ return Effects.changesToDepends(effects) & prim.effects == 0;
}
// ------------------ TRAVERSAL AND EFFECT NUMBERING ---------------------
//
// These methods traverse the IR while updating the current effect numbers.
// They are not specific to GVN.
- //
- // TODO(asgerf): Avoid duplicated code for side effect analysis.
- // Should be easier to fix once primitives and call expressions are the same.
- void addSideEffects(SideEffects fx, {bool length: true}) {
- if (fx.changesInstanceProperty()) {
- effectNumbers.instanceField = makeNewEffect();
- }
- if (fx.changesStaticProperty()) {
- effectNumbers.staticField = makeNewEffect();
- }
- if (fx.changesIndex()) {
- effectNumbers.indexableContent = makeNewEffect();
- }
- if (length && fx.changesIndex()) {
- effectNumbers.indexableLength = makeNewEffect();
- }
+ void addSideEffectsOfPrimitive(Primitive prim) {
+ addSideEffects(prim.effects);
}
- void addAllSideEffects() {
- effectNumbers.instanceField = makeNewEffect();
- effectNumbers.staticField = makeNewEffect();
- effectNumbers.indexableContent = makeNewEffect();
- effectNumbers.indexableLength = makeNewEffect();
+ void addSideEffects(int effectFlags) {
+ effectNumbers.change(effectNumberer, effectFlags);
}
Expression traverseLetHandler(LetHandler node) {
// Assume any kind of side effects may occur in the try block.
- effectsAt[node.handler] = new EffectNumbers()
- ..instanceField = makeNewEffect()
- ..staticField = makeNewEffect()
- ..indexableContent = makeNewEffect()
- ..indexableLength = makeNewEffect();
+ effectsAt[node.handler] = new EffectNumbers.fresh(effectNumberer);
push(node.handler);
return node.body;
}
@@ -433,10 +387,7 @@
loopHeaderFor[param] = currentLoopHeader;
}
if (cont.isRecursive) {
- addSideEffects(loopEffects.getSideEffectsInLoop(cont), length: false);
- if (loopEffects.loopChangesLength(cont)) {
- effectNumbers.indexableLength = makeNewEffect();
- }
+ addSideEffects(loopEffects.getSideEffectsInLoop(cont));
pushAction(() {
List<int> hoistedBindings = loopHoistedBindings[cont];
if (hoistedBindings != null) {
@@ -444,124 +395,32 @@
}
});
} else {
- EffectNumbers join = effectsAt[cont];
- if (join != null) {
- effectNumbers = join;
- } else {
- // This is a call continuation seen immediately after its use.
- // Reuse the current effect numbers.
- }
+ effectNumbers = effectsAt[cont];
+ assert(effectNumbers != null);
}
return cont.body;
}
void visitInvokeContinuation(InvokeContinuation node) {
- Continuation cont = node.continuation.definition;
+ Continuation cont = node.continuation;
if (cont.isRecursive) return;
EffectNumbers join = effectsAt[cont];
if (join == null) {
effectsAt[cont] = effectNumbers.copy();
} else {
- if (effectNumbers.instanceField != join.instanceField) {
- join.instanceField = makeNewEffect();
- }
- if (effectNumbers.staticField != join.staticField) {
- join.staticField = makeNewEffect();
- }
- if (effectNumbers.indexableContent != join.indexableContent) {
- join.indexableContent = makeNewEffect();
- }
- if (effectNumbers.indexableLength != join.indexableLength) {
- join.indexableLength = makeNewEffect();
- }
+ join.join(effectNumberer, effectNumbers);
}
}
void visitBranch(Branch node) {
- Continuation trueCont = node.trueContinuation.definition;
- Continuation falseCont = node.falseContinuation.definition;
+ Continuation trueCont = node.trueContinuation;
+ Continuation falseCont = node.falseContinuation;
// Copy the effect number vector once, so the analysis of one branch does
// not influence the other.
effectsAt[trueCont] = effectNumbers;
effectsAt[falseCont] = effectNumbers.copy();
}
-
- void visitInvokeMethod(InvokeMethod node) {
- addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask));
- }
-
- void visitInvokeStatic(InvokeStatic node) {
- addSideEffects(world.getSideEffectsOfElement(node.target));
- }
-
- void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- FunctionElement target = node.target;
- if (target is ConstructorBodyElement) {
- ConstructorBodyElement body = target;
- target = body.constructor;
- }
- addSideEffects(world.getSideEffectsOfElement(target));
- }
-
- void visitInvokeConstructor(InvokeConstructor node) {
- addSideEffects(world.getSideEffectsOfElement(node.target));
- }
-
- void visitSetStatic(SetStatic node) {
- effectNumbers.staticField = makeNewEffect();
- }
-
- void visitSetField(SetField node) {
- effectNumbers.instanceField = makeNewEffect();
- }
-
- void visitSetIndex(SetIndex node) {
- effectNumbers.indexableContent = makeNewEffect();
- }
-
- void visitForeignCode(ForeignCode node) {
- addSideEffects(node.nativeBehavior.sideEffects);
- }
-
- void visitGetLazyStatic(GetLazyStatic node) {
- // TODO(asgerf): How do we get the side effects of a lazy field initializer?
- addAllSideEffects();
- }
-
- void visitAwait(Await node) {
- addAllSideEffects();
- }
-
- void visitYield(Yield node) {
- addAllSideEffects();
- }
-
- void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- // Push and pop.
- effectNumbers.indexableContent = makeNewEffect();
- effectNumbers.indexableLength = makeNewEffect();
- }
-}
-
-/// For each of the four categories of heap locations, the IR is divided into
-/// regions wherein the given heap locations are known not to be modified.
-///
-/// Each region is identified by its "effect number". Effect numbers from
-/// different categories have no relationship to each other.
-class EffectNumbers {
- int indexableLength = 0;
- int indexableContent = 0;
- int staticField = 0;
- int instanceField = 0;
-
- EffectNumbers copy() {
- return new EffectNumbers()
- ..indexableLength = indexableLength
- ..indexableContent = indexableContent
- ..staticField = staticField
- ..instanceField = instanceField;
- }
}
/// Maps vectors to numbers, such that two vectors with the same contents
@@ -659,7 +518,7 @@
}
processGetLength(GetLength node) {
- if (isImmutableLength(node)) {
+ if (node.isFinal) {
// Omit the effect number for fixed-length lists. Note that if a the list
// gets refined to a fixed-length type, we still won't be able to GVN a
// GetLength across the refinement, because the first GetLength uses an
@@ -670,16 +529,6 @@
}
}
- bool isImmutable(Element element) {
- return element.isFunction ||
- element.isField && world.fieldNeverChanges(element);
- }
-
- bool isImmutableLength(GetLength length) {
- return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
- allowNull: true);
- }
-
bool isNativeField(FieldElement field) {
// TODO(asgerf): We should add a GetNativeField instruction.
return backend.isNative(field);
@@ -688,7 +537,7 @@
processGetField(GetField node) {
if (isNativeField(node.field)) {
vector = null; // Native field access cannot be GVN'ed.
- } else if (isImmutable(node.field)) {
+ } else if (node.isFinal) {
vector = [GvnCode.GET_FIELD, node.field];
} else {
vector = [GvnCode.GET_FIELD, node.field, effectNumbers.instanceField];
@@ -700,7 +549,7 @@
}
visitGetStatic(GetStatic node) {
- if (isImmutable(node.element)) {
+ if (node.isFinal) {
vector = [GvnCode.GET_STATIC, node.element];
} else {
vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
@@ -709,7 +558,7 @@
}
processGetLazyStatic(GetLazyStatic node) {
- if (isImmutable(node.element)) {
+ if (node.isFinal) {
vector = [GvnCode.GET_STATIC, node.element];
} else {
vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
diff --git a/pkg/compiler/lib/src/cps_ir/inline.dart b/pkg/compiler/lib/src/cps_ir/inline.dart
index d6096af..6c9f30c 100644
--- a/pkg/compiler/lib/src/cps_ir/inline.dart
+++ b/pkg/compiler/lib/src/cps_ir/inline.dart
@@ -237,9 +237,9 @@
static int sizeOf(InvocationPrimitive invoke, FunctionDefinition function) {
SizeVisitor visitor = new SizeVisitor();
visitor.visit(function);
- visitor.countArgument(invoke.receiver, function.thisParameter);
- for (int i = 0; i < invoke.arguments.length; ++i) {
- visitor.countArgument(invoke.arguments[i], function.parameters[i]);
+ visitor.countArgument(invoke.receiverRef, function.thisParameter);
+ for (int i = 0; i < invoke.argumentRefs.length; ++i) {
+ visitor.countArgument(invoke.argumentRefs[i], function.parameters[i]);
}
return visitor.size;
}
@@ -336,13 +336,13 @@
/// function that takes optional arguments not passed at the call site.
FunctionDefinition buildAdapter(InvokeMethod node, FunctionElement target) {
Parameter thisParameter = new Parameter(new ThisParameterLocal(target))
- ..type = node.receiver.definition.type;
+ ..type = node.receiver.type;
List<Parameter> parameters = new List<Parameter>.generate(
- node.arguments.length,
+ node.argumentRefs.length,
(int index) {
// TODO(kmillikin): Use a hint for the parameter names.
return new Parameter(null)
- ..type = node.arguments[index].definition.type;
+ ..type = node.argument(index).type;
});
Continuation returnContinuation = new Continuation.retrn();
CpsFragment cps = new CpsFragment();
@@ -444,7 +444,7 @@
return null;
}
- Reference<Primitive> dartReceiver = invoke.dartReceiverReference;
+ Reference<Primitive> dartReceiver = invoke.dartReceiverRef;
TypeMask abstractReceiver =
dartReceiver == null ? null : abstractType(dartReceiver);
// The receiver is non-null in a method body, unless the receiver is known
@@ -455,7 +455,7 @@
? abstractReceiver
: abstractReceiver.nonNullable();
List<TypeMask> abstractArguments =
- invoke.arguments.map(abstractType).toList();
+ invoke.argumentRefs.map(abstractType).toList();
var cachedResult = _inliner.cache.get(target, callStructure,
abstractReceiverInMethod,
abstractArguments);
@@ -465,9 +465,8 @@
Primitive finish(FunctionDefinition function) {
_fragment = new CpsFragment(invoke.sourceInformation);
- Primitive receiver = invoke.receiver?.definition;
- List<Primitive> arguments =
- invoke.arguments.map((Reference ref) => ref.definition).toList();
+ Primitive receiver = invoke.receiver;
+ List<Primitive> arguments = invoke.arguments.toList();
// Add a null check to the inlined function body if necessary. The
// cached function body does not contain the null check.
if (dartReceiver != null && abstractReceiver.isNullable) {
@@ -518,17 +517,17 @@
variable.type = value.definition.type;
}
if (invoke.callingConvention == CallingConvention.Intercepted) {
- setValue(function.thisParameter, invoke.receiver);
+ setValue(function.thisParameter, invoke.receiverRef);
function.parameters[0].type = abstractReceiverInMethod;
- for (int i = 1; i < invoke.arguments.length; ++i) {
- setValue(function.parameters[i], invoke.arguments[i]);
+ for (int i = 1; i < invoke.argumentRefs.length; ++i) {
+ setValue(function.parameters[i], invoke.argumentRefs[i]);
}
} else {
- if (invoke.receiver != null) {
+ if (invoke.receiverRef != null) {
function.thisParameter.type = abstractReceiverInMethod;
}
- for (int i = 0; i < invoke.arguments.length; ++i) {
- setValue(function.parameters[i], invoke.arguments[i]);
+ for (int i = 0; i < invoke.argumentRefs.length; ++i) {
+ setValue(function.parameters[i], invoke.argumentRefs[i]);
}
}
optimizeBeforeInlining(function);
diff --git a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
index 207753f..ef291b1 100644
--- a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
@@ -74,7 +74,7 @@
}
Primitive unfoldInterceptor(Primitive prim) {
- return prim is Interceptor ? prim.input.definition : prim;
+ return prim is Interceptor ? prim.input : prim;
}
/// Sets [refined] to be the current refinement for its value, and pushes an
@@ -128,19 +128,19 @@
}
void visitInvokeStatic(InvokeStatic node) {
- node.arguments.forEach(processReference);
+ node.argumentRefs.forEach(processReference);
_refineArguments(node,
_getSuccessTypesForStaticMethod(types, node.target));
}
void visitInvokeMethod(InvokeMethod node) {
// Update references to their current refined values.
- processReference(node.receiver);
- node.arguments.forEach(processReference);
+ processReference(node.receiverRef);
+ node.argumentRefs.forEach(processReference);
// If the call is intercepted, we want to refine the actual receiver,
// not the interceptor.
- Primitive receiver = unfoldInterceptor(node.receiver.definition);
+ Primitive receiver = unfoldInterceptor(node.receiver);
// Do not try to refine the receiver of closure calls; the class world
// does not know about closure classes.
@@ -160,10 +160,10 @@
}
void visitTypeCast(TypeCast node) {
- Primitive value = node.value.definition;
+ Primitive value = node.value;
- processReference(node.value);
- node.typeArguments.forEach(processReference);
+ processReference(node.valueRef);
+ node.typeArgumentRefs.forEach(processReference);
// Refine the type of the input.
TypeMask type = types.subtypesOf(node.dartType).nullable();
@@ -191,11 +191,11 @@
}
void visitBranch(Branch node) {
- processReference(node.condition);
- Primitive condition = node.condition.definition;
+ processReference(node.conditionRef);
+ Primitive condition = node.condition;
- Continuation trueCont = node.trueContinuation.definition;
- Continuation falseCont = node.falseContinuation.definition;
+ Continuation trueCont = node.trueContinuation;
+ Continuation falseCont = node.falseContinuation;
// Sink both continuations to the Branch to ensure everything in scope
// here is also in scope inside the continuations.
@@ -204,7 +204,7 @@
// If the condition is an 'is' check, promote the checked value.
if (condition is TypeTest) {
- Primitive value = condition.value.definition;
+ Primitive value = condition.value;
TypeMask type = types.subtypesOf(condition.dartType);
Primitive refinedValue = new Refinement(value, type);
pushRefinement(trueCont, refinedValue);
@@ -246,8 +246,8 @@
if (condition is ApplyBuiltinOperator &&
condition.operator == BuiltinOperator.Identical) {
- refineEquality(condition.arguments[0].definition,
- condition.arguments[1].definition,
+ refineEquality(condition.argument(0),
+ condition.argument(1),
trueCont,
falseCont);
return;
diff --git a/pkg/compiler/lib/src/cps_ir/loop_effects.dart b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
index c7680b0..4a73e5d 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_effects.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
@@ -2,25 +2,16 @@
import 'cps_ir_nodes.dart';
import 'loop_hierarchy.dart';
-import '../universe/side_effects.dart';
-import '../elements/elements.dart';
import '../world.dart';
+import 'effects.dart';
-/// Determines which the [SideEffects] that may occur during each loop in
-/// a given function, in addition to whether the loop may change the length
-/// of an indexable object.
-///
-/// TODO(asgerf): Make length a flag on [SideEffects] for better precision and
-/// so we don't need to special case the length in this class.
+/// Determines the side effects that may occur in each loop.
class LoopSideEffects extends TrampolineRecursiveVisitor {
LoopHierarchy loopHierarchy;
final World world;
final Map<Continuation, List<Continuation>> exitContinuations = {};
- final Map<Continuation, SideEffects> loopSideEffects = {};
- final Set<Continuation> loopsChangingLength = new Set<Continuation>();
+ final Map<Continuation, int> loopSideEffects = {};
Continuation currentLoopHeader;
- SideEffects currentLoopSideEffects = new SideEffects.empty();
- bool currentLoopChangesLength = false;
LoopSideEffects(FunctionDefinition node, this.world, {this.loopHierarchy}) {
if (loopHierarchy == null) {
@@ -31,30 +22,25 @@
/// Returns the accumulated effects and dependencies on all paths from the
/// loop entry to any recursive invocation of the loop.
- SideEffects getSideEffectsInLoop(Continuation loop) {
+ int getSideEffectsInLoop(Continuation loop) {
return loopSideEffects[loop];
}
/// True if the length of an indexable object may change between the loop
/// entry and a recursive invocation of the loop.
- bool loopChangesLength(Continuation loop) {
- return loopsChangingLength.contains(loop);
+ bool changesIndexableLength(Continuation loop) {
+ return loopSideEffects[loop] & Effects.changesIndexableLength != 0;
}
@override
Expression traverseContinuation(Continuation cont) {
if (cont.isRecursive) {
- SideEffects oldEffects = currentLoopSideEffects;
- bool oldChangesLength = currentLoopChangesLength;
- loopSideEffects[cont] = currentLoopSideEffects = new SideEffects.empty();
+ loopSideEffects[cont] = Effects.none;
exitContinuations[cont] = <Continuation>[];
pushAction(() {
- oldEffects.add(currentLoopSideEffects);
- if (currentLoopChangesLength) {
- loopsChangingLength.add(cont);
+ if (currentLoopHeader != null) {
+ loopSideEffects[currentLoopHeader] |= loopSideEffects[cont];
}
- currentLoopChangesLength = currentLoopChangesLength || oldChangesLength;
- currentLoopSideEffects = oldEffects;
exitContinuations[cont].forEach(push);
});
}
@@ -78,6 +64,14 @@
return node.body;
}
+ @override
+ Expression traverseLetPrim(LetPrim node) {
+ if (currentLoopHeader != null) {
+ loopSideEffects[currentLoopHeader] |= node.primitive.effects;
+ }
+ return node.body;
+ }
+
void enqueueContinuation(Continuation cont) {
Continuation loop = loopHierarchy.getEnclosingLoop(cont);
if (loop == currentLoopHeader) {
@@ -101,85 +95,4 @@
exitContinuations[inner].add(cont);
}
}
-
- void addSideEffects(SideEffects effects) {
- currentLoopSideEffects.add(effects);
- if (effects.changesIndex()) {
- currentLoopChangesLength = true;
- }
- }
-
- void addAllSideEffects() {
- currentLoopSideEffects.setAllSideEffects();
- currentLoopSideEffects.setDependsOnSomething();
- currentLoopChangesLength = true;
- }
-
- void visitInvokeMethod(InvokeMethod node) {
- addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask));
- }
-
- void visitInvokeStatic(InvokeStatic node) {
- addSideEffects(world.getSideEffectsOfElement(node.target));
- }
-
- void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- FunctionElement target = node.target;
- if (target is ConstructorBodyElement) {
- ConstructorBodyElement body = target;
- target = body.constructor;
- }
- addSideEffects(world.getSideEffectsOfElement(target));
- }
-
- void visitInvokeConstructor(InvokeConstructor node) {
- addSideEffects(world.getSideEffectsOfElement(node.target));
- }
-
- void visitSetStatic(SetStatic node) {
- currentLoopSideEffects.setChangesStaticProperty();
- }
-
- void visitGetStatic(GetStatic node) {
- currentLoopSideEffects.setDependsOnStaticPropertyStore();
- }
-
- void visitGetField(GetField node) {
- currentLoopSideEffects.setDependsOnInstancePropertyStore();
- }
-
- void visitSetField(SetField node) {
- currentLoopSideEffects.setChangesInstanceProperty();
- }
-
- void visitGetIndex(GetIndex node) {
- currentLoopSideEffects.setDependsOnIndexStore();
- }
-
- void visitSetIndex(SetIndex node) {
- // Set the change index flag without setting the change length flag.
- currentLoopSideEffects.setChangesIndex();
- }
-
- void visitForeignCode(ForeignCode node) {
- addSideEffects(node.nativeBehavior.sideEffects);
- }
-
- void visitGetLazyStatic(GetLazyStatic node) {
- // TODO(asgerf): How do we get the side effects of a lazy field initializer?
- addAllSideEffects();
- }
-
- void visitAwait(Await node) {
- addAllSideEffects();
- }
-
- void visitYield(Yield node) {
- addAllSideEffects();
- }
-
- void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- currentLoopSideEffects.setChangesIndex();
- currentLoopChangesLength = true; // Push and pop.
- }
}
diff --git a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
index 897a44e..57d71207 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
@@ -118,14 +118,14 @@
Continuation target;
if (node is InvokeContinuation) {
if (node.isRecursive) {
- target = node.continuation.definition;
+ target = node.continuation;
} else {
- target = loopTarget[node.continuation.definition];
+ target = loopTarget[node.continuation];
}
} else if (node is Branch) {
target = _markInnerLoop(
- loopTarget[node.trueContinuation.definition],
- loopTarget[node.falseContinuation.definition]);
+ loopTarget[node.trueContinuation],
+ loopTarget[node.falseContinuation]);
} else if (node == null) {
// If the code ends abruptly, use the exit loop provided in [update].
target = _exitLoop;
diff --git a/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart b/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart
index e9f04a6..98df30a 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_invariant_branch.dart
@@ -121,7 +121,7 @@
Node use = ref.parent;
if (use is InvokeContinuation) {
for (Parameter loopParam in parameters) {
- use.arguments.add(new Reference<Primitive>(loopParam)..parent = use);
+ use.argumentRefs.add(new Reference<Primitive>(loopParam)..parent = use);
}
}
}
@@ -134,11 +134,11 @@
Branch branch = body;
// Is the condition loop invariant?
- Primitive condition = branch.condition.definition;
+ Primitive condition = branch.condition;
if (loopHeaderFor[condition] == loop) return false;
- Continuation trueCont = branch.trueContinuation.definition;
- Continuation falseCont = branch.falseContinuation.definition;
+ Continuation trueCont = branch.trueContinuation;
+ Continuation falseCont = branch.falseContinuation;
Continuation hoistedCase; // The branch to hoist.
Continuation loopCase; // The branch that is part of the loop.
@@ -212,7 +212,7 @@
//
InvokeContinuation loopEntry = loopBinding.body;
List<Primitive> loopArgs =
- loopEntry.arguments.map((ref) => ref.definition).toList();
+ loopEntry.arguments.toList();
CpsFragment cps = new CpsFragment();
cps.branch(condition,
strict: branch.isStrictCheck,
diff --git a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
index e5ea7a8..0c86696 100644
--- a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
+++ b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
@@ -39,7 +39,7 @@
}
void processSetMutable(SetMutable node) {
- MutableVariable variable = node.variable.definition;
+ MutableVariable variable = node.variable;
if (currentDepth > variableDepth[variable]) {
hasAssignmentInTry.add(variable);
}
@@ -142,29 +142,29 @@
stack.add(new VariableItem());
// Put the initial value into the environment.
- Primitive value = node.value.definition;
+ Primitive value = node.value;
environment[node.variable] = value;
// Preserve variable names.
mergeHints(node.variable, value);
// Remove the mutable variable binding.
- node.value.unlink();
+ node.valueRef.unlink();
node.remove();
} else if (node is LetPrim && node.primitive is SetMutable) {
SetMutable setter = node.primitive;
- MutableVariable variable = setter.variable.definition;
+ MutableVariable variable = setter.variable;
if (shouldRewrite(variable)) {
// As above, update the environment, preserve variables and remove
// the mutable variable assignment.
- environment[variable] = setter.value.definition;
- mergeHints(variable, setter.value.definition);
- setter.value.unlink();
+ environment[variable] = setter.value;
+ mergeHints(variable, setter.value);
+ setter.valueRef.unlink();
node.remove();
}
} else if (node is LetPrim && node.primitive is GetMutable) {
GetMutable getter = node.primitive;
- MutableVariable variable = getter.variable.definition;
+ MutableVariable variable = getter.variable;
if (shouldRewrite(variable)) {
// Replace with the reaching definition from the environment.
Primitive value = environment[variable];
@@ -206,7 +206,7 @@
// Analyze the terminal node.
if (node is InvokeContinuation) {
- Continuation cont = node.continuation.definition;
+ Continuation cont = node.continuation;
if (cont.isReturnContinuation) return;
// This is a call to a join continuation. Add arguments for the phi
// parameters that were added to this continuation.
@@ -214,7 +214,7 @@
for (int i = 0; i < phiCount; ++i) {
Primitive value = environment[mutableVariables[i]];
Reference<Primitive> arg = new Reference<Primitive>(value);
- node.arguments.add(arg);
+ node.argumentRefs.add(arg);
arg.parent = node;
}
} else if (node is Branch) {
@@ -222,10 +222,10 @@
// Clone the environments once so the processing of one branch does not
// mutate the environment needed to process the other branch.
stack.add(new ContinuationItem(
- node.trueContinuation.definition,
+ node.trueContinuation,
new Map<MutableVariable, Primitive>.from(environment)));
stack.add(new ContinuationItem(
- node.falseContinuation.definition,
+ node.falseContinuation,
environment));
} else {
assert(node is Throw || node is Unreachable);
diff --git a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
index 689dac6..d9c59b6 100644
--- a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
@@ -137,7 +137,7 @@
for (Reference ref = node.firstRef; ref != null; ref = ref.next) {
if (ref.parent is InvokeMethod) {
InvokeMethod invoke = ref.parent;
- if (invoke.receiver != ref) return false;
+ if (invoke.receiverRef != ref) return false;
var interceptedClasses =
backend.getInterceptedClassesOn(invoke.selector.name);
if (interceptedClasses.contains(helpers.jsDoubleClass)) return false;
@@ -173,7 +173,7 @@
// TODO(asgerf): This could be more precise if we used the use-site type,
// since the interceptor may have been hoisted out of a loop, where a less
// precise type is known.
- Primitive input = node.input.definition;
+ Primitive input = node.input;
TypeMask type = input.type;
if (canInterceptNull(node)) return null;
type = type.nonNullable();
@@ -198,7 +198,7 @@
/// successful.
bool constifyInterceptor(Interceptor interceptor) {
LetPrim let = interceptor.parent;
- Primitive input = interceptor.input.definition;
+ Primitive input = interceptor.input;
ClassElement classElement = getSingleInterceptorClass(interceptor);
if (classElement == null) return false;
@@ -261,7 +261,7 @@
@override
void visitInvokeMethod(InvokeMethod node) {
if (node.callingConvention != CallingConvention.Intercepted) return;
- Primitive interceptor = node.receiver.definition;
+ Primitive interceptor = node.receiver;
if (interceptor is! Interceptor ||
interceptor.hasMultipleUses ||
loopHeaderFor[interceptor] != currentLoopHeader) {
@@ -270,12 +270,12 @@
// TODO(asgerf): Consider heuristics for when to use one-shot interceptors.
// E.g. using only one-shot interceptors with a fast path.
node.callingConvention = CallingConvention.OneShotIntercepted;
- node..receiver.unlink()..receiver = node.arguments.removeAt(0);
+ node..receiverRef.unlink()..receiverRef = node.argumentRefs.removeAt(0);
}
@override
void visitTypeTestViaFlag(TypeTestViaFlag node) {
- Primitive interceptor = node.interceptor.definition;
+ Primitive interceptor = node.interceptor;
if (interceptor is! Interceptor ||
interceptor.hasMultipleUses ||
loopHeaderFor[interceptor] != currentLoopHeader ||
@@ -283,7 +283,7 @@
return;
}
Interceptor inter = interceptor;
- Primitive value = inter.input.definition;
+ Primitive value = inter.input;
node.replaceWith(new TypeTest(value, node.dartType, [])..type = node.type);
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart b/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
index 6f9fac5..aed13e6 100644
--- a/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
+++ b/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
@@ -117,7 +117,7 @@
}
void visitInvokeContinuation(InvokeContinuation node) {
- Continuation cont = node.continuation.definition;
+ Continuation cont = node.continuation;
if (cont.isReturnContinuation) return;
if (node.isRecursive) return;
Map<Primitive, int> target = valuesAt[cont];
@@ -131,9 +131,9 @@
}
visitBranch(Branch node) {
- Primitive condition = node.condition.definition.effectiveDefinition;
- Continuation trueCont = node.trueContinuation.definition;
- Continuation falseCont = node.falseContinuation.definition;
+ Primitive condition = node.condition.effectiveDefinition;
+ Continuation trueCont = node.trueContinuation;
+ Continuation falseCont = node.falseContinuation;
if (condition.hasExactlyOneUse) {
// Handle common case specially. Do not add [condition] to the map if
// there are no other uses.
@@ -167,7 +167,7 @@
// self-interceptor.
// TODO(25646): If TypeMasks could represent "any self-interceptor" this
// optimization should be subsumed by type propagation.
- node.receiver.changeTo(node.dartReceiver);
+ node.receiverRef.changeTo(node.dartReceiver);
// Replace the extra receiver argument with a dummy value if the
// target definitely does not use it.
@@ -176,7 +176,7 @@
Constant dummy = new Constant(new IntConstantValue(0))
..type = typeSystem.intType;
new LetPrim(dummy).insertAbove(node.parent);
- node.arguments[0].changeTo(dummy);
+ node.argumentRefs[0].changeTo(dummy);
node.callingConvention = CallingConvention.DummyIntercepted;
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
index f1191ff..59cac26 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -19,7 +19,8 @@
/// one continuation. The reference chains for parameters are therefore
/// meaningless during this pass, until repaired by [AlphaRenamer] at
/// the end.
-class RedundantJoinEliminator extends TrampolineRecursiveVisitor implements Pass {
+class RedundantJoinEliminator extends TrampolineRecursiveVisitor
+ implements Pass {
String get passName => 'Redundant join elimination';
final Set<Branch> workSet = new Set<Branch>();
@@ -80,7 +81,7 @@
// enclosing continuation.
// Note: Do not use the parent pointer for this check, because parameters
// are temporarily shared between different continuations during this pass.
- Primitive condition = branch.condition.definition;
+ Primitive condition = branch.condition;
int parameterIndex = branchCont.parameters.indexOf(condition);
if (parameterIndex == -1) return;
@@ -92,7 +93,7 @@
InvokeContinuation trueCall, falseCall;
for (Reference ref = branchCont.firstRef; ref != null; ref = ref.next) {
InvokeContinuation invoke = ref.parent;
- Primitive argument = invoke.arguments[parameterIndex].definition;
+ Primitive argument = invoke.argument(parameterIndex);
if (argument is! Constant) return; // Branching condition is unknown.
Constant constant = argument;
if (isTruthyConstant(constant.value, strict: branch.isStrictCheck)) {
@@ -139,7 +140,8 @@
Expression use = ref.parent;
if (use is InvokeContinuation) {
for (Parameter param in branchCont.parameters) {
- use.arguments.add(new Reference<Primitive>(param)..parent = use);
+ use.argumentRefs.add(
+ new Reference<Primitive>(param)..parent = use);
}
} else {
// The branch will be eliminated, so don't worry about updating it.
@@ -153,8 +155,8 @@
assert(branchCont.body == branch);
- Continuation trueCont = branch.trueContinuation.definition;
- Continuation falseCont = branch.falseContinuation.definition;
+ Continuation trueCont = branch.trueContinuation;
+ Continuation falseCont = branch.falseContinuation;
assert(branchCont != trueCont);
assert(branchCont != falseCont);
@@ -168,19 +170,19 @@
while (branchCont.firstRef != null) {
Reference reference = branchCont.firstRef;
InvokeContinuation invoke = branchCont.firstRef.parent;
- Constant condition = invoke.arguments[parameterIndex].definition;
+ Constant condition = invoke.argument(parameterIndex);
if (isTruthyConstant(condition.value, strict: branch.isStrictCheck)) {
- invoke.continuation.changeTo(trueCont);
+ invoke.continuationRef.changeTo(trueCont);
} else {
- invoke.continuation.changeTo(falseCont);
+ invoke.continuationRef.changeTo(falseCont);
}
assert(branchCont.firstRef != reference);
}
// Remove the now-unused branchCont continuation.
assert(branchCont.hasNoUses);
- branch.trueContinuation.unlink();
- branch.falseContinuation.unlink();
+ branch.trueContinuationRef.unlink();
+ branch.falseContinuationRef.unlink();
outerLetCont.continuations.remove(branchCont);
if (outerLetCont.continuations.isEmpty) {
outerLetCont.remove();
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
index f5d5423..b612d13 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
@@ -47,7 +47,7 @@
List<InvokeContinuation> invokes = <InvokeContinuation>[];
for (Reference ref = cont.firstRef; ref != null; ref = ref.next) {
Node parent = ref.parent;
- if (parent is InvokeContinuation && ref == parent.continuation) {
+ if (parent is InvokeContinuation && ref == parent.continuationRef) {
invokes.add(parent);
} else {
return; // Can't optimize.
@@ -64,7 +64,7 @@
Primitive uniqueDefinitionOf(int i) {
Primitive value = null;
for (InvokeContinuation invoke in invokes) {
- Primitive def = invoke.arguments[i].definition.effectiveDefinition;
+ Primitive def = invoke.argument(i).effectiveDefinition;
if (cont.parameters[i] == def) {
// Invocation param == param in LetCont (i.e. a recursive call).
@@ -110,7 +110,7 @@
if (src != dst) {
cont.parameters[dst] = cont.parameters[src];
for (InvokeContinuation invoke in invokes) {
- invoke.arguments[dst] = invoke.arguments[src];
+ invoke.argumentRefs[dst] = invoke.argumentRefs[src];
}
}
dst++;
@@ -126,7 +126,7 @@
ref = ref.next) {
Node parent = ref.parent;
if (parent is InvokeContinuation) {
- Continuation thatCont = parent.continuation.definition;
+ Continuation thatCont = parent.continuation;
if (thatCont != cont) {
workSet.add(thatCont);
}
@@ -140,7 +140,7 @@
// arguments are unlinked to keep definition usages up to date.
oldDefinition.replaceUsesWith(uniqueDefinition);
for (InvokeContinuation invoke in invokes) {
- invoke.arguments[src].unlink();
+ invoke.argumentRefs[src].unlink();
}
// Finally, if the substituted definition is not in scope of the affected
@@ -156,7 +156,7 @@
// Remove trailing items from parameter and argument lists.
cont.parameters.length = dst;
for (InvokeContinuation invoke in invokes) {
- invoke.arguments.length = dst;
+ invoke.argumentRefs.length = dst;
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
index b220847..5eb8156 100644
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -77,7 +77,7 @@
for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
Node use = ref.parent;
if (use is GetField) continue;
- if (use is SetField && use.object == ref) continue;
+ if (use is SetField && use.objectRef == ref) continue;
return;
}
@@ -102,7 +102,7 @@
int i = 0;
allocation.classElement.forEachInstanceField(
(ClassElement enclosingClass, FieldElement field) {
- Primitive argument = allocation.arguments[i++].definition;
+ Primitive argument = allocation.argument(i++);
fieldInitialValues[field] = argument;
},
includeSuperAndInjectedMembers: true);
@@ -127,7 +127,7 @@
insertionPoint = let..insertBelow(insertionPoint);
}
LetMutable let = new LetMutable(variable, initialValue);
- let.value.parent = let;
+ let.valueRef.parent = let;
insertionPoint = let..insertBelow(insertionPoint);
}
@@ -141,7 +141,7 @@
if (variable != null) {
GetMutable getter = new GetMutable(variable);
getter.type = getField.type;
- getter.variable.parent = getter;
+ getter.variableRef.parent = getter;
getField.replaceUsesWith(getter);
replacePrimitive(getField, getter);
deletePrimitive(getField);
@@ -150,14 +150,14 @@
getField.replaceUsesWith(value);
deleteLetPrimOf(getField);
}
- } else if (use is SetField && use.object == ref) {
+ } else if (use is SetField && use.objectRef == ref) {
SetField setField = use;
MutableVariable variable = cells[setField.field];
- Primitive value = setField.value.definition;
+ Primitive value = setField.value;
variable.type = variable.type.union(value.type, classWorld);
SetMutable setter = new SetMutable(variable, value);
- setter.variable.parent = setter;
- setter.value.parent = setter;
+ setter.variableRef.parent = setter;
+ setter.valueRef.parent = setter;
setField.replaceUsesWith(setter);
replacePrimitive(setField, setter);
deletePrimitive(setField);
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index 298a082..1c84ca6 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -203,9 +203,9 @@
cont.body = null;
// Substitute the invocation argument for the continuation parameter.
- for (int i = 0; i < invoke.arguments.length; i++) {
+ for (int i = 0; i < invoke.argumentRefs.length; i++) {
Parameter param = cont.parameters[i];
- Primitive argument = invoke.arguments[i].definition;
+ Primitive argument = invoke.argument(i);
param.replaceUsesWith(argument);
argument.useElementAsHint(param.hint);
_checkConstantBranchCondition(argument);
@@ -243,7 +243,7 @@
_removeContinuation(cont);
InvokeContinuation invoke = cont.body;
- Continuation wrappedCont = invoke.continuation.definition;
+ Continuation wrappedCont = invoke.continuation;
for (int i = 0; i < cont.parameters.length; ++i) {
wrappedCont.parameters[i].useElementAsHint(cont.parameters[i].hint);
@@ -280,13 +280,13 @@
// branch is deleted the other target becomes unreferenced and the chosen
// target becomes available for eta-cont and further reductions.
Continuation target;
- Primitive condition = branch.condition.definition;
+ Primitive condition = branch.condition;
if (condition is Constant) {
target = isTruthyConstant(condition.value, strict: branch.isStrictCheck)
- ? branch.trueContinuation.definition
- : branch.falseContinuation.definition;
- } else if (_isBranchTargetOfUselessIf(branch.trueContinuation.definition)) {
- target = branch.trueContinuation.definition;
+ ? branch.trueContinuation
+ : branch.falseContinuation;
+ } else if (_isBranchTargetOfUselessIf(branch.trueContinuation)) {
+ target = branch.trueContinuation;
} else {
return;
}
@@ -331,9 +331,9 @@
// Remove the index'th argument from each invocation.
for (Reference ref = continuation.firstRef; ref != null; ref = ref.next) {
InvokeContinuation invoke = ref.parent;
- Reference<Primitive> argument = invoke.arguments[index];
+ Reference<Primitive> argument = invoke.argumentRefs[index];
argument.unlink();
- invoke.arguments.removeAt(index);
+ invoke.argumentRefs.removeAt(index);
// Removing an argument can create a dead primitive or an eta-redex
// in case the parent is a continuation that now has matching parameters.
_checkDeadPrimitive(argument.definition);
@@ -449,7 +449,7 @@
}
InvokeContinuation invoke = cont.body;
- Continuation invokedCont = invoke.continuation.definition;
+ Continuation invokedCont = invoke.continuation;
// Do not eta-reduce return join-points since the direct-style code is worse
// in the common case (i.e. returns are moved inside `if` branches).
@@ -487,14 +487,14 @@
//
// TODO(kmillikin): find real occurrences of these patterns, and see if they
// can be optimized.
- if (cont.parameters.length != invoke.arguments.length) {
+ if (cont.parameters.length != invoke.argumentRefs.length) {
return false;
}
// TODO(jgruber): Linear in the parameter count. Can be improved to near
// constant time by using union-find data structure.
for (int i = 0; i < cont.parameters.length; i++) {
- if (invoke.arguments[i].definition != cont.parameters[i]) {
+ if (invoke.argument(i) != cont.parameters[i]) {
return false;
}
}
@@ -513,7 +513,7 @@
}
bool _isBranchRedex(Branch branch) {
- return _isUselessIf(branch) || branch.condition.definition is Constant;
+ return _isUselessIf(branch) || branch.condition is Constant;
}
bool _isBranchTargetOfUselessIf(Continuation cont) {
@@ -533,16 +533,16 @@
}
bool _isUselessIf(Branch branch) {
- Continuation trueCont = branch.trueContinuation.definition;
+ Continuation trueCont = branch.trueContinuation;
Expression trueBody = _unfoldDeadRefinements(trueCont.body);
if (trueBody is! InvokeContinuation) return false;
- Continuation falseCont = branch.falseContinuation.definition;
+ Continuation falseCont = branch.falseContinuation;
Expression falseBody = _unfoldDeadRefinements(falseCont.body);
if (falseBody is! InvokeContinuation) return false;
InvokeContinuation trueInvoke = trueBody;
InvokeContinuation falseInvoke = falseBody;
- if (trueInvoke.continuation.definition !=
- falseInvoke.continuation.definition) {
+ if (trueInvoke.continuation !=
+ falseInvoke.continuation) {
return false;
}
// Matching zero arguments should be adequate, since isomorphic true and false
@@ -553,7 +553,7 @@
// dead parameter reduction, where some but not all of the invocations have
// been rewritten. In that case, we will find the redex (once) after both
// of these invocations have been rewritten.
- return trueInvoke.arguments.isEmpty && falseInvoke.arguments.isEmpty;
+ return trueInvoke.argumentRefs.isEmpty && falseInvoke.argumentRefs.isEmpty;
}
bool _isDeadParameter(Parameter parameter) {
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 00cbfb1..6b09771 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -38,6 +38,7 @@
import 'cps_fragment.dart';
import 'cps_ir_nodes.dart';
import 'type_mask_system.dart';
+import 'effects.dart';
class ConstantPropagationLattice {
final TypeMaskSystem typeSystem;
@@ -960,10 +961,10 @@
bool isAlwaysThrowingOrDiverging(Primitive prim) {
if (prim is SetField) {
- return getValue(prim.object.definition).isNullConstant;
+ return getValue(prim.object).isNullConstant;
}
if (prim is SetIndex) {
- return getValue(prim.object.definition).isNullConstant;
+ return getValue(prim.object).isNullConstant;
}
// If a primitive has a value, but can't return anything, it must throw
// or diverge.
@@ -1077,9 +1078,9 @@
//
// (Branch (IsTrue true) k0 k1) -> (InvokeContinuation k0)
void visitBranch(Branch node) {
- Continuation trueCont = node.trueContinuation.definition;
- Continuation falseCont = node.falseContinuation.definition;
- Primitive condition = node.condition.definition;
+ Continuation trueCont = node.trueContinuation;
+ Continuation falseCont = node.falseContinuation;
+ Primitive condition = node.condition;
AbstractConstantValue conditionValue = getValue(condition);
// Change to non-strict check if the condition is a boolean or null.
@@ -1110,9 +1111,9 @@
// a negation again if that's useful.
if (condition is ApplyBuiltinOperator &&
condition.operator == BuiltinOperator.IsFalsy) {
- node.condition.changeTo(condition.arguments.single.definition);
- node.trueContinuation.changeTo(falseCont);
- node.falseContinuation.changeTo(trueCont);
+ node.conditionRef.changeTo(condition.argument(0));
+ node.trueContinuationRef.changeTo(falseCont);
+ node.falseContinuationRef.changeTo(trueCont);
return;
}
}
@@ -1123,19 +1124,19 @@
// pass, but doing it here helps simplify pattern matching code, since the
// effective definition of a primitive can then be found without going
// through redundant InvokeContinuations.
- Continuation cont = node.continuation.definition;
+ Continuation cont = node.continuation;
if (cont.hasExactlyOneUse &&
!cont.isReturnContinuation &&
!cont.isRecursive &&
!node.isEscapingTry) {
- for (int i = 0; i < node.arguments.length; ++i) {
- Primitive argument = node.arguments[i].definition;
+ for (int i = 0; i < node.argumentRefs.length; ++i) {
+ Primitive argument = node.argument(i);
Parameter parameter = cont.parameters[i];
argument.useElementAsHint(parameter.hint);
parameter.replaceUsesWith(argument);
- node.arguments[i].unlink();
+ node.argumentRefs[i].unlink();
}
- node.continuation.unlink();
+ node.continuationRef.unlink();
InteriorNode parent = node.parent;
Expression body = cont.body;
parent.body = body;
@@ -1278,10 +1279,10 @@
/// Replaces the call with a call to [name] with the same inputs.
InvokeMethod makeRenamedInvoke(String name) {
- return new InvokeMethod(node.receiver.definition,
+ return new InvokeMethod(node.receiver,
renameToOptimizedSelector(name),
node.mask,
- node.arguments.map((ref) => ref.definition).toList(),
+ node.arguments.toList(),
sourceInformation: node.sourceInformation,
callingConvention: node.callingConvention);
}
@@ -1522,8 +1523,38 @@
}
switch (node.selector.name) {
case 'length':
- if (!node.selector.isGetter) return null;
- return new GetLength(receiver);
+ if (node.selector.isGetter) {
+ return new GetLength(receiver);
+ }
+ if (node.selector.isSetter) {
+ if (!typeSystem.isDefinitelyExtendableArray(receiver.type,
+ allowNull: true)) {
+ return null;
+ }
+ CpsFragment cps = new CpsFragment(node.sourceInformation);
+ Primitive newLength = node.dartArgument(0);
+ if (!typeSystem.isDefinitelyUint(newLength.type)) {
+ // TODO(asgerf): We could let the SetLength instruction throw for
+ // negative right-hand sides (see length setter in js_array.dart).
+ if (compiler.trustPrimitives) {
+ newLength = cps.refine(newLength, typeSystem.uint32Type);
+ newLength.type = typeSystem.uint32Type;
+ } else {
+ return null;
+ }
+ }
+ cps.letPrim(new ApplyBuiltinMethod(
+ BuiltinMethod.SetLength,
+ receiver,
+ [newLength],
+ node.sourceInformation));
+ if (!typeSystem.isDefinitelyUint32(newLength.type)) {
+ // If the setter succeeded, the length must have been a uint32.
+ cps.refine(newLength, typeSystem.uint32Type);
+ }
+ return cps;
+ }
+ return null;
case '[]':
Primitive index = node.dartArgument(0);
@@ -1640,7 +1671,7 @@
}
LiteralList addedLiteral = addedList;
CpsFragment cps = new CpsFragment(sourceInfo);
- for (Reference value in addedLiteral.values) {
+ for (Reference value in addedLiteral.valueRefs) {
cps.invokeBuiltin(BuiltinMethod.Push,
list,
<Primitive>[value.definition]);
@@ -1678,8 +1709,8 @@
CpsFragment cps = new CpsFragment(node.sourceInformation);
Primitive result = cps.inlineFunction(target,
- node.receiver.definition,
- node.arguments.map((ref) => ref.definition).toList(),
+ node.receiver,
+ node.arguments.toList(),
hint: node.hint);
node.replaceUsesWith(result);
return cps;
@@ -1697,7 +1728,7 @@
for (Reference ref in iterator.refinedUses) {
if (ref.parent is! InvokeMethod) return null;
InvokeMethod use = ref.parent;
- if (ref != use.receiver) return null;
+ if (ref != use.receiverRef) return null;
if (use.selector != Selectors.moveNext &&
use.selector != Selectors.current) {
return null;
@@ -1865,7 +1896,7 @@
if (!call.isClosureCall) return null;
assert(!isInterceptedSelector(call));
- assert(call.argumentCount == node.arguments.length);
+ assert(call.argumentCount == node.argumentRefs.length);
Primitive tearOff = node.dartReceiver.effectiveDefinition;
// Note: We don't know if [tearOff] is actually a tear-off.
@@ -1886,7 +1917,7 @@
// The tear-off will be cleaned up by shrinking reductions.
return new InvokeStatic(target,
new Selector.fromElement(target),
- node.arguments.map((ref) => ref.definition).toList(),
+ node.arguments.toList(),
node.sourceInformation);
}
if (tearOff is InvokeMethod && tearOff.selector.isGetter) {
@@ -1897,7 +1928,7 @@
LetPrim tearOffBinding = tearOff.parent;
- Primitive object = tearOff.receiver.definition;
+ Primitive object = tearOff.receiver;
// Ensure that the object actually has a foo member, since we might
// otherwise alter a noSuchMethod call.
@@ -1932,9 +1963,9 @@
object,
new Selector.call(getter.memberName, call.callStructure),
type,
- node.arguments.map((ref) => ref.definition).toList(),
+ node.arguments.toList(),
sourceInformation: node.sourceInformation);
- node.receiver.changeTo(new Parameter(null)); // Remove the tear off use.
+ node.receiverRef.changeTo(new Parameter(null)); // Remove the tear off use.
if (tearOff.hasNoRefinedUses) {
// Eliminate the getter call if it has no more uses.
@@ -1962,9 +1993,9 @@
if (!call.isClosureCall) return null;
assert(!isInterceptedSelector(call));
- assert(call.argumentCount == node.arguments.length);
+ assert(call.argumentCount == node.argumentRefs.length);
- Primitive receiver = node.receiver.definition;
+ Primitive receiver = node.receiver;
if (receiver is !CreateInstance) return null;
CreateInstance createInstance = receiver;
if (!createInstance.hasExactlyOneUse) return null;
@@ -2004,14 +2035,14 @@
if (use is GetField) continue;
// Closures do not currently have writable fields, but closure conversion
// could esily be changed to allocate some cells in a closure object.
- if (use is SetField && ref == use.object) continue;
+ if (use is SetField && ref == use.objectRef) continue;
return null;
}
CpsFragment cps = new CpsFragment(node.sourceInformation);
Primitive returnValue = cps.inlineFunction(target,
- node.receiver.definition,
- node.arguments.map((ref) => ref.definition).toList(),
+ node.receiver,
+ node.arguments.toList(),
hint: node.hint);
node.replaceUsesWith(returnValue);
return cps;
@@ -2023,21 +2054,33 @@
// might have to return JSNull. That case is handled by visitInvokeMethod
// and visitInvokeMethodDirectly which can sometimes tolerate that null
// is used instead of JSNull.
- Primitive input = node.input.definition;
+ Primitive input = node.input;
if (!input.type.isNullable &&
typeSystem.areDisjoint(input.type, typeSystem.interceptorType)) {
node.replaceUsesWith(input);
}
}
+ visitInvokeConstructor(InvokeConstructor node) {
+ node.effects =
+ Effects.from(compiler.world.getSideEffectsOfElement(node.target));
+ }
+
visitInvokeMethodDirectly(InvokeMethodDirectly node) {
+ Element target = node.target;
+ if (target is ConstructorBodyElement) {
+ ConstructorBodyElement constructorBody = target;
+ target = constructorBody.constructor;
+ }
+ node.effects =
+ Effects.from(compiler.world.getSideEffectsOfElement(target));
TypeMask receiverType = node.dartReceiver.type;
if (node.callingConvention == CallingConvention.Intercepted &&
typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) {
// Some direct calls take an interceptor because the target class is
// mixed into a native class. If it is known at the call site that the
// receiver is non-intercepted, get rid of the interceptor.
- node.receiver.changeTo(node.dartReceiver);
+ node.receiverRef.changeTo(node.dartReceiver);
}
}
@@ -2054,6 +2097,9 @@
TypeMask receiverType = node.dartReceiver.type;
node.mask = typeSystem.intersection(node.mask, receiverType);
+ node.effects = Effects.from(
+ compiler.world.getSideEffectsOfSelector(node.selector, node.mask));
+
bool canBeNonThrowingCallOnNull =
selectorsOnNull.contains(node.selector) &&
receiverType.isNullable;
@@ -2063,7 +2109,7 @@
typeSystem.areDisjoint(receiverType, typeSystem.interceptorType)) {
// Use the Dart receiver as the JS receiver. This changes the wording of
// the error message when the receiver is null, but we accept this.
- node.receiver.changeTo(node.dartReceiver);
+ node.receiverRef.changeTo(node.dartReceiver);
// Replace the extra receiver argument with a dummy value if the
// target definitely does not use it.
@@ -2071,14 +2117,14 @@
node.selector)) {
Constant dummy = makeConstantPrimitive(new IntConstantValue(0));
new LetPrim(dummy).insertAbove(node.parent);
- node.arguments[0].changeTo(dummy);
+ node.argumentRefs[0].changeTo(dummy);
node.callingConvention = CallingConvention.DummyIntercepted;
}
}
}
CpsFragment visitTypeCast(TypeCast node) {
- AbstractConstantValue value = getValue(node.value.definition);
+ AbstractConstantValue value = getValue(node.value);
switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) {
case AbstractBool.Maybe:
case AbstractBool.Nothing:
@@ -2086,7 +2132,7 @@
case AbstractBool.True:
// Return an unused primitive moved again.
- node.replaceUsesWith(node.value.definition);
+ node.replaceUsesWith(node.value);
return new CpsFragment(); // Remove the node.
case AbstractBool.False:
@@ -2099,7 +2145,7 @@
/// Specialize calls to internal static methods.
specializeInternalMethodCall(InvokeStatic node) {
if (node.target == backend.helpers.stringInterpolationHelper) {
- Primitive argument = node.arguments[0].definition;
+ Primitive argument = node.argument(0);
AbstractConstantValue value = getValue(argument);
if (lattice.isDefinitelyString(value)) {
node.replaceUsesWith(argument);
@@ -2119,9 +2165,9 @@
}
}
} else if (node.target == compiler.identicalFunction) {
- if (node.arguments.length == 2) {
+ if (node.argumentRefs.length == 2) {
return new ApplyBuiltinOperator(BuiltinOperator.Identical,
- [node.arguments[0].definition, node.arguments[1].definition],
+ [node.argument(0), node.argument(1)],
node.sourceInformation);
}
}
@@ -2129,6 +2175,8 @@
}
visitInvokeStatic(InvokeStatic node) {
+ node.effects = Effects.from(
+ compiler.world.getSideEffectsOfElement(node.target));
return specializeInternalMethodCall(node);
}
@@ -2165,13 +2213,11 @@
// Concatenate consecutive constants.
bool argumentsWereRemoved = false;
int i = 0;
- while (i < node.arguments.length - 1) {
+ while (i < node.argumentRefs.length - 1) {
int startOfSequence = i;
- AbstractConstantValue firstValue =
- getValue(node.arguments[i++].definition);
+ AbstractConstantValue firstValue = getValue(node.argument(i++));
if (!firstValue.isConstant) continue;
- AbstractConstantValue secondValue =
- getValue(node.arguments[i++].definition);
+ AbstractConstantValue secondValue = getValue(node.argument(i++));
if (!secondValue.isConstant) continue;
ast.DartString string =
@@ -2180,9 +2226,8 @@
// We found a sequence of at least two constants.
// Look for the end of the sequence.
- while (i < node.arguments.length) {
- AbstractConstantValue value =
- getValue(node.arguments[i].definition);
+ while (i < node.argumentRefs.length) {
+ AbstractConstantValue value = getValue(node.argument(i));
if (!value.isConstant) break;
string = new ast.ConsDartString(string, getString(value));
++i;
@@ -2191,18 +2236,18 @@
makeConstantPrimitive(new StringConstantValue(string));
new LetPrim(prim).insertAbove(node.parent);
for (int k = startOfSequence; k < i; ++k) {
- node.arguments[k].unlink();
- node.arguments[k] = null; // Remove the argument after the loop.
+ node.argumentRefs[k].unlink();
+ node.argumentRefs[k] = null; // Remove the argument after the loop.
}
- node.arguments[startOfSequence] = new Reference<Primitive>(prim);
- node.arguments[startOfSequence].parent = node;
+ node.argumentRefs[startOfSequence] = new Reference<Primitive>(prim);
+ node.argumentRefs[startOfSequence].parent = node;
argumentsWereRemoved = true;
}
if (argumentsWereRemoved) {
- node.arguments.removeWhere((ref) => ref == null);
+ node.argumentRefs.removeWhere((ref) => ref == null);
}
- if (node.arguments.length == 1) {
- Primitive input = node.arguments[0].definition;
+ if (node.argumentRefs.length == 1) {
+ Primitive input = node.argument(0);
node.replaceUsesWith(input);
input.useElementAsHint(node.hint);
}
@@ -2211,8 +2256,8 @@
break;
case BuiltinOperator.Identical:
- Primitive leftArg = node.arguments[0].definition;
- Primitive rightArg = node.arguments[1].definition;
+ Primitive leftArg = node.argument(0);
+ Primitive rightArg = node.argument(1);
AbstractConstantValue left = getValue(leftArg);
AbstractConstantValue right = getValue(rightArg);
BuiltinOperator newOperator;
@@ -2239,7 +2284,7 @@
}
if (newOperator != null) {
return new ApplyBuiltinOperator(newOperator,
- node.arguments.map((ref) => ref.definition).toList(),
+ node.arguments.toList(),
node.sourceInformation);
}
break;
@@ -2253,8 +2298,8 @@
node.operator == BuiltinOperator.LooseNeq;
for (int firstIndex in [0, 1]) {
int secondIndex = 1 - firstIndex;
- Primitive firstArg = node.arguments[firstIndex].definition;
- Primitive secondArg = node.arguments[secondIndex].definition;
+ Primitive firstArg = node.argument(firstIndex);
+ Primitive secondArg = node.argument(secondIndex);
AbstractConstantValue first = getValue(firstArg);
if (!lattice.isDefinitelyBool(first)) continue;
AbstractConstantValue second = getValue(secondArg);
@@ -2285,7 +2330,7 @@
}
visitTypeTest(TypeTest node) {
- Primitive prim = node.value.definition;
+ Primitive prim = node.value;
Primitive unaryBuiltinOperator(BuiltinOperator operator) =>
new ApplyBuiltinOperator(
@@ -2391,11 +2436,11 @@
// The [BoundsChecker] pass does not try to eliminate checks that could be
// eliminated by constant folding.
if (node.hasNoChecks) return;
- Primitive indexPrim = node.index.definition;
+ Primitive indexPrim = node.index;
int index = lattice.intValue(getValue(indexPrim));
- int length = node.length == null
+ int length = node.lengthRef == null
? null
- : lattice.intValue(getValue(node.length.definition));
+ : lattice.intValue(getValue(node.length));
if (index != null && length != null && index < length) {
node.checks &= ~BoundsCheck.UPPER_BOUND;
}
@@ -2408,8 +2453,8 @@
if (typeSystem.isDefinitelyInt(indexPrim.type)) {
node.checks &= ~BoundsCheck.INTEGER;
}
- if (!node.lengthUsedInCheck && node.length != null) {
- node..length.unlink()..length = null;
+ if (!node.lengthUsedInCheck && node.lengthRef != null) {
+ node..lengthRef.unlink()..lengthRef = null;
}
if (node.checks == BoundsCheck.NONE) {
// We can't remove the bounds check node because it may still be used to
@@ -2420,12 +2465,12 @@
// restrict code motion. However, if we want to run this pass after
// [BoundsChecker] that would not be safe any more, so for now we
// keep the node for forward compatibilty.
- node..index.unlink()..index = null;
+ node..indexRef.unlink()..indexRef = null;
}
}
visitReceiverCheck(ReceiverCheck node) {
- Primitive input = node.value.definition;
+ Primitive input = node.value;
if (!input.type.isNullable &&
(node.isNullCheck ||
!input.type.needsNoSuchMethodHandling(node.selector, classWorld))) {
@@ -2435,6 +2480,11 @@
return null;
}
+ visitGetLength(GetLength node) {
+ node.isFinal = typeSystem.isDefinitelyFixedLengthIndexable(
+ node.object.type, allowNull: true);
+ }
+
visitReadTypeVariable(ReadTypeVariable node) {
// Pattern match on
//
@@ -2449,11 +2499,11 @@
// TODO(sra): A non-shrinking version of this rewrite could be done as part
// of scalar replacement.
- if (node.target.definition is CreateInstance) {
- CreateInstance instance = node.target.definition;
- if (instance.typeInformation != null &&
- instance.typeInformation.definition is TypeExpression) {
- TypeExpression typeExpression = instance.typeInformation.definition;
+ if (node.target is CreateInstance) {
+ CreateInstance instance = node.target;
+ if (instance.typeInformationRef != null &&
+ instance.typeInformation is TypeExpression) {
+ TypeExpression typeExpression = instance.typeInformation;
assert(typeExpression.kind == TypeExpressionKind.INSTANCE);
ClassElement context = node.variable.element.enclosingClass;
// In the general case, a substitution could generate a large type
@@ -2463,8 +2513,8 @@
if (!functionCompiler.glue.needsSubstitutionForTypeVariableAccess(
context)) {
int index = functionCompiler.glue.getTypeVariableIndex(node.variable);
- if (0 <= index && index < typeExpression.arguments.length) {
- node.replaceUsesWith(typeExpression.arguments[index].definition);
+ if (0 <= index && index < typeExpression.argumentRefs.length) {
+ node.replaceUsesWith(typeExpression.argument(index));
return new CpsFragment();
}
}
@@ -2696,13 +2746,13 @@
}
void visitLetMutable(LetMutable node) {
- setValue(node.variable, getValue(node.value.definition));
+ setValue(node.variable, getValue(node.value));
push(node.body);
}
void visitInvokeStatic(InvokeStatic node) {
if (node.target == backend.helpers.stringInterpolationHelper) {
- AbstractConstantValue argValue = getValue(node.arguments[0].definition);
+ AbstractConstantValue argValue = getValue(node.argument(0));
setResult(node, lattice.stringify(argValue), canReplace: true);
return;
}
@@ -2712,13 +2762,13 @@
}
void visitInvokeContinuation(InvokeContinuation node) {
- Continuation cont = node.continuation.definition;
+ Continuation cont = node.continuation;
setReachable(cont);
// Forward the constant status of all continuation invokes to the
// continuation. Note that this is effectively a phi node in SSA terms.
- for (int i = 0; i < node.arguments.length; i++) {
- Primitive def = node.arguments[i].definition;
+ for (int i = 0; i < node.argumentRefs.length; i++) {
+ Primitive def = node.argument(i);
AbstractConstantValue cell = getValue(def);
setValue(cont.parameters[i], cell);
}
@@ -2726,7 +2776,6 @@
void visitInvokeMethod(InvokeMethod node) {
AbstractConstantValue receiver = getValue(node.dartReceiver);
- node.receiverIsNotNull = receiver.isDefinitelyNotNull;
if (receiver.isNothing) {
return setResult(node, lattice.nothing);
}
@@ -2796,7 +2845,7 @@
void unaryOp(
AbstractConstantValue operation(AbstractConstantValue argument),
TypeMask defaultType) {
- AbstractConstantValue value = getValue(node.arguments[0].definition);
+ AbstractConstantValue value = getValue(node.argument(0));
setValue(node, operation(value) ?? nonConstant(defaultType));
}
@@ -2804,8 +2853,8 @@
AbstractConstantValue operation(AbstractConstantValue left,
AbstractConstantValue right),
TypeMask defaultType) {
- AbstractConstantValue left = getValue(node.arguments[0].definition);
- AbstractConstantValue right = getValue(node.arguments[1].definition);
+ AbstractConstantValue left = getValue(node.argument(0));
+ AbstractConstantValue right = getValue(node.argument(1));
setValue(node, operation(left, right) ?? nonConstant(defaultType));
}
@@ -2830,7 +2879,7 @@
switch (node.operator) {
case BuiltinOperator.StringConcatenate:
ast.DartString stringValue = const ast.LiteralDartString('');
- for (Reference<Primitive> arg in node.arguments) {
+ for (Reference<Primitive> arg in node.argumentRefs) {
AbstractConstantValue value = getValue(arg.definition);
if (value.isNothing) {
setValue(node, lattice.nothing);
@@ -2865,8 +2914,8 @@
bool negated =
node.operator == BuiltinOperator.StrictNeq ||
node.operator == BuiltinOperator.LooseNeq;
- AbstractConstantValue left = getValue(node.arguments[0].definition);
- AbstractConstantValue right = getValue(node.arguments[1].definition);
+ AbstractConstantValue left = getValue(node.argument(0));
+ AbstractConstantValue right = getValue(node.argument(1));
if (left.isNothing || right.isNothing) {
setValue(node, lattice.nothing);
return;
@@ -2980,7 +3029,7 @@
}
void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- AbstractConstantValue receiver = getValue(node.receiver.definition);
+ AbstractConstantValue receiver = getValue(node.receiver);
if (node.method == BuiltinMethod.Pop) {
setValue(node, nonConstant(
typeSystem.elementTypeOfIndexable(receiver.type)));
@@ -3017,7 +3066,7 @@
}
void visitBranch(Branch node) {
- AbstractConstantValue conditionCell = getValue(node.condition.definition);
+ AbstractConstantValue conditionCell = getValue(node.condition);
AbstractBool boolifiedValue = node.isStrictCheck
? lattice.strictBoolify(conditionCell)
: lattice.boolify(conditionCell);
@@ -3025,20 +3074,20 @@
case AbstractBool.Nothing:
break;
case AbstractBool.True:
- setReachable(node.trueContinuation.definition);
+ setReachable(node.trueContinuation);
break;
case AbstractBool.False:
- setReachable(node.falseContinuation.definition);
+ setReachable(node.falseContinuation);
break;
case AbstractBool.Maybe:
- setReachable(node.trueContinuation.definition);
- setReachable(node.falseContinuation.definition);
+ setReachable(node.trueContinuation);
+ setReachable(node.falseContinuation);
break;
}
}
void visitTypeTest(TypeTest node) {
- handleTypeTest(node, getValue(node.value.definition), node.dartType);
+ handleTypeTest(node, getValue(node.value), node.dartType);
}
void visitTypeTestViaFlag(TypeTestViaFlag node) {
@@ -3071,7 +3120,7 @@
}
void visitTypeCast(TypeCast node) {
- AbstractConstantValue input = getValue(node.value.definition);
+ AbstractConstantValue input = getValue(node.value);
switch (lattice.isSubtypeOf(input, node.dartType, allowNull: true)) {
case AbstractBool.Nothing:
setValue(node, lattice.nothing);
@@ -3096,7 +3145,7 @@
}
void visitSetMutable(SetMutable node) {
- setValue(node.variable.definition, getValue(node.value.definition));
+ setValue(node.variable, getValue(node.value));
}
void visitLiteralList(LiteralList node) {
@@ -3118,7 +3167,7 @@
}
void visitGetMutable(GetMutable node) {
- setValue(node, getValue(node.variable.definition));
+ setValue(node, getValue(node.variable));
}
void visitMutableVariable(MutableVariable node) {
@@ -3150,8 +3199,8 @@
}
void visitInterceptor(Interceptor node) {
- push(node.input.definition);
- AbstractConstantValue value = getValue(node.input.definition);
+ push(node.input);
+ AbstractConstantValue value = getValue(node.input);
if (value.isNothing) {
setValue(node, nothing);
} else if (value.isNullable &&
@@ -3167,7 +3216,7 @@
}
void visitGetField(GetField node) {
- AbstractConstantValue object = getValue(node.object.definition);
+ AbstractConstantValue object = getValue(node.object);
if (object.isNothing || object.isNullConstant) {
setValue(node, nothing);
return;
@@ -3220,8 +3269,8 @@
@override
void visitForeignCode(ForeignCode node) {
bool firstArgumentIsNullable = false;
- if (node.arguments.length > 0) {
- AbstractConstantValue first = getValue(node.arguments.first.definition);
+ if (node.argumentRefs.length > 0) {
+ AbstractConstantValue first = getValue(node.argumentRefs.first.definition);
if (first.isNothing) {
setValue(node, nothing);
return;
@@ -3238,7 +3287,7 @@
@override
void visitGetLength(GetLength node) {
- AbstractConstantValue input = getValue(node.object.definition);
+ AbstractConstantValue input = getValue(node.object);
node.objectIsNotNull = input.isDefinitelyNotNull;
AbstractConstantValue length = lattice.lengthSpecial(input);
if (length != null) {
@@ -3252,7 +3301,7 @@
@override
void visitGetIndex(GetIndex node) {
- AbstractConstantValue object = getValue(node.object.definition);
+ AbstractConstantValue object = getValue(node.object);
if (object.isNothing || object.isNullConstant) {
setValue(node, nothing);
} else {
@@ -3283,12 +3332,12 @@
@override
void visitBoundsCheck(BoundsCheck node) {
- setValue(node, getValue(node.object.definition));
+ setValue(node, getValue(node.object));
}
@override
void visitReceiverCheck(ReceiverCheck node) {
- AbstractConstantValue value = getValue(node.value.definition);
+ AbstractConstantValue value = getValue(node.value);
if (node.isNullCheck) {
// Avoid expensive TypeMask operations for null checks.
setValue(node, lattice.nonNullable(value));
diff --git a/pkg/compiler/lib/src/cps_ir/update_refinements.dart b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
index 5ce47a2..313f2cb 100644
--- a/pkg/compiler/lib/src/cps_ir/update_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
@@ -37,9 +37,9 @@
}
visitReceiverCheck(ReceiverCheck node) {
- if (refine(node.value)) {
+ if (refine(node.valueRef)) {
// Update the type if the input has changed.
- Primitive value = node.value.definition;
+ Primitive value = node.value;
if (value.type.needsNoSuchMethodHandling(node.selector, classWorld)) {
node.type = typeSystem.receiverTypeFor(node.selector, value.type);
} else {
@@ -76,7 +76,7 @@
visitBoundsCheck(BoundsCheck node) {
super.visitBoundsCheck(node);
if (node.hasIntegerCheck &&
- typeSystem.isDefinitelyInt(node.index.definition.type)) {
+ typeSystem.isDefinitelyInt(node.index.type)) {
node.checks &= ~BoundsCheck.INTEGER;
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
index a8944c6..ca510f7 100644
--- a/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
+++ b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
@@ -94,7 +94,7 @@
}
void visitLetMutable(LetMutable node) {
- escape(node.value);
+ escape(node.valueRef);
}
void visitLetCont(LetCont node) {
@@ -125,24 +125,24 @@
Primitive prim = node.primitive;
if (prim is CreateInstance) {
unescaped.add(prim);
- prim.arguments.forEach(escape);
+ prim.argumentRefs.forEach(escape);
return;
}
if (unescaped.isEmpty) return;
if (prim is SetField) {
- escape(prim.value);
- Primitive object = prim.object.definition;
+ escape(prim.valueRef);
+ Primitive object = prim.object;
if (object is CreateInstance && unescaped.contains(object)) {
int index = getFieldIndex(object.classElement, prim.field);
if (index == -1) {
// This field is not initialized at creation time, so we cannot pull
// set SetField into the CreateInstance instruction. We have to
// leave the instruction here, and this counts as a use of the object.
- escape(prim.object);
+ escape(prim.objectRef);
} else {
// Replace the field initializer with the new value. There are no uses
// of the object before this, so the old value cannot have been seen.
- object.arguments[index].changeTo(prim.value.definition);
+ object.argumentRefs[index].changeTo(prim.value);
prim.destroy();
// The right-hand side might not be in scope at the CreateInstance.
// Sink the creation down to this point.
@@ -156,13 +156,13 @@
// When reading the field of a newly created object, just use the initial
// value and destroy the GetField. This can unblock the other optimization
// since we remove a use of the object.
- Primitive object = prim.object.definition;
+ Primitive object = prim.object;
if (object is CreateInstance && unescaped.contains(object)) {
int index = getFieldIndex(object.classElement, prim.field);
if (index == -1) {
- escape(prim.object);
+ escape(prim.objectRef);
} else {
- prim.replaceUsesWith(object.arguments[index].definition);
+ prim.replaceUsesWith(object.argument(index));
prim.destroy();
node.remove();
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index 1d2549d..4d0f497 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -1211,20 +1211,20 @@
return js.js('# >>> 0', [op]);
}
-
- /// The JS name of a built-in method.
- static final Map<BuiltinMethod, String> builtinMethodName =
- const <BuiltinMethod, String>{
- BuiltinMethod.Push: 'push',
- BuiltinMethod.Pop: 'pop',
- };
-
@override
js.Expression visitApplyBuiltinMethod(tree_ir.ApplyBuiltinMethod node) {
- String name = builtinMethodName[node.method];
js.Expression receiver = visitExpression(node.receiver);
List<js.Expression> args = visitExpressionList(node.arguments);
- return js.js('#.#(#)', [receiver, name, args]);
+ switch (node.method) {
+ case BuiltinMethod.Push:
+ return js.js('#.push(#)', [receiver, args]);
+
+ case BuiltinMethod.Pop:
+ return js.js('#.pop()', [receiver]);
+
+ case BuiltinMethod.SetLength:
+ return js.js('#.length = #', [receiver, args[0]]);
+ }
}
@override
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
index 2596b91..4ca64fa 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
@@ -150,7 +150,7 @@
// Replace the dummy with the exception parameter. It must be set after
// replacing all uses of [_exceptionParameter].
- unwrapped.arguments[0].changeTo(_exceptionParameter);
+ unwrapped.argumentRefs[0].changeTo(_exceptionParameter);
if (stackTraceParameter.hasAtLeastOneUse) {
InvokeStatic stackTraceValue = insertStaticCallAbove(
@@ -174,9 +174,9 @@
// The subexpression of throw is wrapped in the JavaScript output.
Primitive wrappedException = insertStaticCallAbove(
_glue.getWrapExceptionHelper(),
- [node.value.definition],
+ [node.value],
node);
- node.value.changeTo(wrappedException);
+ node.valueRef.changeTo(wrappedException);
}
processRethrow(Rethrow node) {
@@ -201,16 +201,16 @@
// Some platform libraries will compare non-interceptable objects against
// null using the Dart == operator. These must be translated directly.
if (node.selector == Selectors.equals &&
- node.arguments.length == 1 &&
- isNullConstant(node.arguments[0].definition)) {
+ node.argumentRefs.length == 1 &&
+ isNullConstant(node.argument(0))) {
node.replaceWith(new ApplyBuiltinOperator(
BuiltinOperator.Identical,
- [node.receiver.definition, node.arguments[0].definition],
+ [node.receiver, node.argument(0)],
node.sourceInformation));
return;
}
- Primitive receiver = node.receiver.definition;
+ Primitive receiver = node.receiver;
Primitive newReceiver;
if (receiver == explicitReceiverParameter) {
@@ -225,15 +225,15 @@
}
new LetPrim(newReceiver).insertAbove(node.parent);
}
- node.arguments.insert(0, node.receiver);
- node.receiver = new Reference<Primitive>(newReceiver)..parent = node;
+ node.argumentRefs.insert(0, node.receiverRef);
+ node.receiverRef = new Reference<Primitive>(newReceiver)..parent = node;
node.callingConvention = CallingConvention.Intercepted;
}
processInvokeMethodDirectly(InvokeMethodDirectly node) {
if (!_glue.isInterceptedMethod(node.target)) return;
- Primitive receiver = node.receiver.definition;
+ Primitive receiver = node.receiver;
Primitive newReceiver;
if (receiver == explicitReceiverParameter) {
@@ -248,8 +248,8 @@
}
new LetPrim(newReceiver).insertAbove(node.parent);
}
- node.arguments.insert(0, node.receiver);
- node.receiver = new Reference<Primitive>(newReceiver)..parent = node;
+ node.argumentRefs.insert(0, node.receiverRef);
+ node.receiverRef = new Reference<Primitive>(newReceiver)..parent = node;
node.callingConvention = CallingConvention.Intercepted;
}
}
diff --git a/pkg/compiler/lib/src/serialization/element_serialization.dart b/pkg/compiler/lib/src/serialization/element_serialization.dart
index 6e7f5d4..173dd1e 100644
--- a/pkg/compiler/lib/src/serialization/element_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/element_serialization.dart
@@ -381,7 +381,6 @@
encoder.setElement(Key.TYPE_DECLARATION, element.typeDeclaration);
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializePosition(element, encoder);
- TypeDeclarationElement typeDeclaration = element.typeDeclaration;
encoder.setType(Key.TYPE, element.type);
encoder.setInt(Key.INDEX, element.index);
encoder.setType(Key.BOUND, element.bound);
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index c31ee4a..23153bf 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -12,8 +12,6 @@
import '../common.dart';
import '../common/resolution.dart' show
Resolution;
-import '../compiler.dart'
- show Compiler;
import '../constants/constructors.dart';
import '../constants/expressions.dart';
import '../core_types.dart';
@@ -96,9 +94,6 @@
String get fixedBackendName => _unsupported('fixedBackendName');
@override
- bool get hasFixedBackendName => _unsupported('hasFixedBackendName');
-
- @override
LibraryElement get implementationLibrary => library;
@override
@@ -132,15 +127,6 @@
bool get isMixinApplication => false;
@override
- bool get isNative => false;
-
- @override
- bool get isJsInterop => false;
-
- @override
- String get jsInteropName => null;
-
- @override
bool get isOperator => false;
@override
@@ -375,7 +361,6 @@
List<ExportElement> _exports;
ListedContainer _exportsMap;
ListedContainer _importsMap;
- Map<LibraryTag, LibraryElement> _libraryDependencies;
LibraryElementZ(ObjectDecoder decoder)
: super(decoder);
@@ -463,9 +448,6 @@
}
@override
- bool get canUseNative => false;
-
- @override
Element findExported(String elementName) => _unsupported('findExported');
void _ensureImports() {
@@ -893,9 +875,6 @@
}
@override
- String get nativeTagInfo => _unsupported('nativeTagInfo');
-
- @override
void reverseBackendMembers() => _unsupported('reverseBackendMembers');
@override
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index a9c2831..324f45f 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -396,7 +396,7 @@
NodeCallback visitLetMutable(cps_ir.LetMutable node) {
Variable variable = addMutableVariable(node.variable);
- Expression value = getVariableUse(node.value);
+ Expression value = getVariableUse(node.valueRef);
return (Statement next) => Assign.makeStatement(variable, value, next);
}
@@ -406,7 +406,7 @@
// (not a function like interior and call expressions).
Statement visitThrow(cps_ir.Throw node) {
- Expression value = getVariableUse(node.value);
+ Expression value = getVariableUse(node.valueRef);
return new Throw(value);
}
@@ -420,13 +420,13 @@
// arguments to formal parameter variables, followed by the body if
// the continuation is singly reference or a break if it is multiply
// referenced.
- cps_ir.Continuation cont = node.continuation.definition;
+ cps_ir.Continuation cont = node.continuation;
if (cont == returnContinuation) {
- assert(node.arguments.length == 1);
- return new Return(getVariableUse(node.arguments.single),
+ assert(node.argumentRefs.length == 1);
+ return new Return(getVariableUse(node.argumentRefs.single),
sourceInformation: node.sourceInformation);
} else {
- List<Expression> arguments = translateArguments(node.arguments);
+ List<Expression> arguments = translateArguments(node.argumentRefs);
return buildPhiAssignments(cont.parameters, arguments,
() {
// Translate invocations of recursive and non-recursive
@@ -456,7 +456,7 @@
/// Translates a branch condition to a tree expression.
Expression translateCondition(cps_ir.Branch branch) {
- Expression value = getVariableUse(branch.condition);
+ Expression value = getVariableUse(branch.conditionRef);
if (branch.isStrictCheck) {
return new ApplyBuiltinOperator(
BuiltinOperator.StrictEq,
@@ -469,12 +469,12 @@
Statement visitBranch(cps_ir.Branch node) {
Expression condition = translateCondition(node);
Statement thenStatement, elseStatement;
- cps_ir.Continuation cont = node.trueContinuation.definition;
+ cps_ir.Continuation cont = node.trueContinuation;
assert(cont.parameters.isEmpty);
thenStatement = cont.hasExactlyOneUse
? translateExpression(cont.body)
: new Break(labels[cont]);
- cont = node.falseContinuation.definition;
+ cont = node.falseContinuation;
assert(cont.parameters.isEmpty);
elseStatement = cont.hasExactlyOneUse
? translateExpression(cont.body)
@@ -489,13 +489,13 @@
//
Expression visitSetField(cps_ir.SetField node) {
- return new SetField(getVariableUse(node.object),
+ return new SetField(getVariableUse(node.objectRef),
node.field,
- getVariableUse(node.value));
+ getVariableUse(node.valueRef));
}
Expression visitInterceptor(cps_ir.Interceptor node) {
- return new Interceptor(getVariableUse(node.input),
+ return new Interceptor(getVariableUse(node.inputRef),
node.interceptedClasses,
node.sourceInformation);
}
@@ -503,14 +503,14 @@
Expression visitCreateInstance(cps_ir.CreateInstance node) {
return new CreateInstance(
node.classElement,
- translateArguments(node.arguments),
- getVariableUseOrNull(node.typeInformation),
+ translateArguments(node.argumentRefs),
+ getVariableUseOrNull(node.typeInformationRef),
node.sourceInformation);
}
Expression visitGetField(cps_ir.GetField node) {
- return new GetField(getVariableUse(node.object), node.field,
- objectIsNotNull: !node.object.definition.type.isNullable);
+ return new GetField(getVariableUse(node.objectRef), node.field,
+ objectIsNotNull: !node.object.type.isNullable);
}
Expression visitCreateBox(cps_ir.CreateBox node) {
@@ -520,16 +520,16 @@
Expression visitCreateInvocationMirror(cps_ir.CreateInvocationMirror node) {
return new CreateInvocationMirror(
node.selector,
- translateArguments(node.arguments));
+ translateArguments(node.argumentRefs));
}
Expression visitGetMutable(cps_ir.GetMutable node) {
- return getMutableVariableUse(node.variable);
+ return getMutableVariableUse(node.variableRef);
}
Expression visitSetMutable(cps_ir.SetMutable node) {
- Variable variable = getMutableVariable(node.variable.definition);
- Expression value = getVariableUse(node.value);
+ Variable variable = getMutableVariable(node.variable);
+ Expression value = getVariableUse(node.valueRef);
return new Assign(variable, value);
}
@@ -540,18 +540,18 @@
Expression visitLiteralList(cps_ir.LiteralList node) {
return new LiteralList(
node.dartType,
- translateArguments(node.values));
+ translateArguments(node.valueRefs));
}
Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
return new ReifyRuntimeType(
- getVariableUse(node.value), node.sourceInformation);
+ getVariableUse(node.valueRef), node.sourceInformation);
}
Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
return new ReadTypeVariable(
node.variable,
- getVariableUse(node.target),
+ getVariableUse(node.targetRef),
node.sourceInformation);
}
@@ -559,17 +559,17 @@
return new TypeExpression(
node.kind,
node.dartType,
- node.arguments.map(getVariableUse).toList());
+ node.argumentRefs.map(getVariableUse).toList());
}
Expression visitTypeTest(cps_ir.TypeTest node) {
- Expression value = getVariableUse(node.value);
- List<Expression> typeArgs = translateArguments(node.typeArguments);
+ Expression value = getVariableUse(node.valueRef);
+ List<Expression> typeArgs = translateArguments(node.typeArgumentRefs);
return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: true);
}
Expression visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) {
- Expression value = getVariableUse(node.interceptor);
+ Expression value = getVariableUse(node.interceptorRef);
// TODO(sra): Move !! to cps_ir level.
return new Not(new Not(new GetTypeTestProperty(value, node.dartType)));
}
@@ -581,42 +581,42 @@
Expression visitSetStatic(cps_ir.SetStatic node) {
return new SetStatic(
node.element,
- getVariableUse(node.value),
+ getVariableUse(node.valueRef),
node.sourceInformation);
}
Expression visitApplyBuiltinOperator(cps_ir.ApplyBuiltinOperator node) {
if (node.operator == BuiltinOperator.IsFalsy) {
- return new Not(getVariableUse(node.arguments.single));
+ return new Not(getVariableUse(node.argumentRefs.single));
}
return new ApplyBuiltinOperator(node.operator,
- translateArguments(node.arguments));
+ translateArguments(node.argumentRefs));
}
Expression visitApplyBuiltinMethod(cps_ir.ApplyBuiltinMethod node) {
return new ApplyBuiltinMethod(node.method,
- getVariableUse(node.receiver),
- translateArguments(node.arguments),
- receiverIsNotNull: !node.receiver.definition.type.isNullable);
+ getVariableUse(node.receiverRef),
+ translateArguments(node.argumentRefs),
+ receiverIsNotNull: !node.receiver.type.isNullable);
}
Expression visitGetLength(cps_ir.GetLength node) {
- return new GetLength(getVariableUse(node.object));
+ return new GetLength(getVariableUse(node.objectRef));
}
Expression visitGetIndex(cps_ir.GetIndex node) {
- return new GetIndex(getVariableUse(node.object),
- getVariableUse(node.index));
+ return new GetIndex(getVariableUse(node.objectRef),
+ getVariableUse(node.indexRef));
}
Expression visitSetIndex(cps_ir.SetIndex node) {
- return new SetIndex(getVariableUse(node.object),
- getVariableUse(node.index),
- getVariableUse(node.value));
+ return new SetIndex(getVariableUse(node.objectRef),
+ getVariableUse(node.indexRef),
+ getVariableUse(node.valueRef));
}
Expression visitInvokeStatic(cps_ir.InvokeStatic node) {
- List<Expression> arguments = translateArguments(node.arguments);
+ List<Expression> arguments = translateArguments(node.argumentRefs);
return new InvokeStatic(node.target, node.selector, arguments,
node.sourceInformation);
}
@@ -624,17 +624,17 @@
Expression visitInvokeMethod(cps_ir.InvokeMethod node) {
if (node.callingConvention == cps_ir.CallingConvention.OneShotIntercepted) {
List<Expression> arguments = new List.generate(
- 1 + node.arguments.length,
- (n) => getVariableUse(n == 0 ? node.receiver : node.arguments[n - 1]),
+ 1 + node.argumentRefs.length,
+ (n) => getVariableUse(n == 0 ? node.receiverRef : node.argumentRefs[n - 1]),
growable: false);
return new OneShotInterceptor(node.selector, node.mask, arguments,
node.sourceInformation);
}
InvokeMethod invoke = new InvokeMethod(
- getVariableUse(node.receiver),
+ getVariableUse(node.receiverRef),
node.selector,
node.mask,
- translateArguments(node.arguments),
+ translateArguments(node.argumentRefs),
node.sourceInformation);
// Sometimes we know the Dart receiver is non-null because it has been
// refined, which implies that the JS receiver also can not be null at the
@@ -644,25 +644,25 @@
// interceptor is non-null because it intercepts JSNull.
invoke.receiverIsNotNull =
!node.dartReceiver.type.isNullable ||
- !node.receiver.definition.type.isNullable;
+ !node.receiver.type.isNullable;
return invoke;
}
Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
- Expression receiver = getVariableUse(node.receiver);
- List<Expression> arguments = translateArguments(node.arguments);
+ Expression receiver = getVariableUse(node.receiverRef);
+ List<Expression> arguments = translateArguments(node.argumentRefs);
return new InvokeMethodDirectly(receiver, node.target,
node.selector, arguments, node.sourceInformation);
}
Expression visitTypeCast(cps_ir.TypeCast node) {
- Expression value = getVariableUse(node.value);
- List<Expression> typeArgs = translateArguments(node.typeArguments);
+ Expression value = getVariableUse(node.valueRef);
+ List<Expression> typeArgs = translateArguments(node.typeArgumentRefs);
return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false);
}
Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) {
- List<Expression> arguments = translateArguments(node.arguments);
+ List<Expression> arguments = translateArguments(node.argumentRefs);
return new InvokeConstructor(
node.dartType,
node.target,
@@ -673,8 +673,8 @@
visitForeignCode(cps_ir.ForeignCode node) {
List<Expression> arguments =
- node.arguments.map(getVariableUse).toList(growable: false);
- List<bool> nullableArguments = node.arguments
+ node.argumentRefs.map(getVariableUse).toList(growable: false);
+ List<bool> nullableArguments = node.argumentRefs
.map((argument) => argument.definition.type.isNullable)
.toList(growable: false);
if (node.codeTemplate.isExpression) {
@@ -704,8 +704,8 @@
// In the Tree IR, syntax is more important, so the receiver check uses
// "useInvoke" to denote if an invocation should be emitted.
return new ReceiverCheck(
- condition: getVariableUseOrNull(node.condition),
- value: getVariableUse(node.value),
+ condition: getVariableUseOrNull(node.conditionRef),
+ value: getVariableUse(node.valueRef),
selector: node.selector,
useSelector: node.useSelector,
useInvoke: !node.isNullCheck,
@@ -720,13 +720,13 @@
@override
NodeCallback visitYield(cps_ir.Yield node) {
return (Statement next) {
- return new Yield(getVariableUse(node.input), node.hasStar, next);
+ return new Yield(getVariableUse(node.inputRef), node.hasStar, next);
};
}
@override
Expression visitAwait(cps_ir.Await node) {
- return new Await(getVariableUse(node.input));
+ return new Await(getVariableUse(node.inputRef));
}
@override
diff --git a/pkg/compiler/samples/jsonify/jsonify.dart b/pkg/compiler/samples/jsonify/jsonify.dart
index 152f39e..6e1e728 100644
--- a/pkg/compiler/samples/jsonify/jsonify.dart
+++ b/pkg/compiler/samples/jsonify/jsonify.dart
@@ -17,7 +17,6 @@
show BackDoor;
import '../../lib/src/filenames.dart';
-import '../../lib/src/io/source_file.dart';
import '../../lib/src/source_file_provider.dart';
import '../../lib/src/util/uri_extras.dart';
diff --git a/pkg/meta/CHANGELOG.md b/pkg/meta/CHANGELOG.md
index 6c3009b..fc3f06e 100644
--- a/pkg/meta/CHANGELOG.md
+++ b/pkg/meta/CHANGELOG.md
@@ -1,3 +1,7 @@
## 0.9.0
-* Introduce `@protected` annotation for methods that must only be called from
-instance methods of subclasses.
+* Introduce `@protected` annotation for members that must only be called from
+instance members of subclasses.
+* Introduce `@required` annotation for optional parameters that should be treated
+as required.
+* Introduce `@mustCallSuper` annotation for methods that must be invoked by all
+overriding methods.
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index a914ff6..c94fd80 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -18,17 +18,90 @@
/// in the language tour.
library meta;
-/// Used to annotate an instance method `m` in a class `C`. Indicates that `m`
-/// should only be invoked from instance methods of `C` or classes that extend
-/// or mix in `C`, either directly or indirectly. Additionally indicates that
-/// `m` should only be invoked on `this`, whether explicitly or implicitly.
+/// Used to annotate an instance method `m`. Indicates that `m` must either be
+/// abstract or must return a newly allocated object. In addition, every method
+/// that either implements or overrides `m` is implicitly annotated with this
+/// same annotation.
///
-/// Tools, such as the analyzer, can provide feedback if an invocation of a
-/// method marked as being protected is used outside of an instance method
-/// defined on a class that extends or mixes in the class in which the protected
-/// method is defined, or that uses a receiver other than `this`.
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than an instance method,
+/// or
+/// * a method that has this annotation that can return anything other than a
+/// newly allocated object.
+const _Factory factory = const _Factory();
+
+/// Used to annotate a const constructor `c`. Indicates that any invocation of
+/// the constructor must use the keyword `const` unless one or more of the
+/// arguments to the constructor is not a compile-time constant.
+///
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than a const constructor,
+/// or
+/// * an invocation of a constructor that has this annotation is not invoked
+/// using the `const` keyword unless one or more of the arguments to the
+/// constructor is not a compile-time constant.
+const _Literal literal = const _Literal();
+
+/// Used to annotate an instance method `m`. Indicates that every invocation of
+/// a method that overrides `m` must also invoke `m`. In addition, every method
+/// that overrides `m` is implicitly annotated with this same annotation.
+///
+/// Note that private methods with this annotation cannot be validly overridden
+/// outside of the library that defines the annotated method.
+///
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than an instance method,
+/// or
+/// * a method that overrides a method that has this annotation can return
+/// without invoking the overridden method.
+const _MustCallSuper mustCallSuper = const _MustCallSuper();
+
+/// Used to annotate an instance member (method, getter, setter, operator, or
+/// field) `m` in a class `C`. If the annotation is on a field it applies to the
+/// getter, and setter if appropriate, that are induced by the field. Indicates
+/// that `m` should only be invoked from instance methods of `C` or classes that
+/// extend or mix in `C`, either directly or indirectly. Additionally indicates
+/// that `m` should only be invoked on `this`, whether explicitly or implicitly.
+///
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than an instance member,
+/// or
+/// * an invocation of a member that has this annotation is used outside of an
+/// instance member defined on a class that extends or mixes in the class in
+/// which the protected member is defined, or that uses a receiver other than
+/// `this`.
const _Protected protected = const _Protected();
+/// Used to annotate a named parameter `p` in a method or function `f`.
+/// Indicates that every invocation of `f` must include an argument
+/// corresponding to `p`, despite the fact that `p` would otherwise be an
+/// optional parameter.
+///
+/// Tools, such as the analyzer, can provide feedback if
+/// * the annotation is associated with anything other than a named parameter,
+/// * the annotation is associated with a named parameter in a method `m1` that
+/// overrides a method `m0` and `m0` defines a named parameter with the same
+/// name that does not have this annotation, or
+/// * an invocation of a method or function does not include an argument
+/// corresponding to a named parameter that has this annotation.
+const _Required required = const _Required();
+
+class _Factory {
+ const _Factory();
+}
+
+class _Literal {
+ const _Literal();
+}
+
+class _MustCallSuper {
+ const _MustCallSuper();
+}
+
class _Protected {
const _Protected();
}
+
+class _Required {
+ const _Required();
+}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index ef18a9b..f0e031c 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -53,9 +53,10 @@
analyzer/test/generated/ast_test: Pass, Slow # Issue 21628
analyzer/test/generated/compile_time_error_code_test: Pass, Slow
analyzer/test/generated/compile_time_error_code_test: Pass, Slow # Issue 21628
-analyzer/test/generated/constant_test.dart: Pass, Slow # Issue 24914
+analyzer/test/generated/constant_test: Pass, Slow # Issue 24914
analyzer/test/generated/declaration_resolver_test: Pass, Slow # Issue 24914
analyzer/test/generated/element_test: Pass, Slow # Issue 21628
+analyzer/test/generated/error_suppression_test: Pass, Slow # Issue 21628
analyzer/test/generated/engine_test: SkipSlow
analyzer/test/generated/incremental_resolver_test: Pass, Slow # Issue 21628
analyzer/test/generated/incremental_scanner_test: Pass, Slow # Issue 21628
@@ -92,6 +93,8 @@
analyzer/test/src/task/options_test: Pass, Slow # Issue 21628
analyzer/test/src/task/options_work_manager_test: Pass, Slow # Issue 21628
analyzer/test/src/task/strong/checker_test: Pass, Slow # Issue 21628
+analyzer/test/src/task/strong/inferred_type_test: Pass, Slow # Issue 21628
+analyzer/test/src/task/yaml_test: Pass, Slow # Issue 21628
collection/test/equality_test/01: Fail # Issue 1533
collection/test/equality_test/02: Fail # Issue 1533
collection/test/equality_test/03: Fail # Issue 1533
@@ -214,3 +217,6 @@
analyzer/test/src/task/strong/checker_test: Crash # t: Failed assertion: line 88 pos 12: '!variable2index.containsKey(element)' is not true.
analyzer/test/src/task/strong/inferred_type_test: Crash # t: Failed assertion: line 88 pos 12: '!variable2index.containsKey(element)' is not true.
analyzer/test/src/task/strong_mode_test: Crash # Issue 24485
+
+[ $noopt || $runtime == dart_precompiled || $runtime == dart_product ]
+*: SkipByDesign # The pkg test framework imports dart:mirrors.
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 6932f93..62b69fb 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -87,6 +87,65 @@
}
}
+config("dart_config_no_precompiler") {
+ defines = []
+
+ if (dart_target_arch != "") {
+ if (dart_target_arch == "arm") {
+ defines += [ "TARGET_ARCH_ARM" ]
+ } else if (dart_target_arch == "arm64") {
+ defines += [ "TARGET_ARCH_ARM64" ]
+ } else if (dart_target_arch == "mips") {
+ defines += [ "TARGET_ARCH_MIPS" ]
+ } else if (dart_target_arch == "x64") {
+ defines += [ "TARGET_ARCH_X64" ]
+ } else if (dart_target_arch == "ia32") {
+ defines += [ "TARGET_ARCH_IA32" ]
+ } else {
+ print("Invalid |dart_target_arch|")
+ assert(false)
+ }
+ }
+
+ if (dart_debug) {
+ defines += ["DEBUG"]
+ } else {
+ defines += ["NDEBUG"]
+ }
+
+ cflags = [
+ "-Werror",
+ "-Wall",
+ "-Wextra", # Also known as -W.
+ "-Wno-unused-parameter",
+ "-Wnon-virtual-dtor",
+ "-Wvla",
+ "-Wno-conversion-null",
+ "-Woverloaded-virtual",
+ "-g3",
+ "-ggdb3",
+ "-fno-rtti",
+ "-fno-exceptions",
+ ]
+
+ if (dart_debug) {
+ cflags += [
+ "-O1",
+ ]
+ } else {
+ cflags += [
+ "-O3",
+ ]
+ }
+
+ if (is_asan) {
+ ldflags = [
+ "-Wl,-u_sanitizer_options_link_helper",
+ "-fsanitize=address",
+ ]
+ }
+}
+
static_library("libdart") {
configs += [":dart_config"]
@@ -119,6 +178,38 @@
}
+static_library("libdart_precompiled_runtime") {
+ configs += [":dart_config_no_precompiler"]
+ deps = [
+ "vm:libdart_lib_precompiled_runtime",
+ "vm:libdart_vm_precompiled_runtime",
+ "third_party/double-conversion/src:libdouble_conversion",
+ ":generate_version_cc_file",
+ ]
+ include_dirs = [
+ ".",
+ ]
+ public_configs = [":dart_public_config"]
+ sources = [
+ "include/dart_api.h",
+ "include/dart_mirrors_api.h",
+ "include/dart_native_api.h",
+ "include/dart_tools_api.h",
+ "vm/dart_api_impl.cc",
+ "vm/debugger_api_impl.cc",
+ "vm/mirrors_api_impl.cc",
+ "vm/native_api_impl.cc",
+ "vm/version.h",
+ "$target_gen_dir/version.cc",
+ ]
+ defines = [
+ # Using DART_SHARED_LIB to export the Dart API entries.
+ "DART_SHARED_LIB",
+ "DART_PRECOMPILED_RUNTIME",
+ ]
+}
+
+
action("generate_version_cc_file") {
deps = [
":libdart_dependency_helper",
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 197eb32..02ba3c4 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -238,6 +238,7 @@
custom_sources_filter = [
"*net/nss_memio.cc",
"*net/nss_memio.h",
+ "*root_certificates.cc",
"*secure_socket.cc",
"*secure_socket.h",
"filter.cc",
@@ -292,6 +293,7 @@
custom_sources_filter = [
"*net/nss_memio.cc",
"*net/nss_memio.h",
+ "*root_certificates.cc",
"*secure_socket.cc",
"*secure_socket.h",
"*filter_unsupported.cc",
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index f1f7e2c..ea9f3d7 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -1014,7 +1014,10 @@
TimerUtils::InitOnce();
EventHandler::Start();
+#if !defined(PRODUCT)
+ // Constant true in PRODUCT mode.
vm_options.AddArgument("--load_deferred_eagerly");
+#endif
if (IsSnapshottingForPrecompilation()) {
vm_options.AddArgument("--precompilation");
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 4642486..bb21b9f 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -340,7 +340,10 @@
precompiled_snapshot_directory = arg;
}
gen_precompiled_snapshot = true;
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ // The precompiled runtime has FLAG_precompilation set as const.
vm_options->AddArgument("--precompilation");
+#endif
return true;
}
@@ -355,7 +358,10 @@
precompiled_snapshot_directory = &precompiled_snapshot_directory[1];
}
run_precompiled_snapshot = true;
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ // The precompiled runtime has FLAG_precompilation set as const.
vm_options->AddArgument("--precompilation");
+#endif
return true;
}
@@ -1556,11 +1562,14 @@
Platform::Exit(kErrorExitCode);
}
+#if !defined(PRODUCT)
+ // Constant true in PRODUCT mode.
if (generate_script_snapshot ||
generate_full_snapshot_after_run ||
run_full_snapshot) {
vm_options.AddArgument("--load_deferred_eagerly");
}
+#endif
#if defined(DART_PRECOMPILER) && !defined(DART_NO_SNAPSHOT)
// Always set --precompilation with dart_noopt.
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index f63d9d0..7d79dc6 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -29,6 +29,15 @@
#include "include/dart_api.h"
+// Return the error from the containing function if handle is an error handle.
+#define RETURN_IF_ERROR(handle) \
+ { \
+ Dart_Handle __handle = handle; \
+ if (Dart_IsError((__handle))) { \
+ return __handle; \
+ } \
+ }
+
namespace dart {
namespace bin {
@@ -103,13 +112,30 @@
}
-static void SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+static void DeleteFilter(
+ void* isolate_data,
+ Dart_WeakPersistentHandle handle,
+ void* context_pointer) {
+ SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
+ delete filter;
+}
+
+
+static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
+ ASSERT(filter != NULL);
+ Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
+ RETURN_IF_ERROR(dart_this);
ASSERT(Dart_IsInstance(dart_this));
- ThrowIfError(Dart_SetNativeInstanceField(
+ Dart_Handle err = Dart_SetNativeInstanceField(
dart_this,
kSSLFilterNativeFieldIndex,
- reinterpret_cast<intptr_t>(filter)));
+ reinterpret_cast<intptr_t>(filter));
+ RETURN_IF_ERROR(err);
+ Dart_NewWeakPersistentHandle(dart_this,
+ reinterpret_cast<void*>(filter),
+ sizeof(*filter),
+ DeleteFilter);
+ return Dart_Null();
}
@@ -134,19 +160,22 @@
}
-static void SetSecurityContext(Dart_NativeArguments args,
- SSL_CTX* context) {
+static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
+ SSL_CTX* context) {
const int approximate_size_of_context = 1500;
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
+ RETURN_IF_ERROR(dart_this);
ASSERT(Dart_IsInstance(dart_this));
- ThrowIfError(Dart_SetNativeInstanceField(
+ Dart_Handle err = Dart_SetNativeInstanceField(
dart_this,
kSecurityContextNativeFieldIndex,
- reinterpret_cast<intptr_t>(context)));
+ reinterpret_cast<intptr_t>(context));
+ RETURN_IF_ERROR(err);
Dart_NewWeakPersistentHandle(dart_this,
context,
approximate_size_of_context,
FreeSecurityContext);
+ return Dart_Null();
}
@@ -171,9 +200,19 @@
void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
- SSLFilter* filter = new SSLFilter;
- SetFilter(args, filter);
- filter->Init(dart_this);
+ SSLFilter* filter = new SSLFilter();
+ Dart_Handle err = SetFilter(args, filter);
+ if (Dart_IsError(err)) {
+ delete filter;
+ Dart_PropagateError(err);
+ }
+ err = filter->Init(dart_this);
+ if (Dart_IsError(err)) {
+ // The finalizer was set up by SetFilter. It will delete `filter` if there
+ // is an error.
+ filter->Destroy();
+ Dart_PropagateError(err);
+ }
}
@@ -215,9 +254,13 @@
void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
SSLFilter* filter = GetFilter(args);
- SetFilter(args, NULL);
+ // The SSLFilter is deleted in the finalizer for the Dart object created by
+ // SetFilter. There is no need to NULL-out the native field for the SSLFilter
+ // here because the SSLFilter won't be deleted until the finalizer for the
+ // Dart object runs while the Dart object is being GCd. This approach avoids a
+ // leak if Destroy isn't called, and avoids a NULL-dereference if Destroy is
+ // called more than once.
filter->Destroy();
- delete filter;
}
@@ -271,7 +314,8 @@
void FUNCTION_NAME(SecureSocket_PeerCertificate)
(Dart_NativeArguments args) {
- Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
+ Dart_Handle cert = ThrowIfError(GetFilter(args)->PeerCertificate());
+ Dart_SetReturnValue(args, cert);
}
@@ -281,19 +325,34 @@
}
+static void ReleaseCertificate(
+ void* isolate_data,
+ Dart_WeakPersistentHandle handle,
+ void* context_pointer) {
+ X509* cert = reinterpret_cast<X509*>(context_pointer);
+ X509_free(cert);
+}
+
+
+// Returns the handle for a Dart object wrapping the X509 certificate object.
+// The caller should own a reference to the X509 object whose reference count
+// won't drop to zero before the ReleaseCertificate finalizer runs.
static Dart_Handle WrappedX509Certificate(X509* certificate) {
+ const intptr_t approximate_size_of_certificate = 1500;
if (certificate == NULL) {
return Dart_Null();
}
Dart_Handle x509_type =
DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
if (Dart_IsError(x509_type)) {
+ X509_free(certificate);
return x509_type;
}
Dart_Handle arguments[] = { NULL };
Dart_Handle result =
Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
if (Dart_IsError(result)) {
+ X509_free(certificate);
return result;
}
ASSERT(Dart_IsInstance(result));
@@ -302,8 +361,13 @@
kX509NativeFieldIndex,
reinterpret_cast<intptr_t>(certificate));
if (Dart_IsError(status)) {
+ X509_free(certificate);
return status;
}
+ Dart_NewWeakPersistentHandle(result,
+ reinterpret_cast<void*>(certificate),
+ approximate_size_of_certificate,
+ ReleaseCertificate);
return result;
}
@@ -326,6 +390,11 @@
if (Dart_IsNull(callback)) {
return 0;
}
+
+ // Upref since the Dart X509 object may outlive the SecurityContext.
+ if (certificate != NULL) {
+ X509_up_ref(certificate);
+ }
Dart_Handle args[1];
args[0] = WrappedX509Certificate(certificate);
if (Dart_IsError(args[0])) {
@@ -354,7 +423,11 @@
SSL_CTX_set_min_version(context, TLS1_VERSION);
SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM");
SSL_CTX_set_cipher_list_tls11(context, "HIGH:MEDIUM");
- SetSecurityContext(args, context);
+ Dart_Handle err = SetSecurityContext(args, context);
+ if (Dart_IsError(err)) {
+ SSL_CTX_free(context);
+ Dart_PropagateError(err);
+ }
}
@@ -1154,7 +1227,7 @@
}
-void SSLFilter::Init(Dart_Handle dart_this) {
+Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
if (!library_initialized_) {
InitializeLibrary();
}
@@ -1168,24 +1241,40 @@
bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
ASSERT(bad_certificate_callback_ != NULL);
- InitializeBuffers(dart_this);
+ // Caller handles cleanup on an error.
+ return InitializeBuffers(dart_this);
}
-void SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
+Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
// Create SSLFilter buffers as ExternalUint8Array objects.
- Dart_Handle dart_buffers_object = ThrowIfError(
- Dart_GetField(dart_this, DartUtils::NewString("buffers")));
- Dart_Handle secure_filter_impl_type =
- Dart_InstanceGetType(dart_this);
- Dart_Handle dart_buffer_size = ThrowIfError(
- Dart_GetField(secure_filter_impl_type, DartUtils::NewString("SIZE")));
- int64_t buffer_size = DartUtils::GetIntegerValue(dart_buffer_size);
- Dart_Handle dart_encrypted_buffer_size = ThrowIfError(
- Dart_GetField(secure_filter_impl_type,
- DartUtils::NewString("ENCRYPTED_SIZE")));
- int64_t encrypted_buffer_size =
- DartUtils::GetIntegerValue(dart_encrypted_buffer_size);
+ Dart_Handle buffers_string = DartUtils::NewString("buffers");
+ RETURN_IF_ERROR(buffers_string);
+ Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
+ RETURN_IF_ERROR(dart_buffers_object);
+ Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
+ RETURN_IF_ERROR(secure_filter_impl_type);
+ Dart_Handle size_string = DartUtils::NewString("SIZE");
+ RETURN_IF_ERROR(size_string);
+ Dart_Handle dart_buffer_size = Dart_GetField(
+ secure_filter_impl_type, size_string);
+ RETURN_IF_ERROR(dart_buffer_size);
+
+ int64_t buffer_size = 0;
+ Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
+ RETURN_IF_ERROR(err);
+
+ Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
+ RETURN_IF_ERROR(encrypted_size_string);
+
+ Dart_Handle dart_encrypted_buffer_size = Dart_GetField(
+ secure_filter_impl_type, encrypted_size_string);
+ RETURN_IF_ERROR(dart_encrypted_buffer_size);
+
+ int64_t encrypted_buffer_size = 0;
+ err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
+ RETURN_IF_ERROR(err);
+
if (buffer_size <= 0 || buffer_size > 1 * MB) {
FATAL("Invalid buffer size in _ExternalBuffer");
}
@@ -1195,21 +1284,44 @@
buffer_size_ = static_cast<int>(buffer_size);
encrypted_buffer_size_ = static_cast<int>(encrypted_buffer_size);
-
Dart_Handle data_identifier = DartUtils::NewString("data");
+ RETURN_IF_ERROR(data_identifier);
+
+ for (int i = 0; i < kNumBuffers; i++) {
+ int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
+ buffers_[i] = new uint8_t[size];
+ ASSERT(buffers_[i] != NULL);
+ dart_buffer_objects_[i] = NULL;
+ }
+
+ Dart_Handle result = Dart_Null();
for (int i = 0; i < kNumBuffers; ++i) {
int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
- dart_buffer_objects_[i] =
- Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i));
+ result = Dart_ListGetAt(dart_buffers_object, i);
+ if (Dart_IsError(result)) {
+ break;
+ }
+
+ dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
ASSERT(dart_buffer_objects_[i] != NULL);
- buffers_[i] = new uint8_t[size];
- Dart_Handle data = ThrowIfError(
- Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size));
- ThrowIfError(
- Dart_SetField(Dart_HandleFromPersistent(dart_buffer_objects_[i]),
- data_identifier,
- data));
+ Dart_Handle data =
+ Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
+ if (Dart_IsError(data)) {
+ result = data;
+ break;
+ }
+ result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
+ if (Dart_IsError(result)) {
+ break;
+ }
+ result = Dart_SetField(result, data_identifier, data);
+ if (Dart_IsError(result)) {
+ break;
+ }
}
+
+ // Caller handles cleanup on an error.
+ return result;
}
@@ -1241,12 +1353,10 @@
Dart_Handle SSLFilter::PeerCertificate() {
+ // SSL_get_peer_certificate incs the refcount of certificate. X509_free is
+ // called by the finalizer set up by WrappedX509Certificate.
X509* certificate = SSL_get_peer_certificate(ssl_);
- Dart_Handle x509_object = WrappedX509Certificate(certificate);
- if (Dart_IsError(x509_object)) {
- Dart_PropagateError(x509_object);
- }
- return x509_object;
+ return WrappedX509Certificate(certificate);
}
@@ -1484,7 +1594,7 @@
}
-void SSLFilter::Destroy() {
+SSLFilter::~SSLFilter() {
if (ssl_ != NULL) {
SSL_free(ssl_);
ssl_ = NULL;
@@ -1498,13 +1608,37 @@
hostname_ = NULL;
}
for (int i = 0; i < kNumBuffers; ++i) {
- Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
- delete[] buffers_[i];
+ if (buffers_[i] != NULL) {
+ delete[] buffers_[i];
+ buffers_[i] = NULL;
+ }
}
- Dart_DeletePersistentHandle(string_start_);
- Dart_DeletePersistentHandle(string_length_);
- Dart_DeletePersistentHandle(handshake_complete_);
- Dart_DeletePersistentHandle(bad_certificate_callback_);
+}
+
+
+void SSLFilter::Destroy() {
+ for (int i = 0; i < kNumBuffers; ++i) {
+ if (dart_buffer_objects_[i] != NULL) {
+ Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
+ dart_buffer_objects_[i] = NULL;
+ }
+ }
+ if (string_start_ != NULL) {
+ Dart_DeletePersistentHandle(string_start_);
+ string_start_ = NULL;
+ }
+ if (string_length_ != NULL) {
+ Dart_DeletePersistentHandle(string_length_);
+ string_length_ = NULL;
+ }
+ if (handshake_complete_ != NULL) {
+ Dart_DeletePersistentHandle(handshake_complete_);
+ handshake_complete_ = NULL;
+ }
+ if (bad_certificate_callback_ != NULL) {
+ Dart_DeletePersistentHandle(bad_certificate_callback_);
+ bad_certificate_callback_ = NULL;
+ }
}
diff --git a/runtime/bin/secure_socket.h b/runtime/bin/secure_socket.h
index bd5eda3..754d240 100644
--- a/runtime/bin/secure_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -62,7 +62,9 @@
in_handshake_(false),
hostname_(NULL) { }
- void Init(Dart_Handle dart_this);
+ ~SSLFilter();
+
+ Dart_Handle Init(Dart_Handle dart_this);
void Connect(const char* hostname,
SSL_CTX* context,
bool is_server,
@@ -120,7 +122,7 @@
static bool isBufferEncrypted(int i) {
return static_cast<BufferIndex>(i) >= kFirstEncrypted;
}
- void InitializeBuffers(Dart_Handle dart_this);
+ Dart_Handle InitializeBuffers(Dart_Handle dart_this);
void InitializePlatformData();
DISALLOW_COPY_AND_ASSIGN(SSLFilter);
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
index ccfc1c1..455b132 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -137,49 +137,34 @@
static final SecurityContext defaultContext =
new _SecurityContext().._trustBuiltinRoots();
- void usePrivateKey(String keyFile, {String password}) {
- usePrivateKeySync(keyFile, password: password);
- }
- void usePrivateKeySync(String keyFile, {String password}) {
- List<int> bytes = (new File(keyFile)).readAsBytesSync();
+ void usePrivateKey(String file, {String password}) {
+ List<int> bytes = (new File(file)).readAsBytesSync();
usePrivateKeyBytes(bytes, password: password);
}
void usePrivateKeyBytes(List<int> keyBytes, {String password})
native "SecurityContext_UsePrivateKeyBytes";
void setTrustedCertificates(String file, {String password}) {
- setTrustedCertificatesSync(file, password: password);
- }
- void setTrustedCertificatesSync(String file, {String password}) {
List<int> bytes = (new File(file)).readAsBytesSync();
setTrustedCertificatesBytes(bytes, password: password);
}
void setTrustedCertificatesBytes(List<int> certBytes, {String password})
native "SecurityContext_SetTrustedCertificatesBytes";
- void useCertificateChain({String file, String directory, String password}) {
- if (directory != null) {
- throw new UnsupportedError(
- "The directory argument to useCertificateChain is not supported.");
- }
- useCertificateChainSync(file, password: password);
- }
- void useCertificateChainSync(String chainFile, {String password}) {
- List<int> bytes = (new File(chainFile)).readAsBytesSync();
+ void useCertificateChain(String file, {String password}) {
+ List<int> bytes = (new File(file)).readAsBytesSync();
useCertificateChainBytes(bytes, password: password);
}
void useCertificateChainBytes(List<int> chainBytes, {String password})
native "SecurityContext_UseCertificateChainBytes";
void setClientAuthorities(String file, {String password}) {
- setClientAuthoritiesSync(file, password: password);
- }
- void setClientAuthoritiesSync(String file, {String password}) {
List<int> bytes = (new File(file)).readAsBytesSync();
setClientAuthoritiesBytes(bytes, password: password);
}
void setClientAuthoritiesBytes(List<int> authCertBytes, {String password})
native "SecurityContext_SetClientAuthoritiesBytes";
+
void setAlpnProtocols(List<String> protocols, bool isServer) {
Uint8List encodedProtocols =
SecurityContext._protocolsToLengthEncoding(protocols);
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index fbc3083..7e66009 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -32,7 +32,7 @@
static int _socketType(nativeSocket) {
var result = _getSocketType(nativeSocket);
if (result is OSError) {
- throw new FileSystemException("Error retreiving socket type", "", result);
+ throw new FileSystemException("Error retrieving socket type", "", result);
}
return result;
}
diff --git a/runtime/lib/bool.cc b/runtime/lib/bool.cc
index b536ccf..dcb1952 100644
--- a/runtime/lib/bool.cc
+++ b/runtime/lib/bool.cc
@@ -21,7 +21,7 @@
GET_NATIVE_ARGUMENT(Bool, default_value, arguments->NativeArgAt(2));
// Call the embedder to supply us with the environment.
const String& env_value =
- String::Handle(Api::CallEnvironmentCallback(thread, name));
+ String::Handle(Api::GetEnvironmentValue(thread, name));
if (!env_value.IsNull()) {
if (Symbols::True().Equals(env_value)) {
return Bool::True().raw();
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 11e307a..13f7513 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -61,6 +61,7 @@
yieldEachIterator = null;
}
isYieldEach = false;
+ // moveNextFn() will update the values of isYieldEach and _current.
if (!moveNextFn(this)) {
moveNextFn = null;
_current = null;
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index 9478fcc..e75ecab 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -237,7 +237,7 @@
GET_NATIVE_ARGUMENT(Integer, default_value, arguments->NativeArgAt(2));
// Call the embedder to supply us with the environment.
const String& env_value =
- String::Handle(Api::CallEnvironmentCallback(thread, name));
+ String::Handle(Api::GetEnvironmentValue(thread, name));
if (!env_value.IsNull()) {
const Integer& result = Integer::Handle(ParseInteger(env_value));
if (!result.IsNull()) {
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index f6d248a..fb51c07 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -151,8 +151,8 @@
return;
}
- Dart_IsolateFlags api_flags;
- state_->isolate_flags()->CopyTo(&api_flags);
+ // Make a copy of the state's isolate flags and hand it to the callback.
+ Dart_IsolateFlags api_flags = *(state_->isolate_flags());
Isolate* isolate = reinterpret_cast<Isolate*>(
(callback)(state_->script_url(),
@@ -391,7 +391,10 @@
// If we were passed a value then override the default flags state for
// checked mode.
if (!checked.IsNull()) {
- state->isolate_flags()->set_checked(checked.value());
+ bool val = checked.value();
+ Dart_IsolateFlags* flags = state->isolate_flags();
+ flags->enable_asserts = val;
+ flags->enable_type_checks = val;
}
ThreadPool::Task* spawn_task = new SpawnIsolateTask(state);
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 10b39ce..aaa28e1 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -270,7 +270,7 @@
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
String& name = String::Handle(func.name());
- name = String::IdentifierPrettyNameRetainPrivate(name);
+ name = String::ScrubNameRetainPrivate(name);
args.SetAt(1, name);
args.SetAt(2, owner_mirror);
args.SetAt(3, instantiator);
@@ -689,7 +689,7 @@
}
// An uninitialized field was found. Check for a getter in the field's
// owner classs.
- const Class& klass = Class::Handle(field.owner());
+ const Class& klass = Class::Handle(field.Owner());
const String& internal_getter_name =
String::Handle(Field::GetterName(getter_name));
getter = klass.LookupStaticFunction(internal_getter_name);
@@ -883,7 +883,7 @@
klass = Function::Cast(decl).origin();
library = klass.library();
} else if (decl.IsField()) {
- klass = Field::Cast(decl).origin();
+ klass = Field::Cast(decl).Origin();
library = klass.library();
} else if (decl.IsLibrary()) {
library ^= decl.raw();
@@ -1993,7 +1993,7 @@
token_pos = cls.token_pos();
} else if (decl.IsField()) {
const Field& field = Field::Cast(decl);
- script = field.script();
+ script = field.Script();
token_pos = field.token_pos();
} else if (decl.IsTypeParameter()) {
const TypeParameter& type_var = TypeParameter::Cast(decl);
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index c34552d..09e4808 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -280,7 +280,7 @@
location, instance_type_name, type_name,
dst_name, Object::null_string());
} else {
- ASSERT(isolate->flags().type_checks());
+ ASSERT(isolate->type_checks());
bound_error_message = String::New(bound_error.ToErrorCString());
Exceptions::CreateAndThrowTypeError(
location, instance_type_name, Symbols::Empty(),
diff --git a/runtime/lib/regexp.cc b/runtime/lib/regexp.cc
index 14bf14f..47b4245 100644
--- a/runtime/lib/regexp.cc
+++ b/runtime/lib/regexp.cc
@@ -15,7 +15,6 @@
namespace dart {
DECLARE_FLAG(bool, trace_irregexp);
-DECLARE_FLAG(bool, interpret_irregexp);
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_factory, 4) {
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index 62e5aac..2821146 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -20,7 +20,7 @@
GET_NATIVE_ARGUMENT(String, default_value, arguments->NativeArgAt(2));
// Call the embedder to supply us with the environment.
const String& env_value =
- String::Handle(Api::CallEnvironmentCallback(thread, name));
+ String::Handle(Api::GetEnvironmentValue(thread, name));
if (!env_value.IsNull()) {
return Symbols::New(env_value);
}
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index e485407..4863c2c 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -45,6 +45,7 @@
export 'package:observatory/src/elements/objectpool_view.dart';
export 'package:observatory/src/elements/observatory_application.dart';
export 'package:observatory/src/elements/observatory_element.dart';
+export 'package:observatory/src/elements/persistent_handles.dart';
export 'package:observatory/src/elements/ports.dart';
export 'package:observatory/src/elements/script_inset.dart';
export 'package:observatory/src/elements/script_ref.dart';
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
index 1f89cbd..4e84fec 100644
--- a/runtime/observatory/lib/elements.html
+++ b/runtime/observatory/lib/elements.html
@@ -38,6 +38,7 @@
<link rel="import" href="src/elements/objectpool_view.html">
<link rel="import" href="src/elements/observatory_application.html">
<link rel="import" href="src/elements/observatory_element.html">
+<link rel="import" href="src/elements/persistent_handles.html">
<link rel="import" href="src/elements/ports.html">
<link rel="import" href="src/elements/script_inset.html">
<link rel="import" href="src/elements/script_ref.html">
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index bda98c0..644b659 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -139,6 +139,7 @@
_pageRegistry.add(new IsolateReconnectPage(this));
_pageRegistry.add(new ErrorViewPage(this));
_pageRegistry.add(new MetricsPage(this));
+ _pageRegistry.add(new PersistentHandlesPage(this));
_pageRegistry.add(new PortsPage(this));
_pageRegistry.add(new LoggingPage(this));
_pageRegistry.add(new TimelinePage(this));
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index 6be5e88..b2216e4 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -266,6 +266,21 @@
}
}
+class PersistentHandlesPage extends SimplePage {
+ PersistentHandlesPage(app)
+ : super('persistent-handles', 'persistent-handles-page', app);
+
+ void _visit(Uri uri) {
+ super._visit(uri);
+ getIsolate(uri).then((isolate) {
+ if (element != null) {
+ PersistentHandlesPageElement page = element;
+ page.isolate = isolate;
+ }
+ });
+ }
+}
+
class HeapMapPage extends SimplePage {
HeapMapPage(app) : super('heap-map', 'heap-map', app);
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 3bf25b5..6595447 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -1492,7 +1492,7 @@
warnOutOfDate();
}
- void _reportIsolateError(Isolate isolate) {
+ void _reportIsolateError(Isolate isolate, String eventKind) {
if (isolate == null) {
return;
}
@@ -1501,14 +1501,26 @@
return;
}
console.newline();
- console.printBold('Isolate exited due to an unhandled exception:');
+ if (eventKind == ServiceEvent.kPauseException) {
+ console.printBold('Isolate will exit due to an unhandled exception:');
+ } else {
+ console.printBold('Isolate has exited due to an unhandled exception:');
+ }
console.print(error.message);
console.newline();
- console.printBold("Type 'set break-on-exception Unhandled' to pause the"
- " isolate when an unhandled exception occurs.");
- console.newline();
- console.printBold("You can make this the default by running with "
- "--pause-isolates-on-unhandled-exceptions");
+ if (eventKind == ServiceEvent.kPauseException &&
+ (error.exception.isStackOverflowError ||
+ error.exception.isOutOfMemoryError)) {
+ console.printBold(
+ 'When an unhandled stack overflow or OOM exception occurs, the VM '
+ 'has run out of memory and cannot keep the stack alive while '
+ 'paused.');
+ } else {
+ console.printBold("Type 'set break-on-exception Unhandled' to pause the"
+ " isolate when an unhandled exception occurs.");
+ console.printBold("You can make this the default by running with "
+ "--pause-isolates-on-unhandled-exceptions");
+ }
}
void _reportPause(ServiceEvent event) {
@@ -1520,7 +1532,12 @@
console.print(
"Paused at isolate exit "
"(type 'continue' or [F7] to exit the isolate')");
- _reportIsolateError(isolate);
+ _reportIsolateError(isolate, event.kind);
+ } else if (event.kind == ServiceEvent.kPauseException) {
+ console.print(
+ "Paused at an unhandled exception "
+ "(type 'continue' or [F7] to exit the isolate')");
+ _reportIsolateError(isolate, event.kind);
} else if (stack['frames'].length > 0) {
Frame frame = stack['frames'][0];
var script = frame.location.script;
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.html b/runtime/observatory/lib/src/elements/isolate_summary.html
index c146bfa..64361ed 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -64,11 +64,13 @@
<template if="{{ isolate.pauseEvent.kind == 'PauseException' }}">
by exception
</template>
- at
- <function-ref ref="{{ isolate.topFrame.function }}">
- </function-ref>
- (<source-link location="{{ isolate.topFrame.location }}">
- </source-link>)
+ <template if="{{ isolate.topFrame != null }}">
+ at
+ <function-ref ref="{{ isolate.topFrame.function }}">
+ </function-ref>
+ (<source-link location="{{ isolate.topFrame.location }}">
+ </source-link>)
+ </template>
</template>
</template>
@@ -168,6 +170,11 @@
</div>
<div class="memberItem">
<div class="memberValue">
+ See <a on-click="{{ goto }}" _href="{{ gotoLink('/persistent-handles', isolate) }}">persistent handles</a>
+ </div>
+ </div>
+ <div class="memberItem">
+ <div class="memberValue">
See <a on-click="{{ goto }}" _href="{{ gotoLink('/ports', isolate) }}">ports</a>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/nav_bar.html b/runtime/observatory/lib/src/elements/nav_bar.html
index c9e6b62..4299d0c 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.html
+++ b/runtime/observatory/lib/src/elements/nav_bar.html
@@ -207,6 +207,8 @@
anchor="metrics"></nav-menu-item>
<nav-menu-item link="{{ makeLink('/heap-snapshot', isolate) }}"
anchor="heap snapshot"></nav-menu-item>
+ <nav-menu-item link="{{ makeLink('/persistent-handles', isolate) }}"
+ anchor="persistent handles"></nav-menu-item>
<nav-menu-item link="{{ makeLink('/ports', isolate) }}"
anchor="ports"></nav-menu-item>
<nav-menu-item link="{{ makeLink('/logging', isolate) }}"
diff --git a/runtime/observatory/lib/src/elements/persistent_handles.dart b/runtime/observatory/lib/src/elements/persistent_handles.dart
new file mode 100644
index 0000000..f6ccfaf
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/persistent_handles.dart
@@ -0,0 +1,178 @@
+// 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.
+
+library persitent_handles_page;
+
+import 'dart:async';
+import 'dart:html';
+import 'observatory_element.dart';
+import 'package:observatory/app.dart';
+import 'package:observatory/elements.dart';
+import 'package:observatory/service.dart';
+import 'package:polymer/polymer.dart';
+
+class WeakPersistentHandlesSortedTable extends SortedTable {
+ factory WeakPersistentHandlesSortedTable() {
+ var columns = [
+ new SortedTableColumn.withFormatter('External Size',
+ Utils.formatSize),
+ new SortedTableColumn('Peer'),
+ new SortedTableColumn('Finalizer Callback'),
+ new SortedTableColumn(''), // Spacer column.
+ new SortedTableColumn('Object'),
+ ];
+ WeakPersistentHandlesSortedTable result =
+ new WeakPersistentHandlesSortedTable._(columns);
+ // Sort by external size.
+ result.sortColumnIndex = 0;
+ return result;
+ }
+
+ WeakPersistentHandlesSortedTable._(columns) : super(columns);
+
+ @override
+ dynamic getSortKeyFor(int row, int col) {
+ return super.getSortKeyFor(row, col);
+ }
+
+ void update(List<ServiceMap> handles, HtmlElement tableBody) {
+ clearRows();
+ for (ServiceMap handle in handles) {
+ var row = [int.parse(handle['externalSize'], onError: (_) => 0),
+ handle['peer'],
+ handle['callbackSymbolName'] +
+ '( ${handle['callbackAddress']} )',
+ '', // Spacer column.
+ handle['object']];
+ addRow(new SortedTableRow(row));
+ print(row);
+ }
+ sort();
+ _updateTableInDom(tableBody);
+ }
+
+ void sortAndDisplay(HtmlElement tableBody) {
+ sort();
+ _updateTableInDom(tableBody);
+ }
+
+
+ void _updateTableInDom(HtmlElement tableBody) {
+ assert(tableBody != null);
+ // Resize DOM table.
+ if (tableBody.children.length > sortedRows.length) {
+ // Shrink the table.
+ var deadRows =
+ tableBody.children.length - sortedRows.length;
+ for (var i = 0; i < deadRows; i++) {
+ tableBody.children.removeLast();
+ }
+ } else if (tableBody.children.length < sortedRows.length) {
+ // Grow table.
+ var newRows = sortedRows.length - tableBody.children.length;
+ for (var i = 0; i < newRows; i++) {
+ _addDomRow(tableBody);
+ }
+ }
+ assert(tableBody.children.length == sortedRows.length);
+ // Fill table.
+ for (var i = 0; i < sortedRows.length; i++) {
+ var rowIndex = sortedRows[i];
+ var tr = tableBody.children[i];
+ _fillDomRow(tr, rowIndex);
+ }
+ }
+
+ void _addDomRow(HtmlElement tableBody) {
+ // Add empty dom row.
+ var tr = new TableRowElement();
+
+ var cell;
+
+ cell = tr.insertCell(-1);
+ cell = tr.insertCell(-1);
+ cell = tr.insertCell(-1);
+
+ // Add spacer.
+ cell = tr.insertCell(-1);
+ cell.classes.add('left-border-spacer');
+
+ // Add class ref.
+ cell = tr.insertCell(-1);
+ AnyServiceRefElement objectRef = new Element.tag('any-service-ref');
+ cell.children.add(objectRef);
+
+ // Add row to table.
+ tableBody.children.add(tr);
+ }
+
+ void _fillDomRow(TableRowElement tr, int rowIndex) {
+ var row = rows[rowIndex];
+
+ for (var i = 0; i < row.values.length - 2; i++) {
+ var cell = tr.children[i];
+ cell.title = row.values[i].toString();
+ cell.text = getFormattedValue(rowIndex, i);
+ cell.style.paddingLeft = '1em';
+ cell.style.paddingRight = '1em';
+ }
+
+ final int objectIndex = row.values.length - 1;
+ AnyServiceRefElement objectRef = tr.children[objectIndex].children[0];
+ objectRef.ref = row.values[objectIndex];
+ }
+}
+
+
+@CustomTag('persistent-handles-page')
+class PersistentHandlesPageElement extends ObservatoryElement {
+ PersistentHandlesPageElement.created() : super.created();
+
+ @observable Isolate isolate;
+ @observable var /*ObservableList | ServiceObject*/ persistentHandles;
+ @observable var /*ObservableList | ServiceObject*/ weakPersistentHandles;
+ @observable WeakPersistentHandlesSortedTable weakPersistentHandlesTable;
+ var _weakPersistentHandlesTableBody;
+
+ void isolateChanged(oldValue) {
+ if (isolate != null) {
+ refresh();
+ }
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ _weakPersistentHandlesTableBody =
+ shadowRoot.querySelector('#weakPersistentHandlesTableBody');
+ weakPersistentHandlesTable =
+ new WeakPersistentHandlesSortedTable();
+ }
+
+ Future refresh() {
+ return isolate.getPersistentHandles().then(_refreshView);
+ }
+
+ _refreshView(/*ObservableList | ServiceObject*/ object) {
+ persistentHandles = object['persistentHandles'];
+ weakPersistentHandles = object['weakPersistentHandles'];
+ weakPersistentHandlesTable.update(
+ weakPersistentHandles,
+ _weakPersistentHandlesTableBody);
+ }
+
+ @observable void changeSort(Event e, var detail, Element target) {
+ if (target is TableCellElement) {
+ if (weakPersistentHandlesTable.sortColumnIndex != target.cellIndex) {
+ weakPersistentHandlesTable.sortColumnIndex = target.cellIndex;
+ weakPersistentHandlesTable.sortDescending = true;
+ } else {
+ weakPersistentHandlesTable.sortDescending =
+ !weakPersistentHandlesTable.sortDescending;
+ }
+ weakPersistentHandlesTable.sortAndDisplay(
+ _weakPersistentHandlesTableBody);
+ }
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/persistent_handles.html b/runtime/observatory/lib/src/elements/persistent_handles.html
new file mode 100644
index 0000000..9005494
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/persistent_handles.html
@@ -0,0 +1,106 @@
+<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="nav_bar.html">
+<link rel="import" href="observatory_element.html">
+
+<polymer-element name="persistent-handles-page" extends="observatory-element">
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <style>
+ .table {
+ border-collapse: collapse!important;
+ margin-bottom: 20px
+ table-layout: fixed;
+ width: 100%;
+ }
+ .table td:nth-of-type(1) {
+ width: 30%;
+ }
+ .th, .td {
+ padding: 8px;
+ vertical-align: top;
+ }
+ .table thead > tr > th {
+ vertical-align: bottom;
+ text-align: left;
+ border-bottom:2px solid #ddd;
+ }
+ .spacer {
+ width: 16px;
+ }
+ .left-border-spacer {
+ width: 16px;
+ border-left: 1px solid;
+ }
+ .clickable {
+ color: #0489c3;
+ text-decoration: none;
+ cursor: pointer;
+ }
+ .clickable:hover {
+ text-decoration: underline;
+ cursor: pointer;
+ }
+ #weakPersistentHandlesTable tr:hover > td {
+ background-color: #F4C7C3;
+ }
+ .nav-option {
+ color: white;
+ float: right;
+ margin: 3px;
+ padding: 8px;
+ }
+ </style>
+ <nav-bar>
+ <top-nav-menu></top-nav-menu>
+ <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
+ <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
+ <nav-menu link="{{ makeLink('/persistent-handles', isolate) }}" anchor="persistent handles" last="{{ true }}"></nav-menu>
+ <nav-refresh callback="{{ refresh }}"></nav-refresh>
+ </nav-bar>
+ <div class="content-centered-big">
+ <template if="{{ persistentHandles.isEmpty }}">
+ <h1>Persistent Handles (0)</h1>
+ <hr>
+ </template>
+ <template if="{{ persistentHandles.isNotEmpty }}">
+ <h1>Persistent Handles ({{ persistentHandles.length }})</h1>
+ <hr>
+ <curly-block expand="{{ persistentHandles.length <= 8 }}">
+ <div class="memberList">
+ <template repeat="{{ persistentHandle in persistentHandles }}">
+ <div class="memberItem">
+ <div class="memberValue">
+ <any-service-ref ref="{{ persistentHandle['object'] }}">
+ </any-service-ref>
+ </div>
+ </div>
+ </template>
+ </div>
+ </curly-block><br><br>
+ </template>
+ <br><br>
+ <template if="{{ weakPersistentHandles.isEmpty }}">
+ <h1>Weak Persistent Handles (0)</h1>
+ <hr>
+ </template>
+ <template if="{{ weakPersistentHandles.isNotEmpty }}">
+ <h1>Weak Persistent Handles ({{ weakPersistentHandles.length }})</h1>
+ <hr>
+ </template>
+ <table id="weakPersistentHandlesTable" class="flex-item-100-percent table">
+ <thead id="weakPersistentHandlesTableHead">
+ <tr>
+ <th on-click="{{changeSort}}" class="clickable" title="External Size">{{ weakPersistentHandlesTable.getColumnLabel(0) }}</th>
+ <th on-click="{{changeSort}}" class="clickable" title="Peer">{{ weakPersistentHandlesTable.getColumnLabel(1) }}</th>
+ <th on-click="{{changeSort}}" class="clickable" title="Finalizer Callback">{{ weakPersistentHandlesTable.getColumnLabel(2) }}</th>
+ <th class="spacer"></th>
+ <th on-click="{{changeSort}}" class="clickable" title="Object">{{ weakPersistentHandlesTable.getColumnLabel(4) }}</th>
+ </tr>
+ </thead>
+ <tbody id="weakPersistentHandlesTableBody">
+ </tbody>
+ </table>
+ <view-footer></view-footer>
+ </div>
+ </template>
+</polymer-element>
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index fbecb10..7a70c11 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -67,6 +67,14 @@
});
}
+ Future saveTimeline() async {
+ return postMessage('save');
+ }
+
+ Future loadTimeline() async {
+ return postMessage('load');
+ }
+
_updateSize() {
IFrameElement e = $['root'];
final totalHeight = window.innerHeight;
diff --git a/runtime/observatory/lib/src/elements/timeline_page.html b/runtime/observatory/lib/src/elements/timeline_page.html
index 50b063d..d0a2bcd 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.html
+++ b/runtime/observatory/lib/src/elements/timeline_page.html
@@ -15,6 +15,8 @@
<nav-refresh callback="{{ clear }}" label="Clear"></nav-refresh>
<nav-refresh callback="{{ recordOn }}" label="Start recording"></nav-refresh>
<nav-refresh callback="{{ recordOff }}" label="Stop recording"></nav-refresh>
+ <nav-refresh callback="{{ saveTimeline }}" label="Save"></nav-refresh>
+ <nav-refresh callback="{{ loadTimeline }}" label="Load"></nav-refresh>
</nav-bar>
<iframe id="root" frameborder="0" src="../../../../timeline.html">
</iframe>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 78b6765..b3a06b9 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -389,6 +389,13 @@
clazz = map['class'];
}
+ // Load the full class object if the isolate is runnable.
+ if (clazz != null) {
+ if (clazz.isolate.runnable) {
+ clazz.load();
+ }
+ }
+
if (mapIsRef) {
return;
}
@@ -1137,7 +1144,7 @@
@observable bool running = false;
@observable bool idle = false;
@observable bool loading = true;
-
+ @observable bool runnable = false;
@observable bool ioEnabled = false;
final List<String> extensionRPCs = new List<String>();
@@ -1193,6 +1200,10 @@
return invokeRpc('_getPorts', {});
}
+ Future<ServiceObject> getPersistentHandles() {
+ return invokeRpc('_getPersistentHandles', {});
+ }
+
Future<List<Class>> getClassRefs() async {
ServiceMap classList = await invokeRpc('getClassList', {});
assert(classList.type == 'ClassList');
@@ -1375,7 +1386,7 @@
}
_loaded = true;
loading = false;
-
+ runnable = map['runnable'] == true;
_upgradeCollection(map, isolate);
originNumber = int.parse(map['_originNumber'], onError:(_) => null);
rootLibrary = map['rootLib'];
@@ -1858,6 +1869,7 @@
void _update(ObservableMap map, bool mapIsRef) {
_loaded = true;
_upgradeCollection(map, owner);
+
assert(map['isolate'] == null || owner == map['isolate']);
timestamp =
new DateTime.fromMillisecondsSinceEpoch(map['timestamp']);
@@ -2041,6 +2053,10 @@
bool get canCache => true;
bool get immutable => false;
+ bool isDart(String libraryName) {
+ return uri == 'dart:$libraryName';
+ }
+
Library._empty(ServiceObjectOwner owner) : super._empty(owner);
void _update(ObservableMap map, bool mapIsRef) {
@@ -2325,6 +2341,25 @@
bool get isWeakProperty => kind == 'WeakProperty';
bool get isClosure => kind == 'Closure';
bool get isStackTrace => kind == 'StackTrace';
+ bool get isStackOverflowError {
+ if (clazz == null) {
+ return false;
+ }
+ if (clazz.library == null) {
+ return false;
+ }
+ return (clazz.name == 'StackOverflowError') && clazz.library.isDart('core');
+ }
+
+ bool get isOutOfMemoryError {
+ if (clazz == null) {
+ return false;
+ }
+ if (clazz.library == null) {
+ return false;
+ }
+ return (clazz.name == 'OutOfMemoryError') && clazz.library.isDart('core');
+ }
// TODO(turnidge): Is this properly backwards compatible when new
// instance kinds are added?
diff --git a/runtime/observatory/observatory_sources.gypi b/runtime/observatory/observatory_sources.gypi
index 865f140..a3a2510 100644
--- a/runtime/observatory/observatory_sources.gypi
+++ b/runtime/observatory/observatory_sources.gypi
@@ -119,6 +119,8 @@
'lib/src/elements/observatory_application.html',
'lib/src/elements/observatory_element.dart',
'lib/src/elements/observatory_element.html',
+ 'lib/src/elements/persistent_handles.dart',
+ 'lib/src/elements/persistent_handles.html',
'lib/src/elements/ports.dart',
'lib/src/elements/ports.html',
'lib/src/elements/script_inset.dart',
diff --git a/runtime/observatory/tests/service/developer_extension_test.dart b/runtime/observatory/tests/service/developer_extension_test.dart
index f8cd30f..5c8e5cd 100644
--- a/runtime/observatory/tests/service/developer_extension_test.dart
+++ b/runtime/observatory/tests/service/developer_extension_test.dart
@@ -152,5 +152,4 @@
},
];
-main(args) async => runIsolateTests(args, tests, testeeConcurrent:test,
- trace_compiler: true);
+main(args) async => runIsolateTests(args, tests, testeeConcurrent:test);
diff --git a/runtime/observatory/web/timeline.js b/runtime/observatory/web/timeline.js
index 27f572c..9bdf46a 100644
--- a/runtime/observatory/web/timeline.js
+++ b/runtime/observatory/web/timeline.js
@@ -105,6 +105,85 @@
}
}
+function saveTimeline() {
+ if (pendingRequests > 0) {
+ var overlay = new tr.ui.b.Overlay();
+ overlay.textContent = 'Cannot save timeline while fetching one.';
+ overlay.title = 'Save error';
+ overlay.visible = true;
+ console.log('cannot save timeline while fetching one.');
+ return;
+ }
+ if (!traceObject ||
+ !traceObject.traceEvents ||
+ (traceObject.traceEvents.length == 0)) {
+ var overlay = new tr.ui.b.Overlay();
+ overlay.textContent = 'Cannot save an empty timeline.';
+ overlay.title = 'Save error';
+ overlay.visible = true;
+ console.log('Cannot save an empty timeline.');
+ return;
+ }
+ var blob = new Blob([JSON.stringify(traceObject)],
+ {type: 'application/json'});
+ var blobUrl = URL.createObjectURL(blob);
+ var link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
+ link.href = blobUrl;
+ var now = new Date();
+ var defaultFilename = "dart-timeline-" +
+ now.getFullYear() +
+ "-" +
+ now.getMonth() +
+ "-" +
+ now.getDate() +
+ ".json";
+ var filename = window.prompt('Save as', defaultFilename);
+ if (filename) {
+ link.download = filename;
+ link.click();
+ }
+}
+
+function loadTimeline() {
+ if (pendingRequests > 0) {
+ var overlay = new tr.ui.b.Overlay();
+ overlay.textContent = 'Cannot load timeline while fetching one.';
+ overlay.title = 'Save error';
+ overlay.visible = true;
+ console.log('Cannot load timeline while fetching one.');
+ return;
+ }
+ var inputElement = document.createElement('input');
+ inputElement.type = 'file';
+ inputElement.multiple = false;
+
+ var changeFired = false;
+ inputElement.addEventListener('change', function(e) {
+ if (changeFired)
+ return;
+ changeFired = true;
+
+ var file = inputElement.files[0];
+ var reader = new FileReader();
+ reader.onload = function(event) {
+ try {
+ traceObject = JSON.parse(event.target.result);
+ updateTimeline(traceObject);
+ } catch (error) {
+ tr.ui.b.Overlay.showError('Error while loading file: ' + error);
+ }
+ };
+ reader.onerror = function(event) {
+ tr.ui.b.Overlay.showError('Error while loading file: ' + event);
+ };
+ reader.onabort = function(event) {
+ tr.ui.b.Overlay.showError('Error while loading file: ' + event);
+ }
+ reader.readAsText(file);
+ });
+ inputElement.click();
+}
+
function onMessage(event) {
var request = JSON.parse(event.data);
var method = request['method'];
@@ -116,6 +195,12 @@
case 'clear':
clearTimeline();
break;
+ case 'save':
+ saveTimeline();
+ break;
+ case 'load':
+ loadTimeline();
+ break;
default:
console.log('Unknown method:' + method + '.');
}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 3032412..da20917 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -65,7 +65,7 @@
cc/Int8ListLengthMaxElements: Skip # Issue 23536, uses 1 GB memory.
[ $arch == mips && $mode == debug ]
-cc/FindCodeObject: Skip # Takes more than 8 minutes. Issue 17440
+cc/FindCodeObject: SkipSlow # Takes more than 8 minutes. Issue 17440
[ $compiler == dart2analyzer ]
dart/optimized_stacktrace_test: StaticWarning
@@ -76,24 +76,24 @@
dart/spawn_shutdown_test: Skip # VM Shutdown test
[ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug && $builder_tag == asan ]
-cc/Dart2JSCompileAll: Skip # Timeout.
+cc/Dart2JSCompileAll: SkipSlow # Timeout.
+
+[ $builder_tag == asan ]
+cc/CodeImmutability: Fail,OK # Address Sanitizer turns a crash into a failure.
[ $noopt ]
dart/byte_array_test: Crash # Incompatible flag --disable_alloc_stubs_after_gc
-[ $noopt || $compiler == precompiler ]
+[ $noopt || $compiler == precompiler || $compiler == dart2app ]
dart/redirection_type_shuffling_test: CompileTimeError # Imports dart:mirrors
-dart/optimized_stacktrace_test: RuntimeError # Expects line and column numbers
-[ $compiler == dart2app ]
-dart/optimized_stacktrace_test: RuntimeError # Expects line and column numbers
+[ $noopt || $runtime == dart_precompiled ]
+# Stacktraces in precompilation omit inlined frames.
+dart/inline_stack_frame_test: Pass, RuntimeError
+dart/optimized_stacktrace_test: Pass, RuntimeError
-[ $runtime == dart_product ]
-dart/data_uri_spawn_test: Skip # Isolate.spawnUri
-
-[ $runtime == dart_precompiled ]
-dart/inline_stack_frame_test: Fail # Issue 24783 - inlined frames missing
-dart/data_uri_spawn_test: RuntimeError # Isolate.spawnUri
+[ $runtime == dart_product || $runtime == dart_precompiled ]
+dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
[ $runtime == vm && $mode == product ]
cc/IsolateSetCheckedMode: Fail,OK # Expects exact type name.
diff --git a/runtime/third_party/binary_size/README.dart b/runtime/third_party/binary_size/README.dart
new file mode 100644
index 0000000..0f2124e
--- /dev/null
+++ b/runtime/third_party/binary_size/README.dart
@@ -0,0 +1 @@
+A local copy of tools/binary_size from Chromium project.
\ No newline at end of file
diff --git a/runtime/third_party/binary_size/src/binary_size_utils.py b/runtime/third_party/binary_size/src/binary_size_utils.py
new file mode 100644
index 0000000..67335c2
--- /dev/null
+++ b/runtime/third_party/binary_size/src/binary_size_utils.py
@@ -0,0 +1,71 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Common utilities for tools that deal with binary size information.
+"""
+
+import logging
+import re
+
+
+def ParseNm(nm_lines):
+ """Parse nm output, returning data for all relevant (to binary size)
+ symbols and ignoring the rest.
+
+ Args:
+ nm_lines: an iterable over lines of nm output.
+
+ Yields:
+ (symbol name, symbol type, symbol size, source file path).
+
+ Path may be None if nm couldn't figure out the source file.
+ """
+
+ # Match lines with size, symbol, optional location, optional discriminator
+ sym_re = re.compile(r'^([0-9a-f]{8,}) ' # address (8+ hex digits)
+ '([0-9a-f]{8,}) ' # size (8+ hex digits)
+ '(.) ' # symbol type, one character
+ '([^\t]+)' # symbol name, separated from next by tab
+ '(?:\t(.*):[\d\?]+)?.*$') # location
+ # Match lines with addr but no size.
+ addr_re = re.compile(r'^[0-9a-f]{8,} (.) ([^\t]+)(?:\t.*)?$')
+ # Match lines that don't have an address at all -- typically external symbols.
+ noaddr_re = re.compile(r'^ {8,} (.) (.*)$')
+ # Match lines with no symbol name, only addr and type
+ addr_only_re = re.compile(r'^[0-9a-f]{8,} (.)$')
+
+ seen_lines = set()
+ for line in nm_lines:
+ line = line.rstrip()
+ if line in seen_lines:
+ # nm outputs identical lines at times. We don't want to treat
+ # those as distinct symbols because that would make no sense.
+ continue
+ seen_lines.add(line)
+ match = sym_re.match(line)
+ if match:
+ address, size, sym_type, sym = match.groups()[0:4]
+ size = int(size, 16)
+ if sym_type in ('B', 'b'):
+ continue # skip all BSS for now.
+ path = match.group(5)
+ yield sym, sym_type, size, path, address
+ continue
+ match = addr_re.match(line)
+ if match:
+ # sym_type, sym = match.groups()[0:2]
+ continue # No size == we don't care.
+ match = noaddr_re.match(line)
+ if match:
+ sym_type, sym = match.groups()
+ if sym_type in ('U', 'w'):
+ continue # external or weak symbol
+ match = addr_only_re.match(line)
+ if match:
+ continue # Nothing to do.
+
+
+ # If we reach this part of the loop, there was something in the
+ # line that we didn't expect or recognize.
+ logging.warning('nm output parser failed to parse: %s', repr(line))
diff --git a/runtime/third_party/binary_size/src/elf_symbolizer.py b/runtime/third_party/binary_size/src/elf_symbolizer.py
new file mode 100644
index 0000000..374063a
--- /dev/null
+++ b/runtime/third_party/binary_size/src/elf_symbolizer.py
@@ -0,0 +1,467 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import datetime
+import logging
+import multiprocessing
+import os
+import posixpath
+import Queue
+import re
+import subprocess
+import sys
+import threading
+import time
+
+
+# addr2line builds a possibly infinite memory cache that can exhaust
+# the computer's memory if allowed to grow for too long. This constant
+# controls how many lookups we do before restarting the process. 4000
+# gives near peak performance without extreme memory usage.
+ADDR2LINE_RECYCLE_LIMIT = 4000
+
+
+class ELFSymbolizer(object):
+ """An uber-fast (multiprocessing, pipelined and asynchronous) ELF symbolizer.
+
+ This class is a frontend for addr2line (part of GNU binutils), designed to
+ symbolize batches of large numbers of symbols for a given ELF file. It
+ supports sharding symbolization against many addr2line instances and
+ pipelining of multiple requests per each instance (in order to hide addr2line
+ internals and OS pipe latencies).
+
+ The interface exhibited by this class is a very simple asynchronous interface,
+ which is based on the following three methods:
+ - SymbolizeAsync(): used to request (enqueue) resolution of a given address.
+ - The |callback| method: used to communicated back the symbol information.
+ - Join(): called to conclude the batch to gather the last outstanding results.
+ In essence, before the Join method returns, this class will have issued as
+ many callbacks as the number of SymbolizeAsync() calls. In this regard, note
+ that due to multiprocess sharding, callbacks can be delivered out of order.
+
+ Some background about addr2line:
+ - it is invoked passing the elf path in the cmdline, piping the addresses in
+ its stdin and getting results on its stdout.
+ - it has pretty large response times for the first requests, but it
+ works very well in streaming mode once it has been warmed up.
+ - it doesn't scale by itself (on more cores). However, spawning multiple
+ instances at the same time on the same file is pretty efficient as they
+ keep hitting the pagecache and become mostly CPU bound.
+ - it might hang or crash, mostly for OOM. This class deals with both of these
+ problems.
+
+ Despite the "scary" imports and the multi* words above, (almost) no multi-
+ threading/processing is involved from the python viewpoint. Concurrency
+ here is achieved by spawning several addr2line subprocesses and handling their
+ output pipes asynchronously. Therefore, all the code here (with the exception
+ of the Queue instance in Addr2Line) should be free from mind-blowing
+ thread-safety concerns.
+
+ The multiprocess sharding works as follows:
+ The symbolizer tries to use the lowest number of addr2line instances as
+ possible (with respect of |max_concurrent_jobs|) and enqueue all the requests
+ in a single addr2line instance. For few symbols (i.e. dozens) sharding isn't
+ worth the startup cost.
+ The multiprocess logic kicks in as soon as the queues for the existing
+ instances grow. Specifically, once all the existing instances reach the
+ |max_queue_size| bound, a new addr2line instance is kicked in.
+ In the case of a very eager producer (i.e. all |max_concurrent_jobs| instances
+ have a backlog of |max_queue_size|), back-pressure is applied on the caller by
+ blocking the SymbolizeAsync method.
+
+ This module has been deliberately designed to be dependency free (w.r.t. of
+ other modules in this project), to allow easy reuse in external projects.
+ """
+
+ def __init__(self, elf_file_path, addr2line_path, callback, inlines=False,
+ max_concurrent_jobs=None, addr2line_timeout=30, max_queue_size=50,
+ source_root_path=None, strip_base_path=None):
+ """Args:
+ elf_file_path: path of the elf file to be symbolized.
+ addr2line_path: path of the toolchain's addr2line binary.
+ callback: a callback which will be invoked for each resolved symbol with
+ the two args (sym_info, callback_arg). The former is an instance of
+ |ELFSymbolInfo| and contains the symbol information. The latter is an
+ embedder-provided argument which is passed to SymbolizeAsync().
+ inlines: when True, the ELFSymbolInfo will contain also the details about
+ the outer inlining functions. When False, only the innermost function
+ will be provided.
+ max_concurrent_jobs: Max number of addr2line instances spawned.
+ Parallelize responsibly, addr2line is a memory and I/O monster.
+ max_queue_size: Max number of outstanding requests per addr2line instance.
+ addr2line_timeout: Max time (in seconds) to wait for a addr2line response.
+ After the timeout, the instance will be considered hung and respawned.
+ source_root_path: In some toolchains only the name of the source file is
+ is output, without any path information; disambiguation searches
+ through the source directory specified by |source_root_path| argument
+ for files whose name matches, adding the full path information to the
+ output. For example, if the toolchain outputs "unicode.cc" and there
+ is a file called "unicode.cc" located under |source_root_path|/foo,
+ the tool will replace "unicode.cc" with
+ "|source_root_path|/foo/unicode.cc". If there are multiple files with
+ the same name, disambiguation will fail because the tool cannot
+ determine which of the files was the source of the symbol.
+ strip_base_path: Rebases the symbols source paths onto |source_root_path|
+ (i.e replace |strip_base_path| with |source_root_path).
+ """
+ assert(os.path.isfile(addr2line_path)), 'Cannot find ' + addr2line_path
+ self.elf_file_path = elf_file_path
+ self.addr2line_path = addr2line_path
+ self.callback = callback
+ self.inlines = inlines
+ self.max_concurrent_jobs = (max_concurrent_jobs or
+ min(multiprocessing.cpu_count(), 4))
+ self.max_queue_size = max_queue_size
+ self.addr2line_timeout = addr2line_timeout
+ self.requests_counter = 0 # For generating monotonic request IDs.
+ self._a2l_instances = [] # Up to |max_concurrent_jobs| _Addr2Line inst.
+
+ # If necessary, create disambiguation lookup table
+ self.disambiguate = source_root_path is not None
+ self.disambiguation_table = {}
+ self.strip_base_path = strip_base_path
+ if(self.disambiguate):
+ self.source_root_path = os.path.abspath(source_root_path)
+ self._CreateDisambiguationTable()
+
+ # Create one addr2line instance. More instances will be created on demand
+ # (up to |max_concurrent_jobs|) depending on the rate of the requests.
+ self._CreateNewA2LInstance()
+
+ def SymbolizeAsync(self, addr, callback_arg=None):
+ """Requests symbolization of a given address.
+
+ This method is not guaranteed to return immediately. It generally does, but
+ in some scenarios (e.g. all addr2line instances have full queues) it can
+ block to create back-pressure.
+
+ Args:
+ addr: address to symbolize.
+ callback_arg: optional argument which will be passed to the |callback|."""
+ assert(isinstance(addr, int))
+
+ # Process all the symbols that have been resolved in the meanwhile.
+ # Essentially, this drains all the addr2line(s) out queues.
+ for a2l_to_purge in self._a2l_instances:
+ a2l_to_purge.ProcessAllResolvedSymbolsInQueue()
+ a2l_to_purge.RecycleIfNecessary()
+
+ # Find the best instance according to this logic:
+ # 1. Find an existing instance with the shortest queue.
+ # 2. If all of instances' queues are full, but there is room in the pool,
+ # (i.e. < |max_concurrent_jobs|) create a new instance.
+ # 3. If there were already |max_concurrent_jobs| instances and all of them
+ # had full queues, make back-pressure.
+
+ # 1.
+ def _SortByQueueSizeAndReqID(a2l):
+ return (a2l.queue_size, a2l.first_request_id)
+ a2l = min(self._a2l_instances, key=_SortByQueueSizeAndReqID)
+
+ # 2.
+ if (a2l.queue_size >= self.max_queue_size and
+ len(self._a2l_instances) < self.max_concurrent_jobs):
+ a2l = self._CreateNewA2LInstance()
+
+ # 3.
+ if a2l.queue_size >= self.max_queue_size:
+ a2l.WaitForNextSymbolInQueue()
+
+ a2l.EnqueueRequest(addr, callback_arg)
+
+ def Join(self):
+ """Waits for all the outstanding requests to complete and terminates."""
+ for a2l in self._a2l_instances:
+ a2l.WaitForIdle()
+ a2l.Terminate()
+
+ def _CreateNewA2LInstance(self):
+ assert(len(self._a2l_instances) < self.max_concurrent_jobs)
+ a2l = ELFSymbolizer.Addr2Line(self)
+ self._a2l_instances.append(a2l)
+ return a2l
+
+ def _CreateDisambiguationTable(self):
+ """ Non-unique file names will result in None entries"""
+ start_time = time.time()
+ logging.info('Collecting information about available source files...')
+ self.disambiguation_table = {}
+
+ for root, _, filenames in os.walk(self.source_root_path):
+ for f in filenames:
+ self.disambiguation_table[f] = os.path.join(root, f) if (f not in
+ self.disambiguation_table) else None
+ logging.info('Finished collecting information about '
+ 'possible files (took %.1f s).',
+ (time.time() - start_time))
+
+
+ class Addr2Line(object):
+ """A python wrapper around an addr2line instance.
+
+ The communication with the addr2line process looks as follows:
+ [STDIN] [STDOUT] (from addr2line's viewpoint)
+ > f001111
+ > f002222
+ < Symbol::Name(foo, bar) for f001111
+ < /path/to/source/file.c:line_number
+ > f003333
+ < Symbol::Name2() for f002222
+ < /path/to/source/file.c:line_number
+ < Symbol::Name3() for f003333
+ < /path/to/source/file.c:line_number
+ """
+
+ SYM_ADDR_RE = re.compile(r'([^:]+):(\?|\d+).*')
+
+ def __init__(self, symbolizer):
+ self._symbolizer = symbolizer
+ self._lib_file_name = posixpath.basename(symbolizer.elf_file_path)
+
+ # The request queue (i.e. addresses pushed to addr2line's stdin and not
+ # yet retrieved on stdout)
+ self._request_queue = collections.deque()
+
+ # This is essentially len(self._request_queue). It has been optimized to a
+ # separate field because turned out to be a perf hot-spot.
+ self.queue_size = 0
+
+ # Keep track of the number of symbols a process has processed to
+ # avoid a single process growing too big and using all the memory.
+ self._processed_symbols_count = 0
+
+ # Objects required to handle the addr2line subprocess.
+ self._proc = None # Subprocess.Popen(...) instance.
+ self._thread = None # Threading.thread instance.
+ self._out_queue = None # Queue.Queue instance (for buffering a2l stdout).
+ self._RestartAddr2LineProcess()
+
+ def EnqueueRequest(self, addr, callback_arg):
+ """Pushes an address to addr2line's stdin (and keeps track of it)."""
+ self._symbolizer.requests_counter += 1 # For global "age" of requests.
+ req_idx = self._symbolizer.requests_counter
+ self._request_queue.append((addr, callback_arg, req_idx))
+ self.queue_size += 1
+ self._WriteToA2lStdin(addr)
+
+ def WaitForIdle(self):
+ """Waits until all the pending requests have been symbolized."""
+ while self.queue_size > 0:
+ self.WaitForNextSymbolInQueue()
+
+ def WaitForNextSymbolInQueue(self):
+ """Waits for the next pending request to be symbolized."""
+ if not self.queue_size:
+ return
+
+ # This outer loop guards against a2l hanging (detecting stdout timeout).
+ while True:
+ start_time = datetime.datetime.now()
+ timeout = datetime.timedelta(seconds=self._symbolizer.addr2line_timeout)
+
+ # The inner loop guards against a2l crashing (checking if it exited).
+ while (datetime.datetime.now() - start_time < timeout):
+ # poll() returns !None if the process exited. a2l should never exit.
+ if self._proc.poll():
+ logging.warning('addr2line crashed, respawning (lib: %s).' %
+ self._lib_file_name)
+ self._RestartAddr2LineProcess()
+ # TODO(primiano): the best thing to do in this case would be
+ # shrinking the pool size as, very likely, addr2line is crashed
+ # due to low memory (and the respawned one will die again soon).
+
+ try:
+ lines = self._out_queue.get(block=True, timeout=0.25)
+ except Queue.Empty:
+ # On timeout (1/4 s.) repeat the inner loop and check if either the
+ # addr2line process did crash or we waited its output for too long.
+ continue
+
+ # In nominal conditions, we get straight to this point.
+ self._ProcessSymbolOutput(lines)
+ return
+
+ # If this point is reached, we waited more than |addr2line_timeout|.
+ logging.warning('Hung addr2line process, respawning (lib: %s).' %
+ self._lib_file_name)
+ self._RestartAddr2LineProcess()
+
+ def ProcessAllResolvedSymbolsInQueue(self):
+ """Consumes all the addr2line output lines produced (without blocking)."""
+ if not self.queue_size:
+ return
+ while True:
+ try:
+ lines = self._out_queue.get_nowait()
+ except Queue.Empty:
+ break
+ self._ProcessSymbolOutput(lines)
+
+ def RecycleIfNecessary(self):
+ """Restarts the process if it has been used for too long.
+
+ A long running addr2line process will consume excessive amounts
+ of memory without any gain in performance."""
+ if self._processed_symbols_count >= ADDR2LINE_RECYCLE_LIMIT:
+ self._RestartAddr2LineProcess()
+
+
+ def Terminate(self):
+ """Kills the underlying addr2line process.
+
+ The poller |_thread| will terminate as well due to the broken pipe."""
+ try:
+ self._proc.kill()
+ self._proc.communicate() # Essentially wait() without risking deadlock.
+ except Exception: # An exception while terminating? How interesting.
+ pass
+ self._proc = None
+
+ def _WriteToA2lStdin(self, addr):
+ self._proc.stdin.write('%s\n' % hex(addr))
+ if self._symbolizer.inlines:
+ # In the case of inlines we output an extra blank line, which causes
+ # addr2line to emit a (??,??:0) tuple that we use as a boundary marker.
+ self._proc.stdin.write('\n')
+ self._proc.stdin.flush()
+
+ def _ProcessSymbolOutput(self, lines):
+ """Parses an addr2line symbol output and triggers the client callback."""
+ (_, callback_arg, _) = self._request_queue.popleft()
+ self.queue_size -= 1
+
+ innermost_sym_info = None
+ sym_info = None
+ for (line1, line2) in lines:
+ prev_sym_info = sym_info
+ name = line1 if not line1.startswith('?') else None
+ source_path = None
+ source_line = None
+ m = ELFSymbolizer.Addr2Line.SYM_ADDR_RE.match(line2)
+ if m:
+ if not m.group(1).startswith('?'):
+ source_path = m.group(1)
+ if not m.group(2).startswith('?'):
+ source_line = int(m.group(2))
+ else:
+ logging.warning('Got invalid symbol path from addr2line: %s' % line2)
+
+ # In case disambiguation is on, and needed
+ was_ambiguous = False
+ disambiguated = False
+ if self._symbolizer.disambiguate:
+ if source_path and not posixpath.isabs(source_path):
+ path = self._symbolizer.disambiguation_table.get(source_path)
+ was_ambiguous = True
+ disambiguated = path is not None
+ source_path = path if disambiguated else source_path
+
+ # Use absolute paths (so that paths are consistent, as disambiguation
+ # uses absolute paths)
+ if source_path and not was_ambiguous:
+ source_path = os.path.abspath(source_path)
+
+ if source_path and self._symbolizer.strip_base_path:
+ # Strip the base path
+ source_path = re.sub('^' + self._symbolizer.strip_base_path,
+ self._symbolizer.source_root_path or '', source_path)
+
+ sym_info = ELFSymbolInfo(name, source_path, source_line, was_ambiguous,
+ disambiguated)
+ if prev_sym_info:
+ prev_sym_info.inlined_by = sym_info
+ if not innermost_sym_info:
+ innermost_sym_info = sym_info
+
+ self._processed_symbols_count += 1
+ self._symbolizer.callback(innermost_sym_info, callback_arg)
+
+ def _RestartAddr2LineProcess(self):
+ if self._proc:
+ self.Terminate()
+
+ # The only reason of existence of this Queue (and the corresponding
+ # Thread below) is the lack of a subprocess.stdout.poll_avail_lines().
+ # Essentially this is a pipe able to extract a couple of lines atomically.
+ self._out_queue = Queue.Queue()
+
+ # Start the underlying addr2line process in line buffered mode.
+
+ cmd = [self._symbolizer.addr2line_path, '--functions', '--demangle',
+ '--exe=' + self._symbolizer.elf_file_path]
+ if self._symbolizer.inlines:
+ cmd += ['--inlines']
+ self._proc = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE, stderr=sys.stderr, close_fds=True)
+
+ # Start the poller thread, which simply moves atomically the lines read
+ # from the addr2line's stdout to the |_out_queue|.
+ self._thread = threading.Thread(
+ target=ELFSymbolizer.Addr2Line.StdoutReaderThread,
+ args=(self._proc.stdout, self._out_queue, self._symbolizer.inlines))
+ self._thread.daemon = True # Don't prevent early process exit.
+ self._thread.start()
+
+ self._processed_symbols_count = 0
+
+ # Replay the pending requests on the new process (only for the case
+ # of a hung addr2line timing out during the game).
+ for (addr, _, _) in self._request_queue:
+ self._WriteToA2lStdin(addr)
+
+ @staticmethod
+ def StdoutReaderThread(process_pipe, queue, inlines):
+ """The poller thread fn, which moves the addr2line stdout to the |queue|.
+
+ This is the only piece of code not running on the main thread. It merely
+ writes to a Queue, which is thread-safe. In the case of inlines, it
+ detects the ??,??:0 marker and sends the lines atomically, such that the
+ main thread always receives all the lines corresponding to one symbol in
+ one shot."""
+ try:
+ lines_for_one_symbol = []
+ while True:
+ line1 = process_pipe.readline().rstrip('\r\n')
+ line2 = process_pipe.readline().rstrip('\r\n')
+ if not line1 or not line2:
+ break
+ inline_has_more_lines = inlines and (len(lines_for_one_symbol) == 0 or
+ (line1 != '??' and line2 != '??:0'))
+ if not inlines or inline_has_more_lines:
+ lines_for_one_symbol += [(line1, line2)]
+ if inline_has_more_lines:
+ continue
+ queue.put(lines_for_one_symbol)
+ lines_for_one_symbol = []
+ process_pipe.close()
+
+ # Every addr2line processes will die at some point, please die silently.
+ except (IOError, OSError):
+ pass
+
+ @property
+ def first_request_id(self):
+ """Returns the request_id of the oldest pending request in the queue."""
+ return self._request_queue[0][2] if self._request_queue else 0
+
+
+class ELFSymbolInfo(object):
+ """The result of the symbolization passed as first arg. of each callback."""
+
+ def __init__(self, name, source_path, source_line, was_ambiguous=False,
+ disambiguated=False):
+ """All the fields here can be None (if addr2line replies with '??')."""
+ self.name = name
+ self.source_path = source_path
+ self.source_line = source_line
+ # In the case of |inlines|=True, the |inlined_by| points to the outer
+ # function inlining the current one (and so on, to form a chain).
+ self.inlined_by = None
+ self.disambiguated = disambiguated
+ self.was_ambiguous = was_ambiguous
+
+ def __str__(self):
+ return '%s [%s:%d]' % (
+ self.name or '??', self.source_path or '??', self.source_line or 0)
diff --git a/runtime/third_party/binary_size/src/explain_binary_size_delta.py b/runtime/third_party/binary_size/src/explain_binary_size_delta.py
new file mode 100755
index 0000000..45c1236
--- /dev/null
+++ b/runtime/third_party/binary_size/src/explain_binary_size_delta.py
@@ -0,0 +1,484 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Describe the size difference of two binaries.
+
+Generates a description of the size difference of two binaries based
+on the difference of the size of various symbols.
+
+This tool needs "nm" dumps of each binary with full symbol
+information. You can obtain the necessary dumps by running the
+run_binary_size_analysis.py script upon each binary, with the
+"--nm-out" parameter set to the location in which you want to save the
+dumps. Example:
+
+ # obtain symbol data from first binary in /tmp/nm1.dump
+ cd $CHECKOUT1_SRC
+ ninja -C out/Release binary_size_tool
+ tools/binary_size/run_binary_size_analysis \
+ --library <path_to_library>
+ --destdir /tmp/throwaway
+ --nm-out /tmp/nm1.dump
+
+ # obtain symbol data from second binary in /tmp/nm2.dump
+ cd $CHECKOUT2_SRC
+ ninja -C out/Release binary_size_tool
+ tools/binary_size/run_binary_size_analysis \
+ --library <path_to_library>
+ --destdir /tmp/throwaway
+ --nm-out /tmp/nm2.dump
+
+ # cleanup useless files
+ rm -r /tmp/throwaway
+
+ # run this tool
+ explain_binary_size_delta.py --nm1 /tmp/nm1.dump --nm2 /tmp/nm2.dump
+"""
+
+import collections
+from collections import Counter
+from math import ceil
+import operator
+import optparse
+import os
+import sys
+
+import binary_size_utils
+
+
+def CalculateSharedAddresses(symbols):
+ """Checks how many symbols share the same memory space. This returns a
+Counter result where result[address] will tell you how many times address was
+used by symbols."""
+ count = Counter()
+ for _, _, _, _, address in symbols:
+ count[address] += 1
+
+ return count
+
+
+def CalculateEffectiveSize(share_count, address, symbol_size):
+ """Given a raw symbol_size and an address, this method returns the
+ size we should blame on this symbol considering it might share the
+ machine code/data with other symbols. Using the raw symbol_size for
+ each symbol would in those cases over estimate the true cost of that
+ block.
+
+ """
+ shared_count = share_count[address]
+ if shared_count == 1:
+ return symbol_size
+
+ assert shared_count > 1
+ return int(ceil(symbol_size / float(shared_count)))
+
+class SymbolDelta(object):
+ """Stores old size, new size and some metadata."""
+ def __init__(self, shared):
+ self.old_size = None
+ self.new_size = None
+ self.shares_space_with_other_symbols = shared
+
+ def __eq__(self, other):
+ return (self.old_size == other.old_size and
+ self.new_size == other.new_size and
+ self.shares_space_with_other_symbols ==
+ other.shares_space_with_other_symbols)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def copy_symbol_delta(self):
+ symbol_delta = SymbolDelta(self.shares_space_with_other_symbols)
+ symbol_delta.old_size = self.old_size
+ symbol_delta.new_size = self.new_size
+ return symbol_delta
+
+class DeltaInfo(SymbolDelta):
+ """Summary of a the change for one symbol between two instances."""
+ def __init__(self, file_path, symbol_type, symbol_name, shared):
+ SymbolDelta.__init__(self, shared)
+ self.file_path = file_path
+ self.symbol_type = symbol_type
+ self.symbol_name = symbol_name
+
+ def __eq__(self, other):
+ return (self.file_path == other.file_path and
+ self.symbol_type == other.symbol_type and
+ self.symbol_name == other.symbol_name and
+ SymbolDelta.__eq__(self, other))
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def ExtractSymbolDelta(self):
+ """Returns a copy of the SymbolDelta for this DeltaInfo."""
+ return SymbolDelta.copy_symbol_delta(self)
+
+def Compare(symbols1, symbols2):
+ """Executes a comparison of the symbols in symbols1 and symbols2.
+
+ Returns:
+ tuple of lists: (added_symbols, removed_symbols, changed_symbols, others)
+ where each list contains DeltaInfo objects.
+ """
+ added = [] # tuples
+ removed = [] # tuples
+ changed = [] # tuples
+ unchanged = [] # tuples
+
+ cache1 = {}
+ cache2 = {}
+ # Make a map of (file, symbol_type) : (symbol_name, effective_symbol_size)
+ share_count1 = CalculateSharedAddresses(symbols1)
+ share_count2 = CalculateSharedAddresses(symbols2)
+ for cache, symbols, share_count in ((cache1, symbols1, share_count1),
+ (cache2, symbols2, share_count2)):
+ for symbol_name, symbol_type, symbol_size, file_path, address in symbols:
+ if 'vtable for ' in symbol_name:
+ symbol_type = '@' # hack to categorize these separately
+ if file_path:
+ file_path = os.path.normpath(file_path)
+ if sys.platform.startswith('win'):
+ file_path = file_path.replace('\\', '/')
+ else:
+ file_path = '(No Path)'
+ # Take into consideration that multiple symbols might share the same
+ # block of code.
+ effective_symbol_size = CalculateEffectiveSize(share_count, address,
+ symbol_size)
+ key = (file_path, symbol_type)
+ bucket = cache.setdefault(key, {})
+ size_list = bucket.setdefault(symbol_name, [])
+ size_list.append((effective_symbol_size,
+ effective_symbol_size != symbol_size))
+
+ # Now diff them. We iterate over the elements in cache1. For each symbol
+ # that we find in cache2, we record whether it was deleted, changed, or
+ # unchanged. We then remove it from cache2; all the symbols that remain
+ # in cache2 at the end of the iteration over cache1 are the 'new' symbols.
+ for key, bucket1 in cache1.items():
+ bucket2 = cache2.get(key)
+ file_path, symbol_type = key;
+ if not bucket2:
+ # A file was removed. Everything in bucket1 is dead.
+ for symbol_name, symbol_size_list in bucket1.items():
+ for (symbol_size, shared) in symbol_size_list:
+ delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
+ delta_info.old_size = symbol_size
+ removed.append(delta_info)
+ else:
+ # File still exists, look for changes within.
+ for symbol_name, symbol_size_list in bucket1.items():
+ size_list2 = bucket2.get(symbol_name)
+ if size_list2 is None:
+ # Symbol no longer exists in bucket2.
+ for (symbol_size, shared) in symbol_size_list:
+ delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
+ delta_info.old_size = symbol_size
+ removed.append(delta_info)
+ else:
+ del bucket2[symbol_name] # Symbol is not new, delete from cache2.
+ if len(symbol_size_list) == 1 and len(size_list2) == 1:
+ symbol_size, shared1 = symbol_size_list[0]
+ size2, shared2 = size_list2[0]
+ delta_info = DeltaInfo(file_path, symbol_type, symbol_name,
+ shared1 or shared2)
+ delta_info.old_size = symbol_size
+ delta_info.new_size = size2
+ if symbol_size != size2:
+ # Symbol has change size in bucket.
+ changed.append(delta_info)
+ else:
+ # Symbol is unchanged.
+ unchanged.append(delta_info)
+ else:
+ # Complex comparison for when a symbol exists multiple times
+ # in the same file (where file can be "unknown file").
+ symbol_size_counter = collections.Counter(symbol_size_list)
+ delta_counter = collections.Counter(symbol_size_list)
+ delta_counter.subtract(size_list2)
+ for delta_counter_key in sorted(delta_counter.keys()):
+ delta = delta_counter[delta_counter_key]
+ unchanged_count = symbol_size_counter[delta_counter_key]
+ (symbol_size, shared) = delta_counter_key
+ if delta > 0:
+ unchanged_count -= delta
+ for _ in range(unchanged_count):
+ delta_info = DeltaInfo(file_path, symbol_type,
+ symbol_name, shared)
+ delta_info.old_size = symbol_size
+ delta_info.new_size = symbol_size
+ unchanged.append(delta_info)
+ if delta > 0: # Used to be more of these than there is now.
+ for _ in range(delta):
+ delta_info = DeltaInfo(file_path, symbol_type,
+ symbol_name, shared)
+ delta_info.old_size = symbol_size
+ removed.append(delta_info)
+ elif delta < 0: # More of this (symbol,size) now.
+ for _ in range(-delta):
+ delta_info = DeltaInfo(file_path, symbol_type,
+ symbol_name, shared)
+ delta_info.new_size = symbol_size
+ added.append(delta_info)
+
+ if len(bucket2) == 0:
+ del cache1[key] # Entire bucket is empty, delete from cache2
+
+ # We have now analyzed all symbols that are in cache1 and removed all of
+ # the encountered symbols from cache2. What's left in cache2 is the new
+ # symbols.
+ for key, bucket2 in cache2.iteritems():
+ file_path, symbol_type = key;
+ for symbol_name, symbol_size_list in bucket2.items():
+ for (symbol_size, shared) in symbol_size_list:
+ delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
+ delta_info.new_size = symbol_size
+ added.append(delta_info)
+ return (added, removed, changed, unchanged)
+
+
+def DeltaStr(number):
+ """Returns the number as a string with a '+' prefix if it's > 0 and
+ a '-' prefix if it's < 0."""
+ result = str(number)
+ if number > 0:
+ result = '+' + result
+ return result
+
+
+def SharedInfoStr(symbol_info):
+ """Returns a string (prefixed by space) explaining that numbers are
+ adjusted because of shared space between symbols, or an empty string
+ if space had not been shared."""
+
+ if symbol_info.shares_space_with_other_symbols:
+ return " (adjusted sizes because of memory sharing)"
+
+ return ""
+
+class CrunchStatsData(object):
+ """Stores a summary of data of a certain kind."""
+ def __init__(self, symbols):
+ self.symbols = symbols
+ self.sources = set()
+ self.before_size = 0
+ self.after_size = 0
+ self.symbols_by_path = {}
+
+
+def CrunchStats(added, removed, changed, unchanged, showsources, showsymbols):
+ """Outputs to stdout a summary of changes based on the symbol lists."""
+ # Split changed into grown and shrunk because that is easier to
+ # discuss.
+ grown = []
+ shrunk = []
+ for item in changed:
+ if item.old_size < item.new_size:
+ grown.append(item)
+ else:
+ shrunk.append(item)
+
+ new_symbols = CrunchStatsData(added)
+ removed_symbols = CrunchStatsData(removed)
+ grown_symbols = CrunchStatsData(grown)
+ shrunk_symbols = CrunchStatsData(shrunk)
+ sections = [new_symbols, removed_symbols, grown_symbols, shrunk_symbols]
+ for section in sections:
+ for item in section.symbols:
+ section.sources.add(item.file_path)
+ if item.old_size is not None:
+ section.before_size += item.old_size
+ if item.new_size is not None:
+ section.after_size += item.new_size
+ bucket = section.symbols_by_path.setdefault(item.file_path, [])
+ bucket.append((item.symbol_name, item.symbol_type,
+ item.ExtractSymbolDelta()))
+
+ total_change = sum(s.after_size - s.before_size for s in sections)
+ summary = 'Total change: %s bytes' % DeltaStr(total_change)
+ print(summary)
+ print('=' * len(summary))
+ for section in sections:
+ if not section.symbols:
+ continue
+ if section.before_size == 0:
+ description = ('added, totalling %s bytes' % DeltaStr(section.after_size))
+ elif section.after_size == 0:
+ description = ('removed, totalling %s bytes' %
+ DeltaStr(-section.before_size))
+ else:
+ if section.after_size > section.before_size:
+ type_str = 'grown'
+ else:
+ type_str = 'shrunk'
+ description = ('%s, for a net change of %s bytes '
+ '(%d bytes before, %d bytes after)' %
+ (type_str, DeltaStr(section.after_size - section.before_size),
+ section.before_size, section.after_size))
+ print(' %d %s across %d sources' %
+ (len(section.symbols), description, len(section.sources)))
+
+ maybe_unchanged_sources = set()
+ unchanged_symbols_size = 0
+ for item in unchanged:
+ maybe_unchanged_sources.add(item.file_path)
+ unchanged_symbols_size += item.old_size # == item.new_size
+ print(' %d unchanged, totalling %d bytes' %
+ (len(unchanged), unchanged_symbols_size))
+
+ # High level analysis, always output.
+ unchanged_sources = maybe_unchanged_sources
+ for section in sections:
+ unchanged_sources = unchanged_sources - section.sources
+ new_sources = (new_symbols.sources -
+ maybe_unchanged_sources -
+ removed_symbols.sources)
+ removed_sources = (removed_symbols.sources -
+ maybe_unchanged_sources -
+ new_symbols.sources)
+ partially_changed_sources = (grown_symbols.sources |
+ shrunk_symbols.sources | new_symbols.sources |
+ removed_symbols.sources) - removed_sources - new_sources
+ allFiles = set()
+ for section in sections:
+ allFiles = allFiles | section.sources
+ allFiles = allFiles | maybe_unchanged_sources
+ print 'Source stats:'
+ print(' %d sources encountered.' % len(allFiles))
+ print(' %d completely new.' % len(new_sources))
+ print(' %d removed completely.' % len(removed_sources))
+ print(' %d partially changed.' % len(partially_changed_sources))
+ print(' %d completely unchanged.' % len(unchanged_sources))
+ remainder = (allFiles - new_sources - removed_sources -
+ partially_changed_sources - unchanged_sources)
+ assert len(remainder) == 0
+
+ if not showsources:
+ return # Per-source analysis, only if requested
+ print 'Per-source Analysis:'
+ delta_by_path = {}
+ for section in sections:
+ for path in section.symbols_by_path:
+ entry = delta_by_path.get(path)
+ if not entry:
+ entry = {'plus': 0, 'minus': 0}
+ delta_by_path[path] = entry
+ for symbol_name, symbol_type, symbol_delta in \
+ section.symbols_by_path[path]:
+ if symbol_delta.old_size is None:
+ delta = symbol_delta.new_size
+ elif symbol_delta.new_size is None:
+ delta = -symbol_delta.old_size
+ else:
+ delta = symbol_delta.new_size - symbol_delta.old_size
+
+ if delta > 0:
+ entry['plus'] += delta
+ else:
+ entry['minus'] += (-1 * delta)
+
+ def delta_sort_key(item):
+ _path, size_data = item
+ growth = size_data['plus'] - size_data['minus']
+ return growth
+
+ for path, size_data in sorted(delta_by_path.iteritems(), key=delta_sort_key,
+ reverse=True):
+ gain = size_data['plus']
+ loss = size_data['minus']
+ delta = size_data['plus'] - size_data['minus']
+ header = ' %s - Source: %s - (gained %d, lost %d)' % (DeltaStr(delta),
+ path, gain, loss)
+ divider = '-' * len(header)
+ print ''
+ print divider
+ print header
+ print divider
+ if showsymbols:
+ def ExtractNewSize(tup):
+ symbol_delta = tup[2]
+ return symbol_delta.new_size
+ def ExtractOldSize(tup):
+ symbol_delta = tup[2]
+ return symbol_delta.old_size
+ if path in new_symbols.symbols_by_path:
+ print ' New symbols:'
+ for symbol_name, symbol_type, symbol_delta in \
+ sorted(new_symbols.symbols_by_path[path],
+ key=ExtractNewSize,
+ reverse=True):
+ print (' %8s: %s type=%s, size=%d bytes%s' %
+ (DeltaStr(symbol_delta.new_size), symbol_name, symbol_type,
+ symbol_delta.new_size, SharedInfoStr(symbol_delta)))
+ if path in removed_symbols.symbols_by_path:
+ print ' Removed symbols:'
+ for symbol_name, symbol_type, symbol_delta in \
+ sorted(removed_symbols.symbols_by_path[path],
+ key=ExtractOldSize):
+ print (' %8s: %s type=%s, size=%d bytes%s' %
+ (DeltaStr(-symbol_delta.old_size), symbol_name, symbol_type,
+ symbol_delta.old_size,
+ SharedInfoStr(symbol_delta)))
+ for (changed_symbols_by_path, type_str) in [
+ (grown_symbols.symbols_by_path, "Grown"),
+ (shrunk_symbols.symbols_by_path, "Shrunk")]:
+ if path in changed_symbols_by_path:
+ print ' %s symbols:' % type_str
+ def changed_symbol_sortkey(item):
+ symbol_name, _symbol_type, symbol_delta = item
+ return (symbol_delta.old_size - symbol_delta.new_size, symbol_name)
+ for symbol_name, symbol_type, symbol_delta in \
+ sorted(changed_symbols_by_path[path], key=changed_symbol_sortkey):
+ print (' %8s: %s type=%s, (was %d bytes, now %d bytes)%s'
+ % (DeltaStr(symbol_delta.new_size - symbol_delta.old_size),
+ symbol_name, symbol_type,
+ symbol_delta.old_size, symbol_delta.new_size,
+ SharedInfoStr(symbol_delta)))
+
+
+def main():
+ usage = """%prog [options]
+
+ Analyzes the symbolic differences between two binary files
+ (typically, not necessarily, two different builds of the same
+ library) and produces a detailed description of symbols that have
+ been added, removed, or whose size has changed.
+
+ Example:
+ explain_binary_size_delta.py --nm1 /tmp/nm1.dump --nm2 /tmp/nm2.dump
+
+ Options are available via '--help'.
+ """
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option('--nm1', metavar='PATH',
+ help='the nm dump of the first library')
+ parser.add_option('--nm2', metavar='PATH',
+ help='the nm dump of the second library')
+ parser.add_option('--showsources', action='store_true', default=False,
+ help='show per-source statistics')
+ parser.add_option('--showsymbols', action='store_true', default=False,
+ help='show all symbol information; implies --showsources')
+ parser.add_option('--verbose', action='store_true', default=False,
+ help='output internal debugging stuff')
+ opts, _args = parser.parse_args()
+
+ if not opts.nm1:
+ parser.error('--nm1 is required')
+ if not opts.nm2:
+ parser.error('--nm2 is required')
+ symbols = []
+ for path in [opts.nm1, opts.nm2]:
+ with file(path, 'r') as nm_input:
+ if opts.verbose:
+ print 'parsing ' + path + '...'
+ symbols.append(list(binary_size_utils.ParseNm(nm_input)))
+ (added, removed, changed, unchanged) = Compare(symbols[0], symbols[1])
+ CrunchStats(added, removed, changed, unchanged,
+ opts.showsources | opts.showsymbols, opts.showsymbols)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/runtime/third_party/binary_size/src/run_binary_size_analysis.py b/runtime/third_party/binary_size/src/run_binary_size_analysis.py
new file mode 100755
index 0000000..d97858d
--- /dev/null
+++ b/runtime/third_party/binary_size/src/run_binary_size_analysis.py
@@ -0,0 +1,666 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generate a spatial analysis against an arbitrary library.
+
+To use, build the 'binary_size_tool' target. Then run this tool, passing
+in the location of the library to be analyzed along with any other options
+you desire.
+"""
+
+import collections
+import json
+import logging
+import multiprocessing
+import optparse
+import os
+import re
+import shutil
+import struct
+import subprocess
+import sys
+import tempfile
+import time
+
+import binary_size_utils
+import elf_symbolizer
+
+# Node dictionary keys. These are output in json read by the webapp so
+# keep them short to save file size.
+# Note: If these change, the webapp must also change.
+NODE_TYPE_KEY = 'k'
+NODE_NAME_KEY = 'n'
+NODE_CHILDREN_KEY = 'children'
+NODE_SYMBOL_TYPE_KEY = 't'
+NODE_SYMBOL_SIZE_KEY = 'value'
+NODE_MAX_DEPTH_KEY = 'maxDepth'
+NODE_LAST_PATH_ELEMENT_KEY = 'lastPathElement'
+
+# The display name of the bucket where we put symbols without path.
+NAME_NO_PATH_BUCKET = '(No Path)'
+
+# Try to keep data buckets smaller than this to avoid killing the
+# graphing lib.
+BIG_BUCKET_LIMIT = 3000
+
+
+def _MkChild(node, name):
+ child = node[NODE_CHILDREN_KEY].get(name)
+ if child is None:
+ child = {NODE_NAME_KEY: name,
+ NODE_CHILDREN_KEY: {}}
+ node[NODE_CHILDREN_KEY][name] = child
+ return child
+
+
+
+def SplitNoPathBucket(node):
+ """NAME_NO_PATH_BUCKET can be too large for the graphing lib to
+ handle. Split it into sub-buckets in that case."""
+ root_children = node[NODE_CHILDREN_KEY]
+ if NAME_NO_PATH_BUCKET in root_children:
+ no_path_bucket = root_children[NAME_NO_PATH_BUCKET]
+ old_children = no_path_bucket[NODE_CHILDREN_KEY]
+ count = 0
+ for symbol_type, symbol_bucket in old_children.iteritems():
+ count += len(symbol_bucket[NODE_CHILDREN_KEY])
+ if count > BIG_BUCKET_LIMIT:
+ new_children = {}
+ no_path_bucket[NODE_CHILDREN_KEY] = new_children
+ current_bucket = None
+ index = 0
+ for symbol_type, symbol_bucket in old_children.iteritems():
+ for symbol_name, value in symbol_bucket[NODE_CHILDREN_KEY].iteritems():
+ if index % BIG_BUCKET_LIMIT == 0:
+ group_no = (index / BIG_BUCKET_LIMIT) + 1
+ current_bucket = _MkChild(no_path_bucket,
+ '%s subgroup %d' % (NAME_NO_PATH_BUCKET,
+ group_no))
+ assert not NODE_TYPE_KEY in node or node[NODE_TYPE_KEY] == 'p'
+ node[NODE_TYPE_KEY] = 'p' # p for path
+ index += 1
+ symbol_size = value[NODE_SYMBOL_SIZE_KEY]
+ AddSymbolIntoFileNode(current_bucket, symbol_type,
+ symbol_name, symbol_size)
+
+
+def MakeChildrenDictsIntoLists(node):
+ largest_list_len = 0
+ if NODE_CHILDREN_KEY in node:
+ largest_list_len = len(node[NODE_CHILDREN_KEY])
+ child_list = []
+ for child in node[NODE_CHILDREN_KEY].itervalues():
+ child_largest_list_len = MakeChildrenDictsIntoLists(child)
+ if child_largest_list_len > largest_list_len:
+ largest_list_len = child_largest_list_len
+ child_list.append(child)
+ node[NODE_CHILDREN_KEY] = child_list
+
+ return largest_list_len
+
+
+def AddSymbolIntoFileNode(node, symbol_type, symbol_name, symbol_size):
+ """Puts symbol into the file path node |node|.
+ Returns the number of added levels in tree. I.e. returns 2."""
+
+ # 'node' is the file node and first step is to find its symbol-type bucket.
+ node[NODE_LAST_PATH_ELEMENT_KEY] = True
+ node = _MkChild(node, symbol_type)
+ assert not NODE_TYPE_KEY in node or node[NODE_TYPE_KEY] == 'b'
+ node[NODE_SYMBOL_TYPE_KEY] = symbol_type
+ node[NODE_TYPE_KEY] = 'b' # b for bucket
+
+ # 'node' is now the symbol-type bucket. Make the child entry.
+ node = _MkChild(node, symbol_name)
+ if NODE_CHILDREN_KEY in node:
+ if node[NODE_CHILDREN_KEY]:
+ logging.warning('A container node used as symbol for %s.' % symbol_name)
+ # This is going to be used as a leaf so no use for child list.
+ del node[NODE_CHILDREN_KEY]
+ node[NODE_SYMBOL_SIZE_KEY] = symbol_size
+ node[NODE_SYMBOL_TYPE_KEY] = symbol_type
+ node[NODE_TYPE_KEY] = 's' # s for symbol
+
+ return 2 # Depth of the added subtree.
+
+
+def MakeCompactTree(symbols, symbol_path_origin_dir):
+ result = {NODE_NAME_KEY: '/',
+ NODE_CHILDREN_KEY: {},
+ NODE_TYPE_KEY: 'p',
+ NODE_MAX_DEPTH_KEY: 0}
+ seen_symbol_with_path = False
+ cwd = os.path.abspath(os.getcwd())
+ for symbol_name, symbol_type, symbol_size, file_path, _address in symbols:
+
+ if 'vtable for ' in symbol_name:
+ symbol_type = '@' # hack to categorize these separately
+ # Take path like '/foo/bar/baz', convert to ['foo', 'bar', 'baz']
+ if file_path and file_path != "??":
+ file_path = os.path.abspath(os.path.join(symbol_path_origin_dir,
+ file_path))
+ # Let the output structure be relative to $CWD if inside $CWD,
+ # otherwise relative to the disk root. This is to avoid
+ # unnecessary click-through levels in the output.
+ if file_path.startswith(cwd + os.sep):
+ file_path = file_path[len(cwd):]
+ if file_path.startswith('/'):
+ file_path = file_path[1:]
+ seen_symbol_with_path = True
+ else:
+ file_path = NAME_NO_PATH_BUCKET
+
+ path_parts = file_path.split('/')
+
+ # Find pre-existing node in tree, or update if it already exists
+ node = result
+ depth = 0
+ while len(path_parts) > 0:
+ path_part = path_parts.pop(0)
+ if len(path_part) == 0:
+ continue
+ depth += 1
+ node = _MkChild(node, path_part)
+ assert not NODE_TYPE_KEY in node or node[NODE_TYPE_KEY] == 'p'
+ node[NODE_TYPE_KEY] = 'p' # p for path
+
+ depth += AddSymbolIntoFileNode(node, symbol_type, symbol_name, symbol_size)
+ result[NODE_MAX_DEPTH_KEY] = max(result[NODE_MAX_DEPTH_KEY], depth)
+
+ if not seen_symbol_with_path:
+ logging.warning('Symbols lack paths. Data will not be structured.')
+
+ # The (no path) bucket can be extremely large if we failed to get
+ # path information. Split it into subgroups if needed.
+ SplitNoPathBucket(result)
+
+ largest_list_len = MakeChildrenDictsIntoLists(result)
+
+ if largest_list_len > BIG_BUCKET_LIMIT:
+ logging.warning('There are sections with %d nodes. '
+ 'Results might be unusable.' % largest_list_len)
+ return result
+
+
+def DumpCompactTree(symbols, symbol_path_origin_dir, outfile):
+ tree_root = MakeCompactTree(symbols, symbol_path_origin_dir)
+ with open(outfile, 'w') as out:
+ out.write('var tree_data=')
+ # Use separators without whitespace to get a smaller file.
+ json.dump(tree_root, out, separators=(',', ':'))
+ print('Writing %d bytes json' % os.path.getsize(outfile))
+
+
+def MakeSourceMap(symbols):
+ sources = {}
+ for _sym, _symbol_type, size, path, _address in symbols:
+ key = None
+ if path:
+ key = os.path.normpath(path)
+ else:
+ key = '[no path]'
+ if key not in sources:
+ sources[key] = {'path': path, 'symbol_count': 0, 'size': 0}
+ record = sources[key]
+ record['size'] += size
+ record['symbol_count'] += 1
+ return sources
+
+
+# Regex for parsing "nm" output. A sample line looks like this:
+# 0167b39c 00000018 t ACCESS_DESCRIPTION_free /path/file.c:95
+#
+# The fields are: address, size, type, name, source location
+# Regular expression explained ( see also: https://xkcd.com/208 ):
+# ([0-9a-f]{8,}+) The address
+# [\s]+ Whitespace separator
+# ([0-9a-f]{8,}+) The size. From here on out it's all optional.
+# [\s]+ Whitespace separator
+# (\S?) The symbol type, which is any non-whitespace char
+# [\s*] Whitespace separator
+# ([^\t]*) Symbol name, any non-tab character (spaces ok!)
+# [\t]? Tab separator
+# (.*) The location (filename[:linennum|?][ (discriminator n)]
+sNmPattern = re.compile(
+ r'([0-9a-f]{8,})[\s]+([0-9a-f]{8,})[\s]*(\S?)[\s*]([^\t]*)[\t]?(.*)')
+
+class Progress():
+ def __init__(self):
+ self.count = 0
+ self.skip_count = 0
+ self.collisions = 0
+ self.time_last_output = time.time()
+ self.count_last_output = 0
+ self.disambiguations = 0
+ self.was_ambiguous = 0
+
+
+def RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs,
+ disambiguate, src_path):
+ nm_output = RunNm(library, nm_binary)
+ nm_output_lines = nm_output.splitlines()
+ nm_output_lines_len = len(nm_output_lines)
+ address_symbol = {}
+ progress = Progress()
+ def map_address_symbol(symbol, addr):
+ progress.count += 1
+ if addr in address_symbol:
+ # 'Collision between %s and %s.' % (str(symbol.name),
+ # str(address_symbol[addr].name))
+ progress.collisions += 1
+ else:
+ if symbol.disambiguated:
+ progress.disambiguations += 1
+ if symbol.was_ambiguous:
+ progress.was_ambiguous += 1
+
+ address_symbol[addr] = symbol
+
+ progress_output()
+
+ def progress_output():
+ progress_chunk = 100
+ if progress.count % progress_chunk == 0:
+ time_now = time.time()
+ time_spent = time_now - progress.time_last_output
+ if time_spent > 1.0:
+ # Only output at most once per second.
+ progress.time_last_output = time_now
+ chunk_size = progress.count - progress.count_last_output
+ progress.count_last_output = progress.count
+ if time_spent > 0:
+ speed = chunk_size / time_spent
+ else:
+ speed = 0
+ progress_percent = (100.0 * (progress.count + progress.skip_count) /
+ nm_output_lines_len)
+ disambiguation_percent = 0
+ if progress.disambiguations != 0:
+ disambiguation_percent = (100.0 * progress.disambiguations /
+ progress.was_ambiguous)
+
+ sys.stdout.write('\r%.1f%%: Looked up %d symbols (%d collisions, '
+ '%d disambiguations where %.1f%% succeeded)'
+ ' - %.1f lookups/s.' %
+ (progress_percent, progress.count, progress.collisions,
+ progress.disambiguations, disambiguation_percent, speed))
+
+ # In case disambiguation was disabled, we remove the source path (which upon
+ # being set signals the symbolizer to enable disambiguation)
+ if not disambiguate:
+ src_path = None
+ symbolizer = elf_symbolizer.ELFSymbolizer(library, addr2line_binary,
+ map_address_symbol,
+ max_concurrent_jobs=jobs,
+ source_root_path=src_path)
+ user_interrupted = False
+ try:
+ for line in nm_output_lines:
+ match = sNmPattern.match(line)
+ if match:
+ location = match.group(5)
+ if not location:
+ addr = int(match.group(1), 16)
+ size = int(match.group(2), 16)
+ if addr in address_symbol: # Already looked up, shortcut
+ # ELFSymbolizer.
+ map_address_symbol(address_symbol[addr], addr)
+ continue
+ elif size == 0:
+ # Save time by not looking up empty symbols (do they even exist?)
+ print('Empty symbol: ' + line)
+ else:
+ symbolizer.SymbolizeAsync(addr, addr)
+ continue
+
+ progress.skip_count += 1
+ except KeyboardInterrupt:
+ user_interrupted = True
+ print('Interrupting - killing subprocesses. Please wait.')
+
+ try:
+ symbolizer.Join()
+ except KeyboardInterrupt:
+ # Don't want to abort here since we will be finished in a few seconds.
+ user_interrupted = True
+ print('Patience you must have my young padawan.')
+
+ print ''
+
+ if user_interrupted:
+ print('Skipping the rest of the file mapping. '
+ 'Output will not be fully classified.')
+
+ symbol_path_origin_dir = os.path.dirname(os.path.abspath(library))
+
+ with open(outfile, 'w') as out:
+ for line in nm_output_lines:
+ match = sNmPattern.match(line)
+ if match:
+ location = match.group(5)
+ if not location:
+ addr = int(match.group(1), 16)
+ symbol = address_symbol.get(addr)
+ if symbol is not None:
+ path = '??'
+ if symbol.source_path is not None:
+ path = os.path.abspath(os.path.join(symbol_path_origin_dir,
+ symbol.source_path))
+ line_number = 0
+ if symbol.source_line is not None:
+ line_number = symbol.source_line
+ out.write('%s\t%s:%d\n' % (line, path, line_number))
+ continue
+
+ out.write('%s\n' % line)
+
+ print('%d symbols in the results.' % len(address_symbol))
+
+
+def RunNm(binary, nm_binary):
+ cmd = [nm_binary, '-C', '--print-size', '--size-sort', '--reverse-sort',
+ binary]
+ nm_process = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ (process_output, err_output) = nm_process.communicate()
+
+ if nm_process.returncode != 0:
+ if err_output:
+ raise Exception, err_output
+ else:
+ raise Exception, process_output
+
+ return process_output
+
+
+def GetNmSymbols(nm_infile, outfile, library, jobs, verbose,
+ addr2line_binary, nm_binary, disambiguate, src_path):
+ if nm_infile is None:
+ if outfile is None:
+ outfile = tempfile.NamedTemporaryFile(delete=False).name
+
+ if verbose:
+ print 'Running parallel addr2line, dumping symbols to ' + outfile
+ RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs,
+ disambiguate, src_path)
+
+ nm_infile = outfile
+
+ elif verbose:
+ print 'Using nm input from ' + nm_infile
+ with file(nm_infile, 'r') as infile:
+ return list(binary_size_utils.ParseNm(infile))
+
+
+PAK_RESOURCE_ID_TO_STRING = { "inited": False }
+
+def LoadPakIdsFromResourceFile(filename):
+ """Given a file name, it loads everything that looks like a resource id
+ into PAK_RESOURCE_ID_TO_STRING."""
+ with open(filename) as resource_header:
+ for line in resource_header:
+ if line.startswith("#define "):
+ line_data = line.split()
+ if len(line_data) == 3:
+ try:
+ resource_number = int(line_data[2])
+ resource_name = line_data[1]
+ PAK_RESOURCE_ID_TO_STRING[resource_number] = resource_name
+ except ValueError:
+ pass
+
+def GetReadablePakResourceName(pak_file, resource_id):
+ """Pak resources have a numeric identifier. It is not helpful when
+ trying to locate where footprint is generated. This does its best to
+ map the number to a usable string."""
+ if not PAK_RESOURCE_ID_TO_STRING['inited']:
+ # Try to find resource header files generated by grit when
+ # building the pak file. We'll look for files named *resources.h"
+ # and lines of the type:
+ # #define MY_RESOURCE_JS 1234
+ PAK_RESOURCE_ID_TO_STRING['inited'] = True
+ gen_dir = os.path.join(os.path.dirname(pak_file), 'gen')
+ if os.path.isdir(gen_dir):
+ for dirname, _dirs, files in os.walk(gen_dir):
+ for filename in files:
+ if filename.endswith('resources.h'):
+ LoadPakIdsFromResourceFile(os.path.join(dirname, filename))
+ return PAK_RESOURCE_ID_TO_STRING.get(resource_id,
+ 'Pak Resource %d' % resource_id)
+
+def AddPakData(symbols, pak_file):
+ """Adds pseudo-symbols from a pak file."""
+ pak_file = os.path.abspath(pak_file)
+ with open(pak_file, 'rb') as pak:
+ data = pak.read()
+
+ PAK_FILE_VERSION = 4
+ HEADER_LENGTH = 2 * 4 + 1 # Two uint32s. (file version, number of entries)
+ # and one uint8 (encoding of text resources)
+ INDEX_ENTRY_SIZE = 2 + 4 # Each entry is a uint16 and a uint32.
+ version, num_entries, _encoding = struct.unpack('<IIB', data[:HEADER_LENGTH])
+ assert version == PAK_FILE_VERSION, ('Unsupported pak file '
+ 'version (%d) in %s. Only '
+ 'support version %d' %
+ (version, pak_file, PAK_FILE_VERSION))
+ if num_entries > 0:
+ # Read the index and data.
+ data = data[HEADER_LENGTH:]
+ for _ in range(num_entries):
+ resource_id, offset = struct.unpack('<HI', data[:INDEX_ENTRY_SIZE])
+ data = data[INDEX_ENTRY_SIZE:]
+ _next_id, next_offset = struct.unpack('<HI', data[:INDEX_ENTRY_SIZE])
+ resource_size = next_offset - offset
+
+ symbol_name = GetReadablePakResourceName(pak_file, resource_id)
+ symbol_path = pak_file
+ symbol_type = 'd' # Data. Approximation.
+ symbol_size = resource_size
+ symbols.append((symbol_name, symbol_type, symbol_size, symbol_path))
+
+def _find_in_system_path(binary):
+ """Locate the full path to binary in the system path or return None
+ if not found."""
+ system_path = os.environ["PATH"].split(os.pathsep)
+ for path in system_path:
+ binary_path = os.path.join(path, binary)
+ if os.path.isfile(binary_path):
+ return binary_path
+ return None
+
+def CheckDebugFormatSupport(library, addr2line_binary):
+ """Kills the program if debug data is in an unsupported format.
+
+ There are two common versions of the DWARF debug formats and
+ since we are right now transitioning from DWARF2 to newer formats,
+ it's possible to have a mix of tools that are not compatible. Detect
+ that and abort rather than produce meaningless output."""
+ tool_output = subprocess.check_output([addr2line_binary, '--version'])
+ version_re = re.compile(r'^GNU [^ ]+ .* (\d+).(\d+).*?$', re.M)
+ parsed_output = version_re.match(tool_output)
+ major = int(parsed_output.group(1))
+ minor = int(parsed_output.group(2))
+ supports_dwarf4 = major > 2 or major == 2 and minor > 22
+
+ if supports_dwarf4:
+ return
+
+ print('Checking version of debug information in %s.' % library)
+ debug_info = subprocess.check_output(['readelf', '--debug-dump=info',
+ '--dwarf-depth=1', library])
+ dwarf_version_re = re.compile(r'^\s+Version:\s+(\d+)$', re.M)
+ parsed_dwarf_format_output = dwarf_version_re.search(debug_info)
+ version = int(parsed_dwarf_format_output.group(1))
+ if version > 2:
+ print('The supplied tools only support DWARF2 debug data but the binary\n' +
+ 'uses DWARF%d. Update the tools or compile the binary\n' % version +
+ 'with -gdwarf-2.')
+ sys.exit(1)
+
+
+def main():
+ usage = """%prog [options]
+
+ Runs a spatial analysis on a given library, looking up the source locations
+ of its symbols and calculating how much space each directory, source file,
+ and so on is taking. The result is a report that can be used to pinpoint
+ sources of large portions of the binary, etceteras.
+
+ Under normal circumstances, you only need to pass two arguments, thusly:
+
+ %prog --library /path/to/library --destdir /path/to/output
+
+ In this mode, the program will dump the symbols from the specified library
+ and map those symbols back to source locations, producing a web-based
+ report in the specified output directory.
+
+ Other options are available via '--help'.
+ """
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option('--nm-in', metavar='PATH',
+ help='if specified, use nm input from <path> instead of '
+ 'generating it. Note that source locations should be '
+ 'present in the file; i.e., no addr2line symbol lookups '
+ 'will be performed when this option is specified. '
+ 'Mutually exclusive with --library.')
+ parser.add_option('--destdir', metavar='PATH',
+ help='write output to the specified directory. An HTML '
+ 'report is generated here along with supporting files; '
+ 'any existing report will be overwritten.')
+ parser.add_option('--library', metavar='PATH',
+ help='if specified, process symbols in the library at '
+ 'the specified path. Mutually exclusive with --nm-in.')
+ parser.add_option('--pak', metavar='PATH',
+ help='if specified, includes the contents of the '
+ 'specified *.pak file in the output.')
+ parser.add_option('--nm-binary',
+ help='use the specified nm binary to analyze library. '
+ 'This is to be used when the nm in the path is not for '
+ 'the right architecture or of the right version.')
+ parser.add_option('--addr2line-binary',
+ help='use the specified addr2line binary to analyze '
+ 'library. This is to be used when the addr2line in '
+ 'the path is not for the right architecture or '
+ 'of the right version.')
+ parser.add_option('--jobs', type='int',
+ help='number of jobs to use for the parallel '
+ 'addr2line processing pool; defaults to 1. More '
+ 'jobs greatly improve throughput but eat RAM like '
+ 'popcorn, and take several gigabytes each. Start low '
+ 'and ramp this number up until your machine begins to '
+ 'struggle with RAM. '
+ 'This argument is only valid when using --library.')
+ parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
+ help='be verbose, printing lots of status information.')
+ parser.add_option('--nm-out', metavar='PATH',
+ help='(deprecated) No-op. nm.out is stored in --destdir.')
+ parser.add_option('--no-nm-out', action='store_true',
+ help='do not keep the nm output file. This file is useful '
+ 'if you want to see the fully processed nm output after '
+ 'the symbols have been mapped to source locations, or if '
+ 'you plan to run explain_binary_size_delta.py. By default '
+ 'the file \'nm.out\' is placed alongside the generated '
+ 'report. The nm.out file is only created when using '
+ '--library.')
+ parser.add_option('--disable-disambiguation', action='store_true',
+ help='disables the disambiguation process altogether,'
+ ' NOTE: this may, depending on your toolchain, produce'
+ ' output with some symbols at the top layer if addr2line'
+ ' could not get the entire source path.')
+ parser.add_option('--source-path', default='./',
+ help='the path to the source code of the output binary, '
+ 'default set to current directory. Used in the'
+ ' disambiguation process.')
+ opts, _args = parser.parse_args()
+
+ if ((not opts.library) and (not opts.nm_in)) or (opts.library and opts.nm_in):
+ parser.error('exactly one of --library or --nm-in is required')
+ if opts.nm_out:
+ print >> sys.stderr, ('WARNING: --nm-out is deprecated and has no effect.')
+ if (opts.nm_in):
+ if opts.jobs:
+ print >> sys.stderr, ('WARNING: --jobs has no effect '
+ 'when used with --nm-in')
+ if not opts.destdir:
+ parser.error('--destdir is a required argument')
+ if not opts.jobs:
+ # Use the number of processors but cap between 2 and 4 since raw
+ # CPU power isn't the limiting factor. It's I/O limited, memory
+ # bus limited and available-memory-limited. Too many processes and
+ # the computer will run out of memory and it will be slow.
+ opts.jobs = max(2, min(4, str(multiprocessing.cpu_count())))
+
+ if opts.addr2line_binary:
+ assert os.path.isfile(opts.addr2line_binary)
+ addr2line_binary = opts.addr2line_binary
+ else:
+ addr2line_binary = _find_in_system_path('addr2line')
+ assert addr2line_binary, 'Unable to find addr2line in the path. '\
+ 'Use --addr2line-binary to specify location.'
+
+ if opts.nm_binary:
+ assert os.path.isfile(opts.nm_binary)
+ nm_binary = opts.nm_binary
+ else:
+ nm_binary = _find_in_system_path('nm')
+ assert nm_binary, 'Unable to find nm in the path. Use --nm-binary '\
+ 'to specify location.'
+
+ if opts.pak:
+ assert os.path.isfile(opts.pak), 'Could not find ' % opts.pak
+
+ print('addr2line: %s' % addr2line_binary)
+ print('nm: %s' % nm_binary)
+
+ if opts.library:
+ CheckDebugFormatSupport(opts.library, addr2line_binary)
+
+ # Prepare output directory and report guts
+ if not os.path.exists(opts.destdir):
+ os.makedirs(opts.destdir, 0755)
+ nm_out = os.path.join(opts.destdir, 'nm.out')
+ if opts.no_nm_out:
+ nm_out = None
+
+ # Copy report boilerplate into output directory. This also proves that the
+ # output directory is safe for writing, so there should be no problems writing
+ # the nm.out file later.
+ data_js_file_name = os.path.join(opts.destdir, 'data.js')
+ d3_out = os.path.join(opts.destdir, 'd3')
+ if not os.path.exists(d3_out):
+ os.makedirs(d3_out, 0755)
+ d3_src = os.path.join(os.path.dirname(__file__),
+ '..',
+ '..',
+ 'd3', 'src')
+ template_src = os.path.join(os.path.dirname(__file__),
+ 'template')
+ shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
+ shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
+ shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir)
+ shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir)
+
+ # Run nm and/or addr2line to gather the data
+ symbols = GetNmSymbols(opts.nm_in, nm_out, opts.library,
+ opts.jobs, opts.verbose is True,
+ addr2line_binary, nm_binary,
+ opts.disable_disambiguation is None,
+ opts.source_path)
+
+ # Post-processing
+ if opts.pak:
+ AddPakData(symbols, opts.pak)
+ if opts.library:
+ symbol_path_origin_dir = os.path.dirname(os.path.abspath(opts.library))
+ else:
+ # Just a guess. Hopefully all paths in the input file are absolute.
+ symbol_path_origin_dir = os.path.abspath(os.getcwd())
+ # Dump JSON for the HTML report.
+ DumpCompactTree(symbols, symbol_path_origin_dir, data_js_file_name)
+ print 'Report saved to ' + opts.destdir + '/index.html'
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js b/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js
new file mode 100644
index 0000000..4bbe82f
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/D3SymbolTreeMap.js
@@ -0,0 +1,938 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO:
+// 1. Visibility functions: base on boxPadding.t, not 15
+// 2. Track a maxDisplayDepth that is user-settable:
+// maxDepth == currentRoot.depth + maxDisplayDepth
+function D3SymbolTreeMap(mapWidth, mapHeight, levelsToShow) {
+ this._mapContainer = undefined;
+ this._mapWidth = mapWidth;
+ this._mapHeight = mapHeight;
+ this.boxPadding = {'l': 5, 'r': 5, 't': 20, 'b': 5};
+ this.infobox = undefined;
+ this._maskContainer = undefined;
+ this._highlightContainer = undefined;
+ // Transition in this order:
+ // 1. Exiting items go away.
+ // 2. Updated items move.
+ // 3. New items enter.
+ this._exitDuration=500;
+ this._updateDuration=500;
+ this._enterDuration=500;
+ this._firstTransition=true;
+ this._layout = undefined;
+ this._currentRoot = undefined;
+ this._currentNodes = undefined;
+ this._treeData = undefined;
+ this._maxLevelsToShow = levelsToShow;
+ this._currentMaxDepth = this._maxLevelsToShow;
+}
+
+/**
+ * Make a number pretty, with comma separators.
+ */
+D3SymbolTreeMap._pretty = function(num) {
+ var asString = String(num);
+ var result = '';
+ var counter = 0;
+ for (var x = asString.length - 1; x >= 0; x--) {
+ counter++;
+ if (counter === 4) {
+ result = ',' + result;
+ counter = 1;
+ }
+ result = asString.charAt(x) + result;
+ }
+ return result;
+}
+
+/**
+ * Express a number in terms of KiB, MiB, GiB, etc.
+ * Note that these are powers of 2, not of 10.
+ */
+D3SymbolTreeMap._byteify = function(num) {
+ var suffix;
+ if (num >= 1024) {
+ if (num >= 1024 * 1024 * 1024) {
+ suffix = 'GiB';
+ num = num / (1024 * 1024 * 1024);
+ } else if (num >= 1024 * 1024) {
+ suffix = 'MiB';
+ num = num / (1024 * 1024);
+ } else if (num >= 1024) {
+ suffix = 'KiB'
+ num = num / 1024;
+ }
+ return num.toFixed(2) + ' ' + suffix;
+ }
+ return num + ' B';
+}
+
+D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS = {
+ // Definitions concisely derived from the nm 'man' page
+ 'A': 'Global absolute (A)',
+ 'B': 'Global uninitialized data (B)',
+ 'b': 'Local uninitialized data (b)',
+ 'C': 'Global uninitialized common (C)',
+ 'D': 'Global initialized data (D)',
+ 'd': 'Local initialized data (d)',
+ 'G': 'Global small initialized data (G)',
+ 'g': 'Local small initialized data (g)',
+ 'i': 'Indirect function (i)',
+ 'N': 'Debugging (N)',
+ 'p': 'Stack unwind (p)',
+ 'R': 'Global read-only data (R)',
+ 'r': 'Local read-only data (r)',
+ 'S': 'Global small uninitialized data (S)',
+ 's': 'Local small uninitialized data (s)',
+ 'T': 'Global code (T)',
+ 't': 'Local code (t)',
+ 'U': 'Undefined (U)',
+ 'u': 'Unique (u)',
+ 'V': 'Global weak object (V)',
+ 'v': 'Local weak object (v)',
+ 'W': 'Global weak symbol (W)',
+ 'w': 'Local weak symbol (w)',
+ '@': 'Vtable entry (@)', // non-standard, hack.
+ '-': 'STABS debugging (-)',
+ '?': 'Unrecognized (?)',
+};
+D3SymbolTreeMap._NM_SYMBOL_TYPES = '';
+for (var symbol_type in D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS) {
+ D3SymbolTreeMap._NM_SYMBOL_TYPES += symbol_type;
+}
+
+/**
+ * Given a symbol type code, look up and return a human-readable description
+ * of that symbol type. If the symbol type does not match one of the known
+ * types, the unrecognized description (corresponding to symbol type '?') is
+ * returned instead of null or undefined.
+ */
+D3SymbolTreeMap._getSymbolDescription = function(type) {
+ var result = D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS[type];
+ if (result === undefined) {
+ result = D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS['?'];
+ }
+ return result;
+}
+
+// Qualitative 12-value pastel Brewer palette.
+D3SymbolTreeMap._colorArray = [
+ 'rgb(141,211,199)',
+ 'rgb(255,255,179)',
+ 'rgb(190,186,218)',
+ 'rgb(251,128,114)',
+ 'rgb(128,177,211)',
+ 'rgb(253,180,98)',
+ 'rgb(179,222,105)',
+ 'rgb(252,205,229)',
+ 'rgb(217,217,217)',
+ 'rgb(188,128,189)',
+ 'rgb(204,235,197)',
+ 'rgb(255,237,111)'];
+
+D3SymbolTreeMap._initColorMap = function() {
+ var map = {};
+ var numColors = D3SymbolTreeMap._colorArray.length;
+ var count = 0;
+ for (var key in D3SymbolTreeMap._NM_SYMBOL_TYPE_DESCRIPTIONS) {
+ var index = count++ % numColors;
+ map[key] = d3.rgb(D3SymbolTreeMap._colorArray[index]);
+ }
+ D3SymbolTreeMap._colorMap = map;
+}
+D3SymbolTreeMap._initColorMap();
+
+D3SymbolTreeMap.getColorForType = function(type) {
+ var result = D3SymbolTreeMap._colorMap[type];
+ if (result === undefined) return d3.rgb('rgb(255,255,255)');
+ return result;
+}
+
+D3SymbolTreeMap.prototype.init = function() {
+ this.infobox = this._createInfoBox();
+ this._mapContainer = d3.select('body').append('div')
+ .style('position', 'relative')
+ .style('width', this._mapWidth)
+ .style('height', this._mapHeight)
+ .style('padding', 0)
+ .style('margin', 0)
+ .style('box-shadow', '5px 5px 5px #888');
+ this._layout = this._createTreeMapLayout();
+ this._setData(tree_data); // TODO: Don't use global 'tree_data'
+}
+
+/**
+ * Sets the data displayed by the treemap and layint out the map.
+ */
+D3SymbolTreeMap.prototype._setData = function(data) {
+ this._treeData = data;
+ console.time('_crunchStats');
+ this._crunchStats(data);
+ console.timeEnd('_crunchStats');
+ this._currentRoot = this._treeData;
+ this._currentNodes = this._layout.nodes(this._currentRoot);
+ this._currentMaxDepth = this._maxLevelsToShow;
+ this._doLayout();
+}
+
+/**
+ * Recursively traverses the entire tree starting from the specified node,
+ * computing statistics and recording metadata as it goes. Call this method
+ * only once per imported tree.
+ */
+D3SymbolTreeMap.prototype._crunchStats = function(node) {
+ var stack = [];
+ stack.idCounter = 0;
+ this._crunchStatsHelper(stack, node);
+}
+
+/**
+ * Invoke the specified visitor function on all data elements currently shown
+ * in the treemap including any and all of their children, starting at the
+ * currently-displayed root and descening recursively. The function will be
+ * passed the datum element representing each node. No traversal guarantees
+ * are made.
+ */
+D3SymbolTreeMap.prototype.visitFromDisplayedRoot = function(visitor) {
+ this._visit(this._currentRoot, visitor);
+}
+
+/**
+ * Helper function for visit functions.
+ */
+D3SymbolTreeMap.prototype._visit = function(datum, visitor) {
+ visitor.call(this, datum);
+ if (datum.children) for (var i = 0; i < datum.children.length; i++) {
+ this._visit(datum.children[i], visitor);
+ }
+}
+
+D3SymbolTreeMap.prototype._crunchStatsHelper = function(stack, node) {
+ // Only overwrite the node ID if it isn't already set.
+ // This allows stats to be crunched multiple times on subsets of data
+ // without breaking the data-to-ID bindings. New nodes get new IDs.
+ if (node.id === undefined) node.id = stack.idCounter++;
+ if (node.children === undefined) {
+ // Leaf node (symbol); accumulate stats.
+ for (var i = 0; i < stack.length; i++) {
+ var ancestor = stack[i];
+ if (!ancestor.symbol_stats) ancestor.symbol_stats = {};
+ if (ancestor.symbol_stats[node.t] === undefined) {
+ // New symbol type we haven't seen before, just record.
+ ancestor.symbol_stats[node.t] = {'count': 1,
+ 'size': node.value};
+ } else {
+ // Existing symbol type, increment.
+ ancestor.symbol_stats[node.t].count++;
+ ancestor.symbol_stats[node.t].size += node.value;
+ }
+ }
+ } else for (var i = 0; i < node.children.length; i++) {
+ stack.push(node);
+ this._crunchStatsHelper(stack, node.children[i]);
+ stack.pop();
+ }
+}
+
+D3SymbolTreeMap.prototype._createTreeMapLayout = function() {
+ var result = d3.layout.treemap()
+ .padding([this.boxPadding.t, this.boxPadding.r,
+ this.boxPadding.b, this.boxPadding.l])
+ .size([this._mapWidth, this._mapHeight]);
+ return result;
+}
+
+D3SymbolTreeMap.prototype.resize = function(width, height) {
+ this._mapWidth = width;
+ this._mapHeight = height;
+ this._mapContainer.style('width', width).style('height', height);
+ this._layout.size([this._mapWidth, this._mapHeight]);
+ this._currentNodes = this._layout.nodes(this._currentRoot);
+ this._doLayout();
+}
+
+D3SymbolTreeMap.prototype._zoomDatum = function(datum) {
+ if (this._currentRoot === datum) return; // already here
+ this._hideHighlight(datum);
+ this._hideInfoBox(datum);
+ this._currentRoot = datum;
+ this._currentNodes = this._layout.nodes(this._currentRoot);
+ this._currentMaxDepth = this._currentRoot.depth + this._maxLevelsToShow;
+ console.log('zooming into datum ' + this._currentRoot.n);
+ this._doLayout();
+}
+
+D3SymbolTreeMap.prototype.setMaxLevels = function(levelsToShow) {
+ this._maxLevelsToShow = levelsToShow;
+ this._currentNodes = this._layout.nodes(this._currentRoot);
+ this._currentMaxDepth = this._currentRoot.depth + this._maxLevelsToShow;
+ console.log('setting max levels to show: ' + this._maxLevelsToShow);
+ this._doLayout();
+}
+
+/**
+ * Clone the specified tree, returning an independent copy of the data.
+ * Only the original attributes expected to exist prior to invoking
+ * _crunchStatsHelper are retained, with the exception of the 'id' attribute
+ * (which must be retained for proper transitions).
+ * If the optional filter parameter is provided, it will be called with 'this'
+ * set to this treemap instance and passed the 'datum' object as an argument.
+ * When specified, the copy will retain only the data for which the filter
+ * function returns true.
+ */
+D3SymbolTreeMap.prototype._clone = function(datum, filter) {
+ var trackingStats = false;
+ if (this.__cloneState === undefined) {
+ console.time('_clone');
+ trackingStats = true;
+ this.__cloneState = {'accepted': 0, 'rejected': 0,
+ 'forced': 0, 'pruned': 0};
+ }
+
+ // Must go depth-first. All parents of children that are accepted by the
+ // filter must be preserved!
+ var copy = {'n': datum.n, 'k': datum.k};
+ var childAccepted = false;
+ if (datum.children !== undefined) {
+ for (var i = 0; i < datum.children.length; i++) {
+ var copiedChild = this._clone(datum.children[i], filter);
+ if (copiedChild !== undefined) {
+ childAccepted = true; // parent must also be accepted.
+ if (copy.children === undefined) copy.children = [];
+ copy.children.push(copiedChild);
+ }
+ }
+ }
+
+ // Ignore nodes that don't match the filter, when present.
+ var accept = false;
+ if (childAccepted) {
+ // Parent of an accepted child must also be accepted.
+ this.__cloneState.forced++;
+ accept = true;
+ } else if (filter !== undefined && filter.call(this, datum) !== true) {
+ this.__cloneState.rejected++;
+ } else if (datum.children === undefined) {
+ // Accept leaf nodes that passed the filter
+ this.__cloneState.accepted++;
+ accept = true;
+ } else {
+ // Non-leaf node. If no children are accepted, prune it.
+ this.__cloneState.pruned++;
+ }
+
+ if (accept) {
+ if (datum.id !== undefined) copy.id = datum.id;
+ if (datum.lastPathElement !== undefined) {
+ copy.lastPathElement = datum.lastPathElement;
+ }
+ if (datum.t !== undefined) copy.t = datum.t;
+ if (datum.value !== undefined && datum.children === undefined) {
+ copy.value = datum.value;
+ }
+ } else {
+ // Discard the copy we were going to return
+ copy = undefined;
+ }
+
+ if (trackingStats === true) {
+ // We are the fist call in the recursive chain.
+ console.timeEnd('_clone');
+ var totalAccepted = this.__cloneState.accepted +
+ this.__cloneState.forced;
+ console.log(
+ totalAccepted + ' nodes retained (' +
+ this.__cloneState.forced + ' forced by accepted children, ' +
+ this.__cloneState.accepted + ' accepted on their own merits), ' +
+ this.__cloneState.rejected + ' nodes (and their children) ' +
+ 'filtered out,' +
+ this.__cloneState.pruned + ' nodes pruned because because no ' +
+ 'children remained.');
+ delete this.__cloneState;
+ }
+ return copy;
+}
+
+D3SymbolTreeMap.prototype.filter = function(filter) {
+ // Ensure we have a copy of the original root.
+ if (this._backupTree === undefined) this._backupTree = this._treeData;
+ this._mapContainer.selectAll('div').remove();
+ this._setData(this._clone(this._backupTree, filter));
+}
+
+D3SymbolTreeMap.prototype._doLayout = function() {
+ console.time('_doLayout');
+ this._handleInodes();
+ this._handleLeaves();
+ this._firstTransition = false;
+ console.timeEnd('_doLayout');
+}
+
+D3SymbolTreeMap.prototype._highlightElement = function(datum, selection) {
+ this._showHighlight(datum, selection);
+}
+
+D3SymbolTreeMap.prototype._unhighlightElement = function(datum, selection) {
+ this._hideHighlight(datum, selection);
+}
+
+D3SymbolTreeMap.prototype._handleInodes = function() {
+ console.time('_handleInodes');
+ var thisTreeMap = this;
+ var inodes = this._currentNodes.filter(function(datum){
+ return (datum.depth <= thisTreeMap._currentMaxDepth) &&
+ datum.children !== undefined;
+ });
+ var cellsEnter = this._mapContainer.selectAll('div.inode')
+ .data(inodes, function(datum) { return datum.id; })
+ .enter()
+ .append('div').attr('class', 'inode').attr('id', function(datum){
+ return 'node-' + datum.id;});
+
+
+ // Define enter/update/exit for inodes
+ cellsEnter
+ .append('div')
+ .attr('class', 'rect inode_rect_entering')
+ .style('z-index', function(datum) { return datum.id * 2; })
+ .style('position', 'absolute')
+ .style('left', function(datum) { return datum.x; })
+ .style('top', function(datum){ return datum.y; })
+ .style('width', function(datum){ return datum.dx; })
+ .style('height', function(datum){ return datum.dy; })
+ .style('opacity', '0')
+ .style('border', '1px solid black')
+ .style('background-image', function(datum) {
+ return thisTreeMap._makeSymbolBucketBackgroundImage.call(
+ thisTreeMap, datum);
+ })
+ .style('background-color', function(datum) {
+ if (datum.t === undefined) return 'rgb(220,220,220)';
+ return D3SymbolTreeMap.getColorForType(datum.t).toString();
+ })
+ .on('mouseover', function(datum){
+ thisTreeMap._highlightElement.call(
+ thisTreeMap, datum, d3.select(this));
+ thisTreeMap._showInfoBox.call(thisTreeMap, datum);
+ })
+ .on('mouseout', function(datum){
+ thisTreeMap._unhighlightElement.call(
+ thisTreeMap, datum, d3.select(this));
+ thisTreeMap._hideInfoBox.call(thisTreeMap, datum);
+ })
+ .on('mousemove', function(){
+ thisTreeMap._moveInfoBox.call(thisTreeMap, event);
+ })
+ .on('dblclick', function(datum){
+ if (datum !== thisTreeMap._currentRoot) {
+ // Zoom into the selection
+ thisTreeMap._zoomDatum(datum);
+ } else if (datum.parent) {
+ console.log('event.shiftKey=' + event.shiftKey);
+ if (event.shiftKey === true) {
+ // Back to root
+ thisTreeMap._zoomDatum(thisTreeMap._treeData);
+ } else {
+ // Zoom out of the selection
+ thisTreeMap._zoomDatum(datum.parent);
+ }
+ }
+ });
+ cellsEnter
+ .append('div')
+ .attr('class', 'label inode_label_entering')
+ .style('z-index', function(datum) { return (datum.id * 2) + 1; })
+ .style('position', 'absolute')
+ .style('left', function(datum){ return datum.x; })
+ .style('top', function(datum){ return datum.y; })
+ .style('width', function(datum) { return datum.dx; })
+ .style('height', function(datum) { return thisTreeMap.boxPadding.t; })
+ .style('opacity', '0')
+ .style('pointer-events', 'none')
+ .style('-webkit-user-select', 'none')
+ .style('overflow', 'hidden') // required for ellipsis
+ .style('white-space', 'nowrap') // required for ellipsis
+ .style('text-overflow', 'ellipsis')
+ .style('text-align', 'center')
+ .style('vertical-align', 'top')
+ .style('visibility', function(datum) {
+ return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+ })
+ .text(function(datum) {
+ var sizeish = ' [' + D3SymbolTreeMap._byteify(datum.value) + ']'
+ var text;
+ if (datum.k === 'b') { // bucket
+ if (datum === thisTreeMap._currentRoot) {
+ text = thisTreeMap.pathFor(datum) + ': '
+ + D3SymbolTreeMap._getSymbolDescription(datum.t)
+ } else {
+ text = D3SymbolTreeMap._getSymbolDescription(datum.t);
+ }
+ } else if (datum === thisTreeMap._currentRoot) {
+ // The top-most level should always show the complete path
+ text = thisTreeMap.pathFor(datum);
+ } else {
+ // Anything that isn't a bucket or a leaf (symbol) or the
+ // current root should just show its name.
+ text = datum.n;
+ }
+ return text + sizeish;
+ }
+ );
+
+ // Complicated transition logic:
+ // For nodes that are entering, we want to fade them in in-place AFTER
+ // any adjusting nodes have resized and moved around. That way, new nodes
+ // seamlessly appear in the right spot after their containers have resized
+ // and moved around.
+ // To do this we do some trickery:
+ // 1. Define a '_entering' class on the entering elements
+ // 2. Use this to select only the entering elements and apply the opacity
+ // transition.
+ // 3. Use the same transition to drop the '_entering' suffix, so that they
+ // will correctly update in later zoom/resize/whatever operations.
+ // 4. The update transition is achieved by selecting the elements without
+ // the '_entering_' suffix and applying movement and resizing transition
+ // effects.
+ this._mapContainer.selectAll('div.inode_rect_entering').transition()
+ .duration(thisTreeMap._enterDuration).delay(
+ this._firstTransition ? 0 : thisTreeMap._exitDuration +
+ thisTreeMap._updateDuration)
+ .attr('class', 'rect inode_rect')
+ .style('opacity', '1')
+ this._mapContainer.selectAll('div.inode_label_entering').transition()
+ .duration(thisTreeMap._enterDuration).delay(
+ this._firstTransition ? 0 : thisTreeMap._exitDuration +
+ thisTreeMap._updateDuration)
+ .attr('class', 'label inode_label')
+ .style('opacity', '1')
+ this._mapContainer.selectAll('div.inode_rect').transition()
+ .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+ .style('opacity', '1')
+ .style('background-image', function(datum) {
+ return thisTreeMap._makeSymbolBucketBackgroundImage.call(
+ thisTreeMap, datum);
+ })
+ .style('left', function(datum) { return datum.x; })
+ .style('top', function(datum){ return datum.y; })
+ .style('width', function(datum){ return datum.dx; })
+ .style('height', function(datum){ return datum.dy; });
+ this._mapContainer.selectAll('div.inode_label').transition()
+ .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+ .style('opacity', '1')
+ .style('visibility', function(datum) {
+ return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+ })
+ .style('left', function(datum){ return datum.x; })
+ .style('top', function(datum){ return datum.y; })
+ .style('width', function(datum) { return datum.dx; })
+ .style('height', function(datum) { return thisTreeMap.boxPadding.t; })
+ .text(function(datum) {
+ var sizeish = ' [' + D3SymbolTreeMap._byteify(datum.value) + ']'
+ var text;
+ if (datum.k === 'b') {
+ if (datum === thisTreeMap._currentRoot) {
+ text = thisTreeMap.pathFor(datum) + ': ' +
+ D3SymbolTreeMap._getSymbolDescription(datum.t)
+ } else {
+ text = D3SymbolTreeMap._getSymbolDescription(datum.t);
+ }
+ } else if (datum === thisTreeMap._currentRoot) {
+ // The top-most level should always show the complete path
+ text = thisTreeMap.pathFor(datum);
+ } else {
+ // Anything that isn't a bucket or a leaf (symbol) or the
+ // current root should just show its name.
+ text = datum.n;
+ }
+ return text + sizeish;
+ });
+ var exit = this._mapContainer.selectAll('div.inode')
+ .data(inodes, function(datum) { return 'inode-' + datum.id; })
+ .exit();
+ exit.selectAll('div.inode_rect').transition().duration(
+ thisTreeMap._exitDuration).style('opacity', 0);
+ exit.selectAll('div.inode_label').transition().duration(
+ thisTreeMap._exitDuration).style('opacity', 0);
+ exit.transition().delay(thisTreeMap._exitDuration + 1).remove();
+
+ console.log(inodes.length + ' inodes layed out.');
+ console.timeEnd('_handleInodes');
+}
+
+D3SymbolTreeMap.prototype._handleLeaves = function() {
+ console.time('_handleLeaves');
+ var color_fn = d3.scale.category10();
+ var thisTreeMap = this;
+ var leaves = this._currentNodes.filter(function(datum){
+ return (datum.depth <= thisTreeMap._currentMaxDepth) &&
+ datum.children === undefined; });
+ var cellsEnter = this._mapContainer.selectAll('div.leaf')
+ .data(leaves, function(datum) { return datum.id; })
+ .enter()
+ .append('div').attr('class', 'leaf').attr('id', function(datum){
+ return 'node-' + datum.id;
+ });
+
+ // Define enter/update/exit for leaves
+ cellsEnter
+ .append('div')
+ .attr('class', 'rect leaf_rect_entering')
+ .style('z-index', function(datum) { return datum.id * 2; })
+ .style('position', 'absolute')
+ .style('left', function(datum){ return datum.x; })
+ .style('top', function(datum){ return datum.y; })
+ .style('width', function(datum){ return datum.dx; })
+ .style('height', function(datum){ return datum.dy; })
+ .style('opacity', '0')
+ .style('background-color', function(datum) {
+ if (datum.t === undefined) return 'rgb(220,220,220)';
+ return D3SymbolTreeMap.getColorForType(datum.t)
+ .darker(0.3).toString();
+ })
+ .style('border', '1px solid black')
+ .on('mouseover', function(datum){
+ thisTreeMap._highlightElement.call(
+ thisTreeMap, datum, d3.select(this));
+ thisTreeMap._showInfoBox.call(thisTreeMap, datum);
+ })
+ .on('mouseout', function(datum){
+ thisTreeMap._unhighlightElement.call(
+ thisTreeMap, datum, d3.select(this));
+ thisTreeMap._hideInfoBox.call(thisTreeMap, datum);
+ })
+ .on('mousemove', function(){ thisTreeMap._moveInfoBox.call(
+ thisTreeMap, event);
+ });
+ cellsEnter
+ .append('div')
+ .attr('class', 'label leaf_label_entering')
+ .style('z-index', function(datum) { return (datum.id * 2) + 1; })
+ .style('position', 'absolute')
+ .style('left', function(datum){ return datum.x; })
+ .style('top', function(datum){ return datum.y; })
+ .style('width', function(datum) { return datum.dx; })
+ .style('height', function(datum) { return datum.dy; })
+ .style('opacity', '0')
+ .style('pointer-events', 'none')
+ .style('-webkit-user-select', 'none')
+ .style('overflow', 'hidden') // required for ellipsis
+ .style('white-space', 'nowrap') // required for ellipsis
+ .style('text-overflow', 'ellipsis')
+ .style('text-align', 'center')
+ .style('vertical-align', 'middle')
+ .style('visibility', function(datum) {
+ return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+ })
+ .text(function(datum) { return datum.n; });
+
+ // Complicated transition logic: See note in _handleInodes()
+ this._mapContainer.selectAll('div.leaf_rect_entering').transition()
+ .duration(thisTreeMap._enterDuration).delay(
+ this._firstTransition ? 0 : thisTreeMap._exitDuration +
+ thisTreeMap._updateDuration)
+ .attr('class', 'rect leaf_rect')
+ .style('opacity', '1')
+ this._mapContainer.selectAll('div.leaf_label_entering').transition()
+ .duration(thisTreeMap._enterDuration).delay(
+ this._firstTransition ? 0 : thisTreeMap._exitDuration +
+ thisTreeMap._updateDuration)
+ .attr('class', 'label leaf_label')
+ .style('opacity', '1')
+ this._mapContainer.selectAll('div.leaf_rect').transition()
+ .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+ .style('opacity', '1')
+ .style('left', function(datum){ return datum.x; })
+ .style('top', function(datum){ return datum.y; })
+ .style('width', function(datum){ return datum.dx; })
+ .style('height', function(datum){ return datum.dy; });
+ this._mapContainer.selectAll('div.leaf_label').transition()
+ .duration(thisTreeMap._updateDuration).delay(thisTreeMap._exitDuration)
+ .style('opacity', '1')
+ .style('visibility', function(datum) {
+ return (datum.dx < 15 || datum.dy < 15) ? 'hidden' : 'visible';
+ })
+ .style('left', function(datum){ return datum.x; })
+ .style('top', function(datum){ return datum.y; })
+ .style('width', function(datum) { return datum.dx; })
+ .style('height', function(datum) { return datum.dy; });
+ var exit = this._mapContainer.selectAll('div.leaf')
+ .data(leaves, function(datum) { return 'leaf-' + datum.id; })
+ .exit();
+ exit.selectAll('div.leaf_rect').transition()
+ .duration(thisTreeMap._exitDuration)
+ .style('opacity', 0);
+ exit.selectAll('div.leaf_label').transition()
+ .duration(thisTreeMap._exitDuration)
+ .style('opacity', 0);
+ exit.transition().delay(thisTreeMap._exitDuration + 1).remove();
+
+ console.log(leaves.length + ' leaves layed out.');
+ console.timeEnd('_handleLeaves');
+}
+
+D3SymbolTreeMap.prototype._makeSymbolBucketBackgroundImage = function(datum) {
+ if (!(datum.t === undefined && datum.depth == this._currentMaxDepth)) {
+ return 'none';
+ }
+ var text = '';
+ var lastStop = 0;
+ for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+ symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+ var stats = datum.symbol_stats[symbol_type];
+ if (stats !== undefined) {
+ if (text.length !== 0) {
+ text += ', ';
+ }
+ var percent = 100 * (stats.size / datum.value);
+ var nowStop = lastStop + percent;
+ var tempcolor = D3SymbolTreeMap.getColorForType(symbol_type);
+ var color = d3.rgb(tempcolor).toString();
+ text += color + ' ' + lastStop + '%, ' + color + ' ' +
+ nowStop + '%';
+ lastStop = nowStop;
+ }
+ }
+ return 'linear-gradient(' + (datum.dx > datum.dy ? 'to right' :
+ 'to bottom') + ', ' + text + ')';
+}
+
+D3SymbolTreeMap.prototype.pathFor = function(datum) {
+ if (datum.__path) return datum.__path;
+ parts=[];
+ node = datum;
+ while (node) {
+ if (node.k === 'p') { // path node
+ if(node.n !== '/') parts.unshift(node.n);
+ }
+ node = node.parent;
+ }
+ datum.__path = '/' + parts.join('/');
+ return datum.__path;
+}
+
+D3SymbolTreeMap.prototype._createHighlight = function(datum, selection) {
+ var x = parseInt(selection.style('left'));
+ var y = parseInt(selection.style('top'));
+ var w = parseInt(selection.style('width'));
+ var h = parseInt(selection.style('height'));
+ datum.highlight = this._mapContainer.append('div')
+ .attr('id', 'h-' + datum.id)
+ .attr('class', 'highlight')
+ .style('pointer-events', 'none')
+ .style('-webkit-user-select', 'none')
+ .style('z-index', '999999')
+ .style('position', 'absolute')
+ .style('top', y-2)
+ .style('left', x-2)
+ .style('width', w+4)
+ .style('height', h+4)
+ .style('margin', 0)
+ .style('padding', 0)
+ .style('border', '4px outset rgba(250,40,200,0.9)')
+ .style('box-sizing', 'border-box')
+ .style('opacity', 0.0);
+}
+
+D3SymbolTreeMap.prototype._showHighlight = function(datum, selection) {
+ if (datum === this._currentRoot) return;
+ if (datum.highlight === undefined) {
+ this._createHighlight(datum, selection);
+ }
+ datum.highlight.transition().duration(200).style('opacity', 1.0);
+}
+
+D3SymbolTreeMap.prototype._hideHighlight = function(datum, selection) {
+ if (datum.highlight === undefined) return;
+ datum.highlight.transition().duration(750)
+ .style('opacity', 0)
+ .each('end', function(){
+ if (datum.highlight) datum.highlight.remove();
+ delete datum.highlight;
+ });
+}
+
+D3SymbolTreeMap.prototype._createInfoBox = function() {
+ return d3.select('body')
+ .append('div')
+ .attr('id', 'infobox')
+ .style('z-index', '2147483647') // (2^31) - 1: Hopefully safe :)
+ .style('position', 'absolute')
+ .style('visibility', 'hidden')
+ .style('background-color', 'rgba(255,255,255, 0.9)')
+ .style('border', '1px solid black')
+ .style('padding', '10px')
+ .style('-webkit-user-select', 'none')
+ .style('box-shadow', '3px 3px rgba(70,70,70,0.5)')
+ .style('border-radius', '10px')
+ .style('white-space', 'nowrap');
+}
+
+D3SymbolTreeMap.prototype._showInfoBox = function(datum) {
+ this.infobox.text('');
+ var numSymbols = 0;
+ var sizeish = D3SymbolTreeMap._pretty(datum.value) + ' bytes (' +
+ D3SymbolTreeMap._byteify(datum.value) + ')';
+ if (datum.k === 'p' || datum.k === 'b') { // path or bucket
+ if (datum.symbol_stats) { // can be empty if filters are applied
+ for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+ symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+ var stats = datum.symbol_stats[symbol_type];
+ if (stats !== undefined) numSymbols += stats.count;
+ }
+ }
+ } else if (datum.k === 's') { // symbol
+ numSymbols = 1;
+ }
+
+ if (datum.k === 'p' && !datum.lastPathElement) {
+ this.infobox.append('div').text('Directory: ' + this.pathFor(datum))
+ this.infobox.append('div').text('Size: ' + sizeish);
+ } else {
+ if (datum.k === 'p') { // path
+ this.infobox.append('div').text('File: ' + this.pathFor(datum))
+ this.infobox.append('div').text('Size: ' + sizeish);
+ } else if (datum.k === 'b') { // bucket
+ this.infobox.append('div').text('Symbol Bucket: ' +
+ D3SymbolTreeMap._getSymbolDescription(datum.t));
+ this.infobox.append('div').text('Count: ' + numSymbols);
+ this.infobox.append('div').text('Size: ' + sizeish);
+ this.infobox.append('div').text('Location: ' + this.pathFor(datum))
+ } else if (datum.k === 's') { // symbol
+ this.infobox.append('div').text('Symbol: ' + datum.n);
+ this.infobox.append('div').text('Type: ' +
+ D3SymbolTreeMap._getSymbolDescription(datum.t));
+ this.infobox.append('div').text('Size: ' + sizeish);
+ this.infobox.append('div').text('Location: ' + this.pathFor(datum))
+ }
+ }
+ if (datum.k === 'p') {
+ this.infobox.append('div')
+ .text('Number of symbols: ' + D3SymbolTreeMap._pretty(numSymbols));
+ if (datum.symbol_stats) { // can be empty if filters are applied
+ var table = this.infobox.append('table')
+ .attr('border', 1).append('tbody');
+ var header = table.append('tr');
+ header.append('th').text('Type');
+ header.append('th').text('Count');
+ header.append('th')
+ .style('white-space', 'nowrap')
+ .text('Total Size (Bytes)');
+ for (var x = 0; x < D3SymbolTreeMap._NM_SYMBOL_TYPES.length; x++) {
+ symbol_type = D3SymbolTreeMap._NM_SYMBOL_TYPES.charAt(x);
+ var stats = datum.symbol_stats[symbol_type];
+ if (stats !== undefined) {
+ var tr = table.append('tr');
+ tr.append('td')
+ .style('white-space', 'nowrap')
+ .text(D3SymbolTreeMap._getSymbolDescription(
+ symbol_type));
+ tr.append('td').text(D3SymbolTreeMap._pretty(stats.count));
+ tr.append('td').text(D3SymbolTreeMap._pretty(stats.size));
+ }
+ }
+ }
+ }
+ this.infobox.style('visibility', 'visible');
+}
+
+D3SymbolTreeMap.prototype._hideInfoBox = function(datum) {
+ this.infobox.style('visibility', 'hidden');
+}
+
+D3SymbolTreeMap.prototype._moveInfoBox = function(event) {
+ var element = document.getElementById('infobox');
+ var w = element.offsetWidth;
+ var h = element.offsetHeight;
+ var offsetLeft = 10;
+ var offsetTop = 10;
+
+ var rightLimit = window.innerWidth;
+ var rightEdge = event.pageX + offsetLeft + w;
+ if (rightEdge > rightLimit) {
+ // Too close to screen edge, reflect around the cursor
+ offsetLeft = -1 * (w + offsetLeft);
+ }
+
+ var bottomLimit = window.innerHeight;
+ var bottomEdge = event.pageY + offsetTop + h;
+ if (bottomEdge > bottomLimit) {
+ // Too close ot screen edge, reflect around the cursor
+ offsetTop = -1 * (h + offsetTop);
+ }
+
+ this.infobox.style('top', (event.pageY + offsetTop) + 'px')
+ .style('left', (event.pageX + offsetLeft) + 'px');
+}
+
+D3SymbolTreeMap.prototype.biggestSymbols = function(maxRecords) {
+ var result = undefined;
+ var smallest = undefined;
+ var sortFunction = function(a,b) {
+ var result = b.value - a.value;
+ if (result !== 0) return result; // sort by size
+ var pathA = treemap.pathFor(a); // sort by path
+ var pathB = treemap.pathFor(b);
+ if (pathA > pathB) return 1;
+ if (pathB > pathA) return -1;
+ return a.n - b.n; // sort by symbol name
+ };
+ this.visitFromDisplayedRoot(function(datum) {
+ if (datum.children) return; // ignore non-leaves
+ if (!result) { // first element
+ result = [datum];
+ smallest = datum.value;
+ return;
+ }
+ if (result.length < maxRecords) { // filling the array
+ result.push(datum);
+ return;
+ }
+ if (datum.value > smallest) { // array is already full
+ result.push(datum);
+ result.sort(sortFunction);
+ result.pop(); // get rid of smallest element
+ smallest = result[maxRecords - 1].value; // new threshold for entry
+ }
+ });
+ result.sort(sortFunction);
+ return result;
+}
+
+D3SymbolTreeMap.prototype.biggestPaths = function(maxRecords) {
+ var result = undefined;
+ var smallest = undefined;
+ var sortFunction = function(a,b) {
+ var result = b.value - a.value;
+ if (result !== 0) return result; // sort by size
+ var pathA = treemap.pathFor(a); // sort by path
+ var pathB = treemap.pathFor(b);
+ if (pathA > pathB) return 1;
+ if (pathB > pathA) return -1;
+ console.log('warning, multiple entries for the same path: ' + pathA);
+ return 0; // should be impossible
+ };
+ this.visitFromDisplayedRoot(function(datum) {
+ if (!datum.lastPathElement) return; // ignore non-files
+ if (!result) { // first element
+ result = [datum];
+ smallest = datum.value;
+ return;
+ }
+ if (result.length < maxRecords) { // filling the array
+ result.push(datum);
+ return;
+ }
+ if (datum.value > smallest) { // array is already full
+ result.push(datum);
+ result.sort(sortFunction);
+ result.pop(); // get rid of smallest element
+ smallest = result[maxRecords - 1].value; // new threshold for entry
+ }
+ });
+ result.sort(sortFunction);
+ return result;
+}
diff --git a/runtime/third_party/binary_size/src/template/index.html b/runtime/third_party/binary_size/src/template/index.html
new file mode 100644
index 0000000..7e1a1fc
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/index.html
@@ -0,0 +1,525 @@
+<!--
+ Copyright 2014 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+<html>
+<head>
+<title>Binary Size Analysis</title>
+<script src="d3/d3.js" charset="utf-8"></script>
+<script src="D3SymbolTreeMap.js" charset="utf-8"></script>
+<script src="data.js" charset="utf-8"></script>
+<style>
+body {
+ margin: 0px;
+ padding: 5px;
+}
+.swatch {
+ border: 1px solid rgb(100,100,100);
+ -webkit-user-select: none;
+ cursor: default;
+}
+</style>
+<script>
+var treemap;
+var filterChanging = false;
+var savedSettings = {};
+
+function init() {
+ if (window.metadata !== undefined && window.metadata.subtitle) {
+ document.getElementById('subtitle').innerHTML = ': ' + escape(metadata.subtitle);
+ }
+ initFilterOptions();
+ treemap = new D3SymbolTreeMap(
+ savedSettings.width,
+ savedSettings.height,
+ savedSettings.maxLevels);
+ treemap.init();
+}
+
+function getIdealSizes() {
+ var width = window.innerWidth - 20;
+ var height = window.innerHeight - 70;
+ return {'width': width, 'height': height};
+}
+
+function showReport(title, data, headers, dataFunction, styleFunction) {
+ var div = d3.select('body').append('div')
+ .style('margin', '0')
+ .style('padding', '5px')
+ .style('position', 'absolute')
+ .style('top', '10%')
+ .style('left', '10%')
+ .style('background-color', 'rgba(255,255,255,0.9)')
+ .style('width', '80%')
+ .style('height', '80%')
+ .style('z-index', '2147483647')
+ .style('border', '3px ridge grey')
+ .style('box-shadow', '10px 10px 5px rgba(80,80,80,0.7)')
+ .style('text-align', 'center')
+ .style('border-radius', '10px');
+ var titlebar = div.append('div')
+ .style('margin', '0')
+ .style('padding', '5px')
+ .style('position', 'absolute')
+ .style('top', '0%')
+ .style('left', '0%')
+ .style('width', '100%')
+ .style('height', '10%')
+ .style('font-size', 'x-large');
+ titlebar.text(title);
+ var controls = div.append('div')
+ .style('margin', '0')
+ .style('padding', '5px')
+ .style('position', 'absolute')
+ .style('top', '90%')
+ .style('left', '0%')
+ .style('width', '100%')
+ .style('height', '10%');
+ controls.append('input').attr('type', 'button')
+ .attr('value', 'Dismiss')
+ .on('click', function(){div.remove();});
+
+ var tableDiv = div.append('div')
+ .style('overflow', 'auto')
+ .style('position', 'absolute')
+ .style('top', '10%')
+ .style('left', '0%')
+ .style('width', '100%')
+ .style('height', '80%')
+ .style('border-top', '1px solid rgb(230,230,230)')
+ .style('border-bottom', '1px solid rgb(230,230,230)');
+ var table = tableDiv.append('table')
+ .attr('border', '1')
+ .attr('cellspacing', '0')
+ .attr('cellpadding', '2')
+ .style('margin-left', 'auto')
+ .style('margin-right', 'auto');
+ var header = table.append('tr');
+ for (var i = 0; i < headers.length; i++) {
+ header.append('th').text(headers[i]);
+ }
+
+ for (var i = 0; i < data.length; i++) {
+ var row = table.append('tr');
+ for (j = 0; j < headers.length; j++) {
+ var td = row.append('td');
+ if (styleFunction) {
+ styleFunction.call(this, td, j);
+ }
+ dataFunction.call(this, data[i], j, td);
+ }
+ }
+}
+
+function bigSymbolsReport() {
+ var list = treemap.biggestSymbols(100);
+ var headers = ['Rank', 'Size (Bytes)', 'Type', 'Location'];
+ var styleFunction = function(selection, index) {
+ if (index === 3) {
+ selection.style('font-family', 'monospace');
+ }
+ };
+ var recordIndex = 1;
+ var dataFunction = function(record, index, cell) {
+ if (index === 0) {
+ cell.text(recordIndex++);
+ } else if (index === 1) {
+ cell.text(D3SymbolTreeMap._pretty(record.value));
+ } else if (index === 2) {
+ cell.text(record.t);
+ } else {
+ if (treemap.pathFor(record).indexOf('/out') == 0) {
+ cell.append('span').text(treemap.pathFor(record));
+ cell.append('br');
+ cell.append('span').text('Symbol: ');
+ cell.append('span').text(record.n);
+ } else {
+ var href = 'https://code.google.com/p/chromium/codesearch#chromium/src'
+ + treemap.pathFor(record)
+ + '&q='
+ + record.n;
+ cell.append('a')
+ .attr('href', href)
+ .attr('target', '_blank')
+ .text(treemap.pathFor(record));
+ cell.append('br');
+ cell.append('span').text('Symbol: ');
+ cell.append('span').text(record.n);
+ }
+ }
+ };
+ showReport('100 Largest Symbols', list, headers, dataFunction, styleFunction);
+}
+
+function bigPathsReport() {
+ var list = treemap.biggestPaths(100);
+ var headers = ['Rank', 'Size (Bytes)', 'Location'];
+ var styleFunction = function(selection, index) {
+ if (index === 2) {
+ selection.style('font-family', 'monospace');
+ }
+ };
+ var recordIndex = 1;
+ var dataFunction = function(record, index, cell) {
+ if (index === 0) {
+ cell.text(recordIndex++);
+ } else if (index === 1) {
+ cell.text(D3SymbolTreeMap._pretty(record.value));
+ } else if (index === 2) {
+ if (treemap.pathFor(record).indexOf('/out') == 0) {
+ cell.text(treemap.pathFor(record));
+ } else {
+ var href = 'https://code.google.com/p/chromium/codesearch#chromium/src' + treemap.pathFor(record);
+ cell.append('a')
+ .attr('href', href)
+ .attr('target', '_blank')
+ .text(treemap.pathFor(record));
+ }
+
+ }
+ };
+ showReport('100 Largest Paths', list, headers, dataFunction, styleFunction);
+}
+
+function symbolFilterTextChanged() {
+ if (filterChanging) return true;
+ filterChanging = true;
+ var enabled = document.getElementById('symbol_types_filter').value;
+ for (var x=0; x<=25; x++) {
+ var checkBox = document.getElementById('check_' + x);
+ checkBox.checked = (enabled.indexOf(checkBox.value) != -1);
+ }
+ filterChanging = false;
+}
+
+function updateFilterText() {
+ if (filterChanging) return true;
+ filterChanging = true;
+ var text = '';
+ for (var x=0; x<=25; x++) {
+ var checkBox = document.getElementById('check_' + x);
+ if (checkBox.checked) {
+ text += checkBox.value;
+ }
+ }
+ document.getElementById('symbol_types_filter').value=text;
+ filterChanging = false;
+}
+
+function initFilterOptions() {
+ updateFilterText();
+ for (var x=0; x<=25; x++) {
+ var checkBox = document.getElementById('check_' + x);
+ checkBox.onchange=updateFilterText;
+ var swatch = document.getElementById('swatch_' + x);
+ swatch.style.backgroundColor = D3SymbolTreeMap.getColorForType(checkBox.value).toString();
+ }
+ var gteCheckbox = document.getElementById('check_gte');
+ gteCheckbox.onchange = function() {
+ document.getElementById('symbol_filter_gte').disabled = !gteCheckbox.checked;
+ }
+ var regexCheckbox = document.getElementById('check_regex');
+ regexCheckbox.onchange = function() {
+ document.getElementById('symbol_filter_regex').disabled = !regexCheckbox.checked;
+ }
+ var excludeRegexCheckbox = document.getElementById('check_exclude_regex');
+ excludeRegexCheckbox.onchange = function() {
+ document.getElementById('symbol_filter_exclude_regex').disabled = !excludeRegexCheckbox.checked;
+ }
+ var idealSizes = getIdealSizes();
+ document.getElementById('width').value = idealSizes.width;
+ document.getElementById('height').value = idealSizes.height;
+ saveFilterSettings();
+}
+
+function filterSetAll(enabled) {
+ for (var x=0; x<=25; x++) {
+ var checkBox = document.getElementById('check_' + x);
+ checkBox.checked = enabled;
+ }
+ updateFilterText();
+}
+
+function showOptions() {
+ loadFilterSettings();
+ var container = document.getElementById('options_container');
+ var w = container.offsetWidth;
+ var h = container.offsetHeight;
+ container.style.margin = '-' + (h/2) + 'px 0 0 -' + (w/2) + 'px';
+ container.style.visibility = 'visible';
+}
+
+function hideOptions() {
+ var container = document.getElementById('options_container');
+ container.style.visibility = 'hidden';
+}
+
+function applySettings() {
+ hideOptions();
+ var oldWidth = savedSettings.width;
+ var oldHeight = savedSettings.height;
+ var oldSymbols = savedSettings.symbolTypes;
+ var oldRegex = savedSettings.regex;
+ var oldExcludeRegex = savedSettings.excludeRegex;
+ var oldGte = savedSettings.gte;
+ var oldMaxLevels = savedSettings.maxLevels;
+ saveFilterSettings();
+ var resizeNeeded = oldWidth !== savedSettings.width || oldHeight !== savedSettings.height;
+ var regexChanged = oldRegex !== savedSettings.regex;
+ var excludeRegexChanged = oldExcludeRegex !== savedSettings.excludeRegex;
+ var symbolsChanged = oldSymbols !== savedSettings.symbolTypes;
+ var gteChanged = oldGte !== savedSettings.gte;
+ var filterChanged = regexChanged || excludeRegexChanged || symbolsChanged || gteChanged;
+ var maxLevelsChanged = oldMaxLevels !== savedSettings.maxLevels;
+
+ if (filterChanged) {
+ // Type filters
+ typeFilter = function(datum) {
+ if (datum.depth === 0) return true; // root node
+ if (datum.t === undefined) return true;
+ return savedSettings.symbolTypes !== undefined &&
+ savedSettings.symbolTypes.indexOf(datum.t) !== -1;
+ }
+
+ // Regex filter
+ var regexFilter = undefined;
+ if (savedSettings.regex !== undefined && savedSettings.regex.length > 0) {
+ console.log('filter: regex is "' + savedSettings.regex + '"');
+ var regex = new RegExp(savedSettings.regex);
+ regexFilter = function(datum) {
+ if (datum.depth === 0) return true; // root node
+ var fullName = this.pathFor(datum);
+ if (datum.children === undefined) { // it is a leaf node (symbol)
+ fullName += ':' + datum.n;
+ }
+ return regex.test(fullName);
+ }
+ }
+
+ // Exclude regex filter
+ var excludeRegexFilter = undefined;
+ if (savedSettings.excludeRegex !== undefined && savedSettings.excludeRegex.length > 0) {
+ console.log('filter: exclude-regex is "' + savedSettings.excludeRegex + '"');
+ var excludeRegex = new RegExp(savedSettings.excludeRegex);
+ excludeRegexFilter = function(datum) {
+ if (datum.depth === 0) return true; // root node
+ var fullName = this.pathFor(datum);
+ if (datum.children === undefined) { // it is a leaf node (symbol)
+ fullName += ':' + datum.n;
+ }
+ return !excludeRegex.test(fullName);
+ }
+ }
+
+ // Size filter
+ var sizeFilter = undefined;
+ if (savedSettings.gte !== undefined) {
+ console.log('filter: minimum size is ' + savedSettings.gte + ' bytes');
+ sizeFilter = function(datum) {
+ if (datum.children !== undefined) return true; // non-leaf
+ if (datum.value === undefined) console.log('whoops');
+ return datum.value >= savedSettings.gte;
+ }
+ }
+
+ // Make a filter to apply to the tree
+ var filter = function(datum) {
+ if (typeFilter && !typeFilter.call(this, datum)) return false;
+ if (regexFilter && !regexFilter.call(this, datum)) return false;
+ if (excludeRegexFilter && !excludeRegexFilter.call(this, datum)) return false;
+ if (sizeFilter && !sizeFilter.call(this, datum)) return false;
+ return true;
+ };
+ treemap.filter(filter);
+ }
+
+ // Adjust levels if needed.
+ if (maxLevelsChanged) {
+ treemap.setMaxLevels(savedSettings.maxLevels);
+ }
+
+ // Resize map if necessary.
+ if (resizeNeeded) {
+ console.log('desired treemap dimensions have changed, requesting resize');
+ treemap.resize(savedSettings.width, savedSettings.height);
+ }
+}
+
+function cancelSettings() {
+ hideOptions();
+ loadFilterSettings();
+}
+
+function saveFilterSettings() {
+ savedSettings.symbolTypes = document.getElementById('symbol_types_filter').value;
+ if (document.getElementById('check_regex').checked) {
+ savedSettings.regex = document.getElementById('symbol_filter_regex').value;
+ } else {
+ savedSettings.regex = undefined;
+ }
+ if (document.getElementById('check_exclude_regex').checked) {
+ savedSettings.excludeRegex = document.getElementById('symbol_filter_exclude_regex').value;
+ } else {
+ savedSettings.excludeRegex = undefined;
+ }
+ if (document.getElementById('check_gte').checked) {
+ savedSettings.gte = parseInt(document.getElementById('symbol_filter_gte').value);
+ } else {
+ savedSettings.gte = undefined;
+ }
+ savedSettings.width = parseInt(document.getElementById('width').value);
+ savedSettings.height = parseInt(document.getElementById('height').value);
+ savedSettings.maxLevels = parseInt(document.getElementById('max_levels').value);
+}
+
+function loadFilterSettings() {
+ document.getElementById('symbol_types_filter').value = savedSettings.symbolTypes;
+ symbolFilterTextChanged();
+ if (savedSettings.regex !== undefined) {
+ document.getElementById('check_regex').checked = true;
+ document.getElementById('symbol_filter_regex').value = savedSettings.regex;
+ } else {
+ document.getElementById('check_regex').checked = false;
+ }
+ if (savedSettings.excludeRegex !== undefined) {
+ document.getElementById('check_exclude_regex').checked = true;
+ document.getElementById('symbol_filter_exclude_regex').value = savedSettings.excludeRegex;
+ } else {
+ document.getElementById('check_exclude_regex').checked = false;
+ }
+ if (savedSettings.gte !== undefined) {
+ document.getElementById('check_gte').checked = true;
+ document.getElementById('symbol_filter_gte').value = savedSettings.gte;
+ } else {
+ document.getElementById('check_gte').checked = false;
+ }
+ document.getElementById('width').value = savedSettings.width;
+ document.getElementById('height').value = savedSettings.height;
+ document.getElementById('max_levels').value = savedSettings.maxLevels;
+}
+
+function escape(str) {
+ return str.replace(/&/g, '&')
+ .replace(/"/g, '"')
+ .replace(/</g, '<')
+ .replace(/>/g, '>');
+}
+</script>
+</head>
+<body onload='init()'>
+<div style='position: absolute; top: 5px; left: 5px;'>
+ <input type='button' onclick='showOptions()' value='Options & Legend...'>
+ <span style='-webkit-user-select: none; cursor: help;' title='Click to view the symbol legend or to configure filters and options for the treemap'>[?]</span>
+</div>
+<div style='position: absolute; right: 5px; top: 5px; white-space: nowrap;'>
+ Reports:
+ <input type='button' onclick='bigSymbolsReport()' value='Large Symbols' title='Click to view a report of the largest 100 symbols that are with the bounds of the treemap that is currently displayed.'>
+ <input type='button' onclick='bigPathsReport()' value='Large Files' title='Click to view a report of the largest 100 source files that are with the bounds of the treemap that is currently displayed.'>
+</div>
+<div style='text-align: center; margin-bottom: 5px;'>
+ <span style='font-size: x-large; font-weight: bold; font-variant: small-caps'>Binary Size Analysis<span id='subtitle'></span></span>
+ <br><span style='font-size: small; font-style: italic;'>Double-click a box to zoom in, double-click outermost title to zoom out.</span>
+</div>
+<table id='options_container' style='visibility: hidden; border: 3px ridge grey; padding: 0px; top: 50%; left: 50%; position: fixed; z-index: 2147483646; overflow: auto; background-color: rgba(255,255,255,0.9); border-radius: 10px; box-shadow: 10px 10px 5px rgba(80,80,80,0.7);'><tr><td style='vertical-align: top'>
+ <table cellspacing=0 cellborder=0 style='width:100%'>
+ <tr><th colspan=3 style='padding-bottom: .25em; text-decoration: underline;'>Symbol Types To Show</th></tr>
+ <tr>
+ <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+ <span class='swatch' id='swatch_0'> </span><input checked type='checkbox' id='check_0' value='A'>Global absolute (A)
+ <br><span class='swatch' id='swatch_1'> </span><input checked type='checkbox' id='check_1' value='B'>Global uninitialized data (B)
+ <br><span class='swatch' id='swatch_2'> </span><input checked type='checkbox' id='check_2' value='b'>Local uninitialized data (b)
+ <br><span class='swatch' id='swatch_3'> </span><input checked type='checkbox' id='check_3' value='C'>Global uninitialized common (C)
+ <br><span class='swatch' id='swatch_4'> </span><input checked type='checkbox' id='check_4' value='D'>Global initialized data (D)
+ <br><span class='swatch' id='swatch_5'> </span><input checked type='checkbox' id='check_5' value='d'>Local initialized data (d)
+ <br><span class='swatch' id='swatch_6'> </span><input checked type='checkbox' id='check_6' value='G'>Global small initialized data (G)
+ <br><span class='swatch' id='swatch_7'> </span><input checked type='checkbox' id='check_7' value='g'>Local small initialized data (g)
+ <br><span class='swatch' id='swatch_8'> </span><input checked type='checkbox' id='check_8' value='i'>Indirect function (i)
+ </td>
+ <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+ <span class='swatch' id='swatch_9'> </span><input checked type='checkbox' id='check_9' value='N'>Debugging (N)
+ <br><span class='swatch' id='swatch_10'> </span><input checked type='checkbox' id='check_10' value='p'>Stack unwind (p)
+ <br><span class='swatch' id='swatch_11'> </span><input checked type='checkbox' id='check_11' value='R'>Global read-only data (R)
+ <br><span class='swatch' id='swatch_12'> </span><input checked type='checkbox' id='check_12' value='r'>Local read-only data (r)
+ <br><span class='swatch' id='swatch_13'> </span><input checked type='checkbox' id='check_13' value='S'>Global small uninitialized data (S)
+ <br><span class='swatch' id='swatch_14'> </span><input checked type='checkbox' id='check_14' value='s'>Local small uninitialized data (s)
+ <br><span class='swatch' id='swatch_15'> </span><input checked type='checkbox' id='check_15' value='T'>Global code (T)
+ <br><span class='swatch' id='swatch_16'> </span><input checked type='checkbox' id='check_16' value='t'>Local code (t)
+ <br><span class='swatch' id='swatch_17'> </span><input checked type='checkbox' id='check_17' value='U'>Undefined (U)
+ </td>
+ <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
+ <span class='swatch' id='swatch_18'> </span><input checked type='checkbox' id='check_18' value='u'>Unique (u)
+ <br><span class='swatch' id='swatch_19'> </span><input checked type='checkbox' id='check_19' value='V'>Global weak object (V)
+ <br><span class='swatch' id='swatch_20'> </span><input checked type='checkbox' id='check_20' value='v'>Local weak object (v)
+ <br><span class='swatch' id='swatch_21'> </span><input checked type='checkbox' id='check_21' value='W'>Global weak symbol (W)
+ <br><span class='swatch' id='swatch_22'> </span><input checked type='checkbox' id='check_22' value='w'>Local weak symbol (w)
+ <br><span class='swatch' id='swatch_23'> </span><input checked type='checkbox' id='check_23' value='@'>Vtable entry (@)
+ <br><span class='swatch' id='swatch_24'> </span><input checked type='checkbox' id='check_24' value='-'>STABS debugging (-)
+ <br><span class='swatch' id='swatch_25'> </span><input checked type='checkbox' id='check_25' value='?'>Unrecognized (?)
+ </td>
+ </tr>
+ <tr><td colspan=3 style='text-align: center; white-space: nowrap; padding-top: 1em;'>
+ Select <input type='button' onclick='filterSetAll(true)' value='All'>,
+ <input type='button' onclick='filterSetAll(false)' value='None'>,
+ or type a string: <input id='symbol_types_filter' size=30 value='' onkeyup='symbolFilterTextChanged()' onblur='updateFilterText()'>
+ <span style='-webkit-user-select: none; cursor: help;' title='Enter codes from the list above for the symbols you want to see. The checkboxes will update automatically to match the string that you enter.'>[?]</span>
+ </td></tr>
+ </table>
+</td></tr><tr><td style='vertical-align: top; padding-top: 10px; border-top: 1px solid grey;'>
+ <table cellspacing=0 cellborder=0 style='width: 100%'>
+ <tr><th colspan=2 style='padding-bottom: .25em; text-decoration: underline;'>Advanced Options</th></tr>
+ <tr>
+ <td style='white-space: nowrap; vertical-align: top;'>
+ <input type='checkbox' id='check_regex'>
+ Only include symbols matching this regex:
+ </td>
+ <td style='text-align: right; vertical-align: top;'>
+ <input disabled id='symbol_filter_regex' size=30 value='' style='text-align: right;'>
+ <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Only symbols that match this regex will be shown. This filter applies before any exclusion regex specified below. The format of each symbol is [path]:[symbol_name]'>[?]</span>
+ </td>
+ </tr>
+ <tr>
+ <td style='white-space: nowrap; vertical-align: top;'>
+ <input type='checkbox' id='check_exclude_regex'>
+ Exclude all symbols matching this regex:
+ </td>
+ <td style='text-align: right; vertical-align: top;'>
+ <input disabled id='symbol_filter_exclude_regex' size=30 value='' style='text-align: right;'>
+ <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Symbols that match this tegex will not be shown. This filter applies after any inclusion filter specified above. The format of each symbol is [path]:[symbol_name]'>[?]</span>
+ </td>
+ </tr>
+ <tr>
+ <td style='white-space: nowrap; vertical-align: top;'>
+ <input type='checkbox' id='check_gte'>
+ Only include symbols that are at least <span style='font-style: italic;'>n</span> bytes:
+ </td>
+ <td style='text-align: right; vertical-align: top;'>
+ <input disabled id='symbol_filter_gte' size=8 value='' style='text-align: right;'>
+ <span style='-webkit-user-select: none; cursor: help;' title='Symbols whose size is less than this value will be hidden.'>[?]</span>
+ </td>
+ </tr>
+ <tr>
+ <td style='white-space: nowrap vertical-align: top;;'>
+ Show at most <span style='font-style: italic;'>n</span> levels of detail at a time:
+ </td>
+ <td style='text-align: right; vertical-align: top;'>
+ <input id='max_levels' size=4 value='2' style='text-align: right;'><span style='-webkit-user-select: none; cursor: help;' title='Increasing this value shows more detail without the need to zoom, but uses more computing power.'>[?]</span>
+ </td>
+ </tr>
+ <tr>
+ <td style='white-space: nowrap vertical-align: top;;'>
+ Set the size of the treemap to <span style='font-style: italic;'>W x H</span> pixels:
+ </td>
+ <td style='text-align: right; vertical-align: top;'>
+ <input id='width' size=4 value='' style='text-align: right;'>
+ x <input id='height' size=4 value='' style='text-align: right;'>
+ </td>
+ </tr>
+ </table>
+</td></tr>
+<tr><td style='padding-top: 10px; text-align: right; border-top: 1px solid grey'>
+ <input type='button' value='Apply' onclick='applySettings()'>
+ <input type='button' value='Cancel' onclick='cancelSettings()'>
+</td></tr></table>
+</body>
+</html>
diff --git a/runtime/third_party/binary_size/src/template/test-data-generator.html b/runtime/third_party/binary_size/src/template/test-data-generator.html
new file mode 100644
index 0000000..9c6790a
--- /dev/null
+++ b/runtime/third_party/binary_size/src/template/test-data-generator.html
@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<!--
+ Copyright 2014 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+<html>
+<head>
+<script>
+function rnd(max) {
+ return Math.round(Math.random()*max);
+}
+
+function gen() {
+ var dirs1=['usr1', 'etc1', 'var1'];
+ var dirs2=['aaa2', 'bbb2', 'ccc2', 'ddd2', 'eee2', 'fff2', 'ggg2', 'hhh2',
+ 'frobozz2', 'kazaam2', 'shazam2'];
+ var dirs3=['iii3', 'jjj3', 'kkk3', 'lll3', 'mmm3', 'nnn3', 'ooo3', 'ppp3',
+ 'wonderllama3', 'excelsior3', 'src3'];
+ var filenames=['awesome.cc', 'rad.h', 'tubular.cxx', 'cool.cc', 'groovy.h',
+ 'excellent.c', 'gnarly.h', 'green.C', 'articulate.cc'];
+ //All possible types (we only see a subset in practice): 'ABbCDdGgiNpRrSsTtUuVvWw-?';
+ var nm_symbol_types = 'trd';
+ var minSize = 4;
+ var maxSize = 10000;
+ var numGen = 300000;
+ var text = 'var nm_data=[\n';
+ var vtablePercent = 5;
+ for (var x=0; x<numGen; x++) {
+ var path = '/' +
+ dirs1[rnd(dirs1.length - 1)] + '/' +
+ dirs2[rnd(dirs2.length - 1)] + '/' +
+ dirs3[rnd(dirs3.length - 1)] + '/' +
+ filenames[rnd(filenames.length - 1)];
+ var isVtable = Math.floor((Math.random()*100)+1) <= vtablePercent;
+ var size = rnd(maxSize);
+ var symbol_name;
+ var type;
+ if (!isVtable) {
+ symbol_name = 'sym' + x.toString(16);
+ type = nm_symbol_types.charAt(rnd(nm_symbol_types.length - 1));
+ } else {
+ symbol_name = 'vtable for ' + x.toString(16);
+ type = '@'
+ }
+ text = text + "{'n': '" + symbol_name +
+ "', 't': '" + type +
+ "', 's': " + size +
+ ", 'p': '" + path + "'},\n";
+ }
+ text += '];';
+
+ eval(text);
+ var treeified = to_d3_tree(nm_data);
+ generateDownloadLink('tree_data=' + JSON.stringify(treeified));
+}
+
+function generateDownloadLink(content) {
+ var blob = new Blob([content], {type: 'text/plain'});
+ var link = document.createElement('a');
+ link.download = 'generated-content.txt';
+ link.href = window.URL.createObjectURL(blob);
+ link.textContent = 'Download ready, click here.';
+ link.dataset.downloadurl = ['text/plain', link.download, link.href].join(':');
+ link.onclick = function(e) {
+ if ('disabled' in this.dataset) { return false; }
+ link.dataset.disabled = true;
+ setTimeout(function() { window.URL.revokeObjectURL(link.href); }, 1500);
+ };
+ document.getElementById('linkcontainer').innerHTML = '';
+ document.getElementById('linkcontainer').appendChild(link);
+}
+
+/**
+ * This function takes in an array of nm records and converts them into a
+ * hierarchical data structure suitable for use in a d3-base treemap layout.
+ * Leaves are individual symbols. The parents of the leaves are logical
+ * groupings by common symbol-type (for BSS, read-only data, code, etc).
+ * Above this, each node represents part of a filesystem path relative
+ * to the parent node. The root node has the name '/', and represents
+ * a root (though not necessarily THE root) of a file system traversal.
+ * The root node also has a special property, 'maxDepth', to which is bound
+ * the deepest level of nesting that was found during conversion: for the
+ * record at path /a/b/c/d.foo, the maxDepth will be 6; the file 'd.foo'
+ * is at depth 4, the type-bucket is depth 5 and the symbols are depth 6.
+ */
+function to_d3_tree(records) {
+ var result = {'n': '/', 'children': [], 'k': 'p'};
+ var maxDepth = 0;
+ //{'n': 'symbol1', 't': 'b', 's': 1000, 'p': '/usr/local/foo/foo.cc'},
+ for (index in records) {
+ var record = records[index];
+ var parts = record.p.split("/");
+ var node = result;
+ var depth = 0;
+ // Walk the tree and find the file that is named by the "location"
+ // field of the record. We create any intermediate nodes required.
+ // This is directly analogous to "mkdir -p".
+ while(parts.length > 0) {
+ var part = parts.shift();
+ if (part.length == 0) continue;
+ depth++;
+ node = _mk_child(node, part, record.s);
+ node.k = 'p'; // p for path
+ }
+ node.lastPathElement = true;
+
+ // 'node' is now the file node. Find the symbol-type bucket.
+ node = _mk_child(node, record.t, record.s);
+ node.t = record.t;
+ node.k = 'b'; // b for bucket
+ depth++;
+ // 'node' is now the symbol-type bucket. Make the child entry.
+ node = _mk_child(node, record.n, record.s);
+ delete node.children;
+ node.value = record.s;
+ node.t = record.t;
+ node.k = 's'; // s for symbol
+ depth++;
+
+ maxDepth = Math.max(maxDepth, depth);
+ }
+ result.maxDepth = maxDepth;
+ return result;
+}
+
+/**
+ * Given a node and a name, return the child within node.children whose
+ * name matches the specified name. If necessary, a new child node is
+ * created and appended to node.children.
+ * If this method creates a new node, the 'name' attribute is set to the
+ * specified name and the 'children' attribute is an empty array, and
+ * total_size is the specified size. Otherwise, the existing node is
+ * returned and its total_size value is incremented by the specified size.
+ */
+function _mk_child(node, name, size) {
+ var child = undefined;
+ for (child_index in node.children) {
+ if (node.children[child_index].n == name) {
+ child = node.children[child_index];
+ }
+ }
+ if (child === undefined) {
+ child = {'n': name, 'children': []};
+ node.children.push(child);
+ }
+ return child;
+}
+</script>
+</head>
+<body style='white-space: pre; font-family: monospace;'>
+This script generates sample data for use in D3SymbolTreeMap, and can be used
+for testing.
+<input type=button onclick='gen();' value='Generate data'></input>
+<div id='linkcontainer'></div>
+</body>
+</html>
diff --git a/runtime/third_party/d3/README.chromium b/runtime/third_party/d3/README.chromium
new file mode 100644
index 0000000..7697762
--- /dev/null
+++ b/runtime/third_party/d3/README.chromium
@@ -0,0 +1,31 @@
+Name: d3
+Short Name: d3
+URL: https://github.com/mbostock/d3
+Version: 3.4.4
+Date: Mon Mar 24 20:45:44 2014 -0700
+Revision: fa55eead411a3c1b01703cb1ddfd59ccc0b23124
+License: BSD 3-Clause
+License File: src/LICENSE
+Security Critical: No
+License Android Compatible: Yes
+
+Description:
+A JavaScript library for manipulating documents based on data.
+
+Subject to the security patch(es) described below, you MAY include d3 in web-facing content, such
+as in pages generated by bots or tools.
+
+
+Local Modifications:
+1. Deleted everything except for:
+* d3.js the standalone non-minified library
+* LICENSE the BSD-style 3-Clause license
+* README.md the readme file from github, for basic information
+
+2. Applied the following patches at the request of security:
+patches/001_no_html.patch Disables the html() convenience functions, which could be used to
+ inject arbitrary content into the page. Instead of using html(),
+ programmatically create the individual nodes and/or text that you
+ require.
+ The html() methods have been modified to throw exceptions that
+ make it obvious that this feature is disabled for security.
diff --git a/runtime/third_party/d3/README.dart b/runtime/third_party/d3/README.dart
new file mode 100644
index 0000000..6abfe09
--- /dev/null
+++ b/runtime/third_party/d3/README.dart
@@ -0,0 +1 @@
+A local copy of third_party/d3 from Chromium project.
\ No newline at end of file
diff --git a/runtime/third_party/d3/patches/001_no_html.patch b/runtime/third_party/d3/patches/001_no_html.patch
new file mode 100644
index 0000000..3c976b0
--- /dev/null
+++ b/runtime/third_party/d3/patches/001_no_html.patch
@@ -0,0 +1,24 @@
+diff --git a/third_party/d3/src/d3.js b/third_party/d3/src/d3.js
+index a3e4b95..8a98c4d 100644
+--- a/third_party/d3/src/d3.js
++++ b/third_party/d3/src/d3.js
+@@ -713,6 +713,7 @@
+ }) : this.node().textContent;
+ };
+ d3_selectionPrototype.html = function(value) {
++ throw "disallowed by chromium security";
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.innerHTML = v == null ? "" : v;
+@@ -9274,9 +9275,11 @@
+ return JSON.parse(request.responseText);
+ }
+ d3.html = function(url, callback) {
++ throw "disallowed by chromium security";
+ return d3_xhr(url, "text/html", d3_html, callback);
+ };
+ function d3_html(request) {
++ throw "disallowed by chromium security";
+ var range = d3_document.createRange();
+ range.selectNode(d3_document.body);
+ return range.createContextualFragment(request.responseText);
diff --git a/runtime/third_party/d3/src/LICENSE b/runtime/third_party/d3/src/LICENSE
new file mode 100644
index 0000000..8301346
--- /dev/null
+++ b/runtime/third_party/d3/src/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2010-2014, Michael Bostock
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* The name Michael Bostock may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/runtime/third_party/d3/src/README.md b/runtime/third_party/d3/src/README.md
new file mode 100644
index 0000000..eb334e2
--- /dev/null
+++ b/runtime/third_party/d3/src/README.md
@@ -0,0 +1,9 @@
+# Data-Driven Documents
+
+<a href="http://d3js.org"><img src="http://d3js.org/logo.svg" align="left" hspace="10" vspace="6"></a>
+
+**D3.js** is a JavaScript library for manipulating documents based on data. **D3** helps you bring data to life using HTML, SVG and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.
+
+Want to learn more? [See the wiki.](https://github.com/mbostock/d3/wiki)
+
+For examples, [see the gallery](https://github.com/mbostock/d3/wiki/Gallery) and [mbostock’s bl.ocks](http://bl.ocks.org/mbostock).
diff --git a/runtime/third_party/d3/src/d3.js b/runtime/third_party/d3/src/d3.js
new file mode 100644
index 0000000..6dcabdf
--- /dev/null
+++ b/runtime/third_party/d3/src/d3.js
@@ -0,0 +1,9297 @@
+!function() {
+ var d3 = {
+ version: "3.4.4"
+ };
+ if (!Date.now) Date.now = function() {
+ return +new Date();
+ };
+ var d3_arraySlice = [].slice, d3_array = function(list) {
+ return d3_arraySlice.call(list);
+ };
+ var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window;
+ try {
+ d3_array(d3_documentElement.childNodes)[0].nodeType;
+ } catch (e) {
+ d3_array = function(list) {
+ var i = list.length, array = new Array(i);
+ while (i--) array[i] = list[i];
+ return array;
+ };
+ }
+ try {
+ d3_document.createElement("div").style.setProperty("opacity", 0, "");
+ } catch (error) {
+ var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
+ d3_element_prototype.setAttribute = function(name, value) {
+ d3_element_setAttribute.call(this, name, value + "");
+ };
+ d3_element_prototype.setAttributeNS = function(space, local, value) {
+ d3_element_setAttributeNS.call(this, space, local, value + "");
+ };
+ d3_style_prototype.setProperty = function(name, value, priority) {
+ d3_style_setProperty.call(this, name, value + "", priority);
+ };
+ }
+ d3.ascending = d3_ascending;
+ function d3_ascending(a, b) {
+ return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+ }
+ d3.descending = function(a, b) {
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+ };
+ d3.min = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = array[i]) != null && a > b) a = b;
+ } else {
+ while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
+ }
+ return a;
+ };
+ d3.max = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = array[i]) != null && b > a) a = b;
+ } else {
+ while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
+ }
+ return a;
+ };
+ d3.extent = function(array, f) {
+ var i = -1, n = array.length, a, b, c;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined;
+ while (++i < n) if ((b = array[i]) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ } else {
+ while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ }
+ return [ a, c ];
+ };
+ d3.sum = function(array, f) {
+ var s = 0, n = array.length, a, i = -1;
+ if (arguments.length === 1) {
+ while (++i < n) if (!isNaN(a = +array[i])) s += a;
+ } else {
+ while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
+ }
+ return s;
+ };
+ function d3_number(x) {
+ return x != null && !isNaN(x);
+ }
+ d3.mean = function(array, f) {
+ var n = array.length, a, m = 0, i = -1, j = 0;
+ if (arguments.length === 1) {
+ while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
+ } else {
+ while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
+ }
+ return j ? m : undefined;
+ };
+ d3.quantile = function(values, p) {
+ var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h;
+ return e ? v + e * (values[h] - v) : v;
+ };
+ d3.median = function(array, f) {
+ if (arguments.length > 1) array = array.map(f);
+ array = array.filter(d3_number);
+ return array.length ? d3.quantile(array.sort(d3_ascending), .5) : undefined;
+ };
+ function d3_bisector(compare) {
+ return {
+ left: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid;
+ }
+ return lo;
+ },
+ right: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1;
+ }
+ return lo;
+ }
+ };
+ }
+ var d3_bisect = d3_bisector(d3_ascending);
+ d3.bisectLeft = d3_bisect.left;
+ d3.bisect = d3.bisectRight = d3_bisect.right;
+ d3.bisector = function(f) {
+ return d3_bisector(f.length === 1 ? function(d, x) {
+ return d3_ascending(f(d), x);
+ } : f);
+ };
+ d3.shuffle = function(array) {
+ var m = array.length, t, i;
+ while (m) {
+ i = Math.random() * m-- | 0;
+ t = array[m], array[m] = array[i], array[i] = t;
+ }
+ return array;
+ };
+ d3.permute = function(array, indexes) {
+ var i = indexes.length, permutes = new Array(i);
+ while (i--) permutes[i] = array[indexes[i]];
+ return permutes;
+ };
+ d3.pairs = function(array) {
+ var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);
+ while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ];
+ return pairs;
+ };
+ d3.zip = function() {
+ if (!(n = arguments.length)) return [];
+ for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {
+ for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
+ zip[j] = arguments[j][i];
+ }
+ }
+ return zips;
+ };
+ function d3_zipLength(d) {
+ return d.length;
+ }
+ d3.transpose = function(matrix) {
+ return d3.zip.apply(d3, matrix);
+ };
+ d3.keys = function(map) {
+ var keys = [];
+ for (var key in map) keys.push(key);
+ return keys;
+ };
+ d3.values = function(map) {
+ var values = [];
+ for (var key in map) values.push(map[key]);
+ return values;
+ };
+ d3.entries = function(map) {
+ var entries = [];
+ for (var key in map) entries.push({
+ key: key,
+ value: map[key]
+ });
+ return entries;
+ };
+ d3.merge = function(arrays) {
+ var n = arrays.length, m, i = -1, j = 0, merged, array;
+ while (++i < n) j += arrays[i].length;
+ merged = new Array(j);
+ while (--n >= 0) {
+ array = arrays[n];
+ m = array.length;
+ while (--m >= 0) {
+ merged[--j] = array[m];
+ }
+ }
+ return merged;
+ };
+ var abs = Math.abs;
+ d3.range = function(start, stop, step) {
+ if (arguments.length < 3) {
+ step = 1;
+ if (arguments.length < 2) {
+ stop = start;
+ start = 0;
+ }
+ }
+ if ((stop - start) / step === Infinity) throw new Error("infinite range");
+ var range = [], k = d3_range_integerScale(abs(step)), i = -1, j;
+ start *= k, stop *= k, step *= k;
+ if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);
+ return range;
+ };
+ function d3_range_integerScale(x) {
+ var k = 1;
+ while (x * k % 1) k *= 10;
+ return k;
+ }
+ function d3_class(ctor, properties) {
+ try {
+ for (var key in properties) {
+ Object.defineProperty(ctor.prototype, key, {
+ value: properties[key],
+ enumerable: false
+ });
+ }
+ } catch (e) {
+ ctor.prototype = properties;
+ }
+ }
+ d3.map = function(object) {
+ var map = new d3_Map();
+ if (object instanceof d3_Map) object.forEach(function(key, value) {
+ map.set(key, value);
+ }); else for (var key in object) map.set(key, object[key]);
+ return map;
+ };
+ function d3_Map() {}
+ d3_class(d3_Map, {
+ has: d3_map_has,
+ get: function(key) {
+ return this[d3_map_prefix + key];
+ },
+ set: function(key, value) {
+ return this[d3_map_prefix + key] = value;
+ },
+ remove: d3_map_remove,
+ keys: d3_map_keys,
+ values: function() {
+ var values = [];
+ this.forEach(function(key, value) {
+ values.push(value);
+ });
+ return values;
+ },
+ entries: function() {
+ var entries = [];
+ this.forEach(function(key, value) {
+ entries.push({
+ key: key,
+ value: value
+ });
+ });
+ return entries;
+ },
+ size: d3_map_size,
+ empty: d3_map_empty,
+ forEach: function(f) {
+ for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) f.call(this, key.substring(1), this[key]);
+ }
+ });
+ var d3_map_prefix = "\x00", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
+ function d3_map_has(key) {
+ return d3_map_prefix + key in this;
+ }
+ function d3_map_remove(key) {
+ key = d3_map_prefix + key;
+ return key in this && delete this[key];
+ }
+ function d3_map_keys() {
+ var keys = [];
+ this.forEach(function(key) {
+ keys.push(key);
+ });
+ return keys;
+ }
+ function d3_map_size() {
+ var size = 0;
+ for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) ++size;
+ return size;
+ }
+ function d3_map_empty() {
+ for (var key in this) if (key.charCodeAt(0) === d3_map_prefixCode) return false;
+ return true;
+ }
+ d3.nest = function() {
+ var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
+ function map(mapType, array, depth) {
+ if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;
+ var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values;
+ while (++i < n) {
+ if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
+ values.push(object);
+ } else {
+ valuesByKey.set(keyValue, [ object ]);
+ }
+ }
+ if (mapType) {
+ object = mapType();
+ setter = function(keyValue, values) {
+ object.set(keyValue, map(mapType, values, depth));
+ };
+ } else {
+ object = {};
+ setter = function(keyValue, values) {
+ object[keyValue] = map(mapType, values, depth);
+ };
+ }
+ valuesByKey.forEach(setter);
+ return object;
+ }
+ function entries(map, depth) {
+ if (depth >= keys.length) return map;
+ var array = [], sortKey = sortKeys[depth++];
+ map.forEach(function(key, keyMap) {
+ array.push({
+ key: key,
+ values: entries(keyMap, depth)
+ });
+ });
+ return sortKey ? array.sort(function(a, b) {
+ return sortKey(a.key, b.key);
+ }) : array;
+ }
+ nest.map = function(array, mapType) {
+ return map(mapType, array, 0);
+ };
+ nest.entries = function(array) {
+ return entries(map(d3.map, array, 0), 0);
+ };
+ nest.key = function(d) {
+ keys.push(d);
+ return nest;
+ };
+ nest.sortKeys = function(order) {
+ sortKeys[keys.length - 1] = order;
+ return nest;
+ };
+ nest.sortValues = function(order) {
+ sortValues = order;
+ return nest;
+ };
+ nest.rollup = function(f) {
+ rollup = f;
+ return nest;
+ };
+ return nest;
+ };
+ d3.set = function(array) {
+ var set = new d3_Set();
+ if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
+ return set;
+ };
+ function d3_Set() {}
+ d3_class(d3_Set, {
+ has: d3_map_has,
+ add: function(value) {
+ this[d3_map_prefix + value] = true;
+ return value;
+ },
+ remove: function(value) {
+ value = d3_map_prefix + value;
+ return value in this && delete this[value];
+ },
+ values: d3_map_keys,
+ size: d3_map_size,
+ empty: d3_map_empty,
+ forEach: function(f) {
+ for (var value in this) if (value.charCodeAt(0) === d3_map_prefixCode) f.call(this, value.substring(1));
+ }
+ });
+ d3.behavior = {};
+ d3.rebind = function(target, source) {
+ var i = 1, n = arguments.length, method;
+ while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
+ return target;
+ };
+ function d3_rebind(target, source, method) {
+ return function() {
+ var value = method.apply(source, arguments);
+ return value === source ? target : value;
+ };
+ }
+ function d3_vendorSymbol(object, name) {
+ if (name in object) return name;
+ name = name.charAt(0).toUpperCase() + name.substring(1);
+ for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
+ var prefixName = d3_vendorPrefixes[i] + name;
+ if (prefixName in object) return prefixName;
+ }
+ }
+ var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ];
+ function d3_noop() {}
+ d3.dispatch = function() {
+ var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ return dispatch;
+ };
+ function d3_dispatch() {}
+ d3_dispatch.prototype.on = function(type, listener) {
+ var i = type.indexOf("."), name = "";
+ if (i >= 0) {
+ name = type.substring(i + 1);
+ type = type.substring(0, i);
+ }
+ if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
+ if (arguments.length === 2) {
+ if (listener == null) for (type in this) {
+ if (this.hasOwnProperty(type)) this[type].on(name, null);
+ }
+ return this;
+ }
+ };
+ function d3_dispatch_event(dispatch) {
+ var listeners = [], listenerByName = new d3_Map();
+ function event() {
+ var z = listeners, i = -1, n = z.length, l;
+ while (++i < n) if (l = z[i].on) l.apply(this, arguments);
+ return dispatch;
+ }
+ event.on = function(name, listener) {
+ var l = listenerByName.get(name), i;
+ if (arguments.length < 2) return l && l.on;
+ if (l) {
+ l.on = null;
+ listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
+ listenerByName.remove(name);
+ }
+ if (listener) listeners.push(listenerByName.set(name, {
+ on: listener
+ }));
+ return dispatch;
+ };
+ return event;
+ }
+ d3.event = null;
+ function d3_eventPreventDefault() {
+ d3.event.preventDefault();
+ }
+ function d3_eventSource() {
+ var e = d3.event, s;
+ while (s = e.sourceEvent) e = s;
+ return e;
+ }
+ function d3_eventDispatch(target) {
+ var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ dispatch.of = function(thiz, argumentz) {
+ return function(e1) {
+ try {
+ var e0 = e1.sourceEvent = d3.event;
+ e1.target = target;
+ d3.event = e1;
+ dispatch[e1.type].apply(thiz, argumentz);
+ } finally {
+ d3.event = e0;
+ }
+ };
+ };
+ return dispatch;
+ }
+ d3.requote = function(s) {
+ return s.replace(d3_requote_re, "\\$&");
+ };
+ var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
+ var d3_subclass = {}.__proto__ ? function(object, prototype) {
+ object.__proto__ = prototype;
+ } : function(object, prototype) {
+ for (var property in prototype) object[property] = prototype[property];
+ };
+ function d3_selection(groups) {
+ d3_subclass(groups, d3_selectionPrototype);
+ return groups;
+ }
+ var d3_select = function(s, n) {
+ return n.querySelector(s);
+ }, d3_selectAll = function(s, n) {
+ return n.querySelectorAll(s);
+ }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) {
+ return d3_selectMatcher.call(n, s);
+ };
+ if (typeof Sizzle === "function") {
+ d3_select = function(s, n) {
+ return Sizzle(s, n)[0] || null;
+ };
+ d3_selectAll = Sizzle;
+ d3_selectMatches = Sizzle.matchesSelector;
+ }
+ d3.selection = function() {
+ return d3_selectionRoot;
+ };
+ var d3_selectionPrototype = d3.selection.prototype = [];
+ d3_selectionPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, group, node;
+ selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(subnode = selector.call(node, node.__data__, i, j));
+ if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selector(selector) {
+ return typeof selector === "function" ? selector : function() {
+ return d3_select(selector, this);
+ };
+ }
+ d3_selectionPrototype.selectAll = function(selector) {
+ var subgroups = [], subgroup, node;
+ selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
+ subgroup.parentNode = node;
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selectorAll(selector) {
+ return typeof selector === "function" ? selector : function() {
+ return d3_selectAll(selector, this);
+ };
+ }
+ var d3_nsPrefix = {
+ svg: "http://www.w3.org/2000/svg",
+ xhtml: "http://www.w3.org/1999/xhtml",
+ xlink: "http://www.w3.org/1999/xlink",
+ xml: "http://www.w3.org/XML/1998/namespace",
+ xmlns: "http://www.w3.org/2000/xmlns/"
+ };
+ d3.ns = {
+ prefix: d3_nsPrefix,
+ qualify: function(name) {
+ var i = name.indexOf(":"), prefix = name;
+ if (i >= 0) {
+ prefix = name.substring(0, i);
+ name = name.substring(i + 1);
+ }
+ return d3_nsPrefix.hasOwnProperty(prefix) ? {
+ space: d3_nsPrefix[prefix],
+ local: name
+ } : name;
+ }
+ };
+ d3_selectionPrototype.attr = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node();
+ name = d3.ns.qualify(name);
+ return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
+ }
+ for (value in name) this.each(d3_selection_attr(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_attr(name, value));
+ };
+ function d3_selection_attr(name, value) {
+ name = d3.ns.qualify(name);
+ function attrNull() {
+ this.removeAttribute(name);
+ }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
+ function attrConstant() {
+ this.setAttribute(name, value);
+ }
+ function attrConstantNS() {
+ this.setAttributeNS(name.space, name.local, value);
+ }
+ function attrFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
+ }
+ function attrFunctionNS() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
+ }
+ return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
+ }
+ function d3_collapse(s) {
+ return s.trim().replace(/\s+/g, " ");
+ }
+ d3_selectionPrototype.classed = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1;
+ if (value = node.classList) {
+ while (++i < n) if (!value.contains(name[i])) return false;
+ } else {
+ value = node.getAttribute("class");
+ while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
+ }
+ return true;
+ }
+ for (value in name) this.each(d3_selection_classed(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_classed(name, value));
+ };
+ function d3_selection_classedRe(name) {
+ return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
+ }
+ function d3_selection_classes(name) {
+ return name.trim().split(/^|\s+/);
+ }
+ function d3_selection_classed(name, value) {
+ name = d3_selection_classes(name).map(d3_selection_classedName);
+ var n = name.length;
+ function classedConstant() {
+ var i = -1;
+ while (++i < n) name[i](this, value);
+ }
+ function classedFunction() {
+ var i = -1, x = value.apply(this, arguments);
+ while (++i < n) name[i](this, x);
+ }
+ return typeof value === "function" ? classedFunction : classedConstant;
+ }
+ function d3_selection_classedName(name) {
+ var re = d3_selection_classedRe(name);
+ return function(node, value) {
+ if (c = node.classList) return value ? c.add(name) : c.remove(name);
+ var c = node.getAttribute("class") || "";
+ if (value) {
+ re.lastIndex = 0;
+ if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name));
+ } else {
+ node.setAttribute("class", d3_collapse(c.replace(re, " ")));
+ }
+ };
+ }
+ d3_selectionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
+ return this;
+ }
+ if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name);
+ priority = "";
+ }
+ return this.each(d3_selection_style(name, value, priority));
+ };
+ function d3_selection_style(name, value, priority) {
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
+ function styleConstant() {
+ this.style.setProperty(name, value, priority);
+ }
+ function styleFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
+ }
+ return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
+ }
+ d3_selectionPrototype.property = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") return this.node()[name];
+ for (value in name) this.each(d3_selection_property(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_property(name, value));
+ };
+ function d3_selection_property(name, value) {
+ function propertyNull() {
+ delete this[name];
+ }
+ function propertyConstant() {
+ this[name] = value;
+ }
+ function propertyFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) delete this[name]; else this[name] = x;
+ }
+ return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
+ }
+ d3_selectionPrototype.text = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.textContent = v == null ? "" : v;
+ } : value == null ? function() {
+ this.textContent = "";
+ } : function() {
+ this.textContent = value;
+ }) : this.node().textContent;
+ };
+ d3_selectionPrototype.html = function(value) {
+ throw "disallowed by chromium security";
+ return arguments.length ? this.each(typeof value === "function" ? function() {
+ var v = value.apply(this, arguments);
+ this.innerHTML = v == null ? "" : v;
+ } : value == null ? function() {
+ this.innerHTML = "";
+ } : function() {
+ this.innerHTML = value;
+ }) : this.node().innerHTML;
+ };
+ d3_selectionPrototype.append = function(name) {
+ name = d3_selection_creator(name);
+ return this.select(function() {
+ return this.appendChild(name.apply(this, arguments));
+ });
+ };
+ function d3_selection_creator(name) {
+ return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() {
+ return this.ownerDocument.createElementNS(name.space, name.local);
+ } : function() {
+ return this.ownerDocument.createElementNS(this.namespaceURI, name);
+ };
+ }
+ d3_selectionPrototype.insert = function(name, before) {
+ name = d3_selection_creator(name);
+ before = d3_selection_selector(before);
+ return this.select(function() {
+ return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
+ });
+ };
+ d3_selectionPrototype.remove = function() {
+ return this.each(function() {
+ var parent = this.parentNode;
+ if (parent) parent.removeChild(this);
+ });
+ };
+ d3_selectionPrototype.data = function(value, key) {
+ var i = -1, n = this.length, group, node;
+ if (!arguments.length) {
+ value = new Array(n = (group = this[0]).length);
+ while (++i < n) {
+ if (node = group[i]) {
+ value[i] = node.__data__;
+ }
+ }
+ return value;
+ }
+ function bind(group, groupData) {
+ var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
+ if (key) {
+ var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue;
+ for (i = -1; ++i < n; ) {
+ keyValue = key.call(node = group[i], node.__data__, i);
+ if (nodeByKeyValue.has(keyValue)) {
+ exitNodes[i] = node;
+ } else {
+ nodeByKeyValue.set(keyValue, node);
+ }
+ keyValues.push(keyValue);
+ }
+ for (i = -1; ++i < m; ) {
+ keyValue = key.call(groupData, nodeData = groupData[i], i);
+ if (node = nodeByKeyValue.get(keyValue)) {
+ updateNodes[i] = node;
+ node.__data__ = nodeData;
+ } else if (!dataByKeyValue.has(keyValue)) {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
+ dataByKeyValue.set(keyValue, nodeData);
+ nodeByKeyValue.remove(keyValue);
+ }
+ for (i = -1; ++i < n; ) {
+ if (nodeByKeyValue.has(keyValues[i])) {
+ exitNodes[i] = group[i];
+ }
+ }
+ } else {
+ for (i = -1; ++i < n0; ) {
+ node = group[i];
+ nodeData = groupData[i];
+ if (node) {
+ node.__data__ = nodeData;
+ updateNodes[i] = node;
+ } else {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
+ }
+ for (;i < m; ++i) {
+ enterNodes[i] = d3_selection_dataNode(groupData[i]);
+ }
+ for (;i < n; ++i) {
+ exitNodes[i] = group[i];
+ }
+ }
+ enterNodes.update = updateNodes;
+ enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
+ enter.push(enterNodes);
+ update.push(updateNodes);
+ exit.push(exitNodes);
+ }
+ var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
+ if (typeof value === "function") {
+ while (++i < n) {
+ bind(group = this[i], value.call(group, group.parentNode.__data__, i));
+ }
+ } else {
+ while (++i < n) {
+ bind(group = this[i], value);
+ }
+ }
+ update.enter = function() {
+ return enter;
+ };
+ update.exit = function() {
+ return exit;
+ };
+ return update;
+ };
+ function d3_selection_dataNode(data) {
+ return {
+ __data__: data
+ };
+ }
+ d3_selectionPrototype.datum = function(value) {
+ return arguments.length ? this.property("__data__", value) : this.property("__data__");
+ };
+ d3_selectionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_filter(selector) {
+ return function() {
+ return d3_selectMatches(this, selector);
+ };
+ }
+ d3_selectionPrototype.order = function() {
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
+ if (node = group[i]) {
+ if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
+ next = node;
+ }
+ }
+ }
+ return this;
+ };
+ d3_selectionPrototype.sort = function(comparator) {
+ comparator = d3_selection_sortComparator.apply(this, arguments);
+ for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
+ return this.order();
+ };
+ function d3_selection_sortComparator(comparator) {
+ if (!arguments.length) comparator = d3_ascending;
+ return function(a, b) {
+ return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
+ };
+ }
+ d3_selectionPrototype.each = function(callback) {
+ return d3_selection_each(this, function(node, i, j) {
+ callback.call(node, node.__data__, i, j);
+ });
+ };
+ function d3_selection_each(groups, callback) {
+ for (var j = 0, m = groups.length; j < m; j++) {
+ for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
+ if (node = group[i]) callback(node, i, j);
+ }
+ }
+ return groups;
+ }
+ d3_selectionPrototype.call = function(callback) {
+ var args = d3_array(arguments);
+ callback.apply(args[0] = this, args);
+ return this;
+ };
+ d3_selectionPrototype.empty = function() {
+ return !this.node();
+ };
+ d3_selectionPrototype.node = function() {
+ for (var j = 0, m = this.length; j < m; j++) {
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ var node = group[i];
+ if (node) return node;
+ }
+ }
+ return null;
+ };
+ d3_selectionPrototype.size = function() {
+ var n = 0;
+ this.each(function() {
+ ++n;
+ });
+ return n;
+ };
+ function d3_selection_enter(selection) {
+ d3_subclass(selection, d3_selection_enterPrototype);
+ return selection;
+ }
+ var d3_selection_enterPrototype = [];
+ d3.selection.enter = d3_selection_enter;
+ d3.selection.enter.prototype = d3_selection_enterPrototype;
+ d3_selection_enterPrototype.append = d3_selectionPrototype.append;
+ d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
+ d3_selection_enterPrototype.node = d3_selectionPrototype.node;
+ d3_selection_enterPrototype.call = d3_selectionPrototype.call;
+ d3_selection_enterPrototype.size = d3_selectionPrototype.size;
+ d3_selection_enterPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, upgroup, group, node;
+ for (var j = -1, m = this.length; ++j < m; ) {
+ upgroup = (group = this[j]).update;
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = group.parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j));
+ subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ d3_selection_enterPrototype.insert = function(name, before) {
+ if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
+ return d3_selectionPrototype.insert.call(this, name, before);
+ };
+ function d3_selection_enterInsertBefore(enter) {
+ var i0, j0;
+ return function(d, i, j) {
+ var group = enter[j].update, n = group.length, node;
+ if (j != j0) j0 = j, i0 = 0;
+ if (i >= i0) i0 = i + 1;
+ while (!(node = group[i0]) && ++i0 < n) ;
+ return node;
+ };
+ }
+ d3_selectionPrototype.transition = function() {
+ var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || {
+ time: Date.now(),
+ ease: d3_ease_cubicInOut,
+ delay: 0,
+ duration: 250
+ };
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) d3_transitionNode(node, i, id, transition);
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_selectionPrototype.interrupt = function() {
+ return this.each(d3_selection_interrupt);
+ };
+ function d3_selection_interrupt() {
+ var lock = this.__transition__;
+ if (lock) ++lock.active;
+ }
+ d3.select = function(node) {
+ var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ];
+ group.parentNode = d3_documentElement;
+ return d3_selection([ group ]);
+ };
+ d3.selectAll = function(nodes) {
+ var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes);
+ group.parentNode = d3_documentElement;
+ return d3_selection([ group ]);
+ };
+ var d3_selectionRoot = d3.select(d3_documentElement);
+ d3_selectionPrototype.on = function(type, listener, capture) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof type !== "string") {
+ if (n < 2) listener = false;
+ for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
+ return this;
+ }
+ if (n < 2) return (n = this.node()["__on" + type]) && n._;
+ capture = false;
+ }
+ return this.each(d3_selection_on(type, listener, capture));
+ };
+ function d3_selection_on(type, listener, capture) {
+ var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener;
+ if (i > 0) type = type.substring(0, i);
+ var filter = d3_selection_onFilters.get(type);
+ if (filter) type = filter, wrap = d3_selection_onFilter;
+ function onRemove() {
+ var l = this[name];
+ if (l) {
+ this.removeEventListener(type, l, l.$);
+ delete this[name];
+ }
+ }
+ function onAdd() {
+ var l = wrap(listener, d3_array(arguments));
+ onRemove.call(this);
+ this.addEventListener(type, this[name] = l, l.$ = capture);
+ l._ = listener;
+ }
+ function removeAll() {
+ var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match;
+ for (var name in this) {
+ if (match = name.match(re)) {
+ var l = this[name];
+ this.removeEventListener(match[1], l, l.$);
+ delete this[name];
+ }
+ }
+ }
+ return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;
+ }
+ var d3_selection_onFilters = d3.map({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+ });
+ d3_selection_onFilters.forEach(function(k) {
+ if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
+ });
+ function d3_selection_onListener(listener, argumentz) {
+ return function(e) {
+ var o = d3.event;
+ d3.event = e;
+ argumentz[0] = this.__data__;
+ try {
+ listener.apply(this, argumentz);
+ } finally {
+ d3.event = o;
+ }
+ };
+ }
+ function d3_selection_onFilter(listener, argumentz) {
+ var l = d3_selection_onListener(listener, argumentz);
+ return function(e) {
+ var target = this, related = e.relatedTarget;
+ if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) {
+ l.call(target, e);
+ }
+ };
+ }
+ var d3_event_dragSelect = "onselectstart" in d3_document ? null : d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0;
+ function d3_event_dragSuppress() {
+ var name = ".dragsuppress-" + ++d3_event_dragId, click = "click" + name, w = d3.select(d3_window).on("touchmove" + name, d3_eventPreventDefault).on("dragstart" + name, d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault);
+ if (d3_event_dragSelect) {
+ var style = d3_documentElement.style, select = style[d3_event_dragSelect];
+ style[d3_event_dragSelect] = "none";
+ }
+ return function(suppressClick) {
+ w.on(name, null);
+ if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
+ if (suppressClick) {
+ function off() {
+ w.on(click, null);
+ }
+ w.on(click, function() {
+ d3_eventPreventDefault();
+ off();
+ }, true);
+ setTimeout(off, 0);
+ }
+ };
+ }
+ d3.mouse = function(container) {
+ return d3_mousePoint(container, d3_eventSource());
+ };
+ function d3_mousePoint(container, e) {
+ if (e.changedTouches) e = e.changedTouches[0];
+ var svg = container.ownerSVGElement || container;
+ if (svg.createSVGPoint) {
+ var point = svg.createSVGPoint();
+ point.x = e.clientX, point.y = e.clientY;
+ point = point.matrixTransform(container.getScreenCTM().inverse());
+ return [ point.x, point.y ];
+ }
+ var rect = container.getBoundingClientRect();
+ return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
+ }
+ d3.touches = function(container, touches) {
+ if (arguments.length < 2) touches = d3_eventSource().touches;
+ return touches ? d3_array(touches).map(function(touch) {
+ var point = d3_mousePoint(container, touch);
+ point.identifier = touch.identifier;
+ return point;
+ }) : [];
+ };
+ d3.behavior.drag = function() {
+ var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, d3_behavior_dragMouseSubject, "mousemove", "mouseup"), touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_behavior_dragTouchSubject, "touchmove", "touchend");
+ function drag() {
+ this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart);
+ }
+ function dragstart(id, position, subject, move, end) {
+ return function() {
+ var that = this, target = d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject()).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(), position0 = position(parent, dragId);
+ if (origin) {
+ dragOffset = origin.apply(that, arguments);
+ dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ];
+ } else {
+ dragOffset = [ 0, 0 ];
+ }
+ dispatch({
+ type: "dragstart"
+ });
+ function moved() {
+ var position1 = position(parent, dragId), dx, dy;
+ if (!position1) return;
+ dx = position1[0] - position0[0];
+ dy = position1[1] - position0[1];
+ dragged |= dx | dy;
+ position0 = position1;
+ dispatch({
+ type: "drag",
+ x: position1[0] + dragOffset[0],
+ y: position1[1] + dragOffset[1],
+ dx: dx,
+ dy: dy
+ });
+ }
+ function ended() {
+ if (!position(parent, dragId)) return;
+ dragSubject.on(move + dragName, null).on(end + dragName, null);
+ dragRestore(dragged && d3.event.target === target);
+ dispatch({
+ type: "dragend"
+ });
+ }
+ };
+ }
+ drag.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return drag;
+ };
+ return d3.rebind(drag, event, "on");
+ };
+ function d3_behavior_dragTouchId() {
+ return d3.event.changedTouches[0].identifier;
+ }
+ function d3_behavior_dragTouchSubject() {
+ return d3.event.target;
+ }
+ function d3_behavior_dragMouseSubject() {
+ return d3_window;
+ }
+ var π = Math.PI, τ = 2 * π, halfπ = π / 2, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π;
+ function d3_sgn(x) {
+ return x > 0 ? 1 : x < 0 ? -1 : 0;
+ }
+ function d3_cross2d(a, b, c) {
+ return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
+ }
+ function d3_acos(x) {
+ return x > 1 ? 0 : x < -1 ? π : Math.acos(x);
+ }
+ function d3_asin(x) {
+ return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);
+ }
+ function d3_sinh(x) {
+ return ((x = Math.exp(x)) - 1 / x) / 2;
+ }
+ function d3_cosh(x) {
+ return ((x = Math.exp(x)) + 1 / x) / 2;
+ }
+ function d3_tanh(x) {
+ return ((x = Math.exp(2 * x)) - 1) / (x + 1);
+ }
+ function d3_haversin(x) {
+ return (x = Math.sin(x / 2)) * x;
+ }
+ var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4;
+ d3.interpolateZoom = function(p0, p1) {
+ var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2];
+ var dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1), dr = r1 - r0, S = (dr || Math.log(w1 / w0)) / ρ;
+ function interpolate(t) {
+ var s = t * S;
+ if (dr) {
+ var coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));
+ return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ];
+ }
+ return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * s) ];
+ }
+ interpolate.duration = S * 1e3;
+ return interpolate;
+ };
+ d3.behavior.zoom = function() {
+ var view = {
+ x: 0,
+ y: 0,
+ k: 1
+ }, translate0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1;
+ function zoom(g) {
+ g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted);
+ }
+ zoom.event = function(g) {
+ g.each(function() {
+ var dispatch = event.of(this, arguments), view1 = view;
+ if (d3_transitionInheritId) {
+ d3.select(this).transition().each("start.zoom", function() {
+ view = this.__chart__ || {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ zoomstarted(dispatch);
+ }).tween("zoom:zoom", function() {
+ var dx = size[0], dy = size[1], cx = dx / 2, cy = dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]);
+ return function(t) {
+ var l = i(t), k = dx / l[2];
+ this.__chart__ = view = {
+ x: cx - l[0] * k,
+ y: cy - l[1] * k,
+ k: k
+ };
+ zoomed(dispatch);
+ };
+ }).each("end.zoom", function() {
+ zoomended(dispatch);
+ });
+ } else {
+ this.__chart__ = view;
+ zoomstarted(dispatch);
+ zoomed(dispatch);
+ zoomended(dispatch);
+ }
+ });
+ };
+ zoom.translate = function(_) {
+ if (!arguments.length) return [ view.x, view.y ];
+ view = {
+ x: +_[0],
+ y: +_[1],
+ k: view.k
+ };
+ rescale();
+ return zoom;
+ };
+ zoom.scale = function(_) {
+ if (!arguments.length) return view.k;
+ view = {
+ x: view.x,
+ y: view.y,
+ k: +_
+ };
+ rescale();
+ return zoom;
+ };
+ zoom.scaleExtent = function(_) {
+ if (!arguments.length) return scaleExtent;
+ scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ];
+ return zoom;
+ };
+ zoom.center = function(_) {
+ if (!arguments.length) return center;
+ center = _ && [ +_[0], +_[1] ];
+ return zoom;
+ };
+ zoom.size = function(_) {
+ if (!arguments.length) return size;
+ size = _ && [ +_[0], +_[1] ];
+ return zoom;
+ };
+ zoom.x = function(z) {
+ if (!arguments.length) return x1;
+ x1 = z;
+ x0 = z.copy();
+ view = {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ return zoom;
+ };
+ zoom.y = function(z) {
+ if (!arguments.length) return y1;
+ y1 = z;
+ y0 = z.copy();
+ view = {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ return zoom;
+ };
+ function location(p) {
+ return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ];
+ }
+ function point(l) {
+ return [ l[0] * view.k + view.x, l[1] * view.k + view.y ];
+ }
+ function scaleTo(s) {
+ view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
+ }
+ function translateTo(p, l) {
+ l = point(l);
+ view.x += p[0] - l[0];
+ view.y += p[1] - l[1];
+ }
+ function rescale() {
+ if (x1) x1.domain(x0.range().map(function(x) {
+ return (x - view.x) / view.k;
+ }).map(x0.invert));
+ if (y1) y1.domain(y0.range().map(function(y) {
+ return (y - view.y) / view.k;
+ }).map(y0.invert));
+ }
+ function zoomstarted(dispatch) {
+ dispatch({
+ type: "zoomstart"
+ });
+ }
+ function zoomed(dispatch) {
+ rescale();
+ dispatch({
+ type: "zoom",
+ scale: view.k,
+ translate: [ view.x, view.y ]
+ });
+ }
+ function zoomended(dispatch) {
+ dispatch({
+ type: "zoomend"
+ });
+ }
+ function mousedowned() {
+ var that = this, target = d3.event.target, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress();
+ d3_selection_interrupt.call(that);
+ zoomstarted(dispatch);
+ function moved() {
+ dragged = 1;
+ translateTo(d3.mouse(that), location0);
+ zoomed(dispatch);
+ }
+ function ended() {
+ subject.on(mousemove, d3_window === that ? mousewheelreset : null).on(mouseup, null);
+ dragRestore(dragged && d3.event.target === target);
+ zoomended(dispatch);
+ }
+ }
+ function touchstarted() {
+ var that = this, dispatch = event.of(that, arguments), locations0 = {}, distance0 = 0, scale0, zoomName = ".zoom-" + d3.event.changedTouches[0].identifier, touchmove = "touchmove" + zoomName, touchend = "touchend" + zoomName, target = d3.select(d3.event.target).on(touchmove, moved).on(touchend, ended), subject = d3.select(that).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress();
+ d3_selection_interrupt.call(that);
+ started();
+ zoomstarted(dispatch);
+ function relocate() {
+ var touches = d3.touches(that);
+ scale0 = view.k;
+ touches.forEach(function(t) {
+ if (t.identifier in locations0) locations0[t.identifier] = location(t);
+ });
+ return touches;
+ }
+ function started() {
+ var changed = d3.event.changedTouches;
+ for (var i = 0, n = changed.length; i < n; ++i) {
+ locations0[changed[i].identifier] = null;
+ }
+ var touches = relocate(), now = Date.now();
+ if (touches.length === 1) {
+ if (now - touchtime < 500) {
+ var p = touches[0], l = locations0[p.identifier];
+ scaleTo(view.k * 2);
+ translateTo(p, l);
+ d3_eventPreventDefault();
+ zoomed(dispatch);
+ }
+ touchtime = now;
+ } else if (touches.length > 1) {
+ var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];
+ distance0 = dx * dx + dy * dy;
+ }
+ }
+ function moved() {
+ var touches = d3.touches(that), p0, l0, p1, l1;
+ for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
+ p1 = touches[i];
+ if (l1 = locations0[p1.identifier]) {
+ if (l0) break;
+ p0 = p1, l0 = l1;
+ }
+ }
+ if (l1) {
+ var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0);
+ p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
+ l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
+ scaleTo(scale1 * scale0);
+ }
+ touchtime = null;
+ translateTo(p0, l0);
+ zoomed(dispatch);
+ }
+ function ended() {
+ if (d3.event.touches.length) {
+ var changed = d3.event.changedTouches;
+ for (var i = 0, n = changed.length; i < n; ++i) {
+ delete locations0[changed[i].identifier];
+ }
+ for (var identifier in locations0) {
+ return void relocate();
+ }
+ }
+ target.on(zoomName, null);
+ subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
+ dragRestore();
+ zoomended(dispatch);
+ }
+ }
+ function mousewheeled() {
+ var dispatch = event.of(this, arguments);
+ if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this),
+ zoomstarted(dispatch);
+ mousewheelTimer = setTimeout(function() {
+ mousewheelTimer = null;
+ zoomended(dispatch);
+ }, 50);
+ d3_eventPreventDefault();
+ var point = center || d3.mouse(this);
+ if (!translate0) translate0 = location(point);
+ scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
+ translateTo(point, translate0);
+ zoomed(dispatch);
+ }
+ function mousewheelreset() {
+ translate0 = null;
+ }
+ function dblclicked() {
+ var dispatch = event.of(this, arguments), p = d3.mouse(this), l = location(p), k = Math.log(view.k) / Math.LN2;
+ zoomstarted(dispatch);
+ scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
+ translateTo(p, l);
+ zoomed(dispatch);
+ zoomended(dispatch);
+ }
+ return d3.rebind(zoom, event, "on");
+ };
+ var d3_behavior_zoomInfinity = [ 0, Infinity ];
+ var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() {
+ return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);
+ }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() {
+ return d3.event.wheelDelta;
+ }, "mousewheel") : (d3_behavior_zoomDelta = function() {
+ return -d3.event.detail;
+ }, "MozMousePixelScroll");
+ function d3_Color() {}
+ d3_Color.prototype.toString = function() {
+ return this.rgb() + "";
+ };
+ d3.hsl = function(h, s, l) {
+ return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
+ };
+ function d3_hsl(h, s, l) {
+ return new d3_Hsl(h, s, l);
+ }
+ function d3_Hsl(h, s, l) {
+ this.h = h;
+ this.s = s;
+ this.l = l;
+ }
+ var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();
+ d3_hslPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, this.l / k);
+ };
+ d3_hslPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, k * this.l);
+ };
+ d3_hslPrototype.rgb = function() {
+ return d3_hsl_rgb(this.h, this.s, this.l);
+ };
+ function d3_hsl_rgb(h, s, l) {
+ var m1, m2;
+ h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
+ s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
+ l = l < 0 ? 0 : l > 1 ? 1 : l;
+ m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
+ m1 = 2 * l - m2;
+ function v(h) {
+ if (h > 360) h -= 360; else if (h < 0) h += 360;
+ if (h < 60) return m1 + (m2 - m1) * h / 60;
+ if (h < 180) return m2;
+ if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
+ return m1;
+ }
+ function vv(h) {
+ return Math.round(v(h) * 255);
+ }
+ return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
+ }
+ d3.hcl = function(h, c, l) {
+ return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);
+ };
+ function d3_hcl(h, c, l) {
+ return new d3_Hcl(h, c, l);
+ }
+ function d3_Hcl(h, c, l) {
+ this.h = h;
+ this.c = c;
+ this.l = l;
+ }
+ var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();
+ d3_hclPrototype.brighter = function(k) {
+ return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
+ };
+ d3_hclPrototype.darker = function(k) {
+ return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
+ };
+ d3_hclPrototype.rgb = function() {
+ return d3_hcl_lab(this.h, this.c, this.l).rgb();
+ };
+ function d3_hcl_lab(h, c, l) {
+ if (isNaN(h)) h = 0;
+ if (isNaN(c)) c = 0;
+ return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
+ }
+ d3.lab = function(l, a, b) {
+ return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b);
+ };
+ function d3_lab(l, a, b) {
+ return new d3_Lab(l, a, b);
+ }
+ function d3_Lab(l, a, b) {
+ this.l = l;
+ this.a = a;
+ this.b = b;
+ }
+ var d3_lab_K = 18;
+ var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
+ var d3_labPrototype = d3_Lab.prototype = new d3_Color();
+ d3_labPrototype.brighter = function(k) {
+ return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+ };
+ d3_labPrototype.darker = function(k) {
+ return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
+ };
+ d3_labPrototype.rgb = function() {
+ return d3_lab_rgb(this.l, this.a, this.b);
+ };
+ function d3_lab_rgb(l, a, b) {
+ var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
+ x = d3_lab_xyz(x) * d3_lab_X;
+ y = d3_lab_xyz(y) * d3_lab_Y;
+ z = d3_lab_xyz(z) * d3_lab_Z;
+ return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
+ }
+ function d3_lab_hcl(l, a, b) {
+ return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l);
+ }
+ function d3_lab_xyz(x) {
+ return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
+ }
+ function d3_xyz_lab(x) {
+ return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
+ }
+ function d3_xyz_rgb(r) {
+ return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
+ }
+ d3.rgb = function(r, g, b) {
+ return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);
+ };
+ function d3_rgbNumber(value) {
+ return d3_rgb(value >> 16, value >> 8 & 255, value & 255);
+ }
+ function d3_rgbString(value) {
+ return d3_rgbNumber(value) + "";
+ }
+ function d3_rgb(r, g, b) {
+ return new d3_Rgb(r, g, b);
+ }
+ function d3_Rgb(r, g, b) {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ }
+ var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color();
+ d3_rgbPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ var r = this.r, g = this.g, b = this.b, i = 30;
+ if (!r && !g && !b) return d3_rgb(i, i, i);
+ if (r && r < i) r = i;
+ if (g && g < i) g = i;
+ if (b && b < i) b = i;
+ return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k)));
+ };
+ d3_rgbPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b));
+ };
+ d3_rgbPrototype.hsl = function() {
+ return d3_rgb_hsl(this.r, this.g, this.b);
+ };
+ d3_rgbPrototype.toString = function() {
+ return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
+ };
+ function d3_rgb_hex(v) {
+ return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
+ }
+ function d3_rgb_parse(format, rgb, hsl) {
+ var r = 0, g = 0, b = 0, m1, m2, color;
+ m1 = /([a-z]+)\((.*)\)/i.exec(format);
+ if (m1) {
+ m2 = m1[2].split(",");
+ switch (m1[1]) {
+ case "hsl":
+ {
+ return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
+ }
+
+ case "rgb":
+ {
+ return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
+ }
+ }
+ }
+ if (color = d3_rgb_names.get(format)) return rgb(color.r, color.g, color.b);
+ if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.substring(1), 16))) {
+ if (format.length === 4) {
+ r = (color & 3840) >> 4;
+ r = r >> 4 | r;
+ g = color & 240;
+ g = g >> 4 | g;
+ b = color & 15;
+ b = b << 4 | b;
+ } else if (format.length === 7) {
+ r = (color & 16711680) >> 16;
+ g = (color & 65280) >> 8;
+ b = color & 255;
+ }
+ }
+ return rgb(r, g, b);
+ }
+ function d3_rgb_hsl(r, g, b) {
+ var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;
+ if (d) {
+ s = l < .5 ? d / (max + min) : d / (2 - max - min);
+ if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;
+ h *= 60;
+ } else {
+ h = NaN;
+ s = l > 0 && l < 1 ? 0 : h;
+ }
+ return d3_hsl(h, s, l);
+ }
+ function d3_rgb_lab(r, g, b) {
+ r = d3_rgb_xyz(r);
+ g = d3_rgb_xyz(g);
+ b = d3_rgb_xyz(b);
+ var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
+ return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
+ }
+ function d3_rgb_xyz(r) {
+ return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
+ }
+ function d3_rgb_parseNumber(c) {
+ var f = parseFloat(c);
+ return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
+ }
+ var d3_rgb_names = d3.map({
+ aliceblue: 15792383,
+ antiquewhite: 16444375,
+ aqua: 65535,
+ aquamarine: 8388564,
+ azure: 15794175,
+ beige: 16119260,
+ bisque: 16770244,
+ black: 0,
+ blanchedalmond: 16772045,
+ blue: 255,
+ blueviolet: 9055202,
+ brown: 10824234,
+ burlywood: 14596231,
+ cadetblue: 6266528,
+ chartreuse: 8388352,
+ chocolate: 13789470,
+ coral: 16744272,
+ cornflowerblue: 6591981,
+ cornsilk: 16775388,
+ crimson: 14423100,
+ cyan: 65535,
+ darkblue: 139,
+ darkcyan: 35723,
+ darkgoldenrod: 12092939,
+ darkgray: 11119017,
+ darkgreen: 25600,
+ darkgrey: 11119017,
+ darkkhaki: 12433259,
+ darkmagenta: 9109643,
+ darkolivegreen: 5597999,
+ darkorange: 16747520,
+ darkorchid: 10040012,
+ darkred: 9109504,
+ darksalmon: 15308410,
+ darkseagreen: 9419919,
+ darkslateblue: 4734347,
+ darkslategray: 3100495,
+ darkslategrey: 3100495,
+ darkturquoise: 52945,
+ darkviolet: 9699539,
+ deeppink: 16716947,
+ deepskyblue: 49151,
+ dimgray: 6908265,
+ dimgrey: 6908265,
+ dodgerblue: 2003199,
+ firebrick: 11674146,
+ floralwhite: 16775920,
+ forestgreen: 2263842,
+ fuchsia: 16711935,
+ gainsboro: 14474460,
+ ghostwhite: 16316671,
+ gold: 16766720,
+ goldenrod: 14329120,
+ gray: 8421504,
+ green: 32768,
+ greenyellow: 11403055,
+ grey: 8421504,
+ honeydew: 15794160,
+ hotpink: 16738740,
+ indianred: 13458524,
+ indigo: 4915330,
+ ivory: 16777200,
+ khaki: 15787660,
+ lavender: 15132410,
+ lavenderblush: 16773365,
+ lawngreen: 8190976,
+ lemonchiffon: 16775885,
+ lightblue: 11393254,
+ lightcoral: 15761536,
+ lightcyan: 14745599,
+ lightgoldenrodyellow: 16448210,
+ lightgray: 13882323,
+ lightgreen: 9498256,
+ lightgrey: 13882323,
+ lightpink: 16758465,
+ lightsalmon: 16752762,
+ lightseagreen: 2142890,
+ lightskyblue: 8900346,
+ lightslategray: 7833753,
+ lightslategrey: 7833753,
+ lightsteelblue: 11584734,
+ lightyellow: 16777184,
+ lime: 65280,
+ limegreen: 3329330,
+ linen: 16445670,
+ magenta: 16711935,
+ maroon: 8388608,
+ mediumaquamarine: 6737322,
+ mediumblue: 205,
+ mediumorchid: 12211667,
+ mediumpurple: 9662683,
+ mediumseagreen: 3978097,
+ mediumslateblue: 8087790,
+ mediumspringgreen: 64154,
+ mediumturquoise: 4772300,
+ mediumvioletred: 13047173,
+ midnightblue: 1644912,
+ mintcream: 16121850,
+ mistyrose: 16770273,
+ moccasin: 16770229,
+ navajowhite: 16768685,
+ navy: 128,
+ oldlace: 16643558,
+ olive: 8421376,
+ olivedrab: 7048739,
+ orange: 16753920,
+ orangered: 16729344,
+ orchid: 14315734,
+ palegoldenrod: 15657130,
+ palegreen: 10025880,
+ paleturquoise: 11529966,
+ palevioletred: 14381203,
+ papayawhip: 16773077,
+ peachpuff: 16767673,
+ peru: 13468991,
+ pink: 16761035,
+ plum: 14524637,
+ powderblue: 11591910,
+ purple: 8388736,
+ red: 16711680,
+ rosybrown: 12357519,
+ royalblue: 4286945,
+ saddlebrown: 9127187,
+ salmon: 16416882,
+ sandybrown: 16032864,
+ seagreen: 3050327,
+ seashell: 16774638,
+ sienna: 10506797,
+ silver: 12632256,
+ skyblue: 8900331,
+ slateblue: 6970061,
+ slategray: 7372944,
+ slategrey: 7372944,
+ snow: 16775930,
+ springgreen: 65407,
+ steelblue: 4620980,
+ tan: 13808780,
+ teal: 32896,
+ thistle: 14204888,
+ tomato: 16737095,
+ turquoise: 4251856,
+ violet: 15631086,
+ wheat: 16113331,
+ white: 16777215,
+ whitesmoke: 16119285,
+ yellow: 16776960,
+ yellowgreen: 10145074
+ });
+ d3_rgb_names.forEach(function(key, value) {
+ d3_rgb_names.set(key, d3_rgbNumber(value));
+ });
+ function d3_functor(v) {
+ return typeof v === "function" ? v : function() {
+ return v;
+ };
+ }
+ d3.functor = d3_functor;
+ function d3_identity(d) {
+ return d;
+ }
+ d3.xhr = d3_xhrType(d3_identity);
+ function d3_xhrType(response) {
+ return function(url, mimeType, callback) {
+ if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType,
+ mimeType = null;
+ return d3_xhr(url, mimeType, response, callback);
+ };
+ }
+ function d3_xhr(url, mimeType, response, callback) {
+ var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null;
+ if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
+ "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {
+ request.readyState > 3 && respond();
+ };
+ function respond() {
+ var status = request.status, result;
+ if (!status && request.responseText || status >= 200 && status < 300 || status === 304) {
+ try {
+ result = response.call(xhr, request);
+ } catch (e) {
+ dispatch.error.call(xhr, e);
+ return;
+ }
+ dispatch.load.call(xhr, result);
+ } else {
+ dispatch.error.call(xhr, request);
+ }
+ }
+ request.onprogress = function(event) {
+ var o = d3.event;
+ d3.event = event;
+ try {
+ dispatch.progress.call(xhr, request);
+ } finally {
+ d3.event = o;
+ }
+ };
+ xhr.header = function(name, value) {
+ name = (name + "").toLowerCase();
+ if (arguments.length < 2) return headers[name];
+ if (value == null) delete headers[name]; else headers[name] = value + "";
+ return xhr;
+ };
+ xhr.mimeType = function(value) {
+ if (!arguments.length) return mimeType;
+ mimeType = value == null ? null : value + "";
+ return xhr;
+ };
+ xhr.responseType = function(value) {
+ if (!arguments.length) return responseType;
+ responseType = value;
+ return xhr;
+ };
+ xhr.response = function(value) {
+ response = value;
+ return xhr;
+ };
+ [ "get", "post" ].forEach(function(method) {
+ xhr[method] = function() {
+ return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
+ };
+ });
+ xhr.send = function(method, data, callback) {
+ if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
+ request.open(method, url, true);
+ if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
+ if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
+ if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
+ if (responseType != null) request.responseType = responseType;
+ if (callback != null) xhr.on("error", callback).on("load", function(request) {
+ callback(null, request);
+ });
+ dispatch.beforesend.call(xhr, request);
+ request.send(data == null ? null : data);
+ return xhr;
+ };
+ xhr.abort = function() {
+ request.abort();
+ return xhr;
+ };
+ d3.rebind(xhr, dispatch, "on");
+ return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
+ }
+ function d3_xhr_fixCallback(callback) {
+ return callback.length === 1 ? function(error, request) {
+ callback(error == null ? request : null);
+ } : callback;
+ }
+ d3.dsv = function(delimiter, mimeType) {
+ var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
+ function dsv(url, row, callback) {
+ if (arguments.length < 3) callback = row, row = null;
+ var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row), callback);
+ xhr.row = function(_) {
+ return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row;
+ };
+ return xhr;
+ }
+ function response(request) {
+ return dsv.parse(request.responseText);
+ }
+ function typedResponse(f) {
+ return function(request) {
+ return dsv.parse(request.responseText, f);
+ };
+ }
+ dsv.parse = function(text, f) {
+ var o;
+ return dsv.parseRows(text, function(row, i) {
+ if (o) return o(row, i - 1);
+ var a = new Function("d", "return {" + row.map(function(name, i) {
+ return JSON.stringify(name) + ": d[" + i + "]";
+ }).join(",") + "}");
+ o = f ? function(row, i) {
+ return f(a(row), i);
+ } : a;
+ });
+ };
+ dsv.parseRows = function(text, f) {
+ var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
+ function token() {
+ if (I >= N) return EOF;
+ if (eol) return eol = false, EOL;
+ var j = I;
+ if (text.charCodeAt(j) === 34) {
+ var i = j;
+ while (i++ < N) {
+ if (text.charCodeAt(i) === 34) {
+ if (text.charCodeAt(i + 1) !== 34) break;
+ ++i;
+ }
+ }
+ I = i + 2;
+ var c = text.charCodeAt(i + 1);
+ if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(i + 2) === 10) ++I;
+ } else if (c === 10) {
+ eol = true;
+ }
+ return text.substring(j + 1, i).replace(/""/g, '"');
+ }
+ while (I < N) {
+ var c = text.charCodeAt(I++), k = 1;
+ if (c === 10) eol = true; else if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(I) === 10) ++I, ++k;
+ } else if (c !== delimiterCode) continue;
+ return text.substring(j, I - k);
+ }
+ return text.substring(j);
+ }
+ while ((t = token()) !== EOF) {
+ var a = [];
+ while (t !== EOL && t !== EOF) {
+ a.push(t);
+ t = token();
+ }
+ if (f && !(a = f(a, n++))) continue;
+ rows.push(a);
+ }
+ return rows;
+ };
+ dsv.format = function(rows) {
+ if (Array.isArray(rows[0])) return dsv.formatRows(rows);
+ var fieldSet = new d3_Set(), fields = [];
+ rows.forEach(function(row) {
+ for (var field in row) {
+ if (!fieldSet.has(field)) {
+ fields.push(fieldSet.add(field));
+ }
+ }
+ });
+ return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) {
+ return fields.map(function(field) {
+ return formatValue(row[field]);
+ }).join(delimiter);
+ })).join("\n");
+ };
+ dsv.formatRows = function(rows) {
+ return rows.map(formatRow).join("\n");
+ };
+ function formatRow(row) {
+ return row.map(formatValue).join(delimiter);
+ }
+ function formatValue(text) {
+ return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
+ }
+ return dsv;
+ };
+ d3.csv = d3.dsv(",", "text/csv");
+ d3.tsv = d3.dsv(" ", "text/tab-separated-values");
+ d3.touch = function(container, touches, identifier) {
+ if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;
+ if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {
+ if ((touch = touches[i]).identifier === identifier) {
+ return d3_mousePoint(container, touch);
+ }
+ }
+ };
+ var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) {
+ setTimeout(callback, 17);
+ };
+ d3.timer = function(callback, delay, then) {
+ var n = arguments.length;
+ if (n < 2) delay = 0;
+ if (n < 3) then = Date.now();
+ var time = then + delay, timer = {
+ c: callback,
+ t: time,
+ f: false,
+ n: null
+ };
+ if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer;
+ d3_timer_queueTail = timer;
+ if (!d3_timer_interval) {
+ d3_timer_timeout = clearTimeout(d3_timer_timeout);
+ d3_timer_interval = 1;
+ d3_timer_frame(d3_timer_step);
+ }
+ };
+ function d3_timer_step() {
+ var now = d3_timer_mark(), delay = d3_timer_sweep() - now;
+ if (delay > 24) {
+ if (isFinite(delay)) {
+ clearTimeout(d3_timer_timeout);
+ d3_timer_timeout = setTimeout(d3_timer_step, delay);
+ }
+ d3_timer_interval = 0;
+ } else {
+ d3_timer_interval = 1;
+ d3_timer_frame(d3_timer_step);
+ }
+ }
+ d3.timer.flush = function() {
+ d3_timer_mark();
+ d3_timer_sweep();
+ };
+ function d3_timer_mark() {
+ var now = Date.now();
+ d3_timer_active = d3_timer_queueHead;
+ while (d3_timer_active) {
+ if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t);
+ d3_timer_active = d3_timer_active.n;
+ }
+ return now;
+ }
+ function d3_timer_sweep() {
+ var t0, t1 = d3_timer_queueHead, time = Infinity;
+ while (t1) {
+ if (t1.f) {
+ t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
+ } else {
+ if (t1.t < time) time = t1.t;
+ t1 = (t0 = t1).n;
+ }
+ }
+ d3_timer_queueTail = t0;
+ return time;
+ }
+ function d3_format_precision(x, p) {
+ return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);
+ }
+ d3.round = function(x, n) {
+ return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
+ };
+ var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix);
+ d3.formatPrefix = function(value, precision) {
+ var i = 0;
+ if (value) {
+ if (value < 0) value *= -1;
+ if (precision) value = d3.round(value, d3_format_precision(value, precision));
+ i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
+ i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3));
+ }
+ return d3_formatPrefixes[8 + i / 3];
+ };
+ function d3_formatPrefix(d, i) {
+ var k = Math.pow(10, abs(8 - i) * 3);
+ return {
+ scale: i > 8 ? function(d) {
+ return d / k;
+ } : function(d) {
+ return d * k;
+ },
+ symbol: d
+ };
+ }
+ function d3_locale_numberFormat(locale) {
+ var locale_decimal = locale.decimal, locale_thousands = locale.thousands, locale_grouping = locale.grouping, locale_currency = locale.currency, formatGroup = locale_grouping ? function(value) {
+ var i = value.length, t = [], j = 0, g = locale_grouping[0];
+ while (i > 0 && g > 0) {
+ t.push(value.substring(i -= g, i + g));
+ g = locale_grouping[j = (j + 1) % locale_grouping.length];
+ }
+ return t.reverse().join(locale_thousands);
+ } : d3_identity;
+ return function(specifier) {
+ var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false;
+ if (precision) precision = +precision.substring(1);
+ if (zfill || fill === "0" && align === "=") {
+ zfill = fill = "0";
+ align = "=";
+ if (comma) width -= Math.floor((width - 1) / 4);
+ }
+ switch (type) {
+ case "n":
+ comma = true;
+ type = "g";
+ break;
+
+ case "%":
+ scale = 100;
+ suffix = "%";
+ type = "f";
+ break;
+
+ case "p":
+ scale = 100;
+ suffix = "%";
+ type = "r";
+ break;
+
+ case "b":
+ case "o":
+ case "x":
+ case "X":
+ if (symbol === "#") prefix = "0" + type.toLowerCase();
+
+ case "c":
+ case "d":
+ integer = true;
+ precision = 0;
+ break;
+
+ case "s":
+ scale = -1;
+ type = "r";
+ break;
+ }
+ if (symbol === "$") prefix = locale_currency[0], suffix = locale_currency[1];
+ if (type == "r" && !precision) type = "g";
+ if (precision != null) {
+ if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision));
+ }
+ type = d3_format_types.get(type) || d3_format_typeDefault;
+ var zcomma = zfill && comma;
+ return function(value) {
+ var fullSuffix = suffix;
+ if (integer && value % 1) return "";
+ var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
+ if (scale < 0) {
+ var unit = d3.formatPrefix(value, precision);
+ value = unit.scale(value);
+ fullSuffix = unit.symbol + suffix;
+ } else {
+ value *= scale;
+ }
+ value = type(value, precision);
+ var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : locale_decimal + value.substring(i + 1);
+ if (!zfill && comma) before = formatGroup(before);
+ var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
+ if (zcomma) before = formatGroup(padding + before);
+ negative += prefix;
+ value = before + after;
+ return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + fullSuffix;
+ };
+ };
+ }
+ var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
+ var d3_format_types = d3.map({
+ b: function(x) {
+ return x.toString(2);
+ },
+ c: function(x) {
+ return String.fromCharCode(x);
+ },
+ o: function(x) {
+ return x.toString(8);
+ },
+ x: function(x) {
+ return x.toString(16);
+ },
+ X: function(x) {
+ return x.toString(16).toUpperCase();
+ },
+ g: function(x, p) {
+ return x.toPrecision(p);
+ },
+ e: function(x, p) {
+ return x.toExponential(p);
+ },
+ f: function(x, p) {
+ return x.toFixed(p);
+ },
+ r: function(x, p) {
+ return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p))));
+ }
+ });
+ function d3_format_typeDefault(x) {
+ return x + "";
+ }
+ var d3_time = d3.time = {}, d3_date = Date;
+ function d3_date_utc() {
+ this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
+ }
+ d3_date_utc.prototype = {
+ getDate: function() {
+ return this._.getUTCDate();
+ },
+ getDay: function() {
+ return this._.getUTCDay();
+ },
+ getFullYear: function() {
+ return this._.getUTCFullYear();
+ },
+ getHours: function() {
+ return this._.getUTCHours();
+ },
+ getMilliseconds: function() {
+ return this._.getUTCMilliseconds();
+ },
+ getMinutes: function() {
+ return this._.getUTCMinutes();
+ },
+ getMonth: function() {
+ return this._.getUTCMonth();
+ },
+ getSeconds: function() {
+ return this._.getUTCSeconds();
+ },
+ getTime: function() {
+ return this._.getTime();
+ },
+ getTimezoneOffset: function() {
+ return 0;
+ },
+ valueOf: function() {
+ return this._.valueOf();
+ },
+ setDate: function() {
+ d3_time_prototype.setUTCDate.apply(this._, arguments);
+ },
+ setDay: function() {
+ d3_time_prototype.setUTCDay.apply(this._, arguments);
+ },
+ setFullYear: function() {
+ d3_time_prototype.setUTCFullYear.apply(this._, arguments);
+ },
+ setHours: function() {
+ d3_time_prototype.setUTCHours.apply(this._, arguments);
+ },
+ setMilliseconds: function() {
+ d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
+ },
+ setMinutes: function() {
+ d3_time_prototype.setUTCMinutes.apply(this._, arguments);
+ },
+ setMonth: function() {
+ d3_time_prototype.setUTCMonth.apply(this._, arguments);
+ },
+ setSeconds: function() {
+ d3_time_prototype.setUTCSeconds.apply(this._, arguments);
+ },
+ setTime: function() {
+ d3_time_prototype.setTime.apply(this._, arguments);
+ }
+ };
+ var d3_time_prototype = Date.prototype;
+ function d3_time_interval(local, step, number) {
+ function round(date) {
+ var d0 = local(date), d1 = offset(d0, 1);
+ return date - d0 < d1 - date ? d0 : d1;
+ }
+ function ceil(date) {
+ step(date = local(new d3_date(date - 1)), 1);
+ return date;
+ }
+ function offset(date, k) {
+ step(date = new d3_date(+date), k);
+ return date;
+ }
+ function range(t0, t1, dt) {
+ var time = ceil(t0), times = [];
+ if (dt > 1) {
+ while (time < t1) {
+ if (!(number(time) % dt)) times.push(new Date(+time));
+ step(time, 1);
+ }
+ } else {
+ while (time < t1) times.push(new Date(+time)), step(time, 1);
+ }
+ return times;
+ }
+ function range_utc(t0, t1, dt) {
+ try {
+ d3_date = d3_date_utc;
+ var utc = new d3_date_utc();
+ utc._ = t0;
+ return range(utc, t1, dt);
+ } finally {
+ d3_date = Date;
+ }
+ }
+ local.floor = local;
+ local.round = round;
+ local.ceil = ceil;
+ local.offset = offset;
+ local.range = range;
+ var utc = local.utc = d3_time_interval_utc(local);
+ utc.floor = utc;
+ utc.round = d3_time_interval_utc(round);
+ utc.ceil = d3_time_interval_utc(ceil);
+ utc.offset = d3_time_interval_utc(offset);
+ utc.range = range_utc;
+ return local;
+ }
+ function d3_time_interval_utc(method) {
+ return function(date, k) {
+ try {
+ d3_date = d3_date_utc;
+ var utc = new d3_date_utc();
+ utc._ = date;
+ return method(utc, k)._;
+ } finally {
+ d3_date = Date;
+ }
+ };
+ }
+ d3_time.year = d3_time_interval(function(date) {
+ date = d3_time.day(date);
+ date.setMonth(0, 1);
+ return date;
+ }, function(date, offset) {
+ date.setFullYear(date.getFullYear() + offset);
+ }, function(date) {
+ return date.getFullYear();
+ });
+ d3_time.years = d3_time.year.range;
+ d3_time.years.utc = d3_time.year.utc.range;
+ d3_time.day = d3_time_interval(function(date) {
+ var day = new d3_date(2e3, 0);
+ day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
+ return day;
+ }, function(date, offset) {
+ date.setDate(date.getDate() + offset);
+ }, function(date) {
+ return date.getDate() - 1;
+ });
+ d3_time.days = d3_time.day.range;
+ d3_time.days.utc = d3_time.day.utc.range;
+ d3_time.dayOfYear = function(date) {
+ var year = d3_time.year(date);
+ return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
+ };
+ [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ].forEach(function(day, i) {
+ i = 7 - i;
+ var interval = d3_time[day] = d3_time_interval(function(date) {
+ (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
+ return date;
+ }, function(date, offset) {
+ date.setDate(date.getDate() + Math.floor(offset) * 7);
+ }, function(date) {
+ var day = d3_time.year(date).getDay();
+ return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
+ });
+ d3_time[day + "s"] = interval.range;
+ d3_time[day + "s"].utc = interval.utc.range;
+ d3_time[day + "OfYear"] = function(date) {
+ var day = d3_time.year(date).getDay();
+ return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7);
+ };
+ });
+ d3_time.week = d3_time.sunday;
+ d3_time.weeks = d3_time.sunday.range;
+ d3_time.weeks.utc = d3_time.sunday.utc.range;
+ d3_time.weekOfYear = d3_time.sundayOfYear;
+ function d3_locale_timeFormat(locale) {
+ var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_days = locale.days, locale_shortDays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths;
+ function d3_time_format(template) {
+ var n = template.length;
+ function format(date) {
+ var string = [], i = -1, j = 0, c, p, f;
+ while (++i < n) {
+ if (template.charCodeAt(i) === 37) {
+ string.push(template.substring(j, i));
+ if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
+ if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p);
+ string.push(c);
+ j = i + 1;
+ }
+ }
+ string.push(template.substring(j, i));
+ return string.join("");
+ }
+ format.parse = function(string) {
+ var d = {
+ y: 1900,
+ m: 0,
+ d: 1,
+ H: 0,
+ M: 0,
+ S: 0,
+ L: 0,
+ Z: null
+ }, i = d3_time_parse(d, template, string, 0);
+ if (i != string.length) return null;
+ if ("p" in d) d.H = d.H % 12 + d.p * 12;
+ var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)();
+ if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) {
+ date.setFullYear(d.y, 0, 1);
+ date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7);
+ } else date.setFullYear(d.y, d.m, d.d);
+ date.setHours(d.H + Math.floor(d.Z / 100), d.M + d.Z % 100, d.S, d.L);
+ return localZ ? date._ : date;
+ };
+ format.toString = function() {
+ return template;
+ };
+ return format;
+ }
+ function d3_time_parse(date, template, string, j) {
+ var c, p, t, i = 0, n = template.length, m = string.length;
+ while (i < n) {
+ if (j >= m) return -1;
+ c = template.charCodeAt(i++);
+ if (c === 37) {
+ t = template.charAt(i++);
+ p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t];
+ if (!p || (j = p(date, string, j)) < 0) return -1;
+ } else if (c != string.charCodeAt(j++)) {
+ return -1;
+ }
+ }
+ return j;
+ }
+ d3_time_format.utc = function(template) {
+ var local = d3_time_format(template);
+ function format(date) {
+ try {
+ d3_date = d3_date_utc;
+ var utc = new d3_date();
+ utc._ = date;
+ return local(utc);
+ } finally {
+ d3_date = Date;
+ }
+ }
+ format.parse = function(string) {
+ try {
+ d3_date = d3_date_utc;
+ var date = local.parse(string);
+ return date && date._;
+ } finally {
+ d3_date = Date;
+ }
+ };
+ format.toString = local.toString;
+ return format;
+ };
+ d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti;
+ var d3_time_periodLookup = d3.map(), d3_time_dayRe = d3_time_formatRe(locale_days), d3_time_dayLookup = d3_time_formatLookup(locale_days), d3_time_dayAbbrevRe = d3_time_formatRe(locale_shortDays), d3_time_dayAbbrevLookup = d3_time_formatLookup(locale_shortDays), d3_time_monthRe = d3_time_formatRe(locale_months), d3_time_monthLookup = d3_time_formatLookup(locale_months), d3_time_monthAbbrevRe = d3_time_formatRe(locale_shortMonths), d3_time_monthAbbrevLookup = d3_time_formatLookup(locale_shortMonths);
+ locale_periods.forEach(function(p, i) {
+ d3_time_periodLookup.set(p.toLowerCase(), i);
+ });
+ var d3_time_formats = {
+ a: function(d) {
+ return locale_shortDays[d.getDay()];
+ },
+ A: function(d) {
+ return locale_days[d.getDay()];
+ },
+ b: function(d) {
+ return locale_shortMonths[d.getMonth()];
+ },
+ B: function(d) {
+ return locale_months[d.getMonth()];
+ },
+ c: d3_time_format(locale_dateTime),
+ d: function(d, p) {
+ return d3_time_formatPad(d.getDate(), p, 2);
+ },
+ e: function(d, p) {
+ return d3_time_formatPad(d.getDate(), p, 2);
+ },
+ H: function(d, p) {
+ return d3_time_formatPad(d.getHours(), p, 2);
+ },
+ I: function(d, p) {
+ return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
+ },
+ j: function(d, p) {
+ return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3);
+ },
+ L: function(d, p) {
+ return d3_time_formatPad(d.getMilliseconds(), p, 3);
+ },
+ m: function(d, p) {
+ return d3_time_formatPad(d.getMonth() + 1, p, 2);
+ },
+ M: function(d, p) {
+ return d3_time_formatPad(d.getMinutes(), p, 2);
+ },
+ p: function(d) {
+ return locale_periods[+(d.getHours() >= 12)];
+ },
+ S: function(d, p) {
+ return d3_time_formatPad(d.getSeconds(), p, 2);
+ },
+ U: function(d, p) {
+ return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2);
+ },
+ w: function(d) {
+ return d.getDay();
+ },
+ W: function(d, p) {
+ return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2);
+ },
+ x: d3_time_format(locale_date),
+ X: d3_time_format(locale_time),
+ y: function(d, p) {
+ return d3_time_formatPad(d.getFullYear() % 100, p, 2);
+ },
+ Y: function(d, p) {
+ return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
+ },
+ Z: d3_time_zone,
+ "%": function() {
+ return "%";
+ }
+ };
+ var d3_time_parsers = {
+ a: d3_time_parseWeekdayAbbrev,
+ A: d3_time_parseWeekday,
+ b: d3_time_parseMonthAbbrev,
+ B: d3_time_parseMonth,
+ c: d3_time_parseLocaleFull,
+ d: d3_time_parseDay,
+ e: d3_time_parseDay,
+ H: d3_time_parseHour24,
+ I: d3_time_parseHour24,
+ j: d3_time_parseDayOfYear,
+ L: d3_time_parseMilliseconds,
+ m: d3_time_parseMonthNumber,
+ M: d3_time_parseMinutes,
+ p: d3_time_parseAmPm,
+ S: d3_time_parseSeconds,
+ U: d3_time_parseWeekNumberSunday,
+ w: d3_time_parseWeekdayNumber,
+ W: d3_time_parseWeekNumberMonday,
+ x: d3_time_parseLocaleDate,
+ X: d3_time_parseLocaleTime,
+ y: d3_time_parseYear,
+ Y: d3_time_parseFullYear,
+ Z: d3_time_parseZone,
+ "%": d3_time_parseLiteralPercent
+ };
+ function d3_time_parseWeekdayAbbrev(date, string, i) {
+ d3_time_dayAbbrevRe.lastIndex = 0;
+ var n = d3_time_dayAbbrevRe.exec(string.substring(i));
+ return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
+ }
+ function d3_time_parseWeekday(date, string, i) {
+ d3_time_dayRe.lastIndex = 0;
+ var n = d3_time_dayRe.exec(string.substring(i));
+ return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
+ }
+ function d3_time_parseMonthAbbrev(date, string, i) {
+ d3_time_monthAbbrevRe.lastIndex = 0;
+ var n = d3_time_monthAbbrevRe.exec(string.substring(i));
+ return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
+ }
+ function d3_time_parseMonth(date, string, i) {
+ d3_time_monthRe.lastIndex = 0;
+ var n = d3_time_monthRe.exec(string.substring(i));
+ return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
+ }
+ function d3_time_parseLocaleFull(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
+ }
+ function d3_time_parseLocaleDate(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
+ }
+ function d3_time_parseLocaleTime(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
+ }
+ function d3_time_parseAmPm(date, string, i) {
+ var n = d3_time_periodLookup.get(string.substring(i, i += 2).toLowerCase());
+ return n == null ? -1 : (date.p = n, i);
+ }
+ return d3_time_format;
+ }
+ var d3_time_formatPads = {
+ "-": "",
+ _: " ",
+ "0": "0"
+ }, d3_time_numberRe = /^\s*\d+/, d3_time_percentRe = /^%/;
+ function d3_time_formatPad(value, fill, width) {
+ var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length;
+ return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
+ }
+ function d3_time_formatRe(names) {
+ return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i");
+ }
+ function d3_time_formatLookup(names) {
+ var map = new d3_Map(), i = -1, n = names.length;
+ while (++i < n) map.set(names[i].toLowerCase(), i);
+ return map;
+ }
+ function d3_time_parseWeekdayNumber(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 1));
+ return n ? (date.w = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseWeekNumberSunday(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i));
+ return n ? (date.U = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseWeekNumberMonday(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i));
+ return n ? (date.W = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseFullYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 4));
+ return n ? (date.y = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1;
+ }
+ function d3_time_parseZone(date, string, i) {
+ return /^[+-]\d{4}$/.test(string = string.substring(i, i + 5)) ? (date.Z = +string,
+ i + 5) : -1;
+ }
+ function d3_time_expandYear(d) {
+ return d + (d > 68 ? 1900 : 2e3);
+ }
+ function d3_time_parseMonthNumber(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.m = n[0] - 1, i + n[0].length) : -1;
+ }
+ function d3_time_parseDay(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.d = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseDayOfYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+ return n ? (date.j = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseHour24(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.H = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseMinutes(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.M = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseSeconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.S = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseMilliseconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+ return n ? (date.L = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_zone(d) {
+ var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(abs(z) / 60), zm = abs(z) % 60;
+ return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2);
+ }
+ function d3_time_parseLiteralPercent(date, string, i) {
+ d3_time_percentRe.lastIndex = 0;
+ var n = d3_time_percentRe.exec(string.substring(i, i + 1));
+ return n ? i + n[0].length : -1;
+ }
+ function d3_time_formatMulti(formats) {
+ var n = formats.length, i = -1;
+ while (++i < n) formats[i][0] = this(formats[i][0]);
+ return function(date) {
+ var i = 0, f = formats[i];
+ while (!f[1](date)) f = formats[++i];
+ return f[0](date);
+ };
+ }
+ d3.locale = function(locale) {
+ return {
+ numberFormat: d3_locale_numberFormat(locale),
+ timeFormat: d3_locale_timeFormat(locale)
+ };
+ };
+ var d3_locale_enUS = d3.locale({
+ decimal: ".",
+ thousands: ",",
+ grouping: [ 3 ],
+ currency: [ "$", "" ],
+ dateTime: "%a %b %e %X %Y",
+ date: "%m/%d/%Y",
+ time: "%H:%M:%S",
+ periods: [ "AM", "PM" ],
+ days: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
+ shortDays: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
+ months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ],
+ shortMonths: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
+ });
+ d3.format = d3_locale_enUS.numberFormat;
+ d3.geo = {};
+ function d3_adder() {}
+ d3_adder.prototype = {
+ s: 0,
+ t: 0,
+ add: function(y) {
+ d3_adderSum(y, this.t, d3_adderTemp);
+ d3_adderSum(d3_adderTemp.s, this.s, this);
+ if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t;
+ },
+ reset: function() {
+ this.s = this.t = 0;
+ },
+ valueOf: function() {
+ return this.s;
+ }
+ };
+ var d3_adderTemp = new d3_adder();
+ function d3_adderSum(a, b, o) {
+ var x = o.s = a + b, bv = x - a, av = x - bv;
+ o.t = a - av + (b - bv);
+ }
+ d3.geo.stream = function(object, listener) {
+ if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
+ d3_geo_streamObjectType[object.type](object, listener);
+ } else {
+ d3_geo_streamGeometry(object, listener);
+ }
+ };
+ function d3_geo_streamGeometry(geometry, listener) {
+ if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
+ d3_geo_streamGeometryType[geometry.type](geometry, listener);
+ }
+ }
+ var d3_geo_streamObjectType = {
+ Feature: function(feature, listener) {
+ d3_geo_streamGeometry(feature.geometry, listener);
+ },
+ FeatureCollection: function(object, listener) {
+ var features = object.features, i = -1, n = features.length;
+ while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
+ }
+ };
+ var d3_geo_streamGeometryType = {
+ Sphere: function(object, listener) {
+ listener.sphere();
+ },
+ Point: function(object, listener) {
+ object = object.coordinates;
+ listener.point(object[0], object[1], object[2]);
+ },
+ MultiPoint: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);
+ },
+ LineString: function(object, listener) {
+ d3_geo_streamLine(object.coordinates, listener, 0);
+ },
+ MultiLineString: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
+ },
+ Polygon: function(object, listener) {
+ d3_geo_streamPolygon(object.coordinates, listener);
+ },
+ MultiPolygon: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
+ },
+ GeometryCollection: function(object, listener) {
+ var geometries = object.geometries, i = -1, n = geometries.length;
+ while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
+ }
+ };
+ function d3_geo_streamLine(coordinates, listener, closed) {
+ var i = -1, n = coordinates.length - closed, coordinate;
+ listener.lineStart();
+ while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]);
+ listener.lineEnd();
+ }
+ function d3_geo_streamPolygon(coordinates, listener) {
+ var i = -1, n = coordinates.length;
+ listener.polygonStart();
+ while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
+ listener.polygonEnd();
+ }
+ d3.geo.area = function(object) {
+ d3_geo_areaSum = 0;
+ d3.geo.stream(object, d3_geo_area);
+ return d3_geo_areaSum;
+ };
+ var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder();
+ var d3_geo_area = {
+ sphere: function() {
+ d3_geo_areaSum += 4 * π;
+ },
+ point: d3_noop,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ d3_geo_areaRingSum.reset();
+ d3_geo_area.lineStart = d3_geo_areaRingStart;
+ },
+ polygonEnd: function() {
+ var area = 2 * d3_geo_areaRingSum;
+ d3_geo_areaSum += area < 0 ? 4 * π + area : area;
+ d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
+ }
+ };
+ function d3_geo_areaRingStart() {
+ var λ00, φ00, λ0, cosφ0, sinφ0;
+ d3_geo_area.point = function(λ, φ) {
+ d3_geo_area.point = nextPoint;
+ λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4),
+ sinφ0 = Math.sin(φ);
+ };
+ function nextPoint(λ, φ) {
+ λ *= d3_radians;
+ φ = φ * d3_radians / 2 + π / 4;
+ var dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(adλ), v = k * sdλ * Math.sin(adλ);
+ d3_geo_areaRingSum.add(Math.atan2(v, u));
+ λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
+ }
+ d3_geo_area.lineEnd = function() {
+ nextPoint(λ00, φ00);
+ };
+ }
+ function d3_geo_cartesian(spherical) {
+ var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ);
+ return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ];
+ }
+ function d3_geo_cartesianDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+ }
+ function d3_geo_cartesianCross(a, b) {
+ return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ];
+ }
+ function d3_geo_cartesianAdd(a, b) {
+ a[0] += b[0];
+ a[1] += b[1];
+ a[2] += b[2];
+ }
+ function d3_geo_cartesianScale(vector, k) {
+ return [ vector[0] * k, vector[1] * k, vector[2] * k ];
+ }
+ function d3_geo_cartesianNormalize(d) {
+ var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ d[0] /= l;
+ d[1] /= l;
+ d[2] /= l;
+ }
+ function d3_geo_spherical(cartesian) {
+ return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ];
+ }
+ function d3_geo_sphericalEqual(a, b) {
+ return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
+ }
+ d3.geo.bounds = function() {
+ var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range;
+ var bound = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ bound.point = ringPoint;
+ bound.lineStart = ringStart;
+ bound.lineEnd = ringEnd;
+ dλSum = 0;
+ d3_geo_area.polygonStart();
+ },
+ polygonEnd: function() {
+ d3_geo_area.polygonEnd();
+ bound.point = point;
+ bound.lineStart = lineStart;
+ bound.lineEnd = lineEnd;
+ if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90;
+ range[0] = λ0, range[1] = λ1;
+ }
+ };
+ function point(λ, φ) {
+ ranges.push(range = [ λ0 = λ, λ1 = λ ]);
+ if (φ < φ0) φ0 = φ;
+ if (φ > φ1) φ1 = φ;
+ }
+ function linePoint(λ, φ) {
+ var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]);
+ if (p0) {
+ var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal);
+ d3_geo_cartesianNormalize(inflection);
+ inflection = d3_geo_spherical(inflection);
+ var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180;
+ if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
+ var φi = inflection[1] * d3_degrees;
+ if (φi > φ1) φ1 = φi;
+ } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
+ var φi = -inflection[1] * d3_degrees;
+ if (φi < φ0) φ0 = φi;
+ } else {
+ if (φ < φ0) φ0 = φ;
+ if (φ > φ1) φ1 = φ;
+ }
+ if (antimeridian) {
+ if (λ < λ_) {
+ if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
+ } else {
+ if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
+ }
+ } else {
+ if (λ1 >= λ0) {
+ if (λ < λ0) λ0 = λ;
+ if (λ > λ1) λ1 = λ;
+ } else {
+ if (λ > λ_) {
+ if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
+ } else {
+ if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
+ }
+ }
+ }
+ } else {
+ point(λ, φ);
+ }
+ p0 = p, λ_ = λ;
+ }
+ function lineStart() {
+ bound.point = linePoint;
+ }
+ function lineEnd() {
+ range[0] = λ0, range[1] = λ1;
+ bound.point = point;
+ p0 = null;
+ }
+ function ringPoint(λ, φ) {
+ if (p0) {
+ var dλ = λ - λ_;
+ dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
+ } else λ__ = λ, φ__ = φ;
+ d3_geo_area.point(λ, φ);
+ linePoint(λ, φ);
+ }
+ function ringStart() {
+ d3_geo_area.lineStart();
+ }
+ function ringEnd() {
+ ringPoint(λ__, φ__);
+ d3_geo_area.lineEnd();
+ if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
+ range[0] = λ0, range[1] = λ1;
+ p0 = null;
+ }
+ function angle(λ0, λ1) {
+ return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1;
+ }
+ function compareRanges(a, b) {
+ return a[0] - b[0];
+ }
+ function withinRange(x, range) {
+ return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
+ }
+ return function(feature) {
+ φ1 = λ1 = -(λ0 = φ0 = Infinity);
+ ranges = [];
+ d3.geo.stream(feature, bound);
+ var n = ranges.length;
+ if (n) {
+ ranges.sort(compareRanges);
+ for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) {
+ b = ranges[i];
+ if (withinRange(b[0], a) || withinRange(b[1], a)) {
+ if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
+ if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
+ } else {
+ merged.push(a = b);
+ }
+ }
+ var best = -Infinity, dλ;
+ for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {
+ b = merged[i];
+ if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
+ }
+ }
+ ranges = range = null;
+ return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ];
+ };
+ }();
+ d3.geo.centroid = function(object) {
+ d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
+ d3.geo.stream(object, d3_geo_centroid);
+ var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z;
+ if (m < ε2) {
+ x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
+ if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;
+ m = x * x + y * y + z * z;
+ if (m < ε2) return [ NaN, NaN ];
+ }
+ return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ];
+ };
+ var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2;
+ var d3_geo_centroid = {
+ sphere: d3_noop,
+ point: d3_geo_centroidPoint,
+ lineStart: d3_geo_centroidLineStart,
+ lineEnd: d3_geo_centroidLineEnd,
+ polygonStart: function() {
+ d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
+ }
+ };
+ function d3_geo_centroidPoint(λ, φ) {
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians);
+ d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));
+ }
+ function d3_geo_centroidPointXYZ(x, y, z) {
+ ++d3_geo_centroidW0;
+ d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
+ d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
+ d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
+ }
+ function d3_geo_centroidLineStart() {
+ var x0, y0, z0;
+ d3_geo_centroid.point = function(λ, φ) {
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians);
+ x0 = cosφ * Math.cos(λ);
+ y0 = cosφ * Math.sin(λ);
+ z0 = Math.sin(φ);
+ d3_geo_centroid.point = nextPoint;
+ d3_geo_centroidPointXYZ(x0, y0, z0);
+ };
+ function nextPoint(λ, φ) {
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
+ d3_geo_centroidW1 += w;
+ d3_geo_centroidX1 += w * (x0 + (x0 = x));
+ d3_geo_centroidY1 += w * (y0 + (y0 = y));
+ d3_geo_centroidZ1 += w * (z0 + (z0 = z));
+ d3_geo_centroidPointXYZ(x0, y0, z0);
+ }
+ }
+ function d3_geo_centroidLineEnd() {
+ d3_geo_centroid.point = d3_geo_centroidPoint;
+ }
+ function d3_geo_centroidRingStart() {
+ var λ00, φ00, x0, y0, z0;
+ d3_geo_centroid.point = function(λ, φ) {
+ λ00 = λ, φ00 = φ;
+ d3_geo_centroid.point = nextPoint;
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians);
+ x0 = cosφ * Math.cos(λ);
+ y0 = cosφ * Math.sin(λ);
+ z0 = Math.sin(φ);
+ d3_geo_centroidPointXYZ(x0, y0, z0);
+ };
+ d3_geo_centroid.lineEnd = function() {
+ nextPoint(λ00, φ00);
+ d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
+ d3_geo_centroid.point = d3_geo_centroidPoint;
+ };
+ function nextPoint(λ, φ) {
+ λ *= d3_radians;
+ var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u);
+ d3_geo_centroidX2 += v * cx;
+ d3_geo_centroidY2 += v * cy;
+ d3_geo_centroidZ2 += v * cz;
+ d3_geo_centroidW1 += w;
+ d3_geo_centroidX1 += w * (x0 + (x0 = x));
+ d3_geo_centroidY1 += w * (y0 + (y0 = y));
+ d3_geo_centroidZ1 += w * (z0 + (z0 = z));
+ d3_geo_centroidPointXYZ(x0, y0, z0);
+ }
+ }
+ function d3_true() {
+ return true;
+ }
+ function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) {
+ var subject = [], clip = [];
+ segments.forEach(function(segment) {
+ if ((n = segment.length - 1) <= 0) return;
+ var n, p0 = segment[0], p1 = segment[n];
+ if (d3_geo_sphericalEqual(p0, p1)) {
+ listener.lineStart();
+ for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
+ listener.lineEnd();
+ return;
+ }
+ var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false);
+ a.o = b;
+ subject.push(a);
+ clip.push(b);
+ a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
+ b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
+ a.o = b;
+ subject.push(a);
+ clip.push(b);
+ });
+ clip.sort(compare);
+ d3_geo_clipPolygonLinkCircular(subject);
+ d3_geo_clipPolygonLinkCircular(clip);
+ if (!subject.length) return;
+ for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
+ clip[i].e = entry = !entry;
+ }
+ var start = subject[0], points, point;
+ while (1) {
+ var current = start, isSubject = true;
+ while (current.v) if ((current = current.n) === start) return;
+ points = current.z;
+ listener.lineStart();
+ do {
+ current.v = current.o.v = true;
+ if (current.e) {
+ if (isSubject) {
+ for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);
+ } else {
+ interpolate(current.x, current.n.x, 1, listener);
+ }
+ current = current.n;
+ } else {
+ if (isSubject) {
+ points = current.p.z;
+ for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);
+ } else {
+ interpolate(current.x, current.p.x, -1, listener);
+ }
+ current = current.p;
+ }
+ current = current.o;
+ points = current.z;
+ isSubject = !isSubject;
+ } while (!current.v);
+ listener.lineEnd();
+ }
+ }
+ function d3_geo_clipPolygonLinkCircular(array) {
+ if (!(n = array.length)) return;
+ var n, i = 0, a = array[0], b;
+ while (++i < n) {
+ a.n = b = array[i];
+ b.p = a;
+ a = b;
+ }
+ a.n = b = array[0];
+ b.p = a;
+ }
+ function d3_geo_clipPolygonIntersection(point, points, other, entry) {
+ this.x = point;
+ this.z = points;
+ this.o = other;
+ this.e = entry;
+ this.v = false;
+ this.n = this.p = null;
+ }
+ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
+ return function(rotate, listener) {
+ var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);
+ var clip = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ clip.point = pointRing;
+ clip.lineStart = ringStart;
+ clip.lineEnd = ringEnd;
+ segments = [];
+ polygon = [];
+ listener.polygonStart();
+ },
+ polygonEnd: function() {
+ clip.point = point;
+ clip.lineStart = lineStart;
+ clip.lineEnd = lineEnd;
+ segments = d3.merge(segments);
+ var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
+ if (segments.length) {
+ d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
+ } else if (clipStartInside) {
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ }
+ listener.polygonEnd();
+ segments = polygon = null;
+ },
+ sphere: function() {
+ listener.polygonStart();
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ listener.polygonEnd();
+ }
+ };
+ function point(λ, φ) {
+ var point = rotate(λ, φ);
+ if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);
+ }
+ function pointLine(λ, φ) {
+ var point = rotate(λ, φ);
+ line.point(point[0], point[1]);
+ }
+ function lineStart() {
+ clip.point = pointLine;
+ line.lineStart();
+ }
+ function lineEnd() {
+ clip.point = point;
+ line.lineEnd();
+ }
+ var segments;
+ var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring;
+ function pointRing(λ, φ) {
+ ring.push([ λ, φ ]);
+ var point = rotate(λ, φ);
+ ringListener.point(point[0], point[1]);
+ }
+ function ringStart() {
+ ringListener.lineStart();
+ ring = [];
+ }
+ function ringEnd() {
+ pointRing(ring[0][0], ring[0][1]);
+ ringListener.lineEnd();
+ var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length;
+ ring.pop();
+ polygon.push(ring);
+ ring = null;
+ if (!n) return;
+ if (clean & 1) {
+ segment = ringSegments[0];
+ var n = segment.length - 1, i = -1, point;
+ listener.lineStart();
+ while (++i < n) listener.point((point = segment[i])[0], point[1]);
+ listener.lineEnd();
+ return;
+ }
+ if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
+ segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
+ }
+ return clip;
+ };
+ }
+ function d3_geo_clipSegmentLength1(segment) {
+ return segment.length > 1;
+ }
+ function d3_geo_clipBufferListener() {
+ var lines = [], line;
+ return {
+ lineStart: function() {
+ lines.push(line = []);
+ },
+ point: function(λ, φ) {
+ line.push([ λ, φ ]);
+ },
+ lineEnd: d3_noop,
+ buffer: function() {
+ var buffer = lines;
+ lines = [];
+ line = null;
+ return buffer;
+ },
+ rejoin: function() {
+ if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
+ }
+ };
+ }
+ function d3_geo_clipSort(a, b) {
+ return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);
+ }
+ function d3_geo_pointInPolygon(point, polygon) {
+ var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0;
+ d3_geo_areaRingSum.reset();
+ for (var i = 0, n = polygon.length; i < n; ++i) {
+ var ring = polygon[i], m = ring.length;
+ if (!m) continue;
+ var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1;
+ while (true) {
+ if (j === m) j = 0;
+ point = ring[j];
+ var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, antimeridian = adλ > π, k = sinφ0 * sinφ;
+ d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));
+ polarAngle += antimeridian ? dλ + sdλ * τ : dλ;
+ if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
+ var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));
+ d3_geo_cartesianNormalize(arc);
+ var intersection = d3_geo_cartesianCross(meridianNormal, arc);
+ d3_geo_cartesianNormalize(intersection);
+ var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
+ if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {
+ winding += antimeridian ^ dλ >= 0 ? 1 : -1;
+ }
+ }
+ if (!j++) break;
+ λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;
+ }
+ }
+ return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ winding & 1;
+ }
+ var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]);
+ function d3_geo_clipAntimeridianLine(listener) {
+ var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;
+ return {
+ lineStart: function() {
+ listener.lineStart();
+ clean = 1;
+ },
+ point: function(λ1, φ1) {
+ var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0);
+ if (abs(dλ - π) < ε) {
+ listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
+ listener.point(sλ0, φ0);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(sλ1, φ0);
+ listener.point(λ1, φ0);
+ clean = 0;
+ } else if (sλ0 !== sλ1 && dλ >= π) {
+ if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
+ if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
+ φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
+ listener.point(sλ0, φ0);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(sλ1, φ0);
+ clean = 0;
+ }
+ listener.point(λ0 = λ1, φ0 = φ1);
+ sλ0 = sλ1;
+ },
+ lineEnd: function() {
+ listener.lineEnd();
+ λ0 = φ0 = NaN;
+ },
+ clean: function() {
+ return 2 - clean;
+ }
+ };
+ }
+ function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
+ var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
+ return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;
+ }
+ function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
+ var φ;
+ if (from == null) {
+ φ = direction * halfπ;
+ listener.point(-π, φ);
+ listener.point(0, φ);
+ listener.point(π, φ);
+ listener.point(π, 0);
+ listener.point(π, -φ);
+ listener.point(0, -φ);
+ listener.point(-π, -φ);
+ listener.point(-π, 0);
+ listener.point(-π, φ);
+ } else if (abs(from[0] - to[0]) > ε) {
+ var s = from[0] < to[0] ? π : -π;
+ φ = direction * s / 2;
+ listener.point(-s, φ);
+ listener.point(0, φ);
+ listener.point(s, φ);
+ } else {
+ listener.point(to[0], to[1]);
+ }
+ }
+ function d3_geo_clipCircle(radius) {
+ var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
+ return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]);
+ function visible(λ, φ) {
+ return Math.cos(λ) * Math.cos(φ) > cr;
+ }
+ function clipLine(listener) {
+ var point0, c0, v0, v00, clean;
+ return {
+ lineStart: function() {
+ v00 = v0 = false;
+ clean = 1;
+ },
+ point: function(λ, φ) {
+ var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;
+ if (!point0 && (v00 = v0 = v)) listener.lineStart();
+ if (v !== v0) {
+ point2 = intersect(point0, point1);
+ if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
+ point1[0] += ε;
+ point1[1] += ε;
+ v = visible(point1[0], point1[1]);
+ }
+ }
+ if (v !== v0) {
+ clean = 0;
+ if (v) {
+ listener.lineStart();
+ point2 = intersect(point1, point0);
+ listener.point(point2[0], point2[1]);
+ } else {
+ point2 = intersect(point0, point1);
+ listener.point(point2[0], point2[1]);
+ listener.lineEnd();
+ }
+ point0 = point2;
+ } else if (notHemisphere && point0 && smallRadius ^ v) {
+ var t;
+ if (!(c & c0) && (t = intersect(point1, point0, true))) {
+ clean = 0;
+ if (smallRadius) {
+ listener.lineStart();
+ listener.point(t[0][0], t[0][1]);
+ listener.point(t[1][0], t[1][1]);
+ listener.lineEnd();
+ } else {
+ listener.point(t[1][0], t[1][1]);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(t[0][0], t[0][1]);
+ }
+ }
+ }
+ if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
+ listener.point(point1[0], point1[1]);
+ }
+ point0 = point1, v0 = v, c0 = c;
+ },
+ lineEnd: function() {
+ if (v0) listener.lineEnd();
+ point0 = null;
+ },
+ clean: function() {
+ return clean | (v00 && v0) << 1;
+ }
+ };
+ }
+ function intersect(a, b, two) {
+ var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b);
+ var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
+ if (!determinant) return !two && a;
+ var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2);
+ d3_geo_cartesianAdd(A, B);
+ var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
+ if (t2 < 0) return;
+ var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu);
+ d3_geo_cartesianAdd(q, A);
+ q = d3_geo_spherical(q);
+ if (!two) return q;
+ var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z;
+ if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
+ var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε;
+ if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;
+ if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {
+ var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
+ d3_geo_cartesianAdd(q1, A);
+ return [ q, d3_geo_spherical(q1) ];
+ }
+ }
+ function code(λ, φ) {
+ var r = smallRadius ? radius : π - radius, code = 0;
+ if (λ < -r) code |= 1; else if (λ > r) code |= 2;
+ if (φ < -r) code |= 4; else if (φ > r) code |= 8;
+ return code;
+ }
+ }
+ function d3_geom_clipLine(x0, y0, x1, y1) {
+ return function(line) {
+ var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r;
+ r = x0 - ax;
+ if (!dx && r > 0) return;
+ r /= dx;
+ if (dx < 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ } else if (dx > 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ }
+ r = x1 - ax;
+ if (!dx && r < 0) return;
+ r /= dx;
+ if (dx < 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ } else if (dx > 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ }
+ r = y0 - ay;
+ if (!dy && r > 0) return;
+ r /= dy;
+ if (dy < 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ } else if (dy > 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ }
+ r = y1 - ay;
+ if (!dy && r < 0) return;
+ r /= dy;
+ if (dy < 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ } else if (dy > 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ }
+ if (t0 > 0) line.a = {
+ x: ax + t0 * dx,
+ y: ay + t0 * dy
+ };
+ if (t1 < 1) line.b = {
+ x: ax + t1 * dx,
+ y: ay + t1 * dy
+ };
+ return line;
+ };
+ }
+ var d3_geo_clipExtentMAX = 1e9;
+ d3.geo.clipExtent = function() {
+ var x0, y0, x1, y1, stream, clip, clipExtent = {
+ stream: function(output) {
+ if (stream) stream.valid = false;
+ stream = clip(output);
+ stream.valid = true;
+ return stream;
+ },
+ extent: function(_) {
+ if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
+ clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
+ if (stream) stream.valid = false, stream = null;
+ return clipExtent;
+ }
+ };
+ return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]);
+ };
+ function d3_geo_clipExtent(x0, y0, x1, y1) {
+ return function(listener) {
+ var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring;
+ var clip = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ listener = bufferListener;
+ segments = [];
+ polygon = [];
+ clean = true;
+ },
+ polygonEnd: function() {
+ listener = listener_;
+ segments = d3.merge(segments);
+ var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length;
+ if (inside || visible) {
+ listener.polygonStart();
+ if (inside) {
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ }
+ if (visible) {
+ d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);
+ }
+ listener.polygonEnd();
+ }
+ segments = polygon = ring = null;
+ }
+ };
+ function insidePolygon(p) {
+ var wn = 0, n = polygon.length, y = p[1];
+ for (var i = 0; i < n; ++i) {
+ for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
+ b = v[j];
+ if (a[1] <= y) {
+ if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn;
+ } else {
+ if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;
+ }
+ a = b;
+ }
+ }
+ return wn !== 0;
+ }
+ function interpolate(from, to, direction, listener) {
+ var a = 0, a1 = 0;
+ if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) {
+ do {
+ listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
+ } while ((a = (a + direction + 4) % 4) !== a1);
+ } else {
+ listener.point(to[0], to[1]);
+ }
+ }
+ function pointVisible(x, y) {
+ return x0 <= x && x <= x1 && y0 <= y && y <= y1;
+ }
+ function point(x, y) {
+ if (pointVisible(x, y)) listener.point(x, y);
+ }
+ var x__, y__, v__, x_, y_, v_, first, clean;
+ function lineStart() {
+ clip.point = linePoint;
+ if (polygon) polygon.push(ring = []);
+ first = true;
+ v_ = false;
+ x_ = y_ = NaN;
+ }
+ function lineEnd() {
+ if (segments) {
+ linePoint(x__, y__);
+ if (v__ && v_) bufferListener.rejoin();
+ segments.push(bufferListener.buffer());
+ }
+ clip.point = point;
+ if (v_) listener.lineEnd();
+ }
+ function linePoint(x, y) {
+ x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
+ y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
+ var v = pointVisible(x, y);
+ if (polygon) ring.push([ x, y ]);
+ if (first) {
+ x__ = x, y__ = y, v__ = v;
+ first = false;
+ if (v) {
+ listener.lineStart();
+ listener.point(x, y);
+ }
+ } else {
+ if (v && v_) listener.point(x, y); else {
+ var l = {
+ a: {
+ x: x_,
+ y: y_
+ },
+ b: {
+ x: x,
+ y: y
+ }
+ };
+ if (clipLine(l)) {
+ if (!v_) {
+ listener.lineStart();
+ listener.point(l.a.x, l.a.y);
+ }
+ listener.point(l.b.x, l.b.y);
+ if (!v) listener.lineEnd();
+ clean = false;
+ } else if (v) {
+ listener.lineStart();
+ listener.point(x, y);
+ clean = false;
+ }
+ }
+ }
+ x_ = x, y_ = y, v_ = v;
+ }
+ return clip;
+ };
+ function corner(p, direction) {
+ return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;
+ }
+ function compare(a, b) {
+ return comparePoints(a.x, b.x);
+ }
+ function comparePoints(a, b) {
+ var ca = corner(a, 1), cb = corner(b, 1);
+ return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0];
+ }
+ }
+ function d3_geo_compose(a, b) {
+ function compose(x, y) {
+ return x = a(x, y), b(x[0], x[1]);
+ }
+ if (a.invert && b.invert) compose.invert = function(x, y) {
+ return x = b.invert(x, y), x && a.invert(x[0], x[1]);
+ };
+ return compose;
+ }
+ function d3_geo_conic(projectAt) {
+ var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1);
+ p.parallels = function(_) {
+ if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ];
+ return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);
+ };
+ return p;
+ }
+ function d3_geo_conicEqualArea(φ0, φ1) {
+ var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n;
+ function forward(λ, φ) {
+ var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
+ return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ];
+ }
+ forward.invert = function(x, y) {
+ var ρ0_y = ρ0 - y;
+ return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ];
+ };
+ return forward;
+ }
+ (d3.geo.conicEqualArea = function() {
+ return d3_geo_conic(d3_geo_conicEqualArea);
+ }).raw = d3_geo_conicEqualArea;
+ d3.geo.albers = function() {
+ return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070);
+ };
+ d3.geo.albersUsa = function() {
+ var lower48 = d3.geo.albers();
+ var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]);
+ var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]);
+ var point, pointStream = {
+ point: function(x, y) {
+ point = [ x, y ];
+ }
+ }, lower48Point, alaskaPoint, hawaiiPoint;
+ function albersUsa(coordinates) {
+ var x = coordinates[0], y = coordinates[1];
+ point = null;
+ (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y);
+ return point;
+ }
+ albersUsa.invert = function(coordinates) {
+ var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k;
+ return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates);
+ };
+ albersUsa.stream = function(stream) {
+ var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream);
+ return {
+ point: function(x, y) {
+ lower48Stream.point(x, y);
+ alaskaStream.point(x, y);
+ hawaiiStream.point(x, y);
+ },
+ sphere: function() {
+ lower48Stream.sphere();
+ alaskaStream.sphere();
+ hawaiiStream.sphere();
+ },
+ lineStart: function() {
+ lower48Stream.lineStart();
+ alaskaStream.lineStart();
+ hawaiiStream.lineStart();
+ },
+ lineEnd: function() {
+ lower48Stream.lineEnd();
+ alaskaStream.lineEnd();
+ hawaiiStream.lineEnd();
+ },
+ polygonStart: function() {
+ lower48Stream.polygonStart();
+ alaskaStream.polygonStart();
+ hawaiiStream.polygonStart();
+ },
+ polygonEnd: function() {
+ lower48Stream.polygonEnd();
+ alaskaStream.polygonEnd();
+ hawaiiStream.polygonEnd();
+ }
+ };
+ };
+ albersUsa.precision = function(_) {
+ if (!arguments.length) return lower48.precision();
+ lower48.precision(_);
+ alaska.precision(_);
+ hawaii.precision(_);
+ return albersUsa;
+ };
+ albersUsa.scale = function(_) {
+ if (!arguments.length) return lower48.scale();
+ lower48.scale(_);
+ alaska.scale(_ * .35);
+ hawaii.scale(_);
+ return albersUsa.translate(lower48.translate());
+ };
+ albersUsa.translate = function(_) {
+ if (!arguments.length) return lower48.translate();
+ var k = lower48.scale(), x = +_[0], y = +_[1];
+ lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point;
+ alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
+ hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
+ return albersUsa;
+ };
+ return albersUsa.scale(1070);
+ };
+ var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
+ point: d3_noop,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ d3_geo_pathAreaPolygon = 0;
+ d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
+ d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
+ }
+ };
+ function d3_geo_pathAreaRingStart() {
+ var x00, y00, x0, y0;
+ d3_geo_pathArea.point = function(x, y) {
+ d3_geo_pathArea.point = nextPoint;
+ x00 = x0 = x, y00 = y0 = y;
+ };
+ function nextPoint(x, y) {
+ d3_geo_pathAreaPolygon += y0 * x - x0 * y;
+ x0 = x, y0 = y;
+ }
+ d3_geo_pathArea.lineEnd = function() {
+ nextPoint(x00, y00);
+ };
+ }
+ var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1;
+ var d3_geo_pathBounds = {
+ point: d3_geo_pathBoundsPoint,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: d3_noop,
+ polygonEnd: d3_noop
+ };
+ function d3_geo_pathBoundsPoint(x, y) {
+ if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
+ if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
+ if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
+ if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
+ }
+ function d3_geo_pathBuffer() {
+ var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = [];
+ var stream = {
+ point: point,
+ lineStart: function() {
+ stream.point = pointLineStart;
+ },
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.lineEnd = lineEndPolygon;
+ },
+ polygonEnd: function() {
+ stream.lineEnd = lineEnd;
+ stream.point = point;
+ },
+ pointRadius: function(_) {
+ pointCircle = d3_geo_pathBufferCircle(_);
+ return stream;
+ },
+ result: function() {
+ if (buffer.length) {
+ var result = buffer.join("");
+ buffer = [];
+ return result;
+ }
+ }
+ };
+ function point(x, y) {
+ buffer.push("M", x, ",", y, pointCircle);
+ }
+ function pointLineStart(x, y) {
+ buffer.push("M", x, ",", y);
+ stream.point = pointLine;
+ }
+ function pointLine(x, y) {
+ buffer.push("L", x, ",", y);
+ }
+ function lineEnd() {
+ stream.point = point;
+ }
+ function lineEndPolygon() {
+ buffer.push("Z");
+ }
+ return stream;
+ }
+ function d3_geo_pathBufferCircle(radius) {
+ return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
+ }
+ var d3_geo_pathCentroid = {
+ point: d3_geo_pathCentroidPoint,
+ lineStart: d3_geo_pathCentroidLineStart,
+ lineEnd: d3_geo_pathCentroidLineEnd,
+ polygonStart: function() {
+ d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+ d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
+ d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
+ }
+ };
+ function d3_geo_pathCentroidPoint(x, y) {
+ d3_geo_centroidX0 += x;
+ d3_geo_centroidY0 += y;
+ ++d3_geo_centroidZ0;
+ }
+ function d3_geo_pathCentroidLineStart() {
+ var x0, y0;
+ d3_geo_pathCentroid.point = function(x, y) {
+ d3_geo_pathCentroid.point = nextPoint;
+ d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+ };
+ function nextPoint(x, y) {
+ var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
+ d3_geo_centroidX1 += z * (x0 + x) / 2;
+ d3_geo_centroidY1 += z * (y0 + y) / 2;
+ d3_geo_centroidZ1 += z;
+ d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+ }
+ }
+ function d3_geo_pathCentroidLineEnd() {
+ d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+ }
+ function d3_geo_pathCentroidRingStart() {
+ var x00, y00, x0, y0;
+ d3_geo_pathCentroid.point = function(x, y) {
+ d3_geo_pathCentroid.point = nextPoint;
+ d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
+ };
+ function nextPoint(x, y) {
+ var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
+ d3_geo_centroidX1 += z * (x0 + x) / 2;
+ d3_geo_centroidY1 += z * (y0 + y) / 2;
+ d3_geo_centroidZ1 += z;
+ z = y0 * x - x0 * y;
+ d3_geo_centroidX2 += z * (x0 + x);
+ d3_geo_centroidY2 += z * (y0 + y);
+ d3_geo_centroidZ2 += z * 3;
+ d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+ }
+ d3_geo_pathCentroid.lineEnd = function() {
+ nextPoint(x00, y00);
+ };
+ }
+ function d3_geo_pathContext(context) {
+ var pointRadius = 4.5;
+ var stream = {
+ point: point,
+ lineStart: function() {
+ stream.point = pointLineStart;
+ },
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.lineEnd = lineEndPolygon;
+ },
+ polygonEnd: function() {
+ stream.lineEnd = lineEnd;
+ stream.point = point;
+ },
+ pointRadius: function(_) {
+ pointRadius = _;
+ return stream;
+ },
+ result: d3_noop
+ };
+ function point(x, y) {
+ context.moveTo(x, y);
+ context.arc(x, y, pointRadius, 0, τ);
+ }
+ function pointLineStart(x, y) {
+ context.moveTo(x, y);
+ stream.point = pointLine;
+ }
+ function pointLine(x, y) {
+ context.lineTo(x, y);
+ }
+ function lineEnd() {
+ stream.point = point;
+ }
+ function lineEndPolygon() {
+ context.closePath();
+ }
+ return stream;
+ }
+ function d3_geo_resample(project) {
+ var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16;
+ function resample(stream) {
+ return (maxDepth ? resampleRecursive : resampleNone)(stream);
+ }
+ function resampleNone(stream) {
+ return d3_geo_transformPoint(stream, function(x, y) {
+ x = project(x, y);
+ stream.point(x[0], x[1]);
+ });
+ }
+ function resampleRecursive(stream) {
+ var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0;
+ var resample = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.polygonStart();
+ resample.lineStart = ringStart;
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ resample.lineStart = lineStart;
+ }
+ };
+ function point(x, y) {
+ x = project(x, y);
+ stream.point(x[0], x[1]);
+ }
+ function lineStart() {
+ x0 = NaN;
+ resample.point = linePoint;
+ stream.lineStart();
+ }
+ function linePoint(λ, φ) {
+ var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ);
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
+ stream.point(x0, y0);
+ }
+ function lineEnd() {
+ resample.point = point;
+ stream.lineEnd();
+ }
+ function ringStart() {
+ lineStart();
+ resample.point = ringPoint;
+ resample.lineEnd = ringEnd;
+ }
+ function ringPoint(λ, φ) {
+ linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
+ resample.point = linePoint;
+ }
+ function ringEnd() {
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
+ resample.lineEnd = lineEnd;
+ lineEnd();
+ }
+ return resample;
+ }
+ function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
+ var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
+ if (d2 > 4 * δ2 && depth--) {
+ var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;
+ if (dz * dz / d2 > δ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
+ stream.point(x2, y2);
+ resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
+ }
+ }
+ }
+ resample.precision = function(_) {
+ if (!arguments.length) return Math.sqrt(δ2);
+ maxDepth = (δ2 = _ * _) > 0 && 16;
+ return resample;
+ };
+ return resample;
+ }
+ d3.geo.path = function() {
+ var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream;
+ function path(object) {
+ if (object) {
+ if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
+ if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream);
+ d3.geo.stream(object, cacheStream);
+ }
+ return contextStream.result();
+ }
+ path.area = function(object) {
+ d3_geo_pathAreaSum = 0;
+ d3.geo.stream(object, projectStream(d3_geo_pathArea));
+ return d3_geo_pathAreaSum;
+ };
+ path.centroid = function(object) {
+ d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
+ d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
+ return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ];
+ };
+ path.bounds = function(object) {
+ d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity);
+ d3.geo.stream(object, projectStream(d3_geo_pathBounds));
+ return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ];
+ };
+ path.projection = function(_) {
+ if (!arguments.length) return projection;
+ projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
+ return reset();
+ };
+ path.context = function(_) {
+ if (!arguments.length) return context;
+ contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);
+ if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
+ return reset();
+ };
+ path.pointRadius = function(_) {
+ if (!arguments.length) return pointRadius;
+ pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
+ return path;
+ };
+ function reset() {
+ cacheStream = null;
+ return path;
+ }
+ return path.projection(d3.geo.albersUsa()).context(null);
+ };
+ function d3_geo_pathProjectStream(project) {
+ var resample = d3_geo_resample(function(x, y) {
+ return project([ x * d3_degrees, y * d3_degrees ]);
+ });
+ return function(stream) {
+ return d3_geo_projectionRadians(resample(stream));
+ };
+ }
+ d3.geo.transform = function(methods) {
+ return {
+ stream: function(stream) {
+ var transform = new d3_geo_transform(stream);
+ for (var k in methods) transform[k] = methods[k];
+ return transform;
+ }
+ };
+ };
+ function d3_geo_transform(stream) {
+ this.stream = stream;
+ }
+ d3_geo_transform.prototype = {
+ point: function(x, y) {
+ this.stream.point(x, y);
+ },
+ sphere: function() {
+ this.stream.sphere();
+ },
+ lineStart: function() {
+ this.stream.lineStart();
+ },
+ lineEnd: function() {
+ this.stream.lineEnd();
+ },
+ polygonStart: function() {
+ this.stream.polygonStart();
+ },
+ polygonEnd: function() {
+ this.stream.polygonEnd();
+ }
+ };
+ function d3_geo_transformPoint(stream, point) {
+ return {
+ point: point,
+ sphere: function() {
+ stream.sphere();
+ },
+ lineStart: function() {
+ stream.lineStart();
+ },
+ lineEnd: function() {
+ stream.lineEnd();
+ },
+ polygonStart: function() {
+ stream.polygonStart();
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ }
+ };
+ }
+ d3.geo.projection = d3_geo_projection;
+ d3.geo.projectionMutator = d3_geo_projectionMutator;
+ function d3_geo_projection(project) {
+ return d3_geo_projectionMutator(function() {
+ return project;
+ })();
+ }
+ function d3_geo_projectionMutator(projectAt) {
+ var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) {
+ x = project(x, y);
+ return [ x[0] * k + δx, δy - x[1] * k ];
+ }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream;
+ function projection(point) {
+ point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
+ return [ point[0] * k + δx, δy - point[1] * k ];
+ }
+ function invert(point) {
+ point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
+ return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
+ }
+ projection.stream = function(output) {
+ if (stream) stream.valid = false;
+ stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output))));
+ stream.valid = true;
+ return stream;
+ };
+ projection.clipAngle = function(_) {
+ if (!arguments.length) return clipAngle;
+ preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians);
+ return invalidate();
+ };
+ projection.clipExtent = function(_) {
+ if (!arguments.length) return clipExtent;
+ clipExtent = _;
+ postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
+ return invalidate();
+ };
+ projection.scale = function(_) {
+ if (!arguments.length) return k;
+ k = +_;
+ return reset();
+ };
+ projection.translate = function(_) {
+ if (!arguments.length) return [ x, y ];
+ x = +_[0];
+ y = +_[1];
+ return reset();
+ };
+ projection.center = function(_) {
+ if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ];
+ λ = _[0] % 360 * d3_radians;
+ φ = _[1] % 360 * d3_radians;
+ return reset();
+ };
+ projection.rotate = function(_) {
+ if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ];
+ δλ = _[0] % 360 * d3_radians;
+ δφ = _[1] % 360 * d3_radians;
+ δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
+ return reset();
+ };
+ d3.rebind(projection, projectResample, "precision");
+ function reset() {
+ projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
+ var center = project(λ, φ);
+ δx = x - center[0] * k;
+ δy = y + center[1] * k;
+ return invalidate();
+ }
+ function invalidate() {
+ if (stream) stream.valid = false, stream = null;
+ return projection;
+ }
+ return function() {
+ project = projectAt.apply(this, arguments);
+ projection.invert = project.invert && invert;
+ return reset();
+ };
+ }
+ function d3_geo_projectionRadians(stream) {
+ return d3_geo_transformPoint(stream, function(x, y) {
+ stream.point(x * d3_radians, y * d3_radians);
+ });
+ }
+ function d3_geo_equirectangular(λ, φ) {
+ return [ λ, φ ];
+ }
+ (d3.geo.equirectangular = function() {
+ return d3_geo_projection(d3_geo_equirectangular);
+ }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
+ d3.geo.rotation = function(rotate) {
+ rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);
+ function forward(coordinates) {
+ coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
+ return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
+ }
+ forward.invert = function(coordinates) {
+ coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
+ return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
+ };
+ return forward;
+ };
+ function d3_geo_identityRotation(λ, φ) {
+ return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
+ }
+ d3_geo_identityRotation.invert = d3_geo_equirectangular;
+ function d3_geo_rotation(δλ, δφ, δγ) {
+ return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation;
+ }
+ function d3_geo_forwardRotationλ(δλ) {
+ return function(λ, φ) {
+ return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
+ };
+ }
+ function d3_geo_rotationλ(δλ) {
+ var rotation = d3_geo_forwardRotationλ(δλ);
+ rotation.invert = d3_geo_forwardRotationλ(-δλ);
+ return rotation;
+ }
+ function d3_geo_rotationφγ(δφ, δγ) {
+ var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ);
+ function rotation(λ, φ) {
+ var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ;
+ return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ];
+ }
+ rotation.invert = function(λ, φ) {
+ var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ;
+ return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ];
+ };
+ return rotation;
+ }
+ d3.geo.circle = function() {
+ var origin = [ 0, 0 ], angle, precision = 6, interpolate;
+ function circle() {
+ var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = [];
+ interpolate(null, null, 1, {
+ point: function(x, y) {
+ ring.push(x = rotate(x, y));
+ x[0] *= d3_degrees, x[1] *= d3_degrees;
+ }
+ });
+ return {
+ type: "Polygon",
+ coordinates: [ ring ]
+ };
+ }
+ circle.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return circle;
+ };
+ circle.angle = function(x) {
+ if (!arguments.length) return angle;
+ interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
+ return circle;
+ };
+ circle.precision = function(_) {
+ if (!arguments.length) return precision;
+ interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
+ return circle;
+ };
+ return circle.angle(90);
+ };
+ function d3_geo_circleInterpolate(radius, precision) {
+ var cr = Math.cos(radius), sr = Math.sin(radius);
+ return function(from, to, direction, listener) {
+ var step = direction * precision;
+ if (from != null) {
+ from = d3_geo_circleAngle(cr, from);
+ to = d3_geo_circleAngle(cr, to);
+ if (direction > 0 ? from < to : from > to) from += direction * τ;
+ } else {
+ from = radius + direction * τ;
+ to = radius - .5 * step;
+ }
+ for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
+ listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]);
+ }
+ };
+ }
+ function d3_geo_circleAngle(cr, point) {
+ var a = d3_geo_cartesian(point);
+ a[0] -= cr;
+ d3_geo_cartesianNormalize(a);
+ var angle = d3_acos(-a[1]);
+ return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
+ }
+ d3.geo.distance = function(a, b) {
+ var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t;
+ return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ);
+ };
+ d3.geo.graticule = function() {
+ var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5;
+ function graticule() {
+ return {
+ type: "MultiLineString",
+ coordinates: lines()
+ };
+ }
+ function lines() {
+ return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) {
+ return abs(x % DX) > ε;
+ }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {
+ return abs(y % DY) > ε;
+ }).map(y));
+ }
+ graticule.lines = function() {
+ return lines().map(function(coordinates) {
+ return {
+ type: "LineString",
+ coordinates: coordinates
+ };
+ });
+ };
+ graticule.outline = function() {
+ return {
+ type: "Polygon",
+ coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ]
+ };
+ };
+ graticule.extent = function(_) {
+ if (!arguments.length) return graticule.minorExtent();
+ return graticule.majorExtent(_).minorExtent(_);
+ };
+ graticule.majorExtent = function(_) {
+ if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ];
+ X0 = +_[0][0], X1 = +_[1][0];
+ Y0 = +_[0][1], Y1 = +_[1][1];
+ if (X0 > X1) _ = X0, X0 = X1, X1 = _;
+ if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
+ return graticule.precision(precision);
+ };
+ graticule.minorExtent = function(_) {
+ if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
+ x0 = +_[0][0], x1 = +_[1][0];
+ y0 = +_[0][1], y1 = +_[1][1];
+ if (x0 > x1) _ = x0, x0 = x1, x1 = _;
+ if (y0 > y1) _ = y0, y0 = y1, y1 = _;
+ return graticule.precision(precision);
+ };
+ graticule.step = function(_) {
+ if (!arguments.length) return graticule.minorStep();
+ return graticule.majorStep(_).minorStep(_);
+ };
+ graticule.majorStep = function(_) {
+ if (!arguments.length) return [ DX, DY ];
+ DX = +_[0], DY = +_[1];
+ return graticule;
+ };
+ graticule.minorStep = function(_) {
+ if (!arguments.length) return [ dx, dy ];
+ dx = +_[0], dy = +_[1];
+ return graticule;
+ };
+ graticule.precision = function(_) {
+ if (!arguments.length) return precision;
+ precision = +_;
+ x = d3_geo_graticuleX(y0, y1, 90);
+ y = d3_geo_graticuleY(x0, x1, precision);
+ X = d3_geo_graticuleX(Y0, Y1, 90);
+ Y = d3_geo_graticuleY(X0, X1, precision);
+ return graticule;
+ };
+ return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]);
+ };
+ function d3_geo_graticuleX(y0, y1, dy) {
+ var y = d3.range(y0, y1 - ε, dy).concat(y1);
+ return function(x) {
+ return y.map(function(y) {
+ return [ x, y ];
+ });
+ };
+ }
+ function d3_geo_graticuleY(x0, x1, dx) {
+ var x = d3.range(x0, x1 - ε, dx).concat(x1);
+ return function(y) {
+ return x.map(function(x) {
+ return [ x, y ];
+ });
+ };
+ }
+ function d3_source(d) {
+ return d.source;
+ }
+ function d3_target(d) {
+ return d.target;
+ }
+ d3.geo.greatArc = function() {
+ var source = d3_source, source_, target = d3_target, target_;
+ function greatArc() {
+ return {
+ type: "LineString",
+ coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ]
+ };
+ }
+ greatArc.distance = function() {
+ return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments));
+ };
+ greatArc.source = function(_) {
+ if (!arguments.length) return source;
+ source = _, source_ = typeof _ === "function" ? null : _;
+ return greatArc;
+ };
+ greatArc.target = function(_) {
+ if (!arguments.length) return target;
+ target = _, target_ = typeof _ === "function" ? null : _;
+ return greatArc;
+ };
+ greatArc.precision = function() {
+ return arguments.length ? greatArc : 0;
+ };
+ return greatArc;
+ };
+ d3.geo.interpolate = function(source, target) {
+ return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);
+ };
+ function d3_geo_interpolate(x0, y0, x1, y1) {
+ var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d);
+ var interpolate = d ? function(t) {
+ var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;
+ return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ];
+ } : function() {
+ return [ x0 * d3_degrees, y0 * d3_degrees ];
+ };
+ interpolate.distance = d;
+ return interpolate;
+ }
+ d3.geo.length = function(object) {
+ d3_geo_lengthSum = 0;
+ d3.geo.stream(object, d3_geo_length);
+ return d3_geo_lengthSum;
+ };
+ var d3_geo_lengthSum;
+ var d3_geo_length = {
+ sphere: d3_noop,
+ point: d3_noop,
+ lineStart: d3_geo_lengthLineStart,
+ lineEnd: d3_noop,
+ polygonStart: d3_noop,
+ polygonEnd: d3_noop
+ };
+ function d3_geo_lengthLineStart() {
+ var λ0, sinφ0, cosφ0;
+ d3_geo_length.point = function(λ, φ) {
+ λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);
+ d3_geo_length.point = nextPoint;
+ };
+ d3_geo_length.lineEnd = function() {
+ d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
+ };
+ function nextPoint(λ, φ) {
+ var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t);
+ d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ);
+ λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;
+ }
+ }
+ function d3_geo_azimuthal(scale, angle) {
+ function azimuthal(λ, φ) {
+ var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ);
+ return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ];
+ }
+ azimuthal.invert = function(x, y) {
+ var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c);
+ return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ];
+ };
+ return azimuthal;
+ }
+ var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) {
+ return Math.sqrt(2 / (1 + cosλcosφ));
+ }, function(ρ) {
+ return 2 * Math.asin(ρ / 2);
+ });
+ (d3.geo.azimuthalEqualArea = function() {
+ return d3_geo_projection(d3_geo_azimuthalEqualArea);
+ }).raw = d3_geo_azimuthalEqualArea;
+ var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) {
+ var c = Math.acos(cosλcosφ);
+ return c && c / Math.sin(c);
+ }, d3_identity);
+ (d3.geo.azimuthalEquidistant = function() {
+ return d3_geo_projection(d3_geo_azimuthalEquidistant);
+ }).raw = d3_geo_azimuthalEquidistant;
+ function d3_geo_conicConformal(φ0, φ1) {
+ var cosφ0 = Math.cos(φ0), t = function(φ) {
+ return Math.tan(π / 4 + φ / 2);
+ }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n;
+ if (!n) return d3_geo_mercator;
+ function forward(λ, φ) {
+ if (F > 0) {
+ if (φ < -halfπ + ε) φ = -halfπ + ε;
+ } else {
+ if (φ > halfπ - ε) φ = halfπ - ε;
+ }
+ var ρ = F / Math.pow(t(φ), n);
+ return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ];
+ }
+ forward.invert = function(x, y) {
+ var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y);
+ return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ];
+ };
+ return forward;
+ }
+ (d3.geo.conicConformal = function() {
+ return d3_geo_conic(d3_geo_conicConformal);
+ }).raw = d3_geo_conicConformal;
+ function d3_geo_conicEquidistant(φ0, φ1) {
+ var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0;
+ if (abs(n) < ε) return d3_geo_equirectangular;
+ function forward(λ, φ) {
+ var ρ = G - φ;
+ return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ];
+ }
+ forward.invert = function(x, y) {
+ var ρ0_y = G - y;
+ return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ];
+ };
+ return forward;
+ }
+ (d3.geo.conicEquidistant = function() {
+ return d3_geo_conic(d3_geo_conicEquidistant);
+ }).raw = d3_geo_conicEquidistant;
+ var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) {
+ return 1 / cosλcosφ;
+ }, Math.atan);
+ (d3.geo.gnomonic = function() {
+ return d3_geo_projection(d3_geo_gnomonic);
+ }).raw = d3_geo_gnomonic;
+ function d3_geo_mercator(λ, φ) {
+ return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ];
+ }
+ d3_geo_mercator.invert = function(x, y) {
+ return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ];
+ };
+ function d3_geo_mercatorProjection(project) {
+ var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto;
+ m.scale = function() {
+ var v = scale.apply(m, arguments);
+ return v === m ? clipAuto ? m.clipExtent(null) : m : v;
+ };
+ m.translate = function() {
+ var v = translate.apply(m, arguments);
+ return v === m ? clipAuto ? m.clipExtent(null) : m : v;
+ };
+ m.clipExtent = function(_) {
+ var v = clipExtent.apply(m, arguments);
+ if (v === m) {
+ if (clipAuto = _ == null) {
+ var k = π * scale(), t = translate();
+ clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]);
+ }
+ } else if (clipAuto) {
+ v = null;
+ }
+ return v;
+ };
+ return m.clipExtent(null);
+ }
+ (d3.geo.mercator = function() {
+ return d3_geo_mercatorProjection(d3_geo_mercator);
+ }).raw = d3_geo_mercator;
+ var d3_geo_orthographic = d3_geo_azimuthal(function() {
+ return 1;
+ }, Math.asin);
+ (d3.geo.orthographic = function() {
+ return d3_geo_projection(d3_geo_orthographic);
+ }).raw = d3_geo_orthographic;
+ var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) {
+ return 1 / (1 + cosλcosφ);
+ }, function(ρ) {
+ return 2 * Math.atan(ρ);
+ });
+ (d3.geo.stereographic = function() {
+ return d3_geo_projection(d3_geo_stereographic);
+ }).raw = d3_geo_stereographic;
+ function d3_geo_transverseMercator(λ, φ) {
+ return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ];
+ }
+ d3_geo_transverseMercator.invert = function(x, y) {
+ return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ];
+ };
+ (d3.geo.transverseMercator = function() {
+ var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate;
+ projection.center = function(_) {
+ return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ -_[1], _[0] ]);
+ };
+ projection.rotate = function(_) {
+ return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(),
+ [ _[0], _[1], _[2] - 90 ]);
+ };
+ return projection.rotate([ 0, 0 ]);
+ }).raw = d3_geo_transverseMercator;
+ d3.geom = {};
+ function d3_geom_pointX(d) {
+ return d[0];
+ }
+ function d3_geom_pointY(d) {
+ return d[1];
+ }
+ d3.geom.hull = function(vertices) {
+ var x = d3_geom_pointX, y = d3_geom_pointY;
+ if (arguments.length) return hull(vertices);
+ function hull(data) {
+ if (data.length < 3) return [];
+ var fx = d3_functor(x), fy = d3_functor(y), i, n = data.length, points = [], flippedPoints = [];
+ for (i = 0; i < n; i++) {
+ points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]);
+ }
+ points.sort(d3_geom_hullOrder);
+ for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]);
+ var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints);
+ var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = [];
+ for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]);
+ for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]);
+ return polygon;
+ }
+ hull.x = function(_) {
+ return arguments.length ? (x = _, hull) : x;
+ };
+ hull.y = function(_) {
+ return arguments.length ? (y = _, hull) : y;
+ };
+ return hull;
+ };
+ function d3_geom_hullUpper(points) {
+ var n = points.length, hull = [ 0, 1 ], hs = 2;
+ for (var i = 2; i < n; i++) {
+ while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs;
+ hull[hs++] = i;
+ }
+ return hull.slice(0, hs);
+ }
+ function d3_geom_hullOrder(a, b) {
+ return a[0] - b[0] || a[1] - b[1];
+ }
+ d3.geom.polygon = function(coordinates) {
+ d3_subclass(coordinates, d3_geom_polygonPrototype);
+ return coordinates;
+ };
+ var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];
+ d3_geom_polygonPrototype.area = function() {
+ var i = -1, n = this.length, a, b = this[n - 1], area = 0;
+ while (++i < n) {
+ a = b;
+ b = this[i];
+ area += a[1] * b[0] - a[0] * b[1];
+ }
+ return area * .5;
+ };
+ d3_geom_polygonPrototype.centroid = function(k) {
+ var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c;
+ if (!arguments.length) k = -1 / (6 * this.area());
+ while (++i < n) {
+ a = b;
+ b = this[i];
+ c = a[0] * b[1] - b[0] * a[1];
+ x += (a[0] + b[0]) * c;
+ y += (a[1] + b[1]) * c;
+ }
+ return [ x * k, y * k ];
+ };
+ d3_geom_polygonPrototype.clip = function(subject) {
+ var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d;
+ while (++i < n) {
+ input = subject.slice();
+ subject.length = 0;
+ b = this[i];
+ c = input[(m = input.length - closed) - 1];
+ j = -1;
+ while (++j < m) {
+ d = input[j];
+ if (d3_geom_polygonInside(d, a, b)) {
+ if (!d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ subject.push(d);
+ } else if (d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ c = d;
+ }
+ if (closed) subject.push(subject[0]);
+ a = b;
+ }
+ return subject;
+ };
+ function d3_geom_polygonInside(p, a, b) {
+ return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
+ }
+ function d3_geom_polygonIntersect(c, d, a, b) {
+ var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
+ return [ x1 + ua * x21, y1 + ua * y21 ];
+ }
+ function d3_geom_polygonClosed(coordinates) {
+ var a = coordinates[0], b = coordinates[coordinates.length - 1];
+ return !(a[0] - b[0] || a[1] - b[1]);
+ }
+ var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = [];
+ function d3_geom_voronoiBeach() {
+ d3_geom_voronoiRedBlackNode(this);
+ this.edge = this.site = this.circle = null;
+ }
+ function d3_geom_voronoiCreateBeach(site) {
+ var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach();
+ beach.site = site;
+ return beach;
+ }
+ function d3_geom_voronoiDetachBeach(beach) {
+ d3_geom_voronoiDetachCircle(beach);
+ d3_geom_voronoiBeaches.remove(beach);
+ d3_geom_voronoiBeachPool.push(beach);
+ d3_geom_voronoiRedBlackNode(beach);
+ }
+ function d3_geom_voronoiRemoveBeach(beach) {
+ var circle = beach.circle, x = circle.x, y = circle.cy, vertex = {
+ x: x,
+ y: y
+ }, previous = beach.P, next = beach.N, disappearing = [ beach ];
+ d3_geom_voronoiDetachBeach(beach);
+ var lArc = previous;
+ while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) {
+ previous = lArc.P;
+ disappearing.unshift(lArc);
+ d3_geom_voronoiDetachBeach(lArc);
+ lArc = previous;
+ }
+ disappearing.unshift(lArc);
+ d3_geom_voronoiDetachCircle(lArc);
+ var rArc = next;
+ while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) {
+ next = rArc.N;
+ disappearing.push(rArc);
+ d3_geom_voronoiDetachBeach(rArc);
+ rArc = next;
+ }
+ disappearing.push(rArc);
+ d3_geom_voronoiDetachCircle(rArc);
+ var nArcs = disappearing.length, iArc;
+ for (iArc = 1; iArc < nArcs; ++iArc) {
+ rArc = disappearing[iArc];
+ lArc = disappearing[iArc - 1];
+ d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
+ }
+ lArc = disappearing[0];
+ rArc = disappearing[nArcs - 1];
+ rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex);
+ d3_geom_voronoiAttachCircle(lArc);
+ d3_geom_voronoiAttachCircle(rArc);
+ }
+ function d3_geom_voronoiAddBeach(site) {
+ var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._;
+ while (node) {
+ dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x;
+ if (dxl > ε) node = node.L; else {
+ dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix);
+ if (dxr > ε) {
+ if (!node.R) {
+ lArc = node;
+ break;
+ }
+ node = node.R;
+ } else {
+ if (dxl > -ε) {
+ lArc = node.P;
+ rArc = node;
+ } else if (dxr > -ε) {
+ lArc = node;
+ rArc = node.N;
+ } else {
+ lArc = rArc = node;
+ }
+ break;
+ }
+ }
+ }
+ var newArc = d3_geom_voronoiCreateBeach(site);
+ d3_geom_voronoiBeaches.insert(lArc, newArc);
+ if (!lArc && !rArc) return;
+ if (lArc === rArc) {
+ d3_geom_voronoiDetachCircle(lArc);
+ rArc = d3_geom_voronoiCreateBeach(lArc.site);
+ d3_geom_voronoiBeaches.insert(newArc, rArc);
+ newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
+ d3_geom_voronoiAttachCircle(lArc);
+ d3_geom_voronoiAttachCircle(rArc);
+ return;
+ }
+ if (!rArc) {
+ newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
+ return;
+ }
+ d3_geom_voronoiDetachCircle(lArc);
+ d3_geom_voronoiDetachCircle(rArc);
+ var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y - ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = {
+ x: (cy * hb - by * hc) / d + ax,
+ y: (bx * hc - cx * hb) / d + ay
+ };
+ d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex);
+ newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex);
+ rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex);
+ d3_geom_voronoiAttachCircle(lArc);
+ d3_geom_voronoiAttachCircle(rArc);
+ }
+ function d3_geom_voronoiLeftBreakPoint(arc, directrix) {
+ var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix;
+ if (!pby2) return rfocx;
+ var lArc = arc.P;
+ if (!lArc) return -Infinity;
+ site = lArc.site;
+ var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix;
+ if (!plby2) return lfocx;
+ var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2;
+ if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
+ return (rfocx + lfocx) / 2;
+ }
+ function d3_geom_voronoiRightBreakPoint(arc, directrix) {
+ var rArc = arc.N;
+ if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix);
+ var site = arc.site;
+ return site.y === directrix ? site.x : Infinity;
+ }
+ function d3_geom_voronoiCell(site) {
+ this.site = site;
+ this.edges = [];
+ }
+ d3_geom_voronoiCell.prototype.prepare = function() {
+ var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge;
+ while (iHalfEdge--) {
+ edge = halfEdges[iHalfEdge].edge;
+ if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1);
+ }
+ halfEdges.sort(d3_geom_voronoiHalfEdgeOrder);
+ return halfEdges.length;
+ };
+ function d3_geom_voronoiCloseCells(extent) {
+ var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2, y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge, halfEdges, nHalfEdges, start, end;
+ while (iCell--) {
+ cell = cells[iCell];
+ if (!cell || !cell.prepare()) continue;
+ halfEdges = cell.edges;
+ nHalfEdges = halfEdges.length;
+ iHalfEdge = 0;
+ while (iHalfEdge < nHalfEdges) {
+ end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y;
+ start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y;
+ if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) {
+ halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? {
+ x: x0,
+ y: abs(x2 - x0) < ε ? y2 : y1
+ } : abs(y3 - y1) < ε && x1 - x3 > ε ? {
+ x: abs(y2 - y1) < ε ? x2 : x1,
+ y: y1
+ } : abs(x3 - x1) < ε && y3 - y0 > ε ? {
+ x: x1,
+ y: abs(x2 - x1) < ε ? y2 : y0
+ } : abs(y3 - y0) < ε && x3 - x0 > ε ? {
+ x: abs(y2 - y0) < ε ? x2 : x0,
+ y: y0
+ } : null), cell.site, null));
+ ++nHalfEdges;
+ }
+ }
+ }
+ }
+ function d3_geom_voronoiHalfEdgeOrder(a, b) {
+ return b.angle - a.angle;
+ }
+ function d3_geom_voronoiCircle() {
+ d3_geom_voronoiRedBlackNode(this);
+ this.x = this.y = this.arc = this.site = this.cy = null;
+ }
+ function d3_geom_voronoiAttachCircle(arc) {
+ var lArc = arc.P, rArc = arc.N;
+ if (!lArc || !rArc) return;
+ var lSite = lArc.site, cSite = arc.site, rSite = rArc.site;
+ if (lSite === rSite) return;
+ var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by;
+ var d = 2 * (ax * cy - ay * cx);
+ if (d >= -ε2) return;
+ var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d, cy = y + by;
+ var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle();
+ circle.arc = arc;
+ circle.site = cSite;
+ circle.x = x + bx;
+ circle.y = cy + Math.sqrt(x * x + y * y);
+ circle.cy = cy;
+ arc.circle = circle;
+ var before = null, node = d3_geom_voronoiCircles._;
+ while (node) {
+ if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) {
+ if (node.L) node = node.L; else {
+ before = node.P;
+ break;
+ }
+ } else {
+ if (node.R) node = node.R; else {
+ before = node;
+ break;
+ }
+ }
+ }
+ d3_geom_voronoiCircles.insert(before, circle);
+ if (!before) d3_geom_voronoiFirstCircle = circle;
+ }
+ function d3_geom_voronoiDetachCircle(arc) {
+ var circle = arc.circle;
+ if (circle) {
+ if (!circle.P) d3_geom_voronoiFirstCircle = circle.N;
+ d3_geom_voronoiCircles.remove(circle);
+ d3_geom_voronoiCirclePool.push(circle);
+ d3_geom_voronoiRedBlackNode(circle);
+ arc.circle = null;
+ }
+ }
+ function d3_geom_voronoiClipEdges(extent) {
+ var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1], extent[1][0], extent[1][1]), i = edges.length, e;
+ while (i--) {
+ e = edges[i];
+ if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) {
+ e.a = e.b = null;
+ edges.splice(i, 1);
+ }
+ }
+ }
+ function d3_geom_voronoiConnectEdge(edge, extent) {
+ var vb = edge.b;
+ if (vb) return true;
+ var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry = rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb;
+ if (ry === ly) {
+ if (fx < x0 || fx >= x1) return;
+ if (lx > rx) {
+ if (!va) va = {
+ x: fx,
+ y: y0
+ }; else if (va.y >= y1) return;
+ vb = {
+ x: fx,
+ y: y1
+ };
+ } else {
+ if (!va) va = {
+ x: fx,
+ y: y1
+ }; else if (va.y < y0) return;
+ vb = {
+ x: fx,
+ y: y0
+ };
+ }
+ } else {
+ fm = (lx - rx) / (ry - ly);
+ fb = fy - fm * fx;
+ if (fm < -1 || fm > 1) {
+ if (lx > rx) {
+ if (!va) va = {
+ x: (y0 - fb) / fm,
+ y: y0
+ }; else if (va.y >= y1) return;
+ vb = {
+ x: (y1 - fb) / fm,
+ y: y1
+ };
+ } else {
+ if (!va) va = {
+ x: (y1 - fb) / fm,
+ y: y1
+ }; else if (va.y < y0) return;
+ vb = {
+ x: (y0 - fb) / fm,
+ y: y0
+ };
+ }
+ } else {
+ if (ly < ry) {
+ if (!va) va = {
+ x: x0,
+ y: fm * x0 + fb
+ }; else if (va.x >= x1) return;
+ vb = {
+ x: x1,
+ y: fm * x1 + fb
+ };
+ } else {
+ if (!va) va = {
+ x: x1,
+ y: fm * x1 + fb
+ }; else if (va.x < x0) return;
+ vb = {
+ x: x0,
+ y: fm * x0 + fb
+ };
+ }
+ }
+ }
+ edge.a = va;
+ edge.b = vb;
+ return true;
+ }
+ function d3_geom_voronoiEdge(lSite, rSite) {
+ this.l = lSite;
+ this.r = rSite;
+ this.a = this.b = null;
+ }
+ function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) {
+ var edge = new d3_geom_voronoiEdge(lSite, rSite);
+ d3_geom_voronoiEdges.push(edge);
+ if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va);
+ if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb);
+ d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite));
+ d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite));
+ return edge;
+ }
+ function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) {
+ var edge = new d3_geom_voronoiEdge(lSite, null);
+ edge.a = va;
+ edge.b = vb;
+ d3_geom_voronoiEdges.push(edge);
+ return edge;
+ }
+ function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) {
+ if (!edge.a && !edge.b) {
+ edge.a = vertex;
+ edge.l = lSite;
+ edge.r = rSite;
+ } else if (edge.l === rSite) {
+ edge.b = vertex;
+ } else {
+ edge.a = vertex;
+ }
+ }
+ function d3_geom_voronoiHalfEdge(edge, lSite, rSite) {
+ var va = edge.a, vb = edge.b;
+ this.edge = edge;
+ this.site = lSite;
+ this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l === lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y);
+ }
+ d3_geom_voronoiHalfEdge.prototype = {
+ start: function() {
+ return this.edge.l === this.site ? this.edge.a : this.edge.b;
+ },
+ end: function() {
+ return this.edge.l === this.site ? this.edge.b : this.edge.a;
+ }
+ };
+ function d3_geom_voronoiRedBlackTree() {
+ this._ = null;
+ }
+ function d3_geom_voronoiRedBlackNode(node) {
+ node.U = node.C = node.L = node.R = node.P = node.N = null;
+ }
+ d3_geom_voronoiRedBlackTree.prototype = {
+ insert: function(after, node) {
+ var parent, grandpa, uncle;
+ if (after) {
+ node.P = after;
+ node.N = after.N;
+ if (after.N) after.N.P = node;
+ after.N = node;
+ if (after.R) {
+ after = after.R;
+ while (after.L) after = after.L;
+ after.L = node;
+ } else {
+ after.R = node;
+ }
+ parent = after;
+ } else if (this._) {
+ after = d3_geom_voronoiRedBlackFirst(this._);
+ node.P = null;
+ node.N = after;
+ after.P = after.L = node;
+ parent = after;
+ } else {
+ node.P = node.N = null;
+ this._ = node;
+ parent = null;
+ }
+ node.L = node.R = null;
+ node.U = parent;
+ node.C = true;
+ after = node;
+ while (parent && parent.C) {
+ grandpa = parent.U;
+ if (parent === grandpa.L) {
+ uncle = grandpa.R;
+ if (uncle && uncle.C) {
+ parent.C = uncle.C = false;
+ grandpa.C = true;
+ after = grandpa;
+ } else {
+ if (after === parent.R) {
+ d3_geom_voronoiRedBlackRotateLeft(this, parent);
+ after = parent;
+ parent = after.U;
+ }
+ parent.C = false;
+ grandpa.C = true;
+ d3_geom_voronoiRedBlackRotateRight(this, grandpa);
+ }
+ } else {
+ uncle = grandpa.L;
+ if (uncle && uncle.C) {
+ parent.C = uncle.C = false;
+ grandpa.C = true;
+ after = grandpa;
+ } else {
+ if (after === parent.L) {
+ d3_geom_voronoiRedBlackRotateRight(this, parent);
+ after = parent;
+ parent = after.U;
+ }
+ parent.C = false;
+ grandpa.C = true;
+ d3_geom_voronoiRedBlackRotateLeft(this, grandpa);
+ }
+ }
+ parent = after.U;
+ }
+ this._.C = false;
+ },
+ remove: function(node) {
+ if (node.N) node.N.P = node.P;
+ if (node.P) node.P.N = node.N;
+ node.N = node.P = null;
+ var parent = node.U, sibling, left = node.L, right = node.R, next, red;
+ if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right);
+ if (parent) {
+ if (parent.L === node) parent.L = next; else parent.R = next;
+ } else {
+ this._ = next;
+ }
+ if (left && right) {
+ red = next.C;
+ next.C = node.C;
+ next.L = left;
+ left.U = next;
+ if (next !== right) {
+ parent = next.U;
+ next.U = node.U;
+ node = next.R;
+ parent.L = node;
+ next.R = right;
+ right.U = next;
+ } else {
+ next.U = parent;
+ parent = next;
+ node = next.R;
+ }
+ } else {
+ red = node.C;
+ node = next;
+ }
+ if (node) node.U = parent;
+ if (red) return;
+ if (node && node.C) {
+ node.C = false;
+ return;
+ }
+ do {
+ if (node === this._) break;
+ if (node === parent.L) {
+ sibling = parent.R;
+ if (sibling.C) {
+ sibling.C = false;
+ parent.C = true;
+ d3_geom_voronoiRedBlackRotateLeft(this, parent);
+ sibling = parent.R;
+ }
+ if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
+ if (!sibling.R || !sibling.R.C) {
+ sibling.L.C = false;
+ sibling.C = true;
+ d3_geom_voronoiRedBlackRotateRight(this, sibling);
+ sibling = parent.R;
+ }
+ sibling.C = parent.C;
+ parent.C = sibling.R.C = false;
+ d3_geom_voronoiRedBlackRotateLeft(this, parent);
+ node = this._;
+ break;
+ }
+ } else {
+ sibling = parent.L;
+ if (sibling.C) {
+ sibling.C = false;
+ parent.C = true;
+ d3_geom_voronoiRedBlackRotateRight(this, parent);
+ sibling = parent.L;
+ }
+ if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
+ if (!sibling.L || !sibling.L.C) {
+ sibling.R.C = false;
+ sibling.C = true;
+ d3_geom_voronoiRedBlackRotateLeft(this, sibling);
+ sibling = parent.L;
+ }
+ sibling.C = parent.C;
+ parent.C = sibling.L.C = false;
+ d3_geom_voronoiRedBlackRotateRight(this, parent);
+ node = this._;
+ break;
+ }
+ }
+ sibling.C = true;
+ node = parent;
+ parent = parent.U;
+ } while (!node.C);
+ if (node) node.C = false;
+ }
+ };
+ function d3_geom_voronoiRedBlackRotateLeft(tree, node) {
+ var p = node, q = node.R, parent = p.U;
+ if (parent) {
+ if (parent.L === p) parent.L = q; else parent.R = q;
+ } else {
+ tree._ = q;
+ }
+ q.U = parent;
+ p.U = q;
+ p.R = q.L;
+ if (p.R) p.R.U = p;
+ q.L = p;
+ }
+ function d3_geom_voronoiRedBlackRotateRight(tree, node) {
+ var p = node, q = node.L, parent = p.U;
+ if (parent) {
+ if (parent.L === p) parent.L = q; else parent.R = q;
+ } else {
+ tree._ = q;
+ }
+ q.U = parent;
+ p.U = q;
+ p.L = q.R;
+ if (p.L) p.L.U = p;
+ q.R = p;
+ }
+ function d3_geom_voronoiRedBlackFirst(node) {
+ while (node.L) node = node.L;
+ return node;
+ }
+ function d3_geom_voronoi(sites, bbox) {
+ var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle;
+ d3_geom_voronoiEdges = [];
+ d3_geom_voronoiCells = new Array(sites.length);
+ d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree();
+ d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree();
+ while (true) {
+ circle = d3_geom_voronoiFirstCircle;
+ if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) {
+ if (site.x !== x0 || site.y !== y0) {
+ d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site);
+ d3_geom_voronoiAddBeach(site);
+ x0 = site.x, y0 = site.y;
+ }
+ site = sites.pop();
+ } else if (circle) {
+ d3_geom_voronoiRemoveBeach(circle.arc);
+ } else {
+ break;
+ }
+ }
+ if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox);
+ var diagram = {
+ cells: d3_geom_voronoiCells,
+ edges: d3_geom_voronoiEdges
+ };
+ d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null;
+ return diagram;
+ }
+ function d3_geom_voronoiVertexOrder(a, b) {
+ return b.y - a.y || b.x - a.x;
+ }
+ d3.geom.voronoi = function(points) {
+ var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent;
+ if (points) return voronoi(points);
+ function voronoi(data) {
+ var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1];
+ d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) {
+ var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) {
+ var s = e.start();
+ return [ s.x, s.y ];
+ }) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : [];
+ polygon.point = data[i];
+ });
+ return polygons;
+ }
+ function sites(data) {
+ return data.map(function(d, i) {
+ return {
+ x: Math.round(fx(d, i) / ε) * ε,
+ y: Math.round(fy(d, i) / ε) * ε,
+ i: i
+ };
+ });
+ }
+ voronoi.links = function(data) {
+ return d3_geom_voronoi(sites(data)).edges.filter(function(edge) {
+ return edge.l && edge.r;
+ }).map(function(edge) {
+ return {
+ source: data[edge.l.i],
+ target: data[edge.r.i]
+ };
+ });
+ };
+ voronoi.triangles = function(data) {
+ var triangles = [];
+ d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) {
+ var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j = -1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l;
+ while (++j < m) {
+ e0 = e1;
+ s0 = s1;
+ e1 = edges[j].edge;
+ s1 = e1.l === site ? e1.r : e1.l;
+ if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) {
+ triangles.push([ data[i], data[s0.i], data[s1.i] ]);
+ }
+ }
+ });
+ return triangles;
+ };
+ voronoi.x = function(_) {
+ return arguments.length ? (fx = d3_functor(x = _), voronoi) : x;
+ };
+ voronoi.y = function(_) {
+ return arguments.length ? (fy = d3_functor(y = _), voronoi) : y;
+ };
+ voronoi.clipExtent = function(_) {
+ if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent;
+ clipExtent = _ == null ? d3_geom_voronoiClipExtent : _;
+ return voronoi;
+ };
+ voronoi.size = function(_) {
+ if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1];
+ return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]);
+ };
+ return voronoi;
+ };
+ var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ];
+ function d3_geom_voronoiTriangleArea(a, b, c) {
+ return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y);
+ }
+ d3.geom.delaunay = function(vertices) {
+ return d3.geom.voronoi().triangles(vertices);
+ };
+ d3.geom.quadtree = function(points, x1, y1, x2, y2) {
+ var x = d3_geom_pointX, y = d3_geom_pointY, compat;
+ if (compat = arguments.length) {
+ x = d3_geom_quadtreeCompatX;
+ y = d3_geom_quadtreeCompatY;
+ if (compat === 3) {
+ y2 = y1;
+ x2 = x1;
+ y1 = x1 = 0;
+ }
+ return quadtree(points);
+ }
+ function quadtree(data) {
+ var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_;
+ if (x1 != null) {
+ x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;
+ } else {
+ x2_ = y2_ = -(x1_ = y1_ = Infinity);
+ xs = [], ys = [];
+ n = data.length;
+ if (compat) for (i = 0; i < n; ++i) {
+ d = data[i];
+ if (d.x < x1_) x1_ = d.x;
+ if (d.y < y1_) y1_ = d.y;
+ if (d.x > x2_) x2_ = d.x;
+ if (d.y > y2_) y2_ = d.y;
+ xs.push(d.x);
+ ys.push(d.y);
+ } else for (i = 0; i < n; ++i) {
+ var x_ = +fx(d = data[i], i), y_ = +fy(d, i);
+ if (x_ < x1_) x1_ = x_;
+ if (y_ < y1_) y1_ = y_;
+ if (x_ > x2_) x2_ = x_;
+ if (y_ > y2_) y2_ = y_;
+ xs.push(x_);
+ ys.push(y_);
+ }
+ }
+ var dx = x2_ - x1_, dy = y2_ - y1_;
+ if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy;
+ function insert(n, d, x, y, x1, y1, x2, y2) {
+ if (isNaN(x) || isNaN(y)) return;
+ if (n.leaf) {
+ var nx = n.x, ny = n.y;
+ if (nx != null) {
+ if (abs(nx - x) + abs(ny - y) < .01) {
+ insertChild(n, d, x, y, x1, y1, x2, y2);
+ } else {
+ var nPoint = n.point;
+ n.x = n.y = n.point = null;
+ insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);
+ insertChild(n, d, x, y, x1, y1, x2, y2);
+ }
+ } else {
+ n.x = x, n.y = y, n.point = d;
+ }
+ } else {
+ insertChild(n, d, x, y, x1, y1, x2, y2);
+ }
+ }
+ function insertChild(n, d, x, y, x1, y1, x2, y2) {
+ var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right;
+ n.leaf = false;
+ n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
+ if (right) x1 = sx; else x2 = sx;
+ if (bottom) y1 = sy; else y2 = sy;
+ insert(n, d, x, y, x1, y1, x2, y2);
+ }
+ var root = d3_geom_quadtreeNode();
+ root.add = function(d) {
+ insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);
+ };
+ root.visit = function(f) {
+ d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);
+ };
+ i = -1;
+ if (x1 == null) {
+ while (++i < n) {
+ insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);
+ }
+ --i;
+ } else data.forEach(root.add);
+ xs = ys = data = d = null;
+ return root;
+ }
+ quadtree.x = function(_) {
+ return arguments.length ? (x = _, quadtree) : x;
+ };
+ quadtree.y = function(_) {
+ return arguments.length ? (y = _, quadtree) : y;
+ };
+ quadtree.extent = function(_) {
+ if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ];
+ if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0],
+ y2 = +_[1][1];
+ return quadtree;
+ };
+ quadtree.size = function(_) {
+ if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ];
+ if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];
+ return quadtree;
+ };
+ return quadtree;
+ };
+ function d3_geom_quadtreeCompatX(d) {
+ return d.x;
+ }
+ function d3_geom_quadtreeCompatY(d) {
+ return d.y;
+ }
+ function d3_geom_quadtreeNode() {
+ return {
+ leaf: true,
+ nodes: [],
+ point: null,
+ x: null,
+ y: null
+ };
+ }
+ function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
+ if (!f(node, x1, y1, x2, y2)) {
+ var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
+ if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
+ if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
+ if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
+ if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
+ }
+ }
+ d3.interpolateRgb = d3_interpolateRgb;
+ function d3_interpolateRgb(a, b) {
+ a = d3.rgb(a);
+ b = d3.rgb(b);
+ var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
+ return function(t) {
+ return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
+ };
+ }
+ d3.interpolateObject = d3_interpolateObject;
+ function d3_interpolateObject(a, b) {
+ var i = {}, c = {}, k;
+ for (k in a) {
+ if (k in b) {
+ i[k] = d3_interpolate(a[k], b[k]);
+ } else {
+ c[k] = a[k];
+ }
+ }
+ for (k in b) {
+ if (!(k in a)) {
+ c[k] = b[k];
+ }
+ }
+ return function(t) {
+ for (k in i) c[k] = i[k](t);
+ return c;
+ };
+ }
+ d3.interpolateNumber = d3_interpolateNumber;
+ function d3_interpolateNumber(a, b) {
+ b -= a = +a;
+ return function(t) {
+ return a + b * t;
+ };
+ }
+ d3.interpolateString = d3_interpolateString;
+ function d3_interpolateString(a, b) {
+ var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
+ a = a + "", b = b + "";
+ d3_interpolate_number.lastIndex = 0;
+ for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
+ if (m.index) s.push(b.substring(s0, s1 = m.index));
+ q.push({
+ i: s.length,
+ x: m[0]
+ });
+ s.push(null);
+ s0 = d3_interpolate_number.lastIndex;
+ }
+ if (s0 < b.length) s.push(b.substring(s0));
+ for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
+ o = q[i];
+ if (o.x == m[0]) {
+ if (o.i) {
+ if (s[o.i + 1] == null) {
+ s[o.i - 1] += o.x;
+ s.splice(o.i, 1);
+ for (j = i + 1; j < n; ++j) q[j].i--;
+ } else {
+ s[o.i - 1] += o.x + s[o.i + 1];
+ s.splice(o.i, 2);
+ for (j = i + 1; j < n; ++j) q[j].i -= 2;
+ }
+ } else {
+ if (s[o.i + 1] == null) {
+ s[o.i] = o.x;
+ } else {
+ s[o.i] = o.x + s[o.i + 1];
+ s.splice(o.i + 1, 1);
+ for (j = i + 1; j < n; ++j) q[j].i--;
+ }
+ }
+ q.splice(i, 1);
+ n--;
+ i--;
+ } else {
+ o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
+ }
+ }
+ while (i < n) {
+ o = q.pop();
+ if (s[o.i + 1] == null) {
+ s[o.i] = o.x;
+ } else {
+ s[o.i] = o.x + s[o.i + 1];
+ s.splice(o.i + 1, 1);
+ }
+ n--;
+ }
+ if (s.length === 1) {
+ return s[0] == null ? (o = q[0].x, function(t) {
+ return o(t) + "";
+ }) : function() {
+ return b;
+ };
+ }
+ return function(t) {
+ for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ }
+ var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
+ d3.interpolate = d3_interpolate;
+ function d3_interpolate(a, b) {
+ var i = d3.interpolators.length, f;
+ while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
+ return f;
+ }
+ d3.interpolators = [ function(a, b) {
+ var t = typeof b;
+ return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : Array.isArray(b) ? d3_interpolateArray : t === "object" && isNaN(b) ? d3_interpolateObject : d3_interpolateNumber)(a, b);
+ } ];
+ d3.interpolateArray = d3_interpolateArray;
+ function d3_interpolateArray(a, b) {
+ var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i;
+ for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));
+ for (;i < na; ++i) c[i] = a[i];
+ for (;i < nb; ++i) c[i] = b[i];
+ return function(t) {
+ for (i = 0; i < n0; ++i) c[i] = x[i](t);
+ return c;
+ };
+ }
+ var d3_ease_default = function() {
+ return d3_identity;
+ };
+ var d3_ease = d3.map({
+ linear: d3_ease_default,
+ poly: d3_ease_poly,
+ quad: function() {
+ return d3_ease_quad;
+ },
+ cubic: function() {
+ return d3_ease_cubic;
+ },
+ sin: function() {
+ return d3_ease_sin;
+ },
+ exp: function() {
+ return d3_ease_exp;
+ },
+ circle: function() {
+ return d3_ease_circle;
+ },
+ elastic: d3_ease_elastic,
+ back: d3_ease_back,
+ bounce: function() {
+ return d3_ease_bounce;
+ }
+ });
+ var d3_ease_mode = d3.map({
+ "in": d3_identity,
+ out: d3_ease_reverse,
+ "in-out": d3_ease_reflect,
+ "out-in": function(f) {
+ return d3_ease_reflect(d3_ease_reverse(f));
+ }
+ });
+ d3.ease = function(name) {
+ var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in";
+ t = d3_ease.get(t) || d3_ease_default;
+ m = d3_ease_mode.get(m) || d3_identity;
+ return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1))));
+ };
+ function d3_ease_clamp(f) {
+ return function(t) {
+ return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
+ };
+ }
+ function d3_ease_reverse(f) {
+ return function(t) {
+ return 1 - f(1 - t);
+ };
+ }
+ function d3_ease_reflect(f) {
+ return function(t) {
+ return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
+ };
+ }
+ function d3_ease_quad(t) {
+ return t * t;
+ }
+ function d3_ease_cubic(t) {
+ return t * t * t;
+ }
+ function d3_ease_cubicInOut(t) {
+ if (t <= 0) return 0;
+ if (t >= 1) return 1;
+ var t2 = t * t, t3 = t2 * t;
+ return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
+ }
+ function d3_ease_poly(e) {
+ return function(t) {
+ return Math.pow(t, e);
+ };
+ }
+ function d3_ease_sin(t) {
+ return 1 - Math.cos(t * halfπ);
+ }
+ function d3_ease_exp(t) {
+ return Math.pow(2, 10 * (t - 1));
+ }
+ function d3_ease_circle(t) {
+ return 1 - Math.sqrt(1 - t * t);
+ }
+ function d3_ease_elastic(a, p) {
+ var s;
+ if (arguments.length < 2) p = .45;
+ if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4;
+ return function(t) {
+ return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p);
+ };
+ }
+ function d3_ease_back(s) {
+ if (!s) s = 1.70158;
+ return function(t) {
+ return t * t * ((s + 1) * t - s);
+ };
+ }
+ function d3_ease_bounce(t) {
+ return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
+ }
+ d3.interpolateHcl = d3_interpolateHcl;
+ function d3_interpolateHcl(a, b) {
+ a = d3.hcl(a);
+ b = d3.hcl(b);
+ var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
+ if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac;
+ if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
+ return function(t) {
+ return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
+ };
+ }
+ d3.interpolateHsl = d3_interpolateHsl;
+ function d3_interpolateHsl(a, b) {
+ a = d3.hsl(a);
+ b = d3.hsl(b);
+ var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;
+ if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as;
+ if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
+ return function(t) {
+ return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + "";
+ };
+ }
+ d3.interpolateLab = d3_interpolateLab;
+ function d3_interpolateLab(a, b) {
+ a = d3.lab(a);
+ b = d3.lab(b);
+ var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
+ return function(t) {
+ return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
+ };
+ }
+ d3.interpolateRound = d3_interpolateRound;
+ function d3_interpolateRound(a, b) {
+ b -= a;
+ return function(t) {
+ return Math.round(a + b * t);
+ };
+ }
+ d3.transform = function(string) {
+ var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
+ return (d3.transform = function(string) {
+ if (string != null) {
+ g.setAttribute("transform", string);
+ var t = g.transform.baseVal.consolidate();
+ }
+ return new d3_transform(t ? t.matrix : d3_transformIdentity);
+ })(string);
+ };
+ function d3_transform(m) {
+ var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
+ if (r0[0] * r1[1] < r1[0] * r0[1]) {
+ r0[0] *= -1;
+ r0[1] *= -1;
+ kx *= -1;
+ kz *= -1;
+ }
+ this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
+ this.translate = [ m.e, m.f ];
+ this.scale = [ kx, ky ];
+ this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
+ }
+ d3_transform.prototype.toString = function() {
+ return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
+ };
+ function d3_transformDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+ }
+ function d3_transformNormalize(a) {
+ var k = Math.sqrt(d3_transformDot(a, a));
+ if (k) {
+ a[0] /= k;
+ a[1] /= k;
+ }
+ return k;
+ }
+ function d3_transformCombine(a, b, k) {
+ a[0] += k * b[0];
+ a[1] += k * b[1];
+ return a;
+ }
+ var d3_transformIdentity = {
+ a: 1,
+ b: 0,
+ c: 0,
+ d: 1,
+ e: 0,
+ f: 0
+ };
+ d3.interpolateTransform = d3_interpolateTransform;
+ function d3_interpolateTransform(a, b) {
+ var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale;
+ if (ta[0] != tb[0] || ta[1] != tb[1]) {
+ s.push("translate(", null, ",", null, ")");
+ q.push({
+ i: 1,
+ x: d3_interpolateNumber(ta[0], tb[0])
+ }, {
+ i: 3,
+ x: d3_interpolateNumber(ta[1], tb[1])
+ });
+ } else if (tb[0] || tb[1]) {
+ s.push("translate(" + tb + ")");
+ } else {
+ s.push("");
+ }
+ if (ra != rb) {
+ if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
+ q.push({
+ i: s.push(s.pop() + "rotate(", null, ")") - 2,
+ x: d3_interpolateNumber(ra, rb)
+ });
+ } else if (rb) {
+ s.push(s.pop() + "rotate(" + rb + ")");
+ }
+ if (wa != wb) {
+ q.push({
+ i: s.push(s.pop() + "skewX(", null, ")") - 2,
+ x: d3_interpolateNumber(wa, wb)
+ });
+ } else if (wb) {
+ s.push(s.pop() + "skewX(" + wb + ")");
+ }
+ if (ka[0] != kb[0] || ka[1] != kb[1]) {
+ n = s.push(s.pop() + "scale(", null, ",", null, ")");
+ q.push({
+ i: n - 4,
+ x: d3_interpolateNumber(ka[0], kb[0])
+ }, {
+ i: n - 2,
+ x: d3_interpolateNumber(ka[1], kb[1])
+ });
+ } else if (kb[0] != 1 || kb[1] != 1) {
+ s.push(s.pop() + "scale(" + kb + ")");
+ }
+ n = q.length;
+ return function(t) {
+ var i = -1, o;
+ while (++i < n) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ }
+ function d3_uninterpolateNumber(a, b) {
+ b = b - (a = +a) ? 1 / (b - a) : 0;
+ return function(x) {
+ return (x - a) * b;
+ };
+ }
+ function d3_uninterpolateClamp(a, b) {
+ b = b - (a = +a) ? 1 / (b - a) : 0;
+ return function(x) {
+ return Math.max(0, Math.min(1, (x - a) * b));
+ };
+ }
+ d3.layout = {};
+ d3.layout.bundle = function() {
+ return function(links) {
+ var paths = [], i = -1, n = links.length;
+ while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
+ return paths;
+ };
+ };
+ function d3_layout_bundlePath(link) {
+ var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
+ while (start !== lca) {
+ start = start.parent;
+ points.push(start);
+ }
+ var k = points.length;
+ while (end !== lca) {
+ points.splice(k, 0, end);
+ end = end.parent;
+ }
+ return points;
+ }
+ function d3_layout_bundleAncestors(node) {
+ var ancestors = [], parent = node.parent;
+ while (parent != null) {
+ ancestors.push(node);
+ node = parent;
+ parent = parent.parent;
+ }
+ ancestors.push(node);
+ return ancestors;
+ }
+ function d3_layout_bundleLeastCommonAncestor(a, b) {
+ if (a === b) return a;
+ var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
+ while (aNode === bNode) {
+ sharedNode = aNode;
+ aNode = aNodes.pop();
+ bNode = bNodes.pop();
+ }
+ return sharedNode;
+ }
+ d3.layout.chord = function() {
+ var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;
+ function relayout() {
+ var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;
+ chords = [];
+ groups = [];
+ k = 0, i = -1;
+ while (++i < n) {
+ x = 0, j = -1;
+ while (++j < n) {
+ x += matrix[i][j];
+ }
+ groupSums.push(x);
+ subgroupIndex.push(d3.range(n));
+ k += x;
+ }
+ if (sortGroups) {
+ groupIndex.sort(function(a, b) {
+ return sortGroups(groupSums[a], groupSums[b]);
+ });
+ }
+ if (sortSubgroups) {
+ subgroupIndex.forEach(function(d, i) {
+ d.sort(function(a, b) {
+ return sortSubgroups(matrix[i][a], matrix[i][b]);
+ });
+ });
+ }
+ k = (τ - padding * n) / k;
+ x = 0, i = -1;
+ while (++i < n) {
+ x0 = x, j = -1;
+ while (++j < n) {
+ var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;
+ subgroups[di + "-" + dj] = {
+ index: di,
+ subindex: dj,
+ startAngle: a0,
+ endAngle: a1,
+ value: v
+ };
+ }
+ groups[di] = {
+ index: di,
+ startAngle: x0,
+ endAngle: x,
+ value: (x - x0) / k
+ };
+ x += padding;
+ }
+ i = -1;
+ while (++i < n) {
+ j = i - 1;
+ while (++j < n) {
+ var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i];
+ if (source.value || target.value) {
+ chords.push(source.value < target.value ? {
+ source: target,
+ target: source
+ } : {
+ source: source,
+ target: target
+ });
+ }
+ }
+ }
+ if (sortChords) resort();
+ }
+ function resort() {
+ chords.sort(function(a, b) {
+ return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);
+ });
+ }
+ chord.matrix = function(x) {
+ if (!arguments.length) return matrix;
+ n = (matrix = x) && matrix.length;
+ chords = groups = null;
+ return chord;
+ };
+ chord.padding = function(x) {
+ if (!arguments.length) return padding;
+ padding = x;
+ chords = groups = null;
+ return chord;
+ };
+ chord.sortGroups = function(x) {
+ if (!arguments.length) return sortGroups;
+ sortGroups = x;
+ chords = groups = null;
+ return chord;
+ };
+ chord.sortSubgroups = function(x) {
+ if (!arguments.length) return sortSubgroups;
+ sortSubgroups = x;
+ chords = null;
+ return chord;
+ };
+ chord.sortChords = function(x) {
+ if (!arguments.length) return sortChords;
+ sortChords = x;
+ if (chords) resort();
+ return chord;
+ };
+ chord.chords = function() {
+ if (!chords) relayout();
+ return chords;
+ };
+ chord.groups = function() {
+ if (!groups) relayout();
+ return groups;
+ };
+ return chord;
+ };
+ d3.layout.force = function() {
+ var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges;
+ function repulse(node) {
+ return function(quad, x1, _, x2) {
+ if (quad.point !== node) {
+ var dx = quad.cx - node.x, dy = quad.cy - node.y, dw = x2 - x1, dn = dx * dx + dy * dy;
+ if (dw * dw / theta2 < dn) {
+ if (dn < chargeDistance2) {
+ var k = quad.charge / dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ }
+ return true;
+ }
+ if (quad.point && dn && dn < chargeDistance2) {
+ var k = quad.pointCharge / dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ }
+ }
+ return !quad.charge;
+ };
+ }
+ force.tick = function() {
+ if ((alpha *= .99) < .005) {
+ event.end({
+ type: "end",
+ alpha: alpha = 0
+ });
+ return true;
+ }
+ var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
+ for (i = 0; i < m; ++i) {
+ o = links[i];
+ s = o.source;
+ t = o.target;
+ x = t.x - s.x;
+ y = t.y - s.y;
+ if (l = x * x + y * y) {
+ l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
+ x *= l;
+ y *= l;
+ t.x -= x * (k = s.weight / (t.weight + s.weight));
+ t.y -= y * k;
+ s.x += x * (k = 1 - k);
+ s.y += y * k;
+ }
+ }
+ if (k = alpha * gravity) {
+ x = size[0] / 2;
+ y = size[1] / 2;
+ i = -1;
+ if (k) while (++i < n) {
+ o = nodes[i];
+ o.x += (x - o.x) * k;
+ o.y += (y - o.y) * k;
+ }
+ }
+ if (charge) {
+ d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
+ i = -1;
+ while (++i < n) {
+ if (!(o = nodes[i]).fixed) {
+ q.visit(repulse(o));
+ }
+ }
+ }
+ i = -1;
+ while (++i < n) {
+ o = nodes[i];
+ if (o.fixed) {
+ o.x = o.px;
+ o.y = o.py;
+ } else {
+ o.x -= (o.px - (o.px = o.x)) * friction;
+ o.y -= (o.py - (o.py = o.y)) * friction;
+ }
+ }
+ event.tick({
+ type: "tick",
+ alpha: alpha
+ });
+ };
+ force.nodes = function(x) {
+ if (!arguments.length) return nodes;
+ nodes = x;
+ return force;
+ };
+ force.links = function(x) {
+ if (!arguments.length) return links;
+ links = x;
+ return force;
+ };
+ force.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return force;
+ };
+ force.linkDistance = function(x) {
+ if (!arguments.length) return linkDistance;
+ linkDistance = typeof x === "function" ? x : +x;
+ return force;
+ };
+ force.distance = force.linkDistance;
+ force.linkStrength = function(x) {
+ if (!arguments.length) return linkStrength;
+ linkStrength = typeof x === "function" ? x : +x;
+ return force;
+ };
+ force.friction = function(x) {
+ if (!arguments.length) return friction;
+ friction = +x;
+ return force;
+ };
+ force.charge = function(x) {
+ if (!arguments.length) return charge;
+ charge = typeof x === "function" ? x : +x;
+ return force;
+ };
+ force.chargeDistance = function(x) {
+ if (!arguments.length) return Math.sqrt(chargeDistance2);
+ chargeDistance2 = x * x;
+ return force;
+ };
+ force.gravity = function(x) {
+ if (!arguments.length) return gravity;
+ gravity = +x;
+ return force;
+ };
+ force.theta = function(x) {
+ if (!arguments.length) return Math.sqrt(theta2);
+ theta2 = x * x;
+ return force;
+ };
+ force.alpha = function(x) {
+ if (!arguments.length) return alpha;
+ x = +x;
+ if (alpha) {
+ if (x > 0) alpha = x; else alpha = 0;
+ } else if (x > 0) {
+ event.start({
+ type: "start",
+ alpha: alpha = x
+ });
+ d3.timer(force.tick);
+ }
+ return force;
+ };
+ force.start = function() {
+ var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
+ for (i = 0; i < n; ++i) {
+ (o = nodes[i]).index = i;
+ o.weight = 0;
+ }
+ for (i = 0; i < m; ++i) {
+ o = links[i];
+ if (typeof o.source == "number") o.source = nodes[o.source];
+ if (typeof o.target == "number") o.target = nodes[o.target];
+ ++o.source.weight;
+ ++o.target.weight;
+ }
+ for (i = 0; i < n; ++i) {
+ o = nodes[i];
+ if (isNaN(o.x)) o.x = position("x", w);
+ if (isNaN(o.y)) o.y = position("y", h);
+ if (isNaN(o.px)) o.px = o.x;
+ if (isNaN(o.py)) o.py = o.y;
+ }
+ distances = [];
+ if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance;
+ strengths = [];
+ if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength;
+ charges = [];
+ if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge;
+ function position(dimension, size) {
+ if (!neighbors) {
+ neighbors = new Array(n);
+ for (j = 0; j < n; ++j) {
+ neighbors[j] = [];
+ }
+ for (j = 0; j < m; ++j) {
+ var o = links[j];
+ neighbors[o.source.index].push(o.target);
+ neighbors[o.target.index].push(o.source);
+ }
+ }
+ var candidates = neighbors[i], j = -1, m = candidates.length, x;
+ while (++j < m) if (!isNaN(x = candidates[j][dimension])) return x;
+ return Math.random() * size;
+ }
+ return force.resume();
+ };
+ force.resume = function() {
+ return force.alpha(.1);
+ };
+ force.stop = function() {
+ return force.alpha(0);
+ };
+ force.drag = function() {
+ if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend);
+ if (!arguments.length) return drag;
+ this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
+ };
+ function dragmove(d) {
+ d.px = d3.event.x, d.py = d3.event.y;
+ force.resume();
+ }
+ return d3.rebind(force, event, "on");
+ };
+ function d3_layout_forceDragstart(d) {
+ d.fixed |= 2;
+ }
+ function d3_layout_forceDragend(d) {
+ d.fixed &= ~6;
+ }
+ function d3_layout_forceMouseover(d) {
+ d.fixed |= 4;
+ d.px = d.x, d.py = d.y;
+ }
+ function d3_layout_forceMouseout(d) {
+ d.fixed &= ~4;
+ }
+ function d3_layout_forceAccumulate(quad, alpha, charges) {
+ var cx = 0, cy = 0;
+ quad.charge = 0;
+ if (!quad.leaf) {
+ var nodes = quad.nodes, n = nodes.length, i = -1, c;
+ while (++i < n) {
+ c = nodes[i];
+ if (c == null) continue;
+ d3_layout_forceAccumulate(c, alpha, charges);
+ quad.charge += c.charge;
+ cx += c.charge * c.cx;
+ cy += c.charge * c.cy;
+ }
+ }
+ if (quad.point) {
+ if (!quad.leaf) {
+ quad.point.x += Math.random() - .5;
+ quad.point.y += Math.random() - .5;
+ }
+ var k = alpha * charges[quad.point.index];
+ quad.charge += quad.pointCharge = k;
+ cx += k * quad.point.x;
+ cy += k * quad.point.y;
+ }
+ quad.cx = cx / quad.charge;
+ quad.cy = cy / quad.charge;
+ }
+ var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1, d3_layout_forceChargeDistance2 = Infinity;
+ d3.layout.hierarchy = function() {
+ var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
+ function recurse(node, depth, nodes) {
+ var childs = children.call(hierarchy, node, depth);
+ node.depth = depth;
+ nodes.push(node);
+ if (childs && (n = childs.length)) {
+ var i = -1, n, c = node.children = new Array(n), v = 0, j = depth + 1, d;
+ while (++i < n) {
+ d = c[i] = recurse(childs[i], j, nodes);
+ d.parent = node;
+ v += d.value;
+ }
+ if (sort) c.sort(sort);
+ if (value) node.value = v;
+ } else {
+ delete node.children;
+ if (value) {
+ node.value = +value.call(hierarchy, node, depth) || 0;
+ }
+ }
+ return node;
+ }
+ function revalue(node, depth) {
+ var children = node.children, v = 0;
+ if (children && (n = children.length)) {
+ var i = -1, n, j = depth + 1;
+ while (++i < n) v += revalue(children[i], j);
+ } else if (value) {
+ v = +value.call(hierarchy, node, depth) || 0;
+ }
+ if (value) node.value = v;
+ return v;
+ }
+ function hierarchy(d) {
+ var nodes = [];
+ recurse(d, 0, nodes);
+ return nodes;
+ }
+ hierarchy.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return hierarchy;
+ };
+ hierarchy.children = function(x) {
+ if (!arguments.length) return children;
+ children = x;
+ return hierarchy;
+ };
+ hierarchy.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return hierarchy;
+ };
+ hierarchy.revalue = function(root) {
+ revalue(root, 0);
+ return root;
+ };
+ return hierarchy;
+ };
+ function d3_layout_hierarchyRebind(object, hierarchy) {
+ d3.rebind(object, hierarchy, "sort", "children", "value");
+ object.nodes = object;
+ object.links = d3_layout_hierarchyLinks;
+ return object;
+ }
+ function d3_layout_hierarchyChildren(d) {
+ return d.children;
+ }
+ function d3_layout_hierarchyValue(d) {
+ return d.value;
+ }
+ function d3_layout_hierarchySort(a, b) {
+ return b.value - a.value;
+ }
+ function d3_layout_hierarchyLinks(nodes) {
+ return d3.merge(nodes.map(function(parent) {
+ return (parent.children || []).map(function(child) {
+ return {
+ source: parent,
+ target: child
+ };
+ });
+ }));
+ }
+ d3.layout.partition = function() {
+ var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
+ function position(node, x, dx, dy) {
+ var children = node.children;
+ node.x = x;
+ node.y = node.depth * dy;
+ node.dx = dx;
+ node.dy = dy;
+ if (children && (n = children.length)) {
+ var i = -1, n, c, d;
+ dx = node.value ? dx / node.value : 0;
+ while (++i < n) {
+ position(c = children[i], x, d = c.value * dx, dy);
+ x += d;
+ }
+ }
+ }
+ function depth(node) {
+ var children = node.children, d = 0;
+ if (children && (n = children.length)) {
+ var i = -1, n;
+ while (++i < n) d = Math.max(d, depth(children[i]));
+ }
+ return 1 + d;
+ }
+ function partition(d, i) {
+ var nodes = hierarchy.call(this, d, i);
+ position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
+ return nodes;
+ }
+ partition.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return partition;
+ };
+ return d3_layout_hierarchyRebind(partition, hierarchy);
+ };
+ d3.layout.pie = function() {
+ var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ;
+ function pie(data) {
+ var values = data.map(function(d, i) {
+ return +value.call(pie, d, i);
+ });
+ var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle);
+ var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values);
+ var index = d3.range(data.length);
+ if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
+ return values[j] - values[i];
+ } : function(i, j) {
+ return sort(data[i], data[j]);
+ });
+ var arcs = [];
+ index.forEach(function(i) {
+ var d;
+ arcs[i] = {
+ data: data[i],
+ value: d = values[i],
+ startAngle: a,
+ endAngle: a += d * k
+ };
+ });
+ return arcs;
+ }
+ pie.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return pie;
+ };
+ pie.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return pie;
+ };
+ pie.startAngle = function(x) {
+ if (!arguments.length) return startAngle;
+ startAngle = x;
+ return pie;
+ };
+ pie.endAngle = function(x) {
+ if (!arguments.length) return endAngle;
+ endAngle = x;
+ return pie;
+ };
+ return pie;
+ };
+ var d3_layout_pieSortByValue = {};
+ d3.layout.stack = function() {
+ var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;
+ function stack(data, index) {
+ var series = data.map(function(d, i) {
+ return values.call(stack, d, i);
+ });
+ var points = series.map(function(d) {
+ return d.map(function(v, i) {
+ return [ x.call(stack, v, i), y.call(stack, v, i) ];
+ });
+ });
+ var orders = order.call(stack, points, index);
+ series = d3.permute(series, orders);
+ points = d3.permute(points, orders);
+ var offsets = offset.call(stack, points, index);
+ var n = series.length, m = series[0].length, i, j, o;
+ for (j = 0; j < m; ++j) {
+ out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
+ for (i = 1; i < n; ++i) {
+ out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
+ }
+ }
+ return data;
+ }
+ stack.values = function(x) {
+ if (!arguments.length) return values;
+ values = x;
+ return stack;
+ };
+ stack.order = function(x) {
+ if (!arguments.length) return order;
+ order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;
+ return stack;
+ };
+ stack.offset = function(x) {
+ if (!arguments.length) return offset;
+ offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;
+ return stack;
+ };
+ stack.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ return stack;
+ };
+ stack.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ return stack;
+ };
+ stack.out = function(z) {
+ if (!arguments.length) return out;
+ out = z;
+ return stack;
+ };
+ return stack;
+ };
+ function d3_layout_stackX(d) {
+ return d.x;
+ }
+ function d3_layout_stackY(d) {
+ return d.y;
+ }
+ function d3_layout_stackOut(d, y0, y) {
+ d.y0 = y0;
+ d.y = y;
+ }
+ var d3_layout_stackOrders = d3.map({
+ "inside-out": function(data) {
+ var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
+ return max[a] - max[b];
+ }), top = 0, bottom = 0, tops = [], bottoms = [];
+ for (i = 0; i < n; ++i) {
+ j = index[i];
+ if (top < bottom) {
+ top += sums[j];
+ tops.push(j);
+ } else {
+ bottom += sums[j];
+ bottoms.push(j);
+ }
+ }
+ return bottoms.reverse().concat(tops);
+ },
+ reverse: function(data) {
+ return d3.range(data.length).reverse();
+ },
+ "default": d3_layout_stackOrderDefault
+ });
+ var d3_layout_stackOffsets = d3.map({
+ silhouette: function(data) {
+ var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
+ for (j = 0; j < m; ++j) {
+ for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+ if (o > max) max = o;
+ sums.push(o);
+ }
+ for (j = 0; j < m; ++j) {
+ y0[j] = (max - sums[j]) / 2;
+ }
+ return y0;
+ },
+ wiggle: function(data) {
+ var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];
+ y0[0] = o = o0 = 0;
+ for (j = 1; j < m; ++j) {
+ for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
+ for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
+ for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
+ s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
+ }
+ s2 += s3 * data[i][j][1];
+ }
+ y0[j] = o -= s1 ? s2 / s1 * dx : 0;
+ if (o < o0) o0 = o;
+ }
+ for (j = 0; j < m; ++j) y0[j] -= o0;
+ return y0;
+ },
+ expand: function(data) {
+ var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
+ for (j = 0; j < m; ++j) {
+ for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+ if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k;
+ }
+ for (j = 0; j < m; ++j) y0[j] = 0;
+ return y0;
+ },
+ zero: d3_layout_stackOffsetZero
+ });
+ function d3_layout_stackOrderDefault(data) {
+ return d3.range(data.length);
+ }
+ function d3_layout_stackOffsetZero(data) {
+ var j = -1, m = data[0].length, y0 = [];
+ while (++j < m) y0[j] = 0;
+ return y0;
+ }
+ function d3_layout_stackMaxIndex(array) {
+ var i = 1, j = 0, v = array[0][1], k, n = array.length;
+ for (;i < n; ++i) {
+ if ((k = array[i][1]) > v) {
+ j = i;
+ v = k;
+ }
+ }
+ return j;
+ }
+ function d3_layout_stackReduceSum(d) {
+ return d.reduce(d3_layout_stackSum, 0);
+ }
+ function d3_layout_stackSum(p, d) {
+ return p + d[1];
+ }
+ d3.layout.histogram = function() {
+ var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;
+ function histogram(data, i) {
+ var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
+ while (++i < m) {
+ bin = bins[i] = [];
+ bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
+ bin.y = 0;
+ }
+ if (m > 0) {
+ i = -1;
+ while (++i < n) {
+ x = values[i];
+ if (x >= range[0] && x <= range[1]) {
+ bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
+ bin.y += k;
+ bin.push(data[i]);
+ }
+ }
+ }
+ return bins;
+ }
+ histogram.value = function(x) {
+ if (!arguments.length) return valuer;
+ valuer = x;
+ return histogram;
+ };
+ histogram.range = function(x) {
+ if (!arguments.length) return ranger;
+ ranger = d3_functor(x);
+ return histogram;
+ };
+ histogram.bins = function(x) {
+ if (!arguments.length) return binner;
+ binner = typeof x === "number" ? function(range) {
+ return d3_layout_histogramBinFixed(range, x);
+ } : d3_functor(x);
+ return histogram;
+ };
+ histogram.frequency = function(x) {
+ if (!arguments.length) return frequency;
+ frequency = !!x;
+ return histogram;
+ };
+ return histogram;
+ };
+ function d3_layout_histogramBinSturges(range, values) {
+ return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
+ }
+ function d3_layout_histogramBinFixed(range, n) {
+ var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
+ while (++x <= n) f[x] = m * x + b;
+ return f;
+ }
+ function d3_layout_histogramRange(values) {
+ return [ d3.min(values), d3.max(values) ];
+ }
+ d3.layout.tree = function() {
+ var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
+ function tree(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0];
+ function firstWalk(node, previousSibling) {
+ var children = node.children, layout = node._tree;
+ if (children && (n = children.length)) {
+ var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1;
+ while (++i < n) {
+ child = children[i];
+ firstWalk(child, previousChild);
+ ancestor = apportion(child, previousChild, ancestor);
+ previousChild = child;
+ }
+ d3_layout_treeShift(node);
+ var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+ layout.mod = layout.prelim - midpoint;
+ } else {
+ layout.prelim = midpoint;
+ }
+ } else {
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
+ }
+ }
+ }
+ function secondWalk(node, x) {
+ node.x = node._tree.prelim + x;
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var i = -1, n;
+ x += node._tree.mod;
+ while (++i < n) {
+ secondWalk(children[i], x);
+ }
+ }
+ }
+ function apportion(node, previousSibling, ancestor) {
+ if (previousSibling) {
+ var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift;
+ while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
+ vom = d3_layout_treeLeft(vom);
+ vop = d3_layout_treeRight(vop);
+ vop._tree.ancestor = node;
+ shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
+ if (shift > 0) {
+ d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
+ sip += shift;
+ sop += shift;
+ }
+ sim += vim._tree.mod;
+ sip += vip._tree.mod;
+ som += vom._tree.mod;
+ sop += vop._tree.mod;
+ }
+ if (vim && !d3_layout_treeRight(vop)) {
+ vop._tree.thread = vim;
+ vop._tree.mod += sim - sop;
+ }
+ if (vip && !d3_layout_treeLeft(vom)) {
+ vom._tree.thread = vip;
+ vom._tree.mod += sip - som;
+ ancestor = node;
+ }
+ }
+ return ancestor;
+ }
+ d3_layout_treeVisitAfter(root, function(node, previousSibling) {
+ node._tree = {
+ ancestor: node,
+ prelim: 0,
+ mod: 0,
+ change: 0,
+ shift: 0,
+ number: previousSibling ? previousSibling._tree.number + 1 : 0
+ };
+ });
+ firstWalk(root);
+ secondWalk(root, -root._tree.prelim);
+ var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1;
+ d3_layout_treeVisitAfter(root, nodeSize ? function(node) {
+ node.x *= size[0];
+ node.y = node.depth * size[1];
+ delete node._tree;
+ } : function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = node.depth / y1 * size[1];
+ delete node._tree;
+ });
+ return nodes;
+ }
+ tree.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return tree;
+ };
+ tree.size = function(x) {
+ if (!arguments.length) return nodeSize ? null : size;
+ nodeSize = (size = x) == null;
+ return tree;
+ };
+ tree.nodeSize = function(x) {
+ if (!arguments.length) return nodeSize ? size : null;
+ nodeSize = (size = x) != null;
+ return tree;
+ };
+ return d3_layout_hierarchyRebind(tree, hierarchy);
+ };
+ function d3_layout_treeSeparation(a, b) {
+ return a.parent == b.parent ? 1 : 2;
+ }
+ function d3_layout_treeLeft(node) {
+ var children = node.children;
+ return children && children.length ? children[0] : node._tree.thread;
+ }
+ function d3_layout_treeRight(node) {
+ var children = node.children, n;
+ return children && (n = children.length) ? children[n - 1] : node._tree.thread;
+ }
+ function d3_layout_treeSearch(node, compare) {
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var child, n, i = -1;
+ while (++i < n) {
+ if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
+ node = child;
+ }
+ }
+ }
+ return node;
+ }
+ function d3_layout_treeRightmost(a, b) {
+ return a.x - b.x;
+ }
+ function d3_layout_treeLeftmost(a, b) {
+ return b.x - a.x;
+ }
+ function d3_layout_treeDeepest(a, b) {
+ return a.depth - b.depth;
+ }
+ function d3_layout_treeVisitAfter(node, callback) {
+ function visit(node, previousSibling) {
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var child, previousChild = null, i = -1, n;
+ while (++i < n) {
+ child = children[i];
+ visit(child, previousChild);
+ previousChild = child;
+ }
+ }
+ callback(node, previousSibling);
+ }
+ visit(node, null);
+ }
+ function d3_layout_treeShift(node) {
+ var shift = 0, change = 0, children = node.children, i = children.length, child;
+ while (--i >= 0) {
+ child = children[i]._tree;
+ child.prelim += shift;
+ child.mod += shift;
+ shift += child.shift + (change += child.change);
+ }
+ }
+ function d3_layout_treeMove(ancestor, node, shift) {
+ ancestor = ancestor._tree;
+ node = node._tree;
+ var change = shift / (node.number - ancestor.number);
+ ancestor.change += change;
+ node.change -= change;
+ node.shift += shift;
+ node.prelim += shift;
+ node.mod += shift;
+ }
+ function d3_layout_treeAncestor(vim, node, ancestor) {
+ return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;
+ }
+ d3.layout.pack = function() {
+ var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius;
+ function pack(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() {
+ return radius;
+ };
+ root.x = root.y = 0;
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r = +r(d.value);
+ });
+ d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+ if (padding) {
+ var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2;
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r += dr;
+ });
+ d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r -= dr;
+ });
+ }
+ d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h));
+ return nodes;
+ }
+ pack.size = function(_) {
+ if (!arguments.length) return size;
+ size = _;
+ return pack;
+ };
+ pack.radius = function(_) {
+ if (!arguments.length) return radius;
+ radius = _ == null || typeof _ === "function" ? _ : +_;
+ return pack;
+ };
+ pack.padding = function(_) {
+ if (!arguments.length) return padding;
+ padding = +_;
+ return pack;
+ };
+ return d3_layout_hierarchyRebind(pack, hierarchy);
+ };
+ function d3_layout_packSort(a, b) {
+ return a.value - b.value;
+ }
+ function d3_layout_packInsert(a, b) {
+ var c = a._pack_next;
+ a._pack_next = b;
+ b._pack_prev = a;
+ b._pack_next = c;
+ c._pack_prev = b;
+ }
+ function d3_layout_packSplice(a, b) {
+ a._pack_next = b;
+ b._pack_prev = a;
+ }
+ function d3_layout_packIntersects(a, b) {
+ var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
+ return .999 * dr * dr > dx * dx + dy * dy;
+ }
+ function d3_layout_packSiblings(node) {
+ if (!(nodes = node.children) || !(n = nodes.length)) return;
+ var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n;
+ function bound(node) {
+ xMin = Math.min(node.x - node.r, xMin);
+ xMax = Math.max(node.x + node.r, xMax);
+ yMin = Math.min(node.y - node.r, yMin);
+ yMax = Math.max(node.y + node.r, yMax);
+ }
+ nodes.forEach(d3_layout_packLink);
+ a = nodes[0];
+ a.x = -a.r;
+ a.y = 0;
+ bound(a);
+ if (n > 1) {
+ b = nodes[1];
+ b.x = b.r;
+ b.y = 0;
+ bound(b);
+ if (n > 2) {
+ c = nodes[2];
+ d3_layout_packPlace(a, b, c);
+ bound(c);
+ d3_layout_packInsert(a, c);
+ a._pack_prev = c;
+ d3_layout_packInsert(c, b);
+ b = a._pack_next;
+ for (i = 3; i < n; i++) {
+ d3_layout_packPlace(a, b, c = nodes[i]);
+ var isect = 0, s1 = 1, s2 = 1;
+ for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
+ if (d3_layout_packIntersects(j, c)) {
+ isect = 1;
+ break;
+ }
+ }
+ if (isect == 1) {
+ for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
+ if (d3_layout_packIntersects(k, c)) {
+ break;
+ }
+ }
+ }
+ if (isect) {
+ if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);
+ i--;
+ } else {
+ d3_layout_packInsert(a, c);
+ b = c;
+ bound(c);
+ }
+ }
+ }
+ }
+ var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
+ for (i = 0; i < n; i++) {
+ c = nodes[i];
+ c.x -= cx;
+ c.y -= cy;
+ cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
+ }
+ node.r = cr;
+ nodes.forEach(d3_layout_packUnlink);
+ }
+ function d3_layout_packLink(node) {
+ node._pack_next = node._pack_prev = node;
+ }
+ function d3_layout_packUnlink(node) {
+ delete node._pack_next;
+ delete node._pack_prev;
+ }
+ function d3_layout_packTransform(node, x, y, k) {
+ var children = node.children;
+ node.x = x += k * node.x;
+ node.y = y += k * node.y;
+ node.r *= k;
+ if (children) {
+ var i = -1, n = children.length;
+ while (++i < n) d3_layout_packTransform(children[i], x, y, k);
+ }
+ }
+ function d3_layout_packPlace(a, b, c) {
+ var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
+ if (db && (dx || dy)) {
+ var da = b.r + c.r, dc = dx * dx + dy * dy;
+ da *= da;
+ db *= db;
+ var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
+ c.x = a.x + x * dx + y * dy;
+ c.y = a.y + x * dy - y * dx;
+ } else {
+ c.x = a.x + db;
+ c.y = a.y;
+ }
+ }
+ d3.layout.cluster = function() {
+ var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
+ function cluster(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
+ d3_layout_treeVisitAfter(root, function(node) {
+ var children = node.children;
+ if (children && children.length) {
+ node.x = d3_layout_clusterX(children);
+ node.y = d3_layout_clusterY(children);
+ } else {
+ node.x = previousNode ? x += separation(node, previousNode) : 0;
+ node.y = 0;
+ previousNode = node;
+ }
+ });
+ var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
+ d3_layout_treeVisitAfter(root, nodeSize ? function(node) {
+ node.x = (node.x - root.x) * size[0];
+ node.y = (root.y - node.y) * size[1];
+ } : function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
+ });
+ return nodes;
+ }
+ cluster.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return cluster;
+ };
+ cluster.size = function(x) {
+ if (!arguments.length) return nodeSize ? null : size;
+ nodeSize = (size = x) == null;
+ return cluster;
+ };
+ cluster.nodeSize = function(x) {
+ if (!arguments.length) return nodeSize ? size : null;
+ nodeSize = (size = x) != null;
+ return cluster;
+ };
+ return d3_layout_hierarchyRebind(cluster, hierarchy);
+ };
+ function d3_layout_clusterY(children) {
+ return 1 + d3.max(children, function(child) {
+ return child.y;
+ });
+ }
+ function d3_layout_clusterX(children) {
+ return children.reduce(function(x, child) {
+ return x + child.x;
+ }, 0) / children.length;
+ }
+ function d3_layout_clusterLeft(node) {
+ var children = node.children;
+ return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
+ }
+ function d3_layout_clusterRight(node) {
+ var children = node.children, n;
+ return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
+ }
+ d3.layout.treemap = function() {
+ var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5));
+ function scale(children, k) {
+ var i = -1, n = children.length, child, area;
+ while (++i < n) {
+ area = (child = children[i]).value * (k < 0 ? 0 : k);
+ child.area = isNaN(area) || area <= 0 ? 0 : area;
+ }
+ }
+ function squarify(node) {
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n;
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while ((n = remaining.length) > 0) {
+ row.push(child = remaining[n - 1]);
+ row.area += child.area;
+ if (mode !== "squarify" || (score = worst(row, u)) <= best) {
+ remaining.pop();
+ best = score;
+ } else {
+ row.area -= row.pop().area;
+ position(row, u, rect, false);
+ u = Math.min(rect.dx, rect.dy);
+ row.length = row.area = 0;
+ best = Infinity;
+ }
+ }
+ if (row.length) {
+ position(row, u, rect, true);
+ row.length = row.area = 0;
+ }
+ children.forEach(squarify);
+ }
+ }
+ function stickify(node) {
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node), remaining = children.slice(), child, row = [];
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while (child = remaining.pop()) {
+ row.push(child);
+ row.area += child.area;
+ if (child.z != null) {
+ position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
+ row.length = row.area = 0;
+ }
+ }
+ children.forEach(stickify);
+ }
+ }
+ function worst(row, u) {
+ var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
+ while (++i < n) {
+ if (!(r = row[i].area)) continue;
+ if (r < rmin) rmin = r;
+ if (r > rmax) rmax = r;
+ }
+ s *= s;
+ u *= u;
+ return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
+ }
+ function position(row, u, rect, flush) {
+ var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o;
+ if (u == rect.dx) {
+ if (flush || v > rect.dy) v = rect.dy;
+ while (++i < n) {
+ o = row[i];
+ o.x = x;
+ o.y = y;
+ o.dy = v;
+ x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
+ }
+ o.z = true;
+ o.dx += rect.x + rect.dx - x;
+ rect.y += v;
+ rect.dy -= v;
+ } else {
+ if (flush || v > rect.dx) v = rect.dx;
+ while (++i < n) {
+ o = row[i];
+ o.x = x;
+ o.y = y;
+ o.dx = v;
+ y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
+ }
+ o.z = false;
+ o.dy += rect.y + rect.dy - y;
+ rect.x += v;
+ rect.dx -= v;
+ }
+ }
+ function treemap(d) {
+ var nodes = stickies || hierarchy(d), root = nodes[0];
+ root.x = 0;
+ root.y = 0;
+ root.dx = size[0];
+ root.dy = size[1];
+ if (stickies) hierarchy.revalue(root);
+ scale([ root ], root.dx * root.dy / root.value);
+ (stickies ? stickify : squarify)(root);
+ if (sticky) stickies = nodes;
+ return nodes;
+ }
+ treemap.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return treemap;
+ };
+ treemap.padding = function(x) {
+ if (!arguments.length) return padding;
+ function padFunction(node) {
+ var p = x.call(treemap, node, node.depth);
+ return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p);
+ }
+ function padConstant(node) {
+ return d3_layout_treemapPad(node, x);
+ }
+ var type;
+ pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ],
+ padConstant) : padConstant;
+ return treemap;
+ };
+ treemap.round = function(x) {
+ if (!arguments.length) return round != Number;
+ round = x ? Math.round : Number;
+ return treemap;
+ };
+ treemap.sticky = function(x) {
+ if (!arguments.length) return sticky;
+ sticky = x;
+ stickies = null;
+ return treemap;
+ };
+ treemap.ratio = function(x) {
+ if (!arguments.length) return ratio;
+ ratio = x;
+ return treemap;
+ };
+ treemap.mode = function(x) {
+ if (!arguments.length) return mode;
+ mode = x + "";
+ return treemap;
+ };
+ return d3_layout_hierarchyRebind(treemap, hierarchy);
+ };
+ function d3_layout_treemapPadNull(node) {
+ return {
+ x: node.x,
+ y: node.y,
+ dx: node.dx,
+ dy: node.dy
+ };
+ }
+ function d3_layout_treemapPad(node, padding) {
+ var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2];
+ if (dx < 0) {
+ x += dx / 2;
+ dx = 0;
+ }
+ if (dy < 0) {
+ y += dy / 2;
+ dy = 0;
+ }
+ return {
+ x: x,
+ y: y,
+ dx: dx,
+ dy: dy
+ };
+ }
+ d3.random = {
+ normal: function(µ, σ) {
+ var n = arguments.length;
+ if (n < 2) σ = 1;
+ if (n < 1) µ = 0;
+ return function() {
+ var x, y, r;
+ do {
+ x = Math.random() * 2 - 1;
+ y = Math.random() * 2 - 1;
+ r = x * x + y * y;
+ } while (!r || r > 1);
+ return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);
+ };
+ },
+ logNormal: function() {
+ var random = d3.random.normal.apply(d3, arguments);
+ return function() {
+ return Math.exp(random());
+ };
+ },
+ bates: function(m) {
+ var random = d3.random.irwinHall(m);
+ return function() {
+ return random() / m;
+ };
+ },
+ irwinHall: function(m) {
+ return function() {
+ for (var s = 0, j = 0; j < m; j++) s += Math.random();
+ return s;
+ };
+ }
+ };
+ d3.scale = {};
+ function d3_scaleExtent(domain) {
+ var start = domain[0], stop = domain[domain.length - 1];
+ return start < stop ? [ start, stop ] : [ stop, start ];
+ }
+ function d3_scaleRange(scale) {
+ return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
+ }
+ function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
+ var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
+ return function(x) {
+ return i(u(x));
+ };
+ }
+ function d3_scale_nice(domain, nice) {
+ var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
+ if (x1 < x0) {
+ dx = i0, i0 = i1, i1 = dx;
+ dx = x0, x0 = x1, x1 = dx;
+ }
+ domain[i0] = nice.floor(x0);
+ domain[i1] = nice.ceil(x1);
+ return domain;
+ }
+ function d3_scale_niceStep(step) {
+ return step ? {
+ floor: function(x) {
+ return Math.floor(x / step) * step;
+ },
+ ceil: function(x) {
+ return Math.ceil(x / step) * step;
+ }
+ } : d3_scale_niceIdentity;
+ }
+ var d3_scale_niceIdentity = {
+ floor: d3_identity,
+ ceil: d3_identity
+ };
+ function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
+ var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
+ if (domain[k] < domain[0]) {
+ domain = domain.slice().reverse();
+ range = range.slice().reverse();
+ }
+ while (++j <= k) {
+ u.push(uninterpolate(domain[j - 1], domain[j]));
+ i.push(interpolate(range[j - 1], range[j]));
+ }
+ return function(x) {
+ var j = d3.bisect(domain, x, 1, k) - 1;
+ return i[j](u[j](x));
+ };
+ }
+ d3.scale.linear = function() {
+ return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false);
+ };
+ function d3_scale_linear(domain, range, interpolate, clamp) {
+ var output, input;
+ function rescale() {
+ var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
+ output = linear(domain, range, uninterpolate, interpolate);
+ input = linear(range, domain, uninterpolate, d3_interpolate);
+ return scale;
+ }
+ function scale(x) {
+ return output(x);
+ }
+ scale.invert = function(y) {
+ return input(y);
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.map(Number);
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.rangeRound = function(x) {
+ return scale.range(x).interpolate(d3_interpolateRound);
+ };
+ scale.clamp = function(x) {
+ if (!arguments.length) return clamp;
+ clamp = x;
+ return rescale();
+ };
+ scale.interpolate = function(x) {
+ if (!arguments.length) return interpolate;
+ interpolate = x;
+ return rescale();
+ };
+ scale.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ scale.tickFormat = function(m, format) {
+ return d3_scale_linearTickFormat(domain, m, format);
+ };
+ scale.nice = function(m) {
+ d3_scale_linearNice(domain, m);
+ return rescale();
+ };
+ scale.copy = function() {
+ return d3_scale_linear(domain, range, interpolate, clamp);
+ };
+ return rescale();
+ }
+ function d3_scale_linearRebind(scale, linear) {
+ return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
+ }
+ function d3_scale_linearNice(domain, m) {
+ return d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));
+ }
+ function d3_scale_linearTickRange(domain, m) {
+ if (m == null) m = 10;
+ var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
+ if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;
+ extent[0] = Math.ceil(extent[0] / step) * step;
+ extent[1] = Math.floor(extent[1] / step) * step + step * .5;
+ extent[2] = step;
+ return extent;
+ }
+ function d3_scale_linearTicks(domain, m) {
+ return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
+ }
+ function d3_scale_linearTickFormat(domain, m, format) {
+ var range = d3_scale_linearTickRange(domain, m);
+ if (format) {
+ var match = d3_format_re.exec(format);
+ match.shift();
+ if (match[8] === "s") {
+ var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1])));
+ if (!match[7]) match[7] = "." + d3_scale_linearPrecision(prefix.scale(range[2]));
+ match[8] = "f";
+ format = d3.format(match.join(""));
+ return function(d) {
+ return format(prefix.scale(d)) + prefix.symbol;
+ };
+ }
+ if (!match[7]) match[7] = "." + d3_scale_linearFormatPrecision(match[8], range);
+ format = match.join("");
+ } else {
+ format = ",." + d3_scale_linearPrecision(range[2]) + "f";
+ }
+ return d3.format(format);
+ }
+ var d3_scale_linearFormatSignificant = {
+ s: 1,
+ g: 1,
+ p: 1,
+ r: 1,
+ e: 1
+ };
+ function d3_scale_linearPrecision(value) {
+ return -Math.floor(Math.log(value) / Math.LN10 + .01);
+ }
+ function d3_scale_linearFormatPrecision(type, range) {
+ var p = d3_scale_linearPrecision(range[2]);
+ return type in d3_scale_linearFormatSignificant ? Math.abs(p - d3_scale_linearPrecision(Math.max(abs(range[0]), abs(range[1])))) + +(type !== "e") : p - (type === "%") * 2;
+ }
+ d3.scale.log = function() {
+ return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]);
+ };
+ function d3_scale_log(linear, base, positive, domain) {
+ function log(x) {
+ return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base);
+ }
+ function pow(x) {
+ return positive ? Math.pow(base, x) : -Math.pow(base, -x);
+ }
+ function scale(x) {
+ return linear(log(x));
+ }
+ scale.invert = function(x) {
+ return pow(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ positive = x[0] >= 0;
+ linear.domain((domain = x.map(Number)).map(log));
+ return scale;
+ };
+ scale.base = function(_) {
+ if (!arguments.length) return base;
+ base = +_;
+ linear.domain(domain.map(log));
+ return scale;
+ };
+ scale.nice = function() {
+ var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative);
+ linear.domain(niced);
+ domain = niced.map(pow);
+ return scale;
+ };
+ scale.ticks = function() {
+ var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base;
+ if (isFinite(j - i)) {
+ if (positive) {
+ for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k);
+ ticks.push(pow(i));
+ } else {
+ ticks.push(pow(i));
+ for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k);
+ }
+ for (i = 0; ticks[i] < u; i++) {}
+ for (j = ticks.length; ticks[j - 1] > v; j--) {}
+ ticks = ticks.slice(i, j);
+ }
+ return ticks;
+ };
+ scale.tickFormat = function(n, format) {
+ if (!arguments.length) return d3_scale_logFormat;
+ if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format);
+ var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12,
+ Math.floor), e;
+ return function(d) {
+ return d / pow(f(log(d) + e)) <= k ? format(d) : "";
+ };
+ };
+ scale.copy = function() {
+ return d3_scale_log(linear.copy(), base, positive, domain);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = {
+ floor: function(x) {
+ return -Math.ceil(-x);
+ },
+ ceil: function(x) {
+ return -Math.floor(-x);
+ }
+ };
+ d3.scale.pow = function() {
+ return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]);
+ };
+ function d3_scale_pow(linear, exponent, domain) {
+ var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
+ function scale(x) {
+ return linear(powp(x));
+ }
+ scale.invert = function(x) {
+ return powb(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ linear.domain((domain = x.map(Number)).map(powp));
+ return scale;
+ };
+ scale.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ scale.tickFormat = function(m, format) {
+ return d3_scale_linearTickFormat(domain, m, format);
+ };
+ scale.nice = function(m) {
+ return scale.domain(d3_scale_linearNice(domain, m));
+ };
+ scale.exponent = function(x) {
+ if (!arguments.length) return exponent;
+ powp = d3_scale_powPow(exponent = x);
+ powb = d3_scale_powPow(1 / exponent);
+ linear.domain(domain.map(powp));
+ return scale;
+ };
+ scale.copy = function() {
+ return d3_scale_pow(linear.copy(), exponent, domain);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ function d3_scale_powPow(e) {
+ return function(x) {
+ return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
+ };
+ }
+ d3.scale.sqrt = function() {
+ return d3.scale.pow().exponent(.5);
+ };
+ d3.scale.ordinal = function() {
+ return d3_scale_ordinal([], {
+ t: "range",
+ a: [ [] ]
+ });
+ };
+ function d3_scale_ordinal(domain, ranger) {
+ var index, range, rangeBand;
+ function scale(x) {
+ return range[((index.get(x) || (ranger.t === "range" ? index.set(x, domain.push(x)) : NaN)) - 1) % range.length];
+ }
+ function steps(start, step) {
+ return d3.range(domain.length).map(function(i) {
+ return start + step * i;
+ });
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = [];
+ index = new d3_Map();
+ var i = -1, n = x.length, xi;
+ while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
+ return scale[ranger.t].apply(scale, ranger.a);
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ rangeBand = 0;
+ ranger = {
+ t: "range",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangePoints = function(x, padding) {
+ if (arguments.length < 2) padding = 0;
+ var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding);
+ range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
+ rangeBand = 0;
+ ranger = {
+ t: "rangePoints",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeBands = function(x, padding, outerPadding) {
+ if (arguments.length < 2) padding = 0;
+ if (arguments.length < 3) outerPadding = padding;
+ var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);
+ range = steps(start + step * outerPadding, step);
+ if (reverse) range.reverse();
+ rangeBand = step * (1 - padding);
+ ranger = {
+ t: "rangeBands",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeRoundBands = function(x, padding, outerPadding) {
+ if (arguments.length < 2) padding = 0;
+ if (arguments.length < 3) outerPadding = padding;
+ var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step;
+ range = steps(start + Math.round(error / 2), step);
+ if (reverse) range.reverse();
+ rangeBand = Math.round(step * (1 - padding));
+ ranger = {
+ t: "rangeRoundBands",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeBand = function() {
+ return rangeBand;
+ };
+ scale.rangeExtent = function() {
+ return d3_scaleExtent(ranger.a[0]);
+ };
+ scale.copy = function() {
+ return d3_scale_ordinal(domain, ranger);
+ };
+ return scale.domain(domain);
+ }
+ d3.scale.category10 = function() {
+ return d3.scale.ordinal().range(d3_category10);
+ };
+ d3.scale.category20 = function() {
+ return d3.scale.ordinal().range(d3_category20);
+ };
+ d3.scale.category20b = function() {
+ return d3.scale.ordinal().range(d3_category20b);
+ };
+ d3.scale.category20c = function() {
+ return d3.scale.ordinal().range(d3_category20c);
+ };
+ var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString);
+ var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString);
+ var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString);
+ var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString);
+ d3.scale.quantile = function() {
+ return d3_scale_quantile([], []);
+ };
+ function d3_scale_quantile(domain, range) {
+ var thresholds;
+ function rescale() {
+ var k = 0, q = range.length;
+ thresholds = [];
+ while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
+ return scale;
+ }
+ function scale(x) {
+ if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)];
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.filter(function(d) {
+ return !isNaN(d);
+ }).sort(d3_ascending);
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.quantiles = function() {
+ return thresholds;
+ };
+ scale.invertExtent = function(y) {
+ y = range.indexOf(y);
+ return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ];
+ };
+ scale.copy = function() {
+ return d3_scale_quantile(domain, range);
+ };
+ return rescale();
+ }
+ d3.scale.quantize = function() {
+ return d3_scale_quantize(0, 1, [ 0, 1 ]);
+ };
+ function d3_scale_quantize(x0, x1, range) {
+ var kx, i;
+ function scale(x) {
+ return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
+ }
+ function rescale() {
+ kx = range.length / (x1 - x0);
+ i = range.length - 1;
+ return scale;
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return [ x0, x1 ];
+ x0 = +x[0];
+ x1 = +x[x.length - 1];
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.invertExtent = function(y) {
+ y = range.indexOf(y);
+ y = y < 0 ? NaN : y / kx + x0;
+ return [ y, y + 1 / kx ];
+ };
+ scale.copy = function() {
+ return d3_scale_quantize(x0, x1, range);
+ };
+ return rescale();
+ }
+ d3.scale.threshold = function() {
+ return d3_scale_threshold([ .5 ], [ 0, 1 ]);
+ };
+ function d3_scale_threshold(domain, range) {
+ function scale(x) {
+ if (x <= x) return range[d3.bisect(domain, x)];
+ }
+ scale.domain = function(_) {
+ if (!arguments.length) return domain;
+ domain = _;
+ return scale;
+ };
+ scale.range = function(_) {
+ if (!arguments.length) return range;
+ range = _;
+ return scale;
+ };
+ scale.invertExtent = function(y) {
+ y = range.indexOf(y);
+ return [ domain[y - 1], domain[y] ];
+ };
+ scale.copy = function() {
+ return d3_scale_threshold(domain, range);
+ };
+ return scale;
+ }
+ d3.scale.identity = function() {
+ return d3_scale_identity([ 0, 1 ]);
+ };
+ function d3_scale_identity(domain) {
+ function identity(x) {
+ return +x;
+ }
+ identity.invert = identity;
+ identity.domain = identity.range = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.map(identity);
+ return identity;
+ };
+ identity.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ identity.tickFormat = function(m, format) {
+ return d3_scale_linearTickFormat(domain, m, format);
+ };
+ identity.copy = function() {
+ return d3_scale_identity(domain);
+ };
+ return identity;
+ }
+ d3.svg = {};
+ d3.svg.arc = function() {
+ var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+ function arc() {
+ var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0,
+ a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);
+ return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z";
+ }
+ arc.innerRadius = function(v) {
+ if (!arguments.length) return innerRadius;
+ innerRadius = d3_functor(v);
+ return arc;
+ };
+ arc.outerRadius = function(v) {
+ if (!arguments.length) return outerRadius;
+ outerRadius = d3_functor(v);
+ return arc;
+ };
+ arc.startAngle = function(v) {
+ if (!arguments.length) return startAngle;
+ startAngle = d3_functor(v);
+ return arc;
+ };
+ arc.endAngle = function(v) {
+ if (!arguments.length) return endAngle;
+ endAngle = d3_functor(v);
+ return arc;
+ };
+ arc.centroid = function() {
+ var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
+ return [ Math.cos(a) * r, Math.sin(a) * r ];
+ };
+ return arc;
+ };
+ var d3_svg_arcOffset = -halfπ, d3_svg_arcMax = τ - ε;
+ function d3_svg_arcInnerRadius(d) {
+ return d.innerRadius;
+ }
+ function d3_svg_arcOuterRadius(d) {
+ return d.outerRadius;
+ }
+ function d3_svg_arcStartAngle(d) {
+ return d.startAngle;
+ }
+ function d3_svg_arcEndAngle(d) {
+ return d.endAngle;
+ }
+ function d3_svg_line(projection) {
+ var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
+ function line(data) {
+ var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
+ function segment() {
+ segments.push("M", interpolate(projection(points), tension));
+ }
+ while (++i < n) {
+ if (defined.call(this, d = data[i], i)) {
+ points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
+ } else if (points.length) {
+ segment();
+ points = [];
+ }
+ }
+ if (points.length) segment();
+ return segments.length ? segments.join("") : null;
+ }
+ line.x = function(_) {
+ if (!arguments.length) return x;
+ x = _;
+ return line;
+ };
+ line.y = function(_) {
+ if (!arguments.length) return y;
+ y = _;
+ return line;
+ };
+ line.defined = function(_) {
+ if (!arguments.length) return defined;
+ defined = _;
+ return line;
+ };
+ line.interpolate = function(_) {
+ if (!arguments.length) return interpolateKey;
+ if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
+ return line;
+ };
+ line.tension = function(_) {
+ if (!arguments.length) return tension;
+ tension = _;
+ return line;
+ };
+ return line;
+ }
+ d3.svg.line = function() {
+ return d3_svg_line(d3_identity);
+ };
+ var d3_svg_lineInterpolators = d3.map({
+ linear: d3_svg_lineLinear,
+ "linear-closed": d3_svg_lineLinearClosed,
+ step: d3_svg_lineStep,
+ "step-before": d3_svg_lineStepBefore,
+ "step-after": d3_svg_lineStepAfter,
+ basis: d3_svg_lineBasis,
+ "basis-open": d3_svg_lineBasisOpen,
+ "basis-closed": d3_svg_lineBasisClosed,
+ bundle: d3_svg_lineBundle,
+ cardinal: d3_svg_lineCardinal,
+ "cardinal-open": d3_svg_lineCardinalOpen,
+ "cardinal-closed": d3_svg_lineCardinalClosed,
+ monotone: d3_svg_lineMonotone
+ });
+ d3_svg_lineInterpolators.forEach(function(key, value) {
+ value.key = key;
+ value.closed = /-closed$/.test(key);
+ });
+ function d3_svg_lineLinear(points) {
+ return points.join("L");
+ }
+ function d3_svg_lineLinearClosed(points) {
+ return d3_svg_lineLinear(points) + "Z";
+ }
+ function d3_svg_lineStep(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]);
+ if (n > 1) path.push("H", p[0]);
+ return path.join("");
+ }
+ function d3_svg_lineStepBefore(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
+ return path.join("");
+ }
+ function d3_svg_lineStepAfter(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
+ return path.join("");
+ }
+ function d3_svg_lineCardinalOpen(points, tension) {
+ return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension));
+ }
+ function d3_svg_lineCardinalClosed(points, tension) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]),
+ points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));
+ }
+ function d3_svg_lineCardinal(points, tension) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
+ }
+ function d3_svg_lineHermite(points, tangents) {
+ if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
+ return d3_svg_lineLinear(points);
+ }
+ var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;
+ if (quad) {
+ path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
+ p0 = points[1];
+ pi = 2;
+ }
+ if (tangents.length > 1) {
+ t = tangents[1];
+ p = points[pi];
+ pi++;
+ path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
+ for (var i = 2; i < tangents.length; i++, pi++) {
+ p = points[pi];
+ t = tangents[i];
+ path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
+ }
+ }
+ if (quad) {
+ var lp = points[pi];
+ path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
+ }
+ return path;
+ }
+ function d3_svg_lineCardinalTangents(points, tension) {
+ var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
+ while (++i < n) {
+ p0 = p1;
+ p1 = p2;
+ p2 = points[i];
+ tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
+ }
+ return tangents;
+ }
+ function d3_svg_lineBasis(points) {
+ if (points.length < 3) return d3_svg_lineLinear(points);
+ var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
+ points.push(points[n - 1]);
+ while (++i <= n) {
+ pi = points[i];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ points.pop();
+ path.push("L", pi);
+ return path.join("");
+ }
+ function d3_svg_lineBasisOpen(points) {
+ if (points.length < 4) return d3_svg_lineLinear(points);
+ var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
+ while (++i < 3) {
+ pi = points[i];
+ px.push(pi[0]);
+ py.push(pi[1]);
+ }
+ path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
+ --i;
+ while (++i < n) {
+ pi = points[i];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBasisClosed(points) {
+ var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
+ while (++i < 4) {
+ pi = points[i % n];
+ px.push(pi[0]);
+ py.push(pi[1]);
+ }
+ path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
+ --i;
+ while (++i < m) {
+ pi = points[i % n];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBundle(points, tension) {
+ var n = points.length - 1;
+ if (n) {
+ var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t;
+ while (++i <= n) {
+ p = points[i];
+ t = i / n;
+ p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
+ p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
+ }
+ }
+ return d3_svg_lineBasis(points);
+ }
+ function d3_svg_lineDot4(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+ }
+ var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
+ function d3_svg_lineBasisBezier(path, x, y) {
+ path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
+ }
+ function d3_svg_lineSlope(p0, p1) {
+ return (p1[1] - p0[1]) / (p1[0] - p0[0]);
+ }
+ function d3_svg_lineFiniteDifferences(points) {
+ var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1);
+ while (++i < j) {
+ m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
+ }
+ m[i] = d;
+ return m;
+ }
+ function d3_svg_lineMonotoneTangents(points) {
+ var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
+ while (++i < j) {
+ d = d3_svg_lineSlope(points[i], points[i + 1]);
+ if (abs(d) < ε) {
+ m[i] = m[i + 1] = 0;
+ } else {
+ a = m[i] / d;
+ b = m[i + 1] / d;
+ s = a * a + b * b;
+ if (s > 9) {
+ s = d * 3 / Math.sqrt(s);
+ m[i] = s * a;
+ m[i + 1] = s * b;
+ }
+ }
+ }
+ i = -1;
+ while (++i <= j) {
+ s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i]));
+ tangents.push([ s || 0, m[i] * s || 0 ]);
+ }
+ return tangents;
+ }
+ function d3_svg_lineMonotone(points) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
+ }
+ d3.svg.line.radial = function() {
+ var line = d3_svg_line(d3_svg_lineRadial);
+ line.radius = line.x, delete line.x;
+ line.angle = line.y, delete line.y;
+ return line;
+ };
+ function d3_svg_lineRadial(points) {
+ var point, i = -1, n = points.length, r, a;
+ while (++i < n) {
+ point = points[i];
+ r = point[0];
+ a = point[1] + d3_svg_arcOffset;
+ point[0] = r * Math.cos(a);
+ point[1] = r * Math.sin(a);
+ }
+ return points;
+ }
+ function d3_svg_area(projection) {
+ var x0 = d3_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7;
+ function area(data) {
+ var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
+ return x;
+ } : d3_functor(x1), fy1 = y0 === y1 ? function() {
+ return y;
+ } : d3_functor(y1), x, y;
+ function segment() {
+ segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z");
+ }
+ while (++i < n) {
+ if (defined.call(this, d = data[i], i)) {
+ points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
+ points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
+ } else if (points0.length) {
+ segment();
+ points0 = [];
+ points1 = [];
+ }
+ }
+ if (points0.length) segment();
+ return segments.length ? segments.join("") : null;
+ }
+ area.x = function(_) {
+ if (!arguments.length) return x1;
+ x0 = x1 = _;
+ return area;
+ };
+ area.x0 = function(_) {
+ if (!arguments.length) return x0;
+ x0 = _;
+ return area;
+ };
+ area.x1 = function(_) {
+ if (!arguments.length) return x1;
+ x1 = _;
+ return area;
+ };
+ area.y = function(_) {
+ if (!arguments.length) return y1;
+ y0 = y1 = _;
+ return area;
+ };
+ area.y0 = function(_) {
+ if (!arguments.length) return y0;
+ y0 = _;
+ return area;
+ };
+ area.y1 = function(_) {
+ if (!arguments.length) return y1;
+ y1 = _;
+ return area;
+ };
+ area.defined = function(_) {
+ if (!arguments.length) return defined;
+ defined = _;
+ return area;
+ };
+ area.interpolate = function(_) {
+ if (!arguments.length) return interpolateKey;
+ if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
+ interpolateReverse = interpolate.reverse || interpolate;
+ L = interpolate.closed ? "M" : "L";
+ return area;
+ };
+ area.tension = function(_) {
+ if (!arguments.length) return tension;
+ tension = _;
+ return area;
+ };
+ return area;
+ }
+ d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
+ d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
+ d3.svg.area = function() {
+ return d3_svg_area(d3_identity);
+ };
+ d3.svg.area.radial = function() {
+ var area = d3_svg_area(d3_svg_lineRadial);
+ area.radius = area.x, delete area.x;
+ area.innerRadius = area.x0, delete area.x0;
+ area.outerRadius = area.x1, delete area.x1;
+ area.angle = area.y, delete area.y;
+ area.startAngle = area.y0, delete area.y0;
+ area.endAngle = area.y1, delete area.y1;
+ return area;
+ };
+ d3.svg.chord = function() {
+ var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+ function chord(d, i) {
+ var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
+ return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z";
+ }
+ function subgroup(self, f, d, i) {
+ var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset;
+ return {
+ r: r,
+ a0: a0,
+ a1: a1,
+ p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
+ p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
+ };
+ }
+ function equals(a, b) {
+ return a.a0 == b.a0 && a.a1 == b.a1;
+ }
+ function arc(r, p, a) {
+ return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p;
+ }
+ function curve(r0, p0, r1, p1) {
+ return "Q 0,0 " + p1;
+ }
+ chord.radius = function(v) {
+ if (!arguments.length) return radius;
+ radius = d3_functor(v);
+ return chord;
+ };
+ chord.source = function(v) {
+ if (!arguments.length) return source;
+ source = d3_functor(v);
+ return chord;
+ };
+ chord.target = function(v) {
+ if (!arguments.length) return target;
+ target = d3_functor(v);
+ return chord;
+ };
+ chord.startAngle = function(v) {
+ if (!arguments.length) return startAngle;
+ startAngle = d3_functor(v);
+ return chord;
+ };
+ chord.endAngle = function(v) {
+ if (!arguments.length) return endAngle;
+ endAngle = d3_functor(v);
+ return chord;
+ };
+ return chord;
+ };
+ function d3_svg_chordRadius(d) {
+ return d.radius;
+ }
+ d3.svg.diagonal = function() {
+ var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
+ function diagonal(d, i) {
+ var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, {
+ x: p0.x,
+ y: m
+ }, {
+ x: p3.x,
+ y: m
+ }, p3 ];
+ p = p.map(projection);
+ return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
+ }
+ diagonal.source = function(x) {
+ if (!arguments.length) return source;
+ source = d3_functor(x);
+ return diagonal;
+ };
+ diagonal.target = function(x) {
+ if (!arguments.length) return target;
+ target = d3_functor(x);
+ return diagonal;
+ };
+ diagonal.projection = function(x) {
+ if (!arguments.length) return projection;
+ projection = x;
+ return diagonal;
+ };
+ return diagonal;
+ };
+ function d3_svg_diagonalProjection(d) {
+ return [ d.x, d.y ];
+ }
+ d3.svg.diagonal.radial = function() {
+ var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;
+ diagonal.projection = function(x) {
+ return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;
+ };
+ return diagonal;
+ };
+ function d3_svg_diagonalRadialProjection(projection) {
+ return function() {
+ var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset;
+ return [ r * Math.cos(a), r * Math.sin(a) ];
+ };
+ }
+ d3.svg.symbol = function() {
+ var type = d3_svg_symbolType, size = d3_svg_symbolSize;
+ function symbol(d, i) {
+ return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));
+ }
+ symbol.type = function(x) {
+ if (!arguments.length) return type;
+ type = d3_functor(x);
+ return symbol;
+ };
+ symbol.size = function(x) {
+ if (!arguments.length) return size;
+ size = d3_functor(x);
+ return symbol;
+ };
+ return symbol;
+ };
+ function d3_svg_symbolSize() {
+ return 64;
+ }
+ function d3_svg_symbolType() {
+ return "circle";
+ }
+ function d3_svg_symbolCircle(size) {
+ var r = Math.sqrt(size / π);
+ return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z";
+ }
+ var d3_svg_symbols = d3.map({
+ circle: d3_svg_symbolCircle,
+ cross: function(size) {
+ var r = Math.sqrt(size / 5) / 2;
+ return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z";
+ },
+ diamond: function(size) {
+ var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
+ return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z";
+ },
+ square: function(size) {
+ var r = Math.sqrt(size) / 2;
+ return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z";
+ },
+ "triangle-down": function(size) {
+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+ return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z";
+ },
+ "triangle-up": function(size) {
+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+ return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z";
+ }
+ });
+ d3.svg.symbolTypes = d3_svg_symbols.keys();
+ var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
+ function d3_transition(groups, id) {
+ d3_subclass(groups, d3_transitionPrototype);
+ groups.id = id;
+ return groups;
+ }
+ var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit;
+ d3_transitionPrototype.call = d3_selectionPrototype.call;
+ d3_transitionPrototype.empty = d3_selectionPrototype.empty;
+ d3_transitionPrototype.node = d3_selectionPrototype.node;
+ d3_transitionPrototype.size = d3_selectionPrototype.size;
+ d3.transition = function(selection) {
+ return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition();
+ };
+ d3.transition.prototype = d3_transitionPrototype;
+ d3_transitionPrototype.select = function(selector) {
+ var id = this.id, subgroups = [], subgroup, subnode, node;
+ selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) {
+ if ("__data__" in node) subnode.__data__ = node.__data__;
+ d3_transitionNode(subnode, i, id, node.__transition__[id]);
+ subgroup.push(subnode);
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_transitionPrototype.selectAll = function(selector) {
+ var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition;
+ selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ transition = node.__transition__[id];
+ subnodes = selector.call(node, node.__data__, i, j);
+ subgroups.push(subgroup = []);
+ for (var k = -1, o = subnodes.length; ++k < o; ) {
+ if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition);
+ subgroup.push(subnode);
+ }
+ }
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_transitionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_transition(subgroups, this.id);
+ };
+ d3_transitionPrototype.tween = function(name, tween) {
+ var id = this.id;
+ if (arguments.length < 2) return this.node().__transition__[id].tween.get(name);
+ return d3_selection_each(this, tween == null ? function(node) {
+ node.__transition__[id].tween.remove(name);
+ } : function(node) {
+ node.__transition__[id].tween.set(name, tween);
+ });
+ };
+ function d3_transition_tween(groups, name, value, tween) {
+ var id = groups.id;
+ return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j)));
+ } : (value = tween(value), function(node) {
+ node.__transition__[id].tween.set(name, value);
+ }));
+ }
+ d3_transitionPrototype.attr = function(nameNS, value) {
+ if (arguments.length < 2) {
+ for (value in nameNS) this.attr(value, nameNS[value]);
+ return this;
+ }
+ var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS);
+ function attrNull() {
+ this.removeAttribute(name);
+ }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
+ function attrTween(b) {
+ return b == null ? attrNull : (b += "", function() {
+ var a = this.getAttribute(name), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.setAttribute(name, i(t));
+ });
+ });
+ }
+ function attrTweenNS(b) {
+ return b == null ? attrNullNS : (b += "", function() {
+ var a = this.getAttributeNS(name.space, name.local), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.setAttributeNS(name.space, name.local, i(t));
+ });
+ });
+ }
+ return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween);
+ };
+ d3_transitionPrototype.attrTween = function(nameNS, tween) {
+ var name = d3.ns.qualify(nameNS);
+ function attrTween(d, i) {
+ var f = tween.call(this, d, i, this.getAttribute(name));
+ return f && function(t) {
+ this.setAttribute(name, f(t));
+ };
+ }
+ function attrTweenNS(d, i) {
+ var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
+ return f && function(t) {
+ this.setAttributeNS(name.space, name.local, f(t));
+ };
+ }
+ return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
+ };
+ d3_transitionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.style(priority, name[priority], value);
+ return this;
+ }
+ priority = "";
+ }
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
+ function styleString(b) {
+ return b == null ? styleNull : (b += "", function() {
+ var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i;
+ return a !== b && (i = d3_interpolate(a, b), function(t) {
+ this.style.setProperty(name, i(t), priority);
+ });
+ });
+ }
+ return d3_transition_tween(this, "style." + name, value, styleString);
+ };
+ d3_transitionPrototype.styleTween = function(name, tween, priority) {
+ if (arguments.length < 3) priority = "";
+ function styleTween(d, i) {
+ var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name));
+ return f && function(t) {
+ this.style.setProperty(name, f(t), priority);
+ };
+ }
+ return this.tween("style." + name, styleTween);
+ };
+ d3_transitionPrototype.text = function(value) {
+ return d3_transition_tween(this, "text", value, d3_transition_text);
+ };
+ function d3_transition_text(b) {
+ if (b == null) b = "";
+ return function() {
+ this.textContent = b;
+ };
+ }
+ d3_transitionPrototype.remove = function() {
+ return this.each("end.transition", function() {
+ var p;
+ if (this.__transition__.count < 2 && (p = this.parentNode)) p.removeChild(this);
+ });
+ };
+ d3_transitionPrototype.ease = function(value) {
+ var id = this.id;
+ if (arguments.length < 1) return this.node().__transition__[id].ease;
+ if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
+ return d3_selection_each(this, function(node) {
+ node.__transition__[id].ease = value;
+ });
+ };
+ d3_transitionPrototype.delay = function(value) {
+ var id = this.id;
+ if (arguments.length < 1) return this.node().__transition__[id].delay;
+ return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].delay = +value.call(node, node.__data__, i, j);
+ } : (value = +value, function(node) {
+ node.__transition__[id].delay = value;
+ }));
+ };
+ d3_transitionPrototype.duration = function(value) {
+ var id = this.id;
+ if (arguments.length < 1) return this.node().__transition__[id].duration;
+ return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
+ node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j));
+ } : (value = Math.max(1, value), function(node) {
+ node.__transition__[id].duration = value;
+ }));
+ };
+ d3_transitionPrototype.each = function(type, listener) {
+ var id = this.id;
+ if (arguments.length < 2) {
+ var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
+ d3_transitionInheritId = id;
+ d3_selection_each(this, function(node, i, j) {
+ d3_transitionInherit = node.__transition__[id];
+ type.call(node, node.__data__, i, j);
+ });
+ d3_transitionInherit = inherit;
+ d3_transitionInheritId = inheritId;
+ } else {
+ d3_selection_each(this, function(node) {
+ var transition = node.__transition__[id];
+ (transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener);
+ });
+ }
+ return this;
+ };
+ d3_transitionPrototype.transition = function() {
+ var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition;
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ if (node = group[i]) {
+ transition = Object.create(node.__transition__[id0]);
+ transition.delay += transition.duration;
+ d3_transitionNode(node, i, id1, transition);
+ }
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id1);
+ };
+ function d3_transitionNode(node, i, id, inherit) {
+ var lock = node.__transition__ || (node.__transition__ = {
+ active: 0,
+ count: 0
+ }), transition = lock[id];
+ if (!transition) {
+ var time = inherit.time;
+ transition = lock[id] = {
+ tween: new d3_Map(),
+ time: time,
+ ease: inherit.ease,
+ delay: inherit.delay,
+ duration: inherit.duration
+ };
+ ++lock.count;
+ d3.timer(function(elapsed) {
+ var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, timer = d3_timer_active, tweened = [];
+ timer.t = delay + time;
+ if (delay <= elapsed) return start(elapsed - delay);
+ timer.c = start;
+ function start(elapsed) {
+ if (lock.active > id) return stop();
+ lock.active = id;
+ transition.event && transition.event.start.call(node, d, i);
+ transition.tween.forEach(function(key, value) {
+ if (value = value.call(node, d, i)) {
+ tweened.push(value);
+ }
+ });
+ d3.timer(function() {
+ timer.c = tick(elapsed || 1) ? d3_true : tick;
+ return 1;
+ }, 0, time);
+ }
+ function tick(elapsed) {
+ if (lock.active !== id) return stop();
+ var t = elapsed / duration, e = ease(t), n = tweened.length;
+ while (n > 0) {
+ tweened[--n].call(node, e);
+ }
+ if (t >= 1) {
+ transition.event && transition.event.end.call(node, d, i);
+ return stop();
+ }
+ }
+ function stop() {
+ if (--lock.count) delete lock[id]; else delete node.__transition__;
+ return 1;
+ }
+ }, 0, time);
+ }
+ }
+ d3.svg.axis = function() {
+ var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_;
+ function axis(g) {
+ g.each(function() {
+ var g = d3.select(this);
+ var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy();
+ var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick.order()).style("opacity", 1), tickTransform;
+ var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"),
+ d3.transition(path));
+ tickEnter.append("line");
+ tickEnter.append("text");
+ var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text");
+ switch (orient) {
+ case "bottom":
+ {
+ tickTransform = d3_svg_axisX;
+ lineEnter.attr("y2", innerTickSize);
+ textEnter.attr("y", Math.max(innerTickSize, 0) + tickPadding);
+ lineUpdate.attr("x2", 0).attr("y2", innerTickSize);
+ textUpdate.attr("x", 0).attr("y", Math.max(innerTickSize, 0) + tickPadding);
+ text.attr("dy", ".71em").style("text-anchor", "middle");
+ pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
+ break;
+ }
+
+ case "top":
+ {
+ tickTransform = d3_svg_axisX;
+ lineEnter.attr("y2", -innerTickSize);
+ textEnter.attr("y", -(Math.max(innerTickSize, 0) + tickPadding));
+ lineUpdate.attr("x2", 0).attr("y2", -innerTickSize);
+ textUpdate.attr("x", 0).attr("y", -(Math.max(innerTickSize, 0) + tickPadding));
+ text.attr("dy", "0em").style("text-anchor", "middle");
+ pathUpdate.attr("d", "M" + range[0] + "," + -outerTickSize + "V0H" + range[1] + "V" + -outerTickSize);
+ break;
+ }
+
+ case "left":
+ {
+ tickTransform = d3_svg_axisY;
+ lineEnter.attr("x2", -innerTickSize);
+ textEnter.attr("x", -(Math.max(innerTickSize, 0) + tickPadding));
+ lineUpdate.attr("x2", -innerTickSize).attr("y2", 0);
+ textUpdate.attr("x", -(Math.max(innerTickSize, 0) + tickPadding)).attr("y", 0);
+ text.attr("dy", ".32em").style("text-anchor", "end");
+ pathUpdate.attr("d", "M" + -outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + -outerTickSize);
+ break;
+ }
+
+ case "right":
+ {
+ tickTransform = d3_svg_axisY;
+ lineEnter.attr("x2", innerTickSize);
+ textEnter.attr("x", Math.max(innerTickSize, 0) + tickPadding);
+ lineUpdate.attr("x2", innerTickSize).attr("y2", 0);
+ textUpdate.attr("x", Math.max(innerTickSize, 0) + tickPadding).attr("y", 0);
+ text.attr("dy", ".32em").style("text-anchor", "start");
+ pathUpdate.attr("d", "M" + outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + outerTickSize);
+ break;
+ }
+ }
+ if (scale1.rangeBand) {
+ var x = scale1, dx = x.rangeBand() / 2;
+ scale0 = scale1 = function(d) {
+ return x(d) + dx;
+ };
+ } else if (scale0.rangeBand) {
+ scale0 = scale1;
+ } else {
+ tickExit.call(tickTransform, scale1);
+ }
+ tickEnter.call(tickTransform, scale0);
+ tickUpdate.call(tickTransform, scale1);
+ });
+ }
+ axis.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = x;
+ return axis;
+ };
+ axis.orient = function(x) {
+ if (!arguments.length) return orient;
+ orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient;
+ return axis;
+ };
+ axis.ticks = function() {
+ if (!arguments.length) return tickArguments_;
+ tickArguments_ = arguments;
+ return axis;
+ };
+ axis.tickValues = function(x) {
+ if (!arguments.length) return tickValues;
+ tickValues = x;
+ return axis;
+ };
+ axis.tickFormat = function(x) {
+ if (!arguments.length) return tickFormat_;
+ tickFormat_ = x;
+ return axis;
+ };
+ axis.tickSize = function(x) {
+ var n = arguments.length;
+ if (!n) return innerTickSize;
+ innerTickSize = +x;
+ outerTickSize = +arguments[n - 1];
+ return axis;
+ };
+ axis.innerTickSize = function(x) {
+ if (!arguments.length) return innerTickSize;
+ innerTickSize = +x;
+ return axis;
+ };
+ axis.outerTickSize = function(x) {
+ if (!arguments.length) return outerTickSize;
+ outerTickSize = +x;
+ return axis;
+ };
+ axis.tickPadding = function(x) {
+ if (!arguments.length) return tickPadding;
+ tickPadding = +x;
+ return axis;
+ };
+ axis.tickSubdivide = function() {
+ return arguments.length && axis;
+ };
+ return axis;
+ };
+ var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = {
+ top: 1,
+ right: 1,
+ bottom: 1,
+ left: 1
+ };
+ function d3_svg_axisX(selection, x) {
+ selection.attr("transform", function(d) {
+ return "translate(" + x(d) + ",0)";
+ });
+ }
+ function d3_svg_axisY(selection, y) {
+ selection.attr("transform", function(d) {
+ return "translate(0," + y(d) + ")";
+ });
+ }
+ d3.svg.brush = function() {
+ var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0];
+ function brush(g) {
+ g.each(function() {
+ var g = d3.select(this).style("pointer-events", "all").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
+ var background = g.selectAll(".background").data([ 0 ]);
+ background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
+ g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move");
+ var resize = g.selectAll(".resize").data(resizes, d3_identity);
+ resize.exit().remove();
+ resize.enter().append("g").attr("class", function(d) {
+ return "resize " + d;
+ }).style("cursor", function(d) {
+ return d3_svg_brushCursor[d];
+ }).append("rect").attr("x", function(d) {
+ return /[ew]$/.test(d) ? -3 : null;
+ }).attr("y", function(d) {
+ return /^[ns]/.test(d) ? -3 : null;
+ }).attr("width", 6).attr("height", 6).style("visibility", "hidden");
+ resize.style("display", brush.empty() ? "none" : null);
+ var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range;
+ if (x) {
+ range = d3_scaleRange(x);
+ backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]);
+ redrawX(gUpdate);
+ }
+ if (y) {
+ range = d3_scaleRange(y);
+ backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]);
+ redrawY(gUpdate);
+ }
+ redraw(gUpdate);
+ });
+ }
+ brush.event = function(g) {
+ g.each(function() {
+ var event_ = event.of(this, arguments), extent1 = {
+ x: xExtent,
+ y: yExtent,
+ i: xExtentDomain,
+ j: yExtentDomain
+ }, extent0 = this.__chart__ || extent1;
+ this.__chart__ = extent1;
+ if (d3_transitionInheritId) {
+ d3.select(this).transition().each("start.brush", function() {
+ xExtentDomain = extent0.i;
+ yExtentDomain = extent0.j;
+ xExtent = extent0.x;
+ yExtent = extent0.y;
+ event_({
+ type: "brushstart"
+ });
+ }).tween("brush:brush", function() {
+ var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y);
+ xExtentDomain = yExtentDomain = null;
+ return function(t) {
+ xExtent = extent1.x = xi(t);
+ yExtent = extent1.y = yi(t);
+ event_({
+ type: "brush",
+ mode: "resize"
+ });
+ };
+ }).each("end.brush", function() {
+ xExtentDomain = extent1.i;
+ yExtentDomain = extent1.j;
+ event_({
+ type: "brush",
+ mode: "resize"
+ });
+ event_({
+ type: "brushend"
+ });
+ });
+ } else {
+ event_({
+ type: "brushstart"
+ });
+ event_({
+ type: "brush",
+ mode: "resize"
+ });
+ event_({
+ type: "brushend"
+ });
+ }
+ });
+ };
+ function redraw(g) {
+ g.selectAll(".resize").attr("transform", function(d) {
+ return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")";
+ });
+ }
+ function redrawX(g) {
+ g.select(".extent").attr("x", xExtent[0]);
+ g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]);
+ }
+ function redrawY(g) {
+ g.select(".extent").attr("y", yExtent[0]);
+ g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]);
+ }
+ function brushstart() {
+ var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = d3.mouse(target), offset;
+ var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup);
+ if (d3.event.changedTouches) {
+ w.on("touchmove.brush", brushmove).on("touchend.brush", brushend);
+ } else {
+ w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend);
+ }
+ g.interrupt().selectAll("*").interrupt();
+ if (dragging) {
+ origin[0] = xExtent[0] - origin[0];
+ origin[1] = yExtent[0] - origin[1];
+ } else if (resizing) {
+ var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
+ offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ];
+ origin[0] = xExtent[ex];
+ origin[1] = yExtent[ey];
+ } else if (d3.event.altKey) center = origin.slice();
+ g.style("pointer-events", "none").selectAll(".resize").style("display", null);
+ d3.select("body").style("cursor", eventTarget.style("cursor"));
+ event_({
+ type: "brushstart"
+ });
+ brushmove();
+ function keydown() {
+ if (d3.event.keyCode == 32) {
+ if (!dragging) {
+ center = null;
+ origin[0] -= xExtent[1];
+ origin[1] -= yExtent[1];
+ dragging = 2;
+ }
+ d3_eventPreventDefault();
+ }
+ }
+ function keyup() {
+ if (d3.event.keyCode == 32 && dragging == 2) {
+ origin[0] += xExtent[1];
+ origin[1] += yExtent[1];
+ dragging = 0;
+ d3_eventPreventDefault();
+ }
+ }
+ function brushmove() {
+ var point = d3.mouse(target), moved = false;
+ if (offset) {
+ point[0] += offset[0];
+ point[1] += offset[1];
+ }
+ if (!dragging) {
+ if (d3.event.altKey) {
+ if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ];
+ origin[0] = xExtent[+(point[0] < center[0])];
+ origin[1] = yExtent[+(point[1] < center[1])];
+ } else center = null;
+ }
+ if (resizingX && move1(point, x, 0)) {
+ redrawX(g);
+ moved = true;
+ }
+ if (resizingY && move1(point, y, 1)) {
+ redrawY(g);
+ moved = true;
+ }
+ if (moved) {
+ redraw(g);
+ event_({
+ type: "brush",
+ mode: dragging ? "move" : "resize"
+ });
+ }
+ }
+ function move1(point, scale, i) {
+ var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max;
+ if (dragging) {
+ r0 -= position;
+ r1 -= size + position;
+ }
+ min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i];
+ if (dragging) {
+ max = (min += position) + size;
+ } else {
+ if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
+ if (position < min) {
+ max = min;
+ min = position;
+ } else {
+ max = position;
+ }
+ }
+ if (extent[0] != min || extent[1] != max) {
+ if (i) yExtentDomain = null; else xExtentDomain = null;
+ extent[0] = min;
+ extent[1] = max;
+ return true;
+ }
+ }
+ function brushend() {
+ brushmove();
+ g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null);
+ d3.select("body").style("cursor", null);
+ w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null);
+ dragRestore();
+ event_({
+ type: "brushend"
+ });
+ }
+ }
+ brush.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ resizes = d3_svg_brushResizes[!x << 1 | !y];
+ return brush;
+ };
+ brush.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ resizes = d3_svg_brushResizes[!x << 1 | !y];
+ return brush;
+ };
+ brush.clamp = function(z) {
+ if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null;
+ if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z;
+ return brush;
+ };
+ brush.extent = function(z) {
+ var x0, x1, y0, y1, t;
+ if (!arguments.length) {
+ if (x) {
+ if (xExtentDomain) {
+ x0 = xExtentDomain[0], x1 = xExtentDomain[1];
+ } else {
+ x0 = xExtent[0], x1 = xExtent[1];
+ if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ }
+ }
+ if (y) {
+ if (yExtentDomain) {
+ y0 = yExtentDomain[0], y1 = yExtentDomain[1];
+ } else {
+ y0 = yExtent[0], y1 = yExtent[1];
+ if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ }
+ }
+ return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];
+ }
+ if (x) {
+ x0 = z[0], x1 = z[1];
+ if (y) x0 = x0[0], x1 = x1[0];
+ xExtentDomain = [ x0, x1 ];
+ if (x.invert) x0 = x(x0), x1 = x(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ];
+ }
+ if (y) {
+ y0 = z[0], y1 = z[1];
+ if (x) y0 = y0[1], y1 = y1[1];
+ yExtentDomain = [ y0, y1 ];
+ if (y.invert) y0 = y(y0), y1 = y(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ];
+ }
+ return brush;
+ };
+ brush.clear = function() {
+ if (!brush.empty()) {
+ xExtent = [ 0, 0 ], yExtent = [ 0, 0 ];
+ xExtentDomain = yExtentDomain = null;
+ }
+ return brush;
+ };
+ brush.empty = function() {
+ return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1];
+ };
+ return d3.rebind(brush, event, "on");
+ };
+ var d3_svg_brushCursor = {
+ n: "ns-resize",
+ e: "ew-resize",
+ s: "ns-resize",
+ w: "ew-resize",
+ nw: "nwse-resize",
+ ne: "nesw-resize",
+ se: "nwse-resize",
+ sw: "nesw-resize"
+ };
+ var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ];
+ var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat;
+ var d3_time_formatUtc = d3_time_format.utc;
+ var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ");
+ d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso;
+ function d3_time_formatIsoNative(date) {
+ return date.toISOString();
+ }
+ d3_time_formatIsoNative.parse = function(string) {
+ var date = new Date(string);
+ return isNaN(date) ? null : date;
+ };
+ d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
+ d3_time.second = d3_time_interval(function(date) {
+ return new d3_date(Math.floor(date / 1e3) * 1e3);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 1e3);
+ }, function(date) {
+ return date.getSeconds();
+ });
+ d3_time.seconds = d3_time.second.range;
+ d3_time.seconds.utc = d3_time.second.utc.range;
+ d3_time.minute = d3_time_interval(function(date) {
+ return new d3_date(Math.floor(date / 6e4) * 6e4);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 6e4);
+ }, function(date) {
+ return date.getMinutes();
+ });
+ d3_time.minutes = d3_time.minute.range;
+ d3_time.minutes.utc = d3_time.minute.utc.range;
+ d3_time.hour = d3_time_interval(function(date) {
+ var timezone = date.getTimezoneOffset() / 60;
+ return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 36e5);
+ }, function(date) {
+ return date.getHours();
+ });
+ d3_time.hours = d3_time.hour.range;
+ d3_time.hours.utc = d3_time.hour.utc.range;
+ d3_time.month = d3_time_interval(function(date) {
+ date = d3_time.day(date);
+ date.setDate(1);
+ return date;
+ }, function(date, offset) {
+ date.setMonth(date.getMonth() + offset);
+ }, function(date) {
+ return date.getMonth();
+ });
+ d3_time.months = d3_time.month.range;
+ d3_time.months.utc = d3_time.month.utc.range;
+ function d3_time_scale(linear, methods, format) {
+ function scale(x) {
+ return linear(x);
+ }
+ scale.invert = function(x) {
+ return d3_time_scaleDate(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
+ linear.domain(x);
+ return scale;
+ };
+ function tickMethod(extent, count) {
+ var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target);
+ return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) {
+ return d / 31536e6;
+ }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i];
+ }
+ scale.nice = function(interval, skip) {
+ var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval);
+ if (method) interval = method[0], skip = method[1];
+ function skipped(date) {
+ return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length;
+ }
+ return scale.domain(d3_scale_nice(domain, skip > 1 ? {
+ floor: function(date) {
+ while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1);
+ return date;
+ },
+ ceil: function(date) {
+ while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1);
+ return date;
+ }
+ } : interval));
+ };
+ scale.ticks = function(interval, skip) {
+ var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ {
+ range: interval
+ }, skip ];
+ if (method) interval = method[0], skip = method[1];
+ return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip);
+ };
+ scale.tickFormat = function() {
+ return format;
+ };
+ scale.copy = function() {
+ return d3_time_scale(linear.copy(), methods, format);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ function d3_time_scaleDate(t) {
+ return new Date(t);
+ }
+ var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
+ var d3_time_scaleLocalMethods = [ [ d3_time.second, 1 ], [ d3_time.second, 5 ], [ d3_time.second, 15 ], [ d3_time.second, 30 ], [ d3_time.minute, 1 ], [ d3_time.minute, 5 ], [ d3_time.minute, 15 ], [ d3_time.minute, 30 ], [ d3_time.hour, 1 ], [ d3_time.hour, 3 ], [ d3_time.hour, 6 ], [ d3_time.hour, 12 ], [ d3_time.day, 1 ], [ d3_time.day, 2 ], [ d3_time.week, 1 ], [ d3_time.month, 1 ], [ d3_time.month, 3 ], [ d3_time.year, 1 ] ];
+ var d3_time_scaleLocalFormat = d3_time_format.multi([ [ ".%L", function(d) {
+ return d.getMilliseconds();
+ } ], [ ":%S", function(d) {
+ return d.getSeconds();
+ } ], [ "%I:%M", function(d) {
+ return d.getMinutes();
+ } ], [ "%I %p", function(d) {
+ return d.getHours();
+ } ], [ "%a %d", function(d) {
+ return d.getDay() && d.getDate() != 1;
+ } ], [ "%b %d", function(d) {
+ return d.getDate() != 1;
+ } ], [ "%B", function(d) {
+ return d.getMonth();
+ } ], [ "%Y", d3_true ] ]);
+ var d3_time_scaleMilliseconds = {
+ range: function(start, stop, step) {
+ return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate);
+ },
+ floor: d3_identity,
+ ceil: d3_identity
+ };
+ d3_time_scaleLocalMethods.year = d3_time.year;
+ d3_time.scale = function() {
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
+ };
+ var d3_time_scaleUtcMethods = d3_time_scaleLocalMethods.map(function(m) {
+ return [ m[0].utc, m[1] ];
+ });
+ var d3_time_scaleUtcFormat = d3_time_formatUtc.multi([ [ ".%L", function(d) {
+ return d.getUTCMilliseconds();
+ } ], [ ":%S", function(d) {
+ return d.getUTCSeconds();
+ } ], [ "%I:%M", function(d) {
+ return d.getUTCMinutes();
+ } ], [ "%I %p", function(d) {
+ return d.getUTCHours();
+ } ], [ "%a %d", function(d) {
+ return d.getUTCDay() && d.getUTCDate() != 1;
+ } ], [ "%b %d", function(d) {
+ return d.getUTCDate() != 1;
+ } ], [ "%B", function(d) {
+ return d.getUTCMonth();
+ } ], [ "%Y", d3_true ] ]);
+ d3_time_scaleUtcMethods.year = d3_time.year.utc;
+ d3_time.scale.utc = function() {
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat);
+ };
+ d3.text = d3_xhrType(function(request) {
+ return request.responseText;
+ });
+ d3.json = function(url, callback) {
+ return d3_xhr(url, "application/json", d3_json, callback);
+ };
+ function d3_json(request) {
+ return JSON.parse(request.responseText);
+ }
+ d3.html = function(url, callback) {
+ throw "disallowed by chromium security";
+ return d3_xhr(url, "text/html", d3_html, callback);
+ };
+ function d3_html(request) {
+ throw "disallowed by chromium security";
+ var range = d3_document.createRange();
+ range.selectNode(d3_document.body);
+ return range.createContextualFragment(request.responseText);
+ }
+ d3.xml = d3_xhrType(function(request) {
+ return request.responseXML;
+ });
+ if (typeof define === "function" && define.amd) {
+ define(d3);
+ } else if (typeof module === "object" && module.exports) {
+ module.exports = d3;
+ } else {
+ this.d3 = d3;
+ }
+}();
\ No newline at end of file
diff --git a/runtime/tools/create_snapshot_bin.py b/runtime/tools/create_snapshot_bin.py
index 344c4e3..78213cf 100755
--- a/runtime/tools/create_snapshot_bin.py
+++ b/runtime/tools/create_snapshot_bin.py
@@ -104,7 +104,9 @@
return 1
# Setup arguments to the snapshot generator binary.
- script_args = ["--error_on_bad_type", "--error_on_bad_override"]
+ script_args = ["--ignore_unrecognized_flags",
+ "--error_on_bad_type",
+ "--error_on_bad_override"]
# Pass along the package_root if there is one.
if options.package_root:
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 2db9a6e..ea968d8 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -55,7 +55,23 @@
set_sources_assignment_filter(["*_test.cc", "*_test.h"])
sources = vm_sources_list.sources
- - ["vtune.cc", "vtune.h"]
+ include_dirs = [
+ "..",
+ ]
+}
+
+
+static_library("libdart_vm_precompiled_runtime") {
+ configs += ["..:dart_config_no_precompiler"]
+ public_configs = [":libdart_vm_config"]
+ defines = ["DART_PRECOMPILED_RUNTIME"]
+ vm_sources_list = exec_script("../../tools/gypi_to_gn.py",
+ [rebase_path("vm_sources.gypi")],
+ "scope",
+ ["vm_sources.gypi"])
+
+ set_sources_assignment_filter(["*_test.cc", "*_test.h"])
+ sources = vm_sources_list.sources
include_dirs = [
"..",
]
@@ -73,7 +89,6 @@
set_sources_assignment_filter(["*_test.cc", "*_test.h"])
sources = vm_sources_list.sources
- - ["vtune.cc", "vtune.h"]
include_dirs = [
"..",
]
@@ -179,6 +194,14 @@
"..",
]
}
+ static_library("libdart_lib_precompiled_runtime") {
+ configs += ["..:dart_config_no_precompiler"]
+ defines = ["DART_PRECOMPILED_RUNTIME"]
+ sources = libsources + [ "bootstrap_nocore.cc", ]
+ include_dirs = [
+ "..",
+ ]
+ }
}
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 63c13f5..f813eb8 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -29,8 +29,6 @@
namespace dart {
-DECLARE_FLAG(bool, precompilation);
-
// Quick access to the current isolate and zone.
#define I (isolate())
#define Z (zone())
@@ -260,7 +258,7 @@
const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data,
- intptr_t cid) {
+ intptr_t cid) {
ASSERT(ic_data.NumArgsTested() == 1);
if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
@@ -375,9 +373,9 @@
void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
- intptr_t index,
- Representation rep,
- intptr_t cid) {
+ intptr_t index,
+ Representation rep,
+ intptr_t cid) {
ExtractNthOutputInstr* extract =
new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
instr->ReplaceUsesWith(extract);
@@ -711,7 +709,7 @@
void AotOptimizer::ReplaceCall(Definition* call,
- Definition* replacement) {
+ Definition* replacement) {
// Remove the original push arguments.
for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
PushArgumentInstr* push = call->PushArgumentAt(i);
@@ -723,9 +721,9 @@
void AotOptimizer::AddCheckSmi(Definition* to_check,
- intptr_t deopt_id,
- Environment* deopt_environment,
- Instruction* insert_before) {
+ intptr_t deopt_id,
+ Environment* deopt_environment,
+ Instruction* insert_before) {
if (to_check->Type()->ToCid() != kSmiCid) {
InsertBefore(insert_before,
new(Z) CheckSmiInstr(new(Z) Value(to_check),
@@ -738,9 +736,9 @@
Instruction* AotOptimizer::GetCheckClass(Definition* to_check,
- const ICData& unary_checks,
- intptr_t deopt_id,
- TokenPosition token_pos) {
+ const ICData& unary_checks,
+ intptr_t deopt_id,
+ TokenPosition token_pos) {
if ((unary_checks.NumberOfUsedChecks() == 1) &&
unary_checks.HasReceiverClassId(kSmiCid)) {
return new(Z) CheckSmiInstr(new(Z) Value(to_check),
@@ -753,10 +751,10 @@
void AotOptimizer::AddCheckClass(Definition* to_check,
- const ICData& unary_checks,
- intptr_t deopt_id,
- Environment* deopt_environment,
- Instruction* insert_before) {
+ const ICData& unary_checks,
+ intptr_t deopt_id,
+ Environment* deopt_environment,
+ Instruction* insert_before) {
// Type propagation has not run yet, we cannot eliminate the check.
Instruction* check = GetCheckClass(
to_check, unary_checks, deopt_id, insert_before->token_pos());
@@ -823,7 +821,7 @@
// E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
// TODO(srdjan): Expand for two-byte and external strings.
bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
- Token::Kind op_kind) {
+ Token::Kind op_kind) {
ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
// Check that left and right are length one strings (either string constants
// or results of string-from-char-code.
@@ -910,7 +908,7 @@
static bool SmiFitsInDouble() { return kSmiBits < 53; }
bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+ Token::Kind op_kind) {
const ICData& ic_data = *call->ic_data();
ASSERT(ic_data.NumArgsTested() == 2);
@@ -1019,7 +1017,7 @@
bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+ Token::Kind op_kind) {
const ICData& ic_data = *call->ic_data();
ASSERT(ic_data.NumArgsTested() == 2);
@@ -1081,7 +1079,7 @@
bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+ Token::Kind op_kind) {
intptr_t operands_type = kIllegalCid;
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
@@ -1290,7 +1288,7 @@
bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+ Token::Kind op_kind) {
ASSERT(call->ArgumentCount() == 1);
Definition* input = call->ArgumentAt(0);
Definition* unary_op = NULL;
@@ -1325,7 +1323,7 @@
// Using field class
RawField* AotOptimizer::GetField(intptr_t class_id,
- const String& field_name) {
+ const String& field_name) {
Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
Field& field = Field::Handle(Z);
while (!cls.IsNull()) {
@@ -1373,8 +1371,7 @@
}
-bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
- bool allow_check) {
+bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
ASSERT(ic_data.HasOneTarget());
@@ -1389,10 +1386,7 @@
ASSERT(!field.IsNull());
if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) {
- if (!allow_check) {
- return false;
- }
- AddReceiverCheck(call);
+ return false;
}
LoadFieldInstr* load = new(Z) LoadFieldInstr(
new(Z) Value(call->ArgumentAt(0)),
@@ -1419,7 +1413,7 @@
bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
- MethodRecognizer::Kind getter) {
+ MethodRecognizer::Kind getter) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1494,7 +1488,7 @@
bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
- MethodRecognizer::Kind getter) {
+ MethodRecognizer::Kind getter) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1520,7 +1514,7 @@
bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
- MethodRecognizer::Kind getter) {
+ MethodRecognizer::Kind getter) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1595,7 +1589,7 @@
bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+ Token::Kind op_kind) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1628,7 +1622,7 @@
bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+ Token::Kind op_kind) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1660,7 +1654,7 @@
bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+ Token::Kind op_kind) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1692,9 +1686,7 @@
// Only unique implicit instance getters can be currently handled.
-// Returns false if 'allow_check' is false and a check is needed.
-bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
- bool allow_check) {
+bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
if (ic_data.NumberOfUsedChecks() == 0) {
@@ -1714,7 +1706,7 @@
// inlining in FlowGraphInliner.
return false;
}
- return InlineImplicitInstanceGetter(call, allow_check);
+ return InlineImplicitInstanceGetter(call);
}
@@ -2040,7 +2032,7 @@
StaticCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
// Cannot handle unboxed instructions.
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
return false;
}
@@ -2049,7 +2041,7 @@
StaticCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
// Cannot handle unboxed instructions.
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
return false;
}
@@ -2058,7 +2050,7 @@
StaticCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
// Cannot handle unboxed instructions.
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
return false;
}
@@ -2431,14 +2423,14 @@
}
if ((op_kind == Token::kGET) &&
- TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
+ TryInlineInstanceGetter(instr)) {
return;
}
const ICData& unary_checks =
ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
if ((unary_checks.NumberOfChecks() > 0) &&
(op_kind == Token::kSET) &&
- TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
+ TryInlineInstanceSetter(instr, unary_checks)) {
return;
}
@@ -2555,7 +2547,7 @@
// Tries to optimize instance call by replacing it with a faster instruction
// (e.g, binary op, field load, ..).
void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
InstanceCallNoopt(instr);
}
@@ -2582,7 +2574,7 @@
break;
}
if (unary_kind != MathUnaryInstr::kIllegal) {
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
// TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
return;
}
@@ -2662,7 +2654,7 @@
case MethodRecognizer::kMathAcos:
case MethodRecognizer::kMathAtan:
case MethodRecognizer::kMathAtan2: {
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
// No UnboxDouble instructions allowed.
return;
}
@@ -2765,11 +2757,10 @@
bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
- const ICData& unary_ic_data,
- bool allow_checks) {
+ const ICData& unary_ic_data) {
ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
(unary_ic_data.NumArgsTested() == 1));
- if (I->flags().type_checks()) {
+ if (I->type_checks()) {
// Checked mode setters are inlined like normal methods by conventional
// inlining.
return false;
@@ -2800,35 +2791,7 @@
ASSERT(!field.IsNull());
if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) {
- if (!allow_checks) {
- return false;
- }
- AddReceiverCheck(instr);
- }
- if (field.guarded_cid() != kDynamicCid) {
- if (!allow_checks) {
- return false;
- }
- InsertBefore(instr,
- new(Z) GuardFieldClassInstr(
- new(Z) Value(instr->ArgumentAt(1)),
- field,
- instr->deopt_id()),
- instr->env(),
- FlowGraph::kEffect);
- }
-
- if (field.needs_length_check()) {
- if (!allow_checks) {
- return false;
- }
- InsertBefore(instr,
- new(Z) GuardFieldLengthInstr(
- new(Z) Value(instr->ArgumentAt(1)),
- field,
- instr->deopt_id()),
- instr->env(),
- FlowGraph::kEffect);
+ return false;
}
// Field guard was detached.
diff --git a/runtime/vm/aot_optimizer.h b/runtime/vm/aot_optimizer.h
index e770ffe..3d1ed1b 100644
--- a/runtime/vm/aot_optimizer.h
+++ b/runtime/vm/aot_optimizer.h
@@ -74,11 +74,9 @@
bool TryReplaceWithEqualityOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
- bool TryInlineInstanceGetter(InstanceCallInstr* call,
- bool allow_check = true);
+ bool TryInlineInstanceGetter(InstanceCallInstr* call);
bool TryInlineInstanceSetter(InstanceCallInstr* call,
- const ICData& unary_ic_data,
- bool allow_check = true);
+ const ICData& unary_ic_data);
bool TryInlineInstanceMethod(InstanceCallInstr* call);
bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
@@ -142,7 +140,7 @@
Token::Kind op_kind);
bool InlineFloat64x2BinaryOp(InstanceCallInstr* call,
Token::Kind op_kind);
- bool InlineImplicitInstanceGetter(InstanceCallInstr* call, bool allow_check);
+ bool InlineImplicitInstanceGetter(InstanceCallInstr* call);
RawBool* InstanceOfAsBool(const ICData& ic_data,
const AbstractType& type,
diff --git a/runtime/vm/assembler.cc b/runtime/vm/assembler.cc
index 495419d..318881c 100644
--- a/runtime/vm/assembler.cc
+++ b/runtime/vm/assembler.cc
@@ -244,16 +244,16 @@
intptr_t ObjectPoolWrapper::AddObject(const Object& obj,
Patchability patchable) {
- return AddObject(ObjectPool::Entry(&obj), patchable);
+ return AddObject(ObjectPoolWrapperEntry(&obj), patchable);
}
intptr_t ObjectPoolWrapper::AddImmediate(uword imm) {
- return AddObject(ObjectPool::Entry(imm, ObjectPool::kImmediate),
+ return AddObject(ObjectPoolWrapperEntry(imm, ObjectPool::kImmediate),
kNotPatchable);
}
-intptr_t ObjectPoolWrapper::AddObject(ObjectPool::Entry entry,
+intptr_t ObjectPoolWrapper::AddObject(ObjectPoolWrapperEntry entry,
Patchability patchable) {
object_pool_.Add(entry);
if (patchable == kNotPatchable) {
@@ -265,7 +265,7 @@
}
-intptr_t ObjectPoolWrapper::FindObject(ObjectPool::Entry entry,
+intptr_t ObjectPoolWrapper::FindObject(ObjectPoolWrapperEntry entry,
Patchability patchable) {
// If the object is not patchable, check if we've already got it in the
// object pool.
@@ -282,20 +282,27 @@
intptr_t ObjectPoolWrapper::FindObject(const Object& obj,
Patchability patchable) {
- return FindObject(ObjectPool::Entry(&obj), patchable);
+ return FindObject(ObjectPoolWrapperEntry(&obj), patchable);
+}
+
+
+intptr_t ObjectPoolWrapper::FindObject(const Object& obj,
+ const Object& equivalence) {
+ return FindObject(ObjectPoolWrapperEntry(&obj, &equivalence),
+ kNotPatchable);
}
intptr_t ObjectPoolWrapper::FindImmediate(uword imm) {
- return FindObject(ObjectPool::Entry(imm, ObjectPool::kImmediate),
+ return FindObject(ObjectPoolWrapperEntry(imm, ObjectPool::kImmediate),
kNotPatchable);
}
intptr_t ObjectPoolWrapper::FindNativeEntry(const ExternalLabel* label,
Patchability patchable) {
- return FindObject(ObjectPool::Entry(label->address(),
- ObjectPool::kNativeEntry),
+ return FindObject(ObjectPoolWrapperEntry(label->address(),
+ ObjectPool::kNativeEntry),
patchable);
}
diff --git a/runtime/vm/assembler.h b/runtime/vm/assembler.h
index c414c0d..5d20c01 100644
--- a/runtime/vm/assembler.h
+++ b/runtime/vm/assembler.h
@@ -212,11 +212,30 @@
};
+struct ObjectPoolWrapperEntry {
+ ObjectPoolWrapperEntry()
+ : raw_value_(), type_(), equivalence_() { }
+ explicit ObjectPoolWrapperEntry(const Object* obj)
+ : obj_(obj), type_(ObjectPool::kTaggedObject), equivalence_(obj) { }
+ explicit ObjectPoolWrapperEntry(const Object* obj, const Object* eqv)
+ : obj_(obj), type_(ObjectPool::kTaggedObject), equivalence_(eqv) { }
+ ObjectPoolWrapperEntry(uword value, ObjectPool::EntryType info)
+ : raw_value_(value), type_(info), equivalence_() { }
+
+ union {
+ const Object* obj_;
+ uword raw_value_;
+ };
+ ObjectPool::EntryType type_;
+ const Object* equivalence_;
+};
+
+
// Pair type parameter for DirectChainedHashMap used for the constant pool.
class ObjIndexPair {
public:
// Typedefs needed for the DirectChainedHashMap template.
- typedef ObjectPool::Entry Key;
+ typedef ObjectPoolWrapperEntry Key;
typedef intptr_t Value;
typedef ObjIndexPair Pair;
@@ -233,6 +252,11 @@
} else {
key_.obj_ = &Object::ZoneHandle(key.obj_->raw());
}
+ if (key.equivalence_->IsNotTemporaryScopedHandle()) {
+ key_.equivalence_ = key.equivalence_;
+ } else {
+ key_.equivalence_ = &Object::ZoneHandle(key.equivalence_->raw());
+ }
} else {
key_.raw_value_ = key.raw_value_;
}
@@ -268,7 +292,8 @@
static inline bool IsKeyEqual(Pair kv, Key key) {
if (kv.key_.type_ != key.type_) return false;
if (kv.key_.type_ == ObjectPool::kTaggedObject) {
- return kv.key_.obj_->raw() == key.obj_->raw();
+ return (kv.key_.obj_->raw() == key.obj_->raw()) &&
+ (kv.key_.equivalence_->raw() == key.equivalence_->raw());
}
return kv.key_.raw_value_ == key.raw_value_;
}
@@ -293,6 +318,8 @@
intptr_t FindObject(const Object& obj,
Patchability patchable = kNotPatchable);
+ intptr_t FindObject(const Object& obj,
+ const Object& equivalence);
intptr_t FindImmediate(uword imm);
intptr_t FindNativeEntry(const ExternalLabel* label,
Patchability patchable);
@@ -300,11 +327,11 @@
RawObjectPool* MakeObjectPool();
private:
- intptr_t AddObject(ObjectPool::Entry entry, Patchability patchable);
- intptr_t FindObject(ObjectPool::Entry entry, Patchability patchable);
+ intptr_t AddObject(ObjectPoolWrapperEntry entry, Patchability patchable);
+ intptr_t FindObject(ObjectPoolWrapperEntry entry, Patchability patchable);
// Objects and jump targets.
- GrowableArray<ObjectPool::Entry> object_pool_;
+ GrowableArray<ObjectPoolWrapperEntry> object_pool_;
// Hashmap for fast lookup in object pool.
DirectChainedHashMap<ObjIndexPair> object_pool_index_table_;
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index e74a8c8..4043fc1 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -21,12 +21,9 @@
namespace dart {
-DECLARE_FLAG(bool, allow_absolute_addresses);
DECLARE_FLAG(bool, check_code_pointer);
DECLARE_FLAG(bool, inline_alloc);
-DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
-
uint32_t Address::encoding3() const {
if (kind_ == Immediate) {
uint32_t offset = encoding_ & kOffset12Mask;
@@ -1568,6 +1565,7 @@
bool Assembler::CanLoadFromObjectPool(const Object& object) const {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
ASSERT(!Thread::CanLoadFromThread(object));
if (!constant_pool_allowed()) {
return false;
@@ -1585,6 +1583,7 @@
bool is_unique,
Register pp) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
// Load common VM constants from the thread. This works also in places where
// no constant pool is set up (e.g. intrinsic code).
if (Thread::CanLoadFromThread(object)) {
@@ -1644,6 +1643,7 @@
void Assembler::PushObject(const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
LoadObject(IP, object);
Push(IP);
}
@@ -1651,6 +1651,7 @@
void Assembler::CompareObject(Register rn, const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
ASSERT(rn != IP);
if (object.IsSmi()) {
CompareImmediate(rn, reinterpret_cast<int32_t>(object.raw()));
@@ -1910,6 +1911,7 @@
const Object& value,
FieldContent old_content) {
ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+ ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
ASSERT(value.IsSmi() || value.InVMHeap() ||
(value.IsOld() && value.IsNotTemporaryScopedHandle()));
// No store buffer update.
@@ -1923,6 +1925,7 @@
const Object& value,
FieldContent old_content) {
ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+ ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
int32_t ignored = 0;
if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) {
StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value,
@@ -2751,6 +2754,21 @@
}
+void Assembler::BranchLinkWithEquivalence(const StubEntry& stub_entry,
+ const Object& equivalence) {
+ const Code& target = Code::Handle(stub_entry.code());
+ // Make sure that class CallPattern is able to patch the label referred
+ // to by this code sequence.
+ // For added code robustness, use 'blx lr' in a patchable sequence and
+ // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
+ const int32_t offset = ObjectPool::element_offset(
+ object_pool_wrapper_.FindObject(target, equivalence));
+ LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, PP, AL);
+ ldr(LR, FieldAddress(CODE_REG, Code::entry_point_offset()));
+ blx(LR); // Use blx instruction so that the return branch prediction works.
+}
+
+
void Assembler::BranchLink(const ExternalLabel* label) {
LoadImmediate(LR, label->address()); // Target address is never patched.
blx(LR); // Use blx instruction so that the return branch prediction works.
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 80b888b..b3014fb 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -680,6 +680,11 @@
void BranchLinkPatchable(const StubEntry& stub_entry);
void BranchLinkPatchable(const Code& code);
+ // Emit a call that shares its object pool entries with other calls
+ // that have the same equivalence marker.
+ void BranchLinkWithEquivalence(const StubEntry& stub_entry,
+ const Object& equivalence);
+
// Branch and link to [base + offset]. Call sequence is never patched.
void BranchLinkOffset(Register base, int32_t offset);
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 59c85c3..70b2f2c 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -21,12 +21,10 @@
namespace dart {
-DECLARE_FLAG(bool, allow_absolute_addresses);
DECLARE_FLAG(bool, check_code_pointer);
DECLARE_FLAG(bool, inline_alloc);
DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches");
-DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
Assembler::Assembler(bool use_far_branches)
@@ -370,6 +368,7 @@
bool Assembler::CanLoadFromObjectPool(const Object& object) const {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
ASSERT(!Thread::CanLoadFromThread(object));
if (!constant_pool_allowed()) {
return false;
@@ -405,6 +404,7 @@
const Object& object,
bool is_unique) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (Thread::CanLoadFromThread(object)) {
ldr(dst, Address(THR, Thread::OffsetFromThread(object)));
} else if (CanLoadFromObjectPool(object)) {
@@ -444,6 +444,7 @@
void Assembler::CompareObject(Register reg, const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (Thread::CanLoadFromThread(object)) {
ldr(TMP, Address(THR, Thread::OffsetFromThread(object)));
CompareRegisters(reg, TMP);
@@ -611,6 +612,17 @@
}
+void Assembler::BranchLinkWithEquivalence(const StubEntry& stub_entry,
+ const Object& equivalence) {
+ const Code& target = Code::Handle(stub_entry.code());
+ const int32_t offset = ObjectPool::element_offset(
+ object_pool_wrapper_.FindObject(target, equivalence));
+ LoadWordFromPoolOffset(CODE_REG, offset);
+ ldr(TMP, FieldAddress(CODE_REG, Code::entry_point_offset()));
+ blr(TMP);
+}
+
+
void Assembler::AddImmediate(Register dest, Register rn, int64_t imm) {
Operand op;
if (imm == 0) {
@@ -939,6 +951,7 @@
const Address& dest,
const Object& value) {
ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+ ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
ASSERT(value.IsSmi() || value.InVMHeap() ||
(value.IsOld() && value.IsNotTemporaryScopedHandle()));
// No store buffer update.
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index ffb6b768..1475625 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -757,6 +757,22 @@
EmitLoadStoreRegPair(STP, rt, rt2, a, sz);
}
+ void ldxr(Register rt, Register rn) {
+ // rt = value
+ // rn = address
+ EmitLoadStoreExclusive(LDXR, R31, rn, rt, kDoubleWord);
+ }
+ void stxr(Register rs, Register rt, Register rn) {
+ // rs = status (1 = failure, 0 = success)
+ // rt = value
+ // rn = address
+ EmitLoadStoreExclusive(STXR, rs, rn, rt, kDoubleWord);
+ }
+ void clrex() {
+ const int32_t encoding = static_cast<int32_t>(CLREX);
+ Emit(encoding);
+ }
+
// Conditional select.
void csel(Register rd, Register rn, Register rm, Condition cond) {
EmitConditionalSelect(CSEL, rd, rn, rm, cond, kDoubleWord);
@@ -1213,6 +1229,11 @@
void BranchLinkPatchable(const StubEntry& stub_entry);
+ // Emit a call that shares its object pool entries with other calls
+ // that have the same equivalence marker.
+ void BranchLinkWithEquivalence(const StubEntry& stub_entry,
+ const Object& equivalence);
+
// Macros accepting a pp Register argument may attempt to load values from
// the object pool when possible. Unless you are sure that the untagged object
// pool pointer is in another register, or that it is not available at all,
@@ -1714,6 +1735,24 @@
Emit(encoding);
}
+ void EmitLoadStoreExclusive(LoadStoreExclusiveOp op, Register rs, Register rn,
+ Register rt, OperandSize sz = kDoubleWord) {
+ ASSERT(sz == kDoubleWord);
+ const int32_t size = B31 | B30;
+
+ ASSERT((rs != kNoRegister) && (rs != ZR));
+ ASSERT((rn != kNoRegister) && (rn != ZR));
+ ASSERT((rt != kNoRegister) && (rt != ZR));
+
+ const int32_t encoding =
+ op | size |
+ (static_cast<int32_t>(ConcreteRegister(rs)) << kRsShift) |
+ (static_cast<int32_t>(ConcreteRegister(rn)) << kRnShift) |
+ (static_cast<int32_t>(ConcreteRegister(rt)) << kRtShift);
+
+ Emit(encoding);
+ }
+
void EmitLoadStoreReg(LoadStoreRegOp op, Register rt, Address a,
OperandSize sz) {
const Register crt = ConcreteRegister(rt);
diff --git a/runtime/vm/assembler_arm64_test.cc b/runtime/vm/assembler_arm64_test.cc
index 9320421..d27358e 100644
--- a/runtime/vm/assembler_arm64_test.cc
+++ b/runtime/vm/assembler_arm64_test.cc
@@ -563,6 +563,52 @@
}
+ASSEMBLER_TEST_GENERATE(Semaphore, assembler) {
+ __ SetupDartSP(kTestStackSpace);
+ __ movz(R0, Immediate(40), 0);
+ __ movz(R1, Immediate(42), 0);
+ __ Push(R0);
+ Label retry;
+ __ Bind(&retry);
+ __ ldxr(R0, SP);
+ __ stxr(TMP, R1, SP); // IP == 0, success
+ __ cmp(TMP, Operand(0));
+ __ b(&retry, NE); // NE if context switch occurred between ldrex and strex.
+ __ Pop(R0); // 42
+ __ mov(CSP, SP);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(Semaphore, test) {
+ EXPECT(test != NULL);
+ typedef int (*Semaphore)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Semaphore, test->entry()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(FailedSemaphore, assembler) {
+ __ SetupDartSP(kTestStackSpace);
+ __ movz(R0, Immediate(40), 0);
+ __ movz(R1, Immediate(42), 0);
+ __ Push(R0);
+ __ ldxr(R0, SP);
+ __ clrex(); // Simulate a context switch.
+ __ stxr(TMP, R1, SP); // IP == 1, failure
+ __ Pop(R0); // 40
+ __ add(R0, R0, Operand(TMP));
+ __ mov(CSP, SP);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(FailedSemaphore, test) {
+ EXPECT(test != NULL);
+ typedef int (*FailedSemaphore)() DART_UNUSED;
+ EXPECT_EQ(41, EXECUTE_TEST_CODE_INT64(FailedSemaphore, test->entry()));
+}
+
+
// Logical register operations.
ASSEMBLER_TEST_GENERATE(AndRegs, assembler) {
__ movz(R1, Immediate(43), 0);
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 8d3fb09..2759cd2 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -18,7 +18,6 @@
namespace dart {
-DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
DECLARE_FLAG(bool, inline_alloc);
@@ -2164,6 +2163,7 @@
void Assembler::LoadObject(Register dst, const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (object.IsSmi() || object.InVMHeap()) {
movl(dst, Immediate(reinterpret_cast<int32_t>(object.raw())));
} else {
@@ -2178,6 +2178,7 @@
void Assembler::LoadObjectSafely(Register dst, const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (Assembler::IsSafe(object)) {
LoadObject(dst, object);
} else {
@@ -2190,6 +2191,7 @@
void Assembler::PushObject(const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (object.IsSmi() || object.InVMHeap()) {
pushl(Immediate(reinterpret_cast<int32_t>(object.raw())));
} else {
@@ -2204,6 +2206,7 @@
void Assembler::CompareObject(Register reg, const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (object.IsSmi() || object.InVMHeap()) {
cmpl(reg, Immediate(reinterpret_cast<int32_t>(object.raw())));
} else {
@@ -2403,6 +2406,7 @@
void Assembler::UnverifiedStoreOldObject(const Address& dest,
const Object& value) {
ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+ ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
ASSERT(value.IsOld());
ASSERT(!value.InVMHeap());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -2417,6 +2421,7 @@
const Object& value,
FieldContent old_content) {
ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+ ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
VerifyHeapWord(dest, old_content);
if (value.IsSmi() || value.InVMHeap()) {
Immediate imm_value(reinterpret_cast<int32_t>(value.raw()));
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 957b549..f5cbd1a 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -14,15 +14,12 @@
namespace dart {
-DECLARE_FLAG(bool, allow_absolute_addresses);
DECLARE_FLAG(bool, check_code_pointer);
DECLARE_FLAG(bool, inline_alloc);
#if defined(USING_SIMULATOR)
DECLARE_FLAG(int, trace_sim_after);
#endif
-DEFINE_FLAG(bool, print_stop_message, false, "Print stop message.");
-
void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) {
ASSERT(Utils::IsAligned(data, 4));
ASSERT(Utils::IsAligned(length, 4));
@@ -536,8 +533,22 @@
}
+void Assembler::BranchLinkWithEquivalence(const StubEntry& stub_entry,
+ const Object& equivalence) {
+ const Code& target = Code::Handle(stub_entry.code());
+ ASSERT(!in_delay_slot_);
+ const int32_t offset = ObjectPool::element_offset(
+ object_pool_wrapper_.FindObject(target, equivalence));
+ LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag);
+ lw(T9, FieldAddress(CODE_REG, Code::entry_point_offset()));
+ jalr(T9);
+ delay_slot_available_ = false; // CodePatcher expects a nop.
+}
+
+
bool Assembler::CanLoadFromObjectPool(const Object& object) const {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
ASSERT(!Thread::CanLoadFromThread(object));
if (!constant_pool_allowed()) {
return false;
@@ -553,6 +564,7 @@
const Object& object,
bool is_unique) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
ASSERT(!in_delay_slot_);
if (Thread::CanLoadFromThread(object)) {
// Load common VM constants from the thread. This works also in places where
@@ -611,6 +623,7 @@
void Assembler::PushObject(const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
ASSERT(!in_delay_slot_);
LoadObject(TMP, object);
Push(TMP);
@@ -738,6 +751,7 @@
const Address& dest,
const Object& value) {
ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+ ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
ASSERT(!in_delay_slot_);
ASSERT(value.IsSmi() || value.InVMHeap() ||
(value.IsOld() && value.IsNotTemporaryScopedHandle()));
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 382d833..1654ac9 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -663,6 +663,10 @@
EmitLoadStore(LHU, rt, addr);
}
+ void ll(Register rt, const Address& addr) {
+ EmitLoadStore(LL, rt, addr);
+ }
+
void lui(Register rt, const Immediate& imm) {
ASSERT(Utils::IsUint(kImmBits, imm.value()));
const uint16_t imm_value = static_cast<uint16_t>(imm.value());
@@ -791,6 +795,11 @@
EmitLoadStore(SB, rt, addr);
}
+ // rt = 1 on success, 0 on failure.
+ void sc(Register rt, const Address& addr) {
+ EmitLoadStore(SC, rt, addr);
+ }
+
void sdc1(DRegister dt, const Address& addr) {
FRegister ft = static_cast<FRegister>(dt * 2);
EmitFpuLoadStore(SDC1, ft, addr);
@@ -926,6 +935,11 @@
void BranchLinkPatchable(const StubEntry& stub_entry);
+ // Emit a call that shares its object pool entries with other calls
+ // that have the same equivalence marker.
+ void BranchLinkWithEquivalence(const StubEntry& stub_entry,
+ const Object& equivalence);
+
void Drop(intptr_t stack_elements) {
ASSERT(stack_elements >= 0);
if (stack_elements > 0) {
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index f23fe93..e3cad3d 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -2169,6 +2169,30 @@
}
+ASSEMBLER_TEST_GENERATE(Semaphore, assembler) {
+ __ EnterFrame();
+ __ LoadImmediate(T0, 40);
+ __ LoadImmediate(T1, 42);
+ __ Push(T0);
+ Label retry;
+ __ Bind(&retry);
+ __ ll(T0, Address(SP));
+ __ mov(T2, T1);
+ __ sc(T2, Address(SP)); // T1 == 1, success
+ __ LoadImmediate(T3, 1);
+ __ bne(T2, T3, &retry); // NE if context switch occurred between ll and sc
+ __ Pop(V0); // 42
+ __ LeaveFrameAndReturn();
+}
+
+
+ASSEMBLER_TEST_RUN(Semaphore, test) {
+ EXPECT(test != NULL);
+ typedef int (*Semaphore)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Semaphore, test->entry()));
+}
+
+
} // namespace dart
#endif // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 02527fc..e80efe6 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -17,12 +17,9 @@
namespace dart {
-DECLARE_FLAG(bool, allow_absolute_addresses);
DECLARE_FLAG(bool, check_code_pointer);
DECLARE_FLAG(bool, inline_alloc);
-DEFINE_FLAG(bool, print_stop_message, true, "Print stop message.");
-
Assembler::Assembler(bool use_far_branches)
: buffer_(),
@@ -97,6 +94,18 @@
}
+void Assembler::CallWithEquivalence(const StubEntry& stub_entry,
+ const Object& equivalence) {
+ ASSERT(constant_pool_allowed());
+ const Code& target = Code::Handle(stub_entry.code());
+ const int32_t offset = ObjectPool::element_offset(
+ object_pool_wrapper_.FindObject(target, equivalence));
+ LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag);
+ movq(TMP, FieldAddress(CODE_REG, Code::entry_point_offset()));
+ call(TMP);
+}
+
+
void Assembler::Call(const StubEntry& stub_entry) {
ASSERT(constant_pool_allowed());
const Code& target = Code::Handle(stub_entry.code());
@@ -2740,6 +2749,7 @@
bool Assembler::CanLoadFromObjectPool(const Object& object) const {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
ASSERT(!Thread::CanLoadFromThread(object));
if (!constant_pool_allowed()) {
return false;
@@ -2776,6 +2786,7 @@
const Object& object,
bool is_unique) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (Thread::CanLoadFromThread(object)) {
movq(dst, Address(THR, Thread::OffsetFromThread(object)));
} else if (CanLoadFromObjectPool(object)) {
@@ -2814,6 +2825,7 @@
void Assembler::StoreObject(const Address& dst, const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (Thread::CanLoadFromThread(object)) {
movq(TMP, Address(THR, Thread::OffsetFromThread(object)));
movq(dst, TMP);
@@ -2829,6 +2841,7 @@
void Assembler::PushObject(const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (Thread::CanLoadFromThread(object)) {
pushq(Address(THR, Thread::OffsetFromThread(object)));
} else if (CanLoadFromObjectPool(object)) {
@@ -2843,6 +2856,7 @@
void Assembler::CompareObject(Register reg, const Object& object) {
ASSERT(!object.IsICData() || ICData::Cast(object).IsOriginal());
+ ASSERT(!object.IsField() || Field::Cast(object).IsOriginal());
if (Thread::CanLoadFromThread(object)) {
cmpq(reg, Address(THR, Thread::OffsetFromThread(object)));
} else if (CanLoadFromObjectPool(object)) {
@@ -3070,6 +3084,7 @@
const Object& value,
FieldContent old_content) {
ASSERT(!value.IsICData() || ICData::Cast(value).IsOriginal());
+ ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
VerifyHeapWord(dest, old_content);
if (VerifiedMemory::enabled()) {
const Register temp = RCX;
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 30feb10..95c474b 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -773,6 +773,10 @@
void J(Condition condition, const StubEntry& stub_entry, Register pp);
void CallPatchable(const StubEntry& stub_entry);
void Call(const StubEntry& stub_entry);
+ // Emit a call that shares its object pool entries with other calls
+ // that have the same equivalence marker.
+ void CallWithEquivalence(const StubEntry& stub_entry,
+ const Object& equivalence);
// Unaware of write barrier (use StoreInto* methods for storing to objects).
// TODO(koda): Add StackAddress/HeapAddress types to prevent misuse.
void StoreObject(const Address& dst, const Object& obj);
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index ef8d4cc..bb1b624 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -19,7 +19,7 @@
#define DEFINE_VISIT_FUNCTION(BaseName) \
void BaseName##Node::Visit(AstNodeVisitor* visitor) { \
if (FLAG_trace_ast_visitor) { \
- THR_Print("Visiting %s\n", PrettyName()); \
+ THR_Print("Visiting %s\n", Name()); \
} \
visitor->Visit##BaseName##Node(this); \
}
@@ -29,7 +29,7 @@
#define DEFINE_NAME_FUNCTION(BaseName) \
-const char* BaseName##Node::PrettyName() const { \
+const char* BaseName##Node::Name() const { \
return #BaseName; \
}
@@ -37,6 +37,17 @@
#undef DEFINE_NAME_FUNCTION
+const Field* AstNode::MayCloneField(const Field& value) {
+ if (Compiler::IsBackgroundCompilation() ||
+ FLAG_force_clone_compiler_objects) {
+ return &Field::ZoneHandle(value.CloneFromOriginal());
+ } else {
+ ASSERT(value.IsZoneHandle());
+ return &value;
+ }
+}
+
+
// A visitor class to collect all the nodes (including children) into an
// array.
class AstNodeCollector : public AstNodeVisitor {
@@ -575,14 +586,15 @@
if (field().is_final()) {
return NULL;
}
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
rhs = new AssignableNode(
field().token_pos(),
rhs,
AbstractType::ZoneHandle(field().type()),
String::ZoneHandle(field().name()));
}
- return new StoreStaticFieldNode(token_pos(), field(), rhs);
+ return new StoreStaticFieldNode(
+ token_pos(), Field::ZoneHandle(field().Original()), rhs);
}
@@ -663,7 +675,7 @@
if (obj.IsField()) {
const Field& field = Field::ZoneHandle(zone, Field::Cast(obj).raw());
if (!field.is_final()) {
- if (isolate->flags().type_checks()) {
+ if (isolate->type_checks()) {
rhs = new AssignableNode(field.token_pos(),
rhs,
AbstractType::ZoneHandle(zone, field.type()),
@@ -698,7 +710,7 @@
if (obj.IsField()) {
const Field& field = Field::ZoneHandle(zone, Field::Cast(obj).raw());
if (!field.is_final()) {
- if (isolate->flags().type_checks()) {
+ if (isolate->type_checks()) {
rhs = new AssignableNode(field.token_pos(),
rhs,
AbstractType::ZoneHandle(zone, field.type()),
@@ -754,7 +766,7 @@
ASSERT(!getter.IsNull() &&
(getter.kind() == RawFunction::kImplicitStaticFinalGetter));
#endif
- if (isolate->flags().type_checks()) {
+ if (isolate->type_checks()) {
rhs = new AssignableNode(
field.token_pos(),
rhs,
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index f212a15..4ca2372 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -92,7 +92,7 @@
#define DECLARE_COMMON_NODE_FUNCTIONS(type) \
virtual void Visit(AstNodeVisitor* visitor); \
- virtual const char* PrettyName() const; \
+ virtual const char* Name() const; \
virtual type* As##type() { return this; }
@@ -116,7 +116,7 @@
virtual void Visit(AstNodeVisitor* visitor) = 0;
virtual void VisitChildren(AstNodeVisitor* visitor) const = 0;
- virtual const char* PrettyName() const = 0;
+ virtual const char* Name() const = 0;
// Convert the node into an assignment node using the rhs which is passed in,
// this is typically used for converting nodes like LoadLocalNode,
@@ -150,6 +150,10 @@
// the former).
virtual const Instance* EvalConstExpr() const { return NULL; }
+ // Return ZoneHandle of a cloned 'value' when in background compilation or
+ // when testing. Otherwise return 'value' itself.
+ static const Field* MayCloneField(const Field& value);
+
protected:
friend class ParsedFunction;
@@ -1241,7 +1245,8 @@
LoadInstanceFieldNode(TokenPosition token_pos,
AstNode* instance,
const Field& field)
- : AstNode(token_pos), instance_(instance), field_(field) {
+ : AstNode(token_pos), instance_(instance),
+ field_(*MayCloneField(field)) {
ASSERT(instance_ != NULL);
ASSERT(field_.IsZoneHandle());
}
@@ -1271,7 +1276,7 @@
AstNode* value)
: AstNode(token_pos),
instance_(instance),
- field_(field),
+ field_(*MayCloneField(field)),
value_(value) {
ASSERT(instance_ != NULL);
ASSERT(field_.IsZoneHandle());
@@ -1301,7 +1306,9 @@
class LoadStaticFieldNode : public AstNode {
public:
LoadStaticFieldNode(TokenPosition token_pos, const Field& field)
- : AstNode(token_pos), field_(field), is_deferred_reference_(false) {
+ : AstNode(token_pos),
+ field_(*MayCloneField(field)),
+ is_deferred_reference_(false) {
ASSERT(field_.IsZoneHandle());
}
@@ -1339,7 +1346,9 @@
StoreStaticFieldNode(TokenPosition token_pos,
const Field& field,
AstNode* value)
- : AstNode(token_pos), field_(field), value_(value) {
+ : AstNode(token_pos),
+ field_(*MayCloneField(field)),
+ value_(value) {
ASSERT(field_.IsZoneHandle());
ASSERT(value_ != NULL);
}
@@ -1561,7 +1570,8 @@
class InitStaticFieldNode : public AstNode {
public:
InitStaticFieldNode(TokenPosition token_pos, const Field& field)
- : AstNode(token_pos), field_(field) {
+ : AstNode(token_pos),
+ field_(*MayCloneField(field)) {
ASSERT(field_.IsZoneHandle());
}
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 3732c3a..e438827 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -21,7 +21,7 @@
void AstPrinter::VisitGenericAstNode(AstNode* node) {
- THR_Print("(%s ", node->PrettyName());
+ THR_Print("(%s ", node->Name());
node->VisitChildren(this);
THR_Print(")");
}
@@ -30,7 +30,7 @@
void AstPrinter::VisitSequenceNode(SequenceNode* node) {
indent_++;
LocalScope* scope = node->scope();
- THR_Print("(%s (scope \"%p\"", node->PrettyName(), scope);
+ THR_Print("(%s (scope \"%p\"", node->Name(), scope);
if (scope != NULL) {
THR_Print(" (%s-%s) loop %d",
scope->begin_token_pos().ToCString(),
@@ -83,7 +83,7 @@
kind = "";
UNREACHABLE();
}
- THR_Print("(%s %s", node->PrettyName(), kind);
+ THR_Print("(%s %s", node->Name(), kind);
node->VisitChildren(this);
THR_Print(")");
}
@@ -92,7 +92,7 @@
void AstPrinter::VisitGenericLocalNode(AstNode* node,
const LocalVariable& var) {
THR_Print("(%s %s%s \"%s\"",
- node->PrettyName(),
+ node->Name(),
var.is_final() ? "final " : "",
String::Handle(var.type().Name()).ToCString(),
var.name().ToCString());
@@ -121,7 +121,7 @@
void AstPrinter::VisitGenericFieldNode(AstNode* node, const Field& field) {
THR_Print("(%s %s%s \"%s\" ",
- node->PrettyName(),
+ node->Name(),
field.is_final() ? "final " : "",
String::Handle(AbstractType::Handle(field.type()).Name()).
ToCString(),
@@ -137,7 +137,7 @@
void AstPrinter::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) {
- VisitGenericFieldNode(node, node->field());
+ VisitGenericFieldNode(node, Field::ZoneHandle(node->field().Original()));
}
@@ -168,14 +168,14 @@
void AstPrinter::VisitLiteralNode(LiteralNode* node) {
const Instance& literal = node->literal();
- THR_Print("(%s \"%s\")", node->PrettyName(), literal.ToCString());
+ THR_Print("(%s \"%s\")", node->Name(), literal.ToCString());
}
void AstPrinter::VisitTypeNode(TypeNode* node) {
const AbstractType& type = node->type();
THR_Print("(%s \"%s\")",
- node->PrettyName(),
+ node->Name(),
String::Handle(type.Name()).ToCString());
}
@@ -184,7 +184,7 @@
const AbstractType& type = node->type();
const String& dst_name = node->dst_name();
THR_Print("(%s (type \"%s\") (of \"%s\") ",
- node->PrettyName(),
+ node->Name(),
String::Handle(type.Name()).ToCString(),
dst_name.ToCString());
node->VisitChildren(this);
@@ -193,7 +193,7 @@
void AstPrinter::VisitAwaitNode(AwaitNode* node) {
- THR_Print("(*****%s***** (scope \"%p\") ", node->PrettyName(), node->scope());
+ THR_Print("(*****%s***** (scope \"%p\") ", node->Name(), node->scope());
node->VisitChildren(this);
THR_Print(")");
}
@@ -201,7 +201,7 @@
void AstPrinter::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
THR_Print("(%s (async_scope \"%p\" await_scope \"%p\"))",
- node->PrettyName(),
+ node->Name(),
node->async_scope(),
node->await_scope());
}
@@ -209,27 +209,27 @@
void AstPrinter::VisitPrimaryNode(PrimaryNode* node) {
THR_Print("(*****%s***** \"%s\")",
- node->PrettyName(),
+ node->Name(),
node->primary().ToCString());
}
void AstPrinter::VisitComparisonNode(ComparisonNode* node) {
- THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
+ THR_Print("(%s %s ", node->Name(), node->TokenName());
node->VisitChildren(this);
THR_Print(")");
}
void AstPrinter::VisitBinaryOpNode(BinaryOpNode* node) {
- THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
+ THR_Print("(%s %s ", node->Name(), node->TokenName());
node->VisitChildren(this);
THR_Print(")");
}
void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) {
- THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
+ THR_Print("(%s %s ", node->Name(), node->TokenName());
node->VisitChildren(this);
THR_Print(" & \"0x%" Px64 "", node->mask32());
THR_Print("\")");
@@ -237,7 +237,7 @@
void AstPrinter::VisitUnaryOpNode(UnaryOpNode* node) {
- THR_Print("(%s %s ", node->PrettyName(), node->TokenName());
+ THR_Print("(%s %s ", node->Name(), node->TokenName());
node->VisitChildren(this);
THR_Print(")");
}
@@ -254,7 +254,7 @@
void AstPrinter::VisitCaseNode(CaseNode* node) {
- THR_Print("(%s (", node->PrettyName());
+ THR_Print("(%s (", node->Name());
for (int i = 0; i < node->case_expressions()->length(); i++) {
node->case_expressions()->NodeAt(i)->Visit(this);
}
@@ -280,7 +280,7 @@
void AstPrinter::VisitForNode(ForNode* node) {
// Complicated because the condition is optional and so we clearly want to
// indicate the subparts.
- THR_Print("(%s (init ", node->PrettyName());
+ THR_Print("(%s (init ", node->Name());
node->initializer()->Visit(this);
if (node->condition() != NULL) {
THR_Print(") (cond ");
@@ -301,7 +301,7 @@
void AstPrinter::VisitJumpNode(JumpNode* node) {
THR_Print("(%s %s %s (scope \"%p\"))",
- node->PrettyName(),
+ node->Name(),
node->TokenName(),
node->label()->name().ToCString(),
node->label()->owner());
@@ -310,7 +310,7 @@
void AstPrinter::VisitInstanceCallNode(InstanceCallNode* node) {
THR_Print("(%s \"%s\" ",
- node->PrettyName(),
+ node->Name(),
node->function_name().ToCString());
node->VisitChildren(this);
THR_Print(")");
@@ -319,7 +319,7 @@
void AstPrinter::VisitStaticCallNode(StaticCallNode* node) {
const char* function_fullname = node->function().ToFullyQualifiedCString();
- THR_Print("(%s \"%s\" ", node->PrettyName(), function_fullname);
+ THR_Print("(%s \"%s\" ", node->Name(), function_fullname);
node->VisitChildren(this);
THR_Print(")");
}
@@ -327,7 +327,7 @@
void AstPrinter::VisitClosureNode(ClosureNode* node) {
const char* function_fullname = node->function().ToFullyQualifiedCString();
- THR_Print("(%s \"%s\")", node->PrettyName(), function_fullname);
+ THR_Print("(%s \"%s\")", node->Name(), function_fullname);
}
@@ -339,32 +339,29 @@
void AstPrinter::VisitConstructorCallNode(ConstructorCallNode* node) {
const char* kind = node->constructor().IsFactory() ? "factory " : "";
const char* constructor_name = node->constructor().ToFullyQualifiedCString();
- THR_Print("(%s %s \"%s\" ", node->PrettyName(), kind, constructor_name);
+ THR_Print("(%s %s \"%s\" ", node->Name(), kind, constructor_name);
node->VisitChildren(this);
THR_Print(")");
}
void AstPrinter::VisitInstanceGetterNode(InstanceGetterNode* node) {
- THR_Print("(%s \"%s\" ",
- node->PrettyName(),
- node->field_name().ToCString());
+ THR_Print("(%s \"%s\" ", node->Name(), node->field_name().ToCString());
node->VisitChildren(this);
THR_Print(")");
}
void AstPrinter::VisitInstanceSetterNode(InstanceSetterNode* node) {
- THR_Print("(%s \"%s\" ",
- node->PrettyName(),
- node->field_name().ToCString());
+ THR_Print("(%s \"%s\" ", node->Name(), node->field_name().ToCString());
node->VisitChildren(this);
THR_Print(")");
}
void AstPrinter::VisitInitStaticFieldNode(InitStaticFieldNode* node) {
- THR_Print("(%s \"%s\")", node->PrettyName(),
+ THR_Print("(%s \"%s\")",
+ node->Name(),
String::Handle(node->field().name()).ToCString());
}
@@ -372,7 +369,7 @@
void AstPrinter::VisitStaticGetterNode(StaticGetterNode* node) {
String& class_name = String::Handle(node->cls().Name());
THR_Print("(%s \"%s.%s\")",
- node->PrettyName(),
+ node->Name(),
class_name.ToCString(),
node->field_name().ToCString());
}
@@ -381,7 +378,7 @@
void AstPrinter::VisitStaticSetterNode(StaticSetterNode* node) {
String& class_name = String::Handle(node->cls().Name());
THR_Print("(%s \"%s.%s\" ",
- node->PrettyName(),
+ node->Name(),
class_name.ToCString(),
node->field_name().ToCString());
node->VisitChildren(this);
@@ -390,14 +387,14 @@
void AstPrinter::VisitLoadIndexedNode(LoadIndexedNode* node) {
- THR_Print("(%s%s ", node->PrettyName(), node->IsSuperLoad() ? " super" : "");
+ THR_Print("(%s%s ", node->Name(), node->IsSuperLoad() ? " super" : "");
node->VisitChildren(this);
THR_Print(")");
}
void AstPrinter::VisitStoreIndexedNode(StoreIndexedNode* node) {
- THR_Print("(%s%s ", node->PrettyName(), node->IsSuperStore() ? " super" : "");
+ THR_Print("(%s%s ", node->Name(), node->IsSuperStore() ? " super" : "");
node->VisitChildren(this);
THR_Print(")");
}
@@ -405,7 +402,7 @@
void AstPrinter::VisitNativeBodyNode(NativeBodyNode* node) {
THR_Print("(%s \"%s\" (%" Pd " args))",
- node->PrettyName(),
+ node->Name(),
node->native_c_function_name().ToCString(),
NativeArguments::ParameterCountForResolution(node->function()));
}
@@ -417,7 +414,7 @@
void AstPrinter::VisitTryCatchNode(TryCatchNode* node) {
- THR_Print("(%s ", node->PrettyName());
+ THR_Print("(%s ", node->Name());
node->try_block()->Visit(this);
node->catch_block()->Visit(this);
if (node->finally_block() != NULL) {
@@ -435,7 +432,7 @@
void AstPrinter::VisitStopNode(StopNode* node) {
- THR_Print("(%s %s)", node->PrettyName(), node->message());
+ THR_Print("(%s %s)", node->Name(), node->message());
}
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index 8b14e29..4b05867 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -521,9 +521,10 @@
void AwaitTransformer::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) {
AstNode* new_value = Transform(node->value());
- result_ = new(Z) StoreStaticFieldNode(node->token_pos(),
- node->field(),
- new_value);
+ result_ = new(Z) StoreStaticFieldNode(
+ node->token_pos(),
+ Field::ZoneHandle(Z, node->field().Original()),
+ new_value);
}
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 488a2d9..1c59f8d 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -20,8 +20,6 @@
namespace dart {
-DECLARE_FLAG(bool, background_compilation);
-
Benchmark* Benchmark::first_ = NULL;
Benchmark* Benchmark::tail_ = NULL;
const char* Benchmark::executable_ = NULL;
@@ -181,10 +179,15 @@
stats->EnableBenchmark();
Timer timer(true, "Compile all of dart2js benchmark");
timer.Start();
+#if !defined(PRODUCT)
+ // Constant in product mode.
const bool old_flag = FLAG_background_compilation;
FLAG_background_compilation = false;
+#endif
Dart_Handle result = Dart_CompileAll();
+#if !defined(PRODUCT)
FLAG_background_compilation = old_flag;
+#endif
EXPECT_VALID(result);
timer.Stop();
int64_t elapsed_time = timer.TotalElapsedTime();
@@ -387,10 +390,14 @@
}
Timer timer(true, "Compile all of dart2js benchmark");
timer.Start();
+#if !defined(PRODUCT)
const bool old_flag = FLAG_background_compilation;
FLAG_background_compilation = false;
+#endif
Dart_Handle result = Dart_CompileAll();
+#if !defined(PRODUCT)
FLAG_background_compilation = old_flag;
+#endif
EXPECT_VALID(result);
timer.Stop();
int64_t elapsed_time = timer.TotalElapsedTime();
diff --git a/runtime/vm/block_scheduler.cc b/runtime/vm/block_scheduler.cc
index 1288d0b..5b3d78d 100644
--- a/runtime/vm/block_scheduler.cc
+++ b/runtime/vm/block_scheduler.cc
@@ -11,8 +11,6 @@
namespace dart {
-DEFINE_FLAG(bool, emit_edge_counters, true, "Emit edge counters at targets.");
-
static intptr_t GetEdgeCount(const Array& edge_counters, intptr_t edge_id) {
if (!FLAG_emit_edge_counters) {
// Assume everything was visited once.
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 74304da..d1e9f5b 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -16,6 +16,7 @@
namespace dart {
DEFINE_FLAG(bool, print_classes, false, "Prints details about loaded classes.");
+DEFINE_FLAG(bool, reify, true, "Reify type arguments of generic types.");
DEFINE_FLAG(bool, trace_class_finalization, false, "Trace class finalization.");
DEFINE_FLAG(bool, trace_type_finalization, false, "Trace type finalization.");
@@ -389,7 +390,7 @@
return;
}
- if (Isolate::Current()->flags().error_on_bad_override()) {
+ if (Isolate::Current()->error_on_bad_override()) {
// Verify that the target is compatible with the redirecting factory.
Error& error = Error::Handle();
if (!target.HasCompatibleParametersWith(factory, &error)) {
@@ -670,6 +671,11 @@
// The class has num_type_parameters type parameters.
const intptr_t num_type_parameters = type_class.NumTypeParameters();
+ // If we are not reifying types, drop type arguments.
+ if (!FLAG_reify) {
+ type.set_arguments(TypeArguments::Handle(Z, TypeArguments::null()));
+ }
+
// Initialize the type argument vector.
// Check the number of parsed type arguments, if any.
// Specifying no type arguments indicates a raw type, which is not an error.
@@ -677,7 +683,7 @@
TypeArguments& arguments = TypeArguments::Handle(Z, type.arguments());
if (!arguments.IsNull() && (arguments.Length() != num_type_parameters)) {
// Wrong number of type arguments. The type is mapped to the raw type.
- if (Isolate::Current()->flags().error_on_bad_type()) {
+ if (Isolate::Current()->error_on_bad_type()) {
const String& type_class_name = String::Handle(Z, type_class.Name());
ReportError(cls, type.token_pos(),
"wrong number of type arguments for class '%s'",
@@ -699,7 +705,7 @@
// super types of type_class, which are initialized from the parsed
// type arguments, followed by the parsed type arguments.
TypeArguments& full_arguments = TypeArguments::Handle(Z);
- if (num_type_arguments > 0) {
+ if (FLAG_reify && (num_type_arguments > 0)) {
// If no type arguments were parsed and if the super types do not prepend
// type arguments to the vector, we can leave the vector as null.
if (!arguments.IsNull() || (num_type_arguments > num_type_parameters)) {
@@ -1456,7 +1462,7 @@
!const_value.IsInstanceOf(type,
Object::null_type_arguments(),
&error))) {
- if (Isolate::Current()->flags().error_on_bad_type()) {
+ if (Isolate::Current()->error_on_bad_type()) {
const AbstractType& const_value_type = AbstractType::Handle(
Z, const_value.GetType());
const String& const_value_type_name = String::Handle(
@@ -1519,7 +1525,7 @@
FinalizeSignature(cls, function);
name = function.name();
// Report signature conflicts only.
- if (Isolate::Current()->flags().error_on_bad_override() &&
+ if (Isolate::Current()->error_on_bad_override() &&
!function.is_static() && !function.IsGenerativeConstructor()) {
// A constructor cannot override anything.
for (intptr_t i = 0; i < interfaces.length(); i++) {
@@ -2259,7 +2265,7 @@
script, func.token_pos(), Report::AtLocation,
Report::kError, Heap::kNew,
"constructor '%s' is illegal in mixin class %s",
- String::Handle(func.PrettyName()).ToCString(),
+ String::Handle(func.UserVisibleName()).ToCString(),
String::Handle(zone, mixin_cls.Name()).ToCString()));
ReportErrors(error, cls, cls.token_pos(),
@@ -2710,7 +2716,7 @@
}
return;
}
- if (Isolate::Current()->flags().error_on_bad_type()) {
+ if (Isolate::Current()->error_on_bad_type()) {
const String& type_class_name = String::Handle(type_class.Name());
ReportError(cls, type.token_pos(),
"wrong number of type arguments for class '%s'",
@@ -3142,7 +3148,7 @@
prev_error, script, type.token_pos(), Report::AtLocation,
Report::kMalformedType, Heap::kOld,
format, args));
- if (Isolate::Current()->flags().error_on_bad_type()) {
+ if (Isolate::Current()->error_on_bad_type()) {
ReportError(error);
}
type.set_error(error);
@@ -3204,7 +3210,7 @@
Report::kMalboundedType, Heap::kOld,
format, args));
va_end(args);
- if (Isolate::Current()->flags().error_on_bad_type()) {
+ if (Isolate::Current()->error_on_bad_type()) {
ReportError(error);
}
type.set_error(error);
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index a286a04..dad76d9 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -6,8 +6,6 @@
namespace dart {
-DECLARE_FLAG(bool, precompilation);
-
void DescriptorList::AddDescriptor(RawPcDescriptors::Kind kind,
intptr_t pc_offset,
intptr_t deopt_id,
@@ -18,7 +16,7 @@
(deopt_id != Thread::kNoDeoptId));
// When precompiling, we only use pc descriptors for exceptions.
- if (!FLAG_precompilation || try_index != -1) {
+ if (!FLAG_precompiled_mode || try_index != -1) {
intptr_t merged_kind_try =
RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
@@ -46,6 +44,9 @@
void CodeSourceMapBuilder::AddEntry(intptr_t pc_offset,
TokenPosition token_pos) {
+ // Require pc offset to monotonically increase.
+ ASSERT((prev_pc_offset < pc_offset) ||
+ ((prev_pc_offset == 0) && (pc_offset == 0)));
CodeSourceMap::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
CodeSourceMap::EncodeInteger(&encoded_data_,
token_pos.value() - prev_token_pos);
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 4e23a6d..758c2e0 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -27,22 +27,11 @@
namespace dart {
-DEFINE_FLAG(bool, deoptimize_alot, false,
- "Deoptimizes all live frames when we are about to return to Dart code from"
- " native entries.");
-DEFINE_FLAG(bool, background_compilation, false,
- "Run optimizing compilation in background");
DEFINE_FLAG(int, max_subtype_cache_entries, 100,
"Maximum number of subtype cache entries (number of checks cached).");
-DEFINE_FLAG(int, optimization_counter_threshold, 30000,
- "Function's usage-counter value before it is optimized, -1 means never");
DEFINE_FLAG(int, regexp_optimization_counter_threshold, 1000,
"RegExp's usage-counter value before it is optimized, -1 means never");
DEFINE_FLAG(charp, optimization_filter, NULL, "Optimize only named function");
-// TODO(srdjan): Remove this flag once background compilation of regular
-// expressions is possible.
-DEFINE_FLAG(bool, regexp_opt_in_background, false,
- "Optimize reg-exp functions in background");
DEFINE_FLAG(int, reoptimization_counter_threshold, 4000,
"Counter threshold before a function gets reoptimized.");
DEFINE_FLAG(bool, stop_on_excessive_deoptimization, false,
@@ -66,17 +55,13 @@
DECLARE_FLAG(bool, trace_compiler);
DECLARE_FLAG(bool, trace_optimizing_compiler);
DECLARE_FLAG(int, max_polymorphic_checks);
-DECLARE_FLAG(bool, precompilation);
-DEFINE_FLAG(bool, use_osr, true, "Use on-stack replacement.");
DEFINE_FLAG(bool, trace_osr, false, "Trace attempts at on-stack replacement.");
DEFINE_FLAG(int, stacktrace_every, 0,
"Compute debugger stacktrace on every N stack overflow checks");
DEFINE_FLAG(charp, stacktrace_filter, NULL,
"Compute stacktrace in named function on stack overflow checks");
-DEFINE_FLAG(int, deoptimize_every, 0,
- "Deoptimize on every N stack overflow checks");
DEFINE_FLAG(charp, deoptimize_filter, NULL,
"Deoptimize in named function on stack overflow checks");
@@ -243,7 +228,7 @@
// Code inlined in the caller should have optimized the case where the
// instantiator can be reused as type argument vector.
ASSERT(instantiator.IsNull() || !type_arguments.IsUninstantiatedIdentity());
- if (isolate->flags().type_checks()) {
+ if (isolate->type_checks()) {
Error& bound_error = Error::Handle();
type_arguments =
type_arguments.InstantiateAndCanonicalizeFrom(instantiator,
@@ -505,8 +490,7 @@
// Return value: instance if a subtype, otherwise throw a TypeError.
DEFINE_RUNTIME_ENTRY(TypeCheck, 5) {
const Instance& src_instance = Instance::CheckedHandle(arguments.ArgAt(0));
- const AbstractType& dst_type =
- AbstractType::CheckedHandle(arguments.ArgAt(1));
+ AbstractType& dst_type = AbstractType::CheckedHandle(arguments.ArgAt(1));
const TypeArguments& instantiator_type_arguments =
TypeArguments::CheckedHandle(arguments.ArgAt(2));
const String& dst_name = String::CheckedHandle(arguments.ArgAt(3));
@@ -531,40 +515,21 @@
const TokenPosition location = GetCallerLocation();
const AbstractType& src_type = AbstractType::Handle(src_instance.GetType());
String& src_type_name = String::Handle(src_type.UserVisibleName());
- String& dst_type_name = String::Handle();
- Library& dst_type_lib = Library::Handle();
if (!dst_type.IsInstantiated()) {
// Instantiate dst_type before reporting the error.
- const AbstractType& instantiated_dst_type = AbstractType::Handle(
- dst_type.InstantiateFrom(instantiator_type_arguments, NULL,
- NULL, NULL, Heap::kNew));
- // Note that instantiated_dst_type may be malbounded.
- dst_type_name = instantiated_dst_type.UserVisibleName();
- dst_type_lib =
- Class::Handle(instantiated_dst_type.type_class()).library();
- } else {
- dst_type_name = dst_type.UserVisibleName();
- dst_type_lib = Class::Handle(dst_type.type_class()).library();
+ dst_type = dst_type.InstantiateFrom(instantiator_type_arguments, NULL,
+ NULL, NULL, Heap::kNew);
+ // Note that instantiated dst_type may be malbounded.
}
+ String& dst_type_name = String::Handle(dst_type.UserVisibleName());
String& bound_error_message = String::Handle();
if (!bound_error.IsNull()) {
- ASSERT(isolate->flags().type_checks());
+ ASSERT(isolate->type_checks());
bound_error_message = String::New(bound_error.ToErrorCString());
}
if (src_type_name.Equals(dst_type_name)) {
- // Qualify the names with their libraries.
- String& lib_name = String::Handle();
- lib_name = Library::Handle(
- Class::Handle(src_type.type_class()).library()).name();
- if (lib_name.Length() != 0) {
- lib_name = String::Concat(lib_name, Symbols::Dot());
- src_type_name = String::Concat(lib_name, src_type_name);
- }
- lib_name = dst_type_lib.name();
- if (lib_name.Length() != 0) {
- lib_name = String::Concat(lib_name, Symbols::Dot());
- dst_type_name = String::Concat(lib_name, dst_type_name);
- }
+ src_type_name = src_type.UserVisibleNameWithURI();
+ dst_type_name = dst_type.UserVisibleNameWithURI();
}
Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name,
dst_name, bound_error_message);
@@ -1384,7 +1349,7 @@
ActivationFrame* frame = stack->FrameAt(i);
// Variable locations and number are unknown when precompiling.
const int num_vars =
- FLAG_precompilation ? 0 : frame->NumLocalVariables();
+ FLAG_precompiled_mode ? 0 : frame->NumLocalVariables();
TokenPosition unused = TokenPosition::kNoSource;
for (intptr_t v = 0; v < num_vars; v++) {
frame->VariableAt(v, &var_name, &unused, &unused, &var_value);
@@ -1476,6 +1441,7 @@
// The requesting function can be already optimized (reoptimization).
// Returns the Code object where to continue execution.
DEFINE_RUNTIME_ENTRY(OptimizeInvokedFunction, 1) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
const Function& function = Function::CheckedHandle(zone,
arguments.ArgAt(0));
ASSERT(!function.IsNull());
@@ -1495,8 +1461,7 @@
}
}
// TODO(srdjan): Fix background compilation of regular expressions.
- if (FLAG_background_compilation &&
- (!function.IsIrregexpFunction() || FLAG_regexp_opt_in_background)) {
+ if (FLAG_background_compilation) {
if (FLAG_enable_inlining_annotations) {
FATAL("Cannot enable inlining annotations and background compilation");
}
@@ -1531,6 +1496,9 @@
ASSERT(!optimized_code.IsNull());
}
arguments.SetReturn(Code::Handle(zone, function.CurrentCode()));
+#else
+ UNREACHABLE();
+#endif // !DART_PRECOMPILED_RUNTIME
}
@@ -1554,9 +1522,6 @@
ASSERT(caller_code.is_optimized());
const Function& target_function = Function::Handle(
zone, caller_code.GetStaticCallTargetFunctionAt(frame->pc()));
- const Code& target_code = Code::Handle(
- zone, caller_code.GetStaticCallTargetCodeAt(frame->pc()));
- ASSERT(!target_code.IsNull());
if (!target_function.HasCode()) {
const Error& error = Error::Handle(
zone, Compiler::CompileFunction(thread, target_function));
@@ -1565,7 +1530,6 @@
}
}
ASSERT(target_function.HasCode());
- ASSERT(target_function.raw() == target_code.function());
const Code& current_target_code = Code::Handle(
zone, target_function.CurrentCode());
@@ -1575,11 +1539,10 @@
caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code);
if (FLAG_trace_patching) {
OS::PrintErr("FixCallersTarget: caller %#" Px " "
- "target '%s' %#" Px " -> %#" Px "\n",
- frame->pc(),
- target_function.ToFullyQualifiedCString(),
- target_code.EntryPoint(),
- current_target_code.EntryPoint());
+ "target '%s' -> %#" Px "\n",
+ frame->pc(),
+ target_function.ToFullyQualifiedCString(),
+ current_target_code.EntryPoint());
}
arguments.SetReturn(current_target_code);
}
@@ -1588,6 +1551,7 @@
// The caller tried to allocate an instance via an invalidated allocation
// stub.
DEFINE_RUNTIME_ENTRY(FixAllocationStubTarget, 0) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
StackFrame* frame = iterator.NextFrame();
ASSERT(frame != NULL);
@@ -1623,6 +1587,9 @@
alloc_stub.EntryPoint());
}
arguments.SetReturn(alloc_stub);
+#else
+ UNREACHABLE();
+#endif
}
@@ -1695,7 +1662,7 @@
}
}
-
+#if !defined(DART_PRECOMPILED_RUNTIME)
static void CopySavedRegisters(uword saved_registers_address,
fpu_register_t** fpu_registers,
intptr_t** cpu_registers) {
@@ -1720,6 +1687,7 @@
}
*cpu_registers = cpu_registers_copy;
}
+#endif
// Copies saved registers and caller's frame into temporary buffers.
@@ -1731,6 +1699,7 @@
2,
uword saved_registers_address,
uword is_lazy_deopt) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
StackZone zone(thread);
@@ -1777,6 +1746,10 @@
// Stack size (FP - SP) in bytes.
return deopt_context->DestStackAdjustment() * kWordSize;
+#else
+ UNREACHABLE();
+ return 0;
+#endif // !DART_PRECOMPILED_RUNTIME
}
END_LEAF_RUNTIME_ENTRY
@@ -1784,6 +1757,7 @@
// The stack has been adjusted to fit all values for unoptimized frame.
// Fill the unoptimized frame.
DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, 1, uword last_fp) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
StackZone zone(thread);
@@ -1818,6 +1792,9 @@
caller_frame->sp() - (kDartFrameFixedSize * kWordSize));
deopt_context->set_dest_frame(start);
deopt_context->FillDestFrame();
+#else
+ UNREACHABLE();
+#endif // !DART_PRECOMPILED_RUNTIME
}
END_LEAF_RUNTIME_ENTRY
@@ -1828,6 +1805,7 @@
// under return address to keep them discoverable by GC that can occur during
// materialization phase.
DEFINE_RUNTIME_ENTRY(DeoptimizeMaterialize, 0) {
+#if !defined(DART_PRECOMPILED_RUNTIME)
DeoptContext* deopt_context = isolate->deopt_context();
intptr_t deopt_arg_count = deopt_context->MaterializeDeferredObjects();
isolate->set_deopt_context(NULL);
@@ -1836,6 +1814,9 @@
// Return value tells deoptimization stub to remove the given number of bytes
// from the stack.
arguments.SetReturn(Smi::Handle(Smi::New(deopt_arg_count * kWordSize)));
+#else
+ UNREACHABLE();
+#endif // !DART_PRECOMPILED_RUNTIME
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 39c8846..dd2ddee 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -24,10 +24,10 @@
#include "vm/flow_graph_builder.h"
#include "vm/flow_graph_compiler.h"
#include "vm/flow_graph_inliner.h"
-#include "vm/flow_graph_optimizer.h"
#include "vm/flow_graph_range_analysis.h"
#include "vm/flow_graph_type_propagator.h"
#include "vm/il_printer.h"
+#include "vm/jit_optimizer.h"
#include "vm/longjump.h"
#include "vm/object.h"
#include "vm/object_store.h"
@@ -59,6 +59,7 @@
"Print the IR flow graph when optimizing.");
DEFINE_FLAG(bool, print_ic_data_map, false,
"Print the deopt-id to ICData map in optimizing compiler.");
+DEFINE_FLAG(bool, print_code_source_map, false, "Print code source map.");
DEFINE_FLAG(bool, range_analysis, true, "Enable range analysis");
DEFINE_FLAG(bool, reorder_basic_blocks, true, "Enable basic-block reordering.");
DEFINE_FLAG(bool, trace_compiler, false, "Trace compiler operations.");
@@ -69,12 +70,9 @@
DEFINE_FLAG(bool, verify_compiler, false,
"Enable compiler verification assertions");
-DECLARE_FLAG(bool, background_compilation);
DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
-DECLARE_FLAG(bool, load_deferred_eagerly);
DECLARE_FLAG(bool, trace_failed_optimization_attempts);
DECLARE_FLAG(bool, trace_irregexp);
-DECLARE_FLAG(bool, precompilation);
#ifndef DART_PRECOMPILED_RUNTIME
@@ -420,7 +418,7 @@
Assembler* assembler,
FlowGraphCompiler* graph_compiler,
FlowGraph* flow_graph) {
- ASSERT(!FLAG_precompilation);
+ ASSERT(!FLAG_precompiled_mode);
const Function& function = parsed_function()->function();
Zone* const zone = thread()->zone();
@@ -460,6 +458,12 @@
caller_inlining_id_map_array.Length() * sizeof(uword));
code.SetInlinedCallerIdMap(caller_inlining_id_map_array);
+ const Array& inlined_id_to_token_pos =
+ Array::Handle(zone, graph_compiler->InliningIdToTokenPos());
+ INC_STAT(thread(), total_code_size,
+ inlined_id_to_token_pos.Length() * sizeof(uword));
+ code.SetInlinedIdToTokenPos(inlined_id_to_token_pos);
+
graph_compiler->FinalizePcDescriptors(code);
code.set_deopt_info_array(deopt_info_array);
@@ -468,6 +472,18 @@
graph_compiler->FinalizeExceptionHandlers(code);
graph_compiler->FinalizeStaticCallTargetsTable(code);
+NOT_IN_PRODUCT(
+ // Set the code source map after setting the inlined information because
+ // we use the inlined information when printing.
+ const CodeSourceMap& code_source_map =
+ CodeSourceMap::Handle(
+ zone,
+ graph_compiler->code_source_map_builder()->Finalize());
+ code.set_code_source_map(code_source_map);
+ if (FLAG_print_code_source_map) {
+ CodeSourceMap::Dump(code_source_map, code, function);
+ }
+);
if (optimized()) {
// Installs code while at safepoint.
if (thread()->IsMutatorThread()) {
@@ -556,7 +572,7 @@
// If optimized_result_code is not NULL then it is caller's responsibility
// to install code.
bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
- ASSERT(!FLAG_precompilation);
+ ASSERT(!FLAG_precompiled_mode);
const Function& function = parsed_function()->function();
if (optimized() && !function.IsOptimizable()) {
return false;
@@ -673,6 +689,8 @@
// Maps inline_id_to_function[inline_id] -> function. Top scope
// function has inline_id 0. The map is populated by the inliner.
GrowableArray<const Function*> inline_id_to_function;
+ // Token position where inlining occured.
+ GrowableArray<TokenPosition> inline_id_to_token_pos;
// For a given inlining-id(index) specifies the caller's inlining-id.
GrowableArray<intptr_t> caller_inline_id;
// Collect all instance fields that are loaded in the graph and
@@ -683,13 +701,13 @@
compiler_timeline,
"OptimizationPasses"));
inline_id_to_function.Add(&function);
+ inline_id_to_token_pos.Add(function.token_pos());
// Top scope function has no caller (-1).
caller_inline_id.Add(-1);
CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer);
- FlowGraphOptimizer optimizer(flow_graph,
- use_speculative_inlining,
- NULL);
+ JitOptimizer optimizer(flow_graph);
+
optimizer.ApplyICData();
DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -716,6 +734,7 @@
FlowGraphInliner inliner(flow_graph,
&inline_id_to_function,
+ &inline_id_to_token_pos,
&caller_inline_id,
use_speculative_inlining,
NULL);
@@ -986,6 +1005,7 @@
FlowGraphCompiler graph_compiler(&assembler, flow_graph,
*parsed_function(), optimized(),
inline_id_to_function,
+ inline_id_to_token_pos,
caller_inline_id);
{
CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer);
@@ -1087,7 +1107,7 @@
const Function& function,
bool optimized,
intptr_t osr_id) {
- ASSERT(!FLAG_precompilation);
+ ASSERT(!FLAG_precompiled_mode);
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
Thread* const thread = Thread::Current();
@@ -1201,7 +1221,7 @@
RawError* Compiler::CompileFunction(Thread* thread,
const Function& function) {
#ifdef DART_PRECOMPILER
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
return Precompiler::CompileFunction(thread, function);
}
#endif
@@ -1268,11 +1288,8 @@
// Optimization must happen in non-mutator/Dart thread if background
// compilation is on. OSR compilation still occurs in the main thread.
- // TODO(Srdjan): Remove assert allowance for regular expression functions
- // once they can be compiled in background.
ASSERT((osr_id != kNoOSRDeoptId) || !FLAG_background_compilation ||
- !thread->IsMutatorThread() ||
- function.IsIrregexpFunction());
+ !thread->IsMutatorThread());
CompilationPipeline* pipeline =
CompilationPipeline::New(thread->zone(), function);
return CompileFunctionHelper(pipeline,
@@ -1361,7 +1378,7 @@
RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
#ifdef DART_PRECOMPILER
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
return Precompiler::EvaluateStaticInitializer(field);
}
#endif
@@ -1405,7 +1422,7 @@
RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
#ifdef DART_PRECOMPILER
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
return Precompiler::ExecuteOnce(fragment);
}
#endif
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index f1b916c..8dd7c2f 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -15,8 +15,6 @@
namespace dart {
-DECLARE_FLAG(bool, background_compilation);
-
VM_TEST_CASE(CompileScript) {
const char* kScriptChars =
"class A {\n"
@@ -98,7 +96,10 @@
CompilerTest::TestCompileFunction(func);
EXPECT(func.HasCode());
EXPECT(!func.HasOptimizedCode());
+#if !defined(PRODUCT)
+ // Constant in product mode.
FLAG_background_compilation = true;
+#endif
BackgroundCompiler::EnsureInit(thread);
Isolate* isolate = thread->isolate();
ASSERT(isolate->background_compiler() != NULL);
@@ -122,7 +123,6 @@
" return unOpt();\n"
"}\n";
- // Isolate::Current()->flags().set_checked(true);
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
EXPECT_VALID(result);
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 695c23c..fa21b0f 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -19,8 +19,6 @@
DEFINE_FLAG(bool, trace_constant_propagation, false,
"Print constant propagation and useless code elimination.");
-DECLARE_FLAG(bool, fields_may_be_reset);
-
// Quick access to the current zone and isolate.
#define I (isolate())
#define Z (graph_->zone())
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index 913a69c..7a0a18b 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -330,6 +330,8 @@
SystemMask = 0xffc00000,
SystemFixed = CompareBranchFixed | B31 | B30 | B24,
HINT = SystemFixed | B17 | B16 | B13 | B4 | B3 | B2 | B1 | B0,
+ CLREX = SystemFixed | B17 | B16 | B13 | B12 | B11 | B10 | B9 | B8 |
+ B6 | B4 | B3 | B2 | B1 | B0,
};
// C3.2.5
@@ -364,6 +366,14 @@
LDRpc = LoadRegLiteralFixed,
};
+// C3.3.6
+enum LoadStoreExclusiveOp {
+ LoadStoreExclusiveMask = 0x3f000000,
+ LoadStoreExclusiveFixed = B27,
+ LDXR = LoadStoreExclusiveFixed | B22,
+ STXR = LoadStoreExclusiveFixed,
+};
+
// C3.3.7-10
enum LoadStoreRegOp {
LoadStoreRegMask = 0x3a000000,
@@ -616,6 +626,7 @@
_V(LoadStoreReg) \
_V(LoadStoreRegPair) \
_V(LoadRegLiteral) \
+_V(LoadStoreExclusive) \
_V(AddSubImm) \
_V(LogicalImm) \
_V(MoveWide) \
@@ -692,6 +703,8 @@
kRtBits = 5,
kRt2Shift = 10,
kRt2Bits = 5,
+ kRsShift = 16,
+ kRsBits = 5,
// V Registers.
kVdShift = 0,
@@ -892,6 +905,8 @@
Bits(kRtShift, kRtBits)); }
inline Register Rt2Field() const { return static_cast<Register>(
Bits(kRt2Shift, kRt2Bits)); }
+ inline Register RsField() const { return static_cast<Register>(
+ Bits(kRsShift, kRsBits)); }
inline VRegister VdField() const { return static_cast<VRegister>(
Bits(kVdShift, kVdBits)); }
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 895d6b1..bef0ebb 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -131,9 +131,8 @@
const bool precompiled = instructions_snapshot != NULL;
// Setup default flags for the VM isolate.
- Isolate::Flags vm_flags;
Dart_IsolateFlags api_flags;
- vm_flags.CopyTo(&api_flags);
+ Isolate::FlagsInitialize(&api_flags);
vm_isolate_ = Isolate::Init("vm-isolate", api_flags, is_vm_isolate);
start_time_ = vm_isolate_->start_time();
vm_isolate_->set_compilation_allowed(!precompiled);
@@ -454,11 +453,14 @@
StubCode::Init(I);
}
+#if !defined(DART_PRECOMPILED_RUNTIME)
// When running precompiled, the megamorphic miss function/code comes from the
// snapshot.
if (!Dart::IsRunningPrecompiledCode()) {
MegamorphicCacheTable::InitMissHandler(I);
}
+#endif
+
const Code& miss_code =
Code::Handle(I->object_store()->megamorphic_miss_code());
I->set_ic_miss_code(miss_code);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 4c27091..4c6fd00 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -51,8 +51,6 @@
#define Z (T->zone())
-DECLARE_FLAG(bool, load_deferred_eagerly);
-DECLARE_FLAG(bool, precompilation);
DECLARE_FLAG(bool, print_class_table);
DECLARE_FLAG(bool, verify_handles);
#if defined(DART_NO_SNAPSHOT)
@@ -1147,7 +1145,7 @@
Dart_FileCloseCallback file_close,
Dart_EntropySource entropy_source,
Dart_GetVMServiceAssetsArchive get_service_assets) {
- if ((instructions_snapshot != NULL) && !FLAG_precompilation) {
+ if ((instructions_snapshot != NULL) && !FLAG_precompiled_mode) {
return strdup("Flag --precompilation was not specified.");
}
if (interrupt != NULL) {
@@ -1242,8 +1240,7 @@
// Setup default flags in case none were passed.
Dart_IsolateFlags api_flags;
if (flags == NULL) {
- Isolate::Flags vm_flags;
- vm_flags.CopyTo(&api_flags);
+ Isolate::FlagsInitialize(&api_flags);
flags = &api_flags;
}
Isolate* I = Dart::CreateIsolate(isolate_name, *flags);
@@ -1613,12 +1610,12 @@
CHECK_API_SCOPE(T);
CHECK_CALLBACK_STATE(T);
API_TIMELINE_BEGIN_END;
- Monitor monitor;
- MonitorLocker ml(&monitor);
+ // The message handler run loop does not expect to have a current isolate
+ // so we exit the isolate here and enter it again after the runloop is done.
+ ::Dart_ExitIsolate();
{
- // The message handler run loop does not expect to have a current isolate
- // so we exit the isolate here and enter it again after the runloop is done.
- Dart_ExitIsolate();
+ Monitor monitor;
+ MonitorLocker ml(&monitor);
RunLoopData data;
data.monitor = &monitor;
data.done = false;
@@ -1628,8 +1625,8 @@
while (!data.done) {
ml.Wait();
}
- ::Dart_EnterIsolate(Api::CastIsolate(I));
}
+ ::Dart_EnterIsolate(Api::CastIsolate(I));
if (T->sticky_error() != Object::null()) {
Dart_Handle error = Api::NewHandle(T, T->sticky_error());
T->clear_sticky_error();
@@ -4321,7 +4318,7 @@
getter = lib.LookupFunctionAllowPrivate(getter_name);
} else if (!field.IsNull() && field.IsUninitialized()) {
// A field was found. Check for a getter in the field's owner classs.
- const Class& cls = Class::Handle(Z, field.owner());
+ const Class& cls = Class::Handle(Z, field.Owner());
const String& getter_name = String::Handle(Z,
Field::GetterName(field_name));
getter = cls.LookupStaticFunctionAllowPrivate(getter_name);
@@ -4967,6 +4964,44 @@
// --- Environment ---
+RawString* Api::GetEnvironmentValue(Thread* thread, const String& name) {
+ String& result = String::Handle(CallEnvironmentCallback(thread, name));
+ if (result.IsNull()) {
+ // Every 'dart:X' library introduces an environment variable
+ // 'dart.library.X' that is set to 'true'.
+ // We just need to make sure to hide private libraries (starting with
+ // "_", and the mirrors library, if it is not supported.
+
+ if (!FLAG_enable_mirrors && name.Equals(Symbols::DartLibraryMirrors())) {
+ return Symbols::False().raw();
+ }
+
+ const String& prefix = Symbols::DartLibrary();
+ if (name.StartsWith(prefix)) {
+ const String& library_name =
+ String::Handle(String::SubString(name, prefix.Length()));
+
+ // Private libraries (starting with "_") are not exposed to the user.
+ if (!library_name.IsNull() && library_name.CharAt(0) != '_') {
+ const String& dart_library_name =
+ String::Handle(String::Concat(Symbols::DartScheme(), library_name));
+ const Library& library =
+ Library::Handle(Library::LookupLibrary(dart_library_name));
+ if (!library.IsNull()) {
+ return Symbols::True().raw();
+ }
+ }
+ }
+ // Check for default VM provided values. If it was not overriden on the
+ // command line.
+ if (Symbols::DartIsVM().Equals(name)) {
+ return Symbols::True().raw();
+ }
+ }
+ return result.raw();
+}
+
+
RawString* Api::CallEnvironmentCallback(Thread* thread, const String& name) {
Isolate* isolate = thread->isolate();
Dart_EnvironmentCallback callback = isolate->environment_callback();
@@ -4988,15 +5023,6 @@
String::Handle(String::New("Illegal environment value")));
}
}
- if (result.IsNull()) {
- // TODO(iposva): Determine whether builtin values can be overriden by the
- // embedder.
- // Check for default VM provided values. If it was not overriden on the
- // command line.
- if (Symbols::DartIsVM().Equals(name)) {
- return Symbols::True().raw();
- }
- }
return result.raw();
}
@@ -6100,7 +6126,7 @@
bool reset_fields) {
API_TIMELINE_BEGIN_END;
DARTSCOPE(Thread::Current());
- if (!FLAG_precompilation) {
+ if (!FLAG_precompiled_mode) {
return Dart_NewApiError("Flag --precompilation was not specified.");
}
Dart_Handle result = Api::CheckAndFinalizePendingClasses(T);
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 9820417..67c0257 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -260,12 +260,13 @@
static void SetWeakHandleReturnValue(NativeArguments* args,
Dart_WeakPersistentHandle retval);
- static RawString* CallEnvironmentCallback(Thread* thread,
- const String& name);
+ static RawString* GetEnvironmentValue(Thread* thread, const String& name);
private:
static Dart_Handle InitNewHandle(Thread* thread, RawObject* raw);
+ static RawString* CallEnvironmentCallback(Thread* thread, const String& name);
+
// Thread local key used by the API. Currently holds the current
// ApiNativeScope if any.
static ThreadLocalKey api_native_key_;
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 8e7d698..91043ed 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -19,7 +19,6 @@
namespace dart {
-DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, verify_acquired_data);
DECLARE_FLAG(bool, ignore_patch_signature_mismatch);
@@ -1906,6 +1905,9 @@
}
+#ifndef PRODUCT
+
+
static const intptr_t kOptExtLength = 16;
static int8_t opt_data[kOptExtLength] = { 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08,
@@ -1974,6 +1976,9 @@
}
+#endif // !PRODUCT
+
+
static void TestTypedDataDirectAccess() {
Dart_Handle str = Dart_NewStringFromCString("junk");
Dart_Handle byte_array = Dart_NewTypedData(Dart_TypedData_kUint8, 10);
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index 3c7d316..b510377 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -213,6 +213,10 @@
return reinterpret_cast<Dart_WeakPersistentHandle>(this);
}
+ intptr_t external_size() const {
+ return ExternalSizeBits::decode(external_data_);
+ }
+
void SetExternalSize(intptr_t size, Isolate* isolate) {
ASSERT(size >= 0);
set_external_size(Utils::RoundUp(size, kObjectAlignment));
@@ -305,10 +309,6 @@
callback_ = callback;
}
- intptr_t external_size() const {
- return ExternalSizeBits::decode(external_data_);
- }
-
void set_external_size(intptr_t size) {
ASSERT(ExternalSizeBits::is_valid(size));
external_data_ = ExternalSizeBits::update(size, external_data_);
@@ -445,6 +445,13 @@
kOffsetOfRawPtrInPersistentHandle>::VisitObjectPointers(visitor);
}
+ // Visit all the handles.
+ void Visit(HandleVisitor* visitor) {
+ Handles<kPersistentHandleSizeInWords,
+ kPersistentHandlesPerChunk,
+ kOffsetOfRawPtrInPersistentHandle>::Visit(visitor);
+ }
+
// Allocates a persistent handle, these have to be destroyed explicitly
// by calling FreeHandle.
PersistentHandle* AllocateHandle() {
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 06e7880..dda7b34 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -46,7 +46,6 @@
DECLARE_FLAG(bool, trace_isolates);
DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
-DECLARE_FLAG(bool, precompilation);
#ifndef PRODUCT
@@ -330,7 +329,9 @@
// If we were paused, notify the service that we have resumed.
const Error& error =
Error::Handle(Thread::Current()->sticky_error());
- ASSERT(error.IsNull() || error.IsUnwindError());
+ ASSERT(error.IsNull() ||
+ error.IsUnwindError() ||
+ error.IsUnhandledException());
// Only send a resume event when the isolate is not unwinding.
if (!error.IsUnwindError()) {
@@ -1056,7 +1057,7 @@
VariableAt(i, &name, &ignore, &ignore, &value);
if (!name.Equals(Symbols::This())) {
if (IsPrivateVariableName(name)) {
- name = String::IdentifierPrettyName(name);
+ name = String::ScrubName(name);
}
param_names.Add(name);
param_values.Add(value);
@@ -1129,7 +1130,7 @@
if (var_name.raw() != Symbols::AsyncOperation().raw()) {
JSONObject jsvar(&jsvars);
jsvar.AddProperty("type", "BoundVariable");
- var_name = String::IdentifierPrettyName(var_name);
+ var_name = String::ScrubName(var_name);
jsvar.AddProperty("name", var_name.ToCString());
jsvar.AddProperty("value", var_value, !full);
// TODO(turnidge): Do we really want to provide this on every
@@ -1518,7 +1519,7 @@
}
if (frame->IsDartFrame()) {
code = frame->LookupDartCode();
- if (code.is_optimized() && !FLAG_precompilation) {
+ if (code.is_optimized() && !FLAG_precompiled_mode) {
deopt_frame = DeoptimizeToArray(thread, frame, code);
for (InlinedFunctionsIterator it(code, frame->pc());
!it.Done();
@@ -1636,7 +1637,7 @@
bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace,
- const Instance& exc) {
+ const Instance& exception) {
if (exc_pause_info_ == kNoPauseOnExceptions) {
return false;
}
@@ -1644,7 +1645,7 @@
return true;
}
ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions);
- ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exc);
+ ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exception);
if (handler_frame == NULL) {
// Did not find an exception handler that catches this exception.
// Note that this check is not precise, since we can't check
@@ -1673,8 +1674,9 @@
}
DebuggerEvent event(isolate_, DebuggerEvent::kExceptionThrown);
event.set_exception(&exc);
- ASSERT(stack_trace->Length() > 0);
- event.set_top_frame(stack_trace->FrameAt(0));
+ if (stack_trace->Length() > 0) {
+ event.set_top_frame(stack_trace->FrameAt(0));
+ }
ASSERT(stack_trace_ == NULL);
stack_trace_ = stack_trace;
Pause(&event);
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 85faf11..0be2d29 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -11,9 +11,6 @@
namespace dart {
-DECLARE_FLAG(bool, background_compilation);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, use_osr);
DECLARE_FLAG(bool, trace_shutdown);
#ifndef PRODUCT
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index a926fdf..1aa11b7 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -143,18 +143,21 @@
TimelineStream* compiler_stream = isolate->GetCompilerStream();
ASSERT(compiler_stream != NULL);
if (compiler_stream->Enabled()) {
+ // Allocate all Dart objects needed before calling StartEvent,
+ // which blocks safe points until Complete is called.
const Code& code = Code::Handle(zone(), code_);
const Function& function = Function::Handle(zone(), code.function());
- const char* function_name = function.QualifiedUserVisibleNameCString();
+ const String& function_name =
+ String::Handle(zone(), function.QualifiedScrubbedName());
const char* reason = DeoptReasonToCString(deopt_reason());
- int counter = function.deoptimization_counter();
+ const int counter = function.deoptimization_counter();
TimelineEvent* timeline_event = compiler_stream->StartEvent();
if (timeline_event != NULL) {
timeline_event->Duration("Deoptimize",
deopt_start_micros_,
OS::GetCurrentMonotonicMicros());
timeline_event->SetNumArguments(3);
- timeline_event->CopyArgument(0, "function", function_name);
+ timeline_event->CopyArgument(0, "function", function_name.ToCString());
timeline_event->CopyArgument(1, "reason", reason);
timeline_event->FormatArgument(2, "deoptimizationCount", "%d", counter);
timeline_event->Complete();
diff --git a/runtime/vm/disassembler_arm64.cc b/runtime/vm/disassembler_arm64.cc
index bf07877..a238641 100644
--- a/runtime/vm/disassembler_arm64.cc
+++ b/runtime/vm/disassembler_arm64.cc
@@ -334,6 +334,10 @@
int reg = instr->RaField();
PrintRegister(reg, R31IsZR);
return 2;
+ } else if (format[1] == 's') { // 'rs: Rs register
+ int reg = instr->RsField();
+ PrintRegister(reg, R31IsZR);
+ return 2;
}
UNREACHABLE();
return -1;
@@ -742,6 +746,26 @@
}
+void ARM64Decoder::DecodeLoadStoreExclusive(Instr* instr) {
+ if ((instr->Bit(23) != 0) ||
+ (instr->Bit(21) != 0) ||
+ (instr->Bit(15) != 0)) {
+ Unknown(instr);
+ }
+ const int32_t size = instr->Bits(30, 2);
+ if (size != 3) {
+ Unknown(instr);
+ }
+
+ const bool is_load = instr->Bit(22) == 1;
+ if (is_load) {
+ Format(instr, "ldxr 'rt, 'rn");
+ } else {
+ Format(instr, "stxr 'rs, 'rt, 'rn");
+ }
+}
+
+
void ARM64Decoder::DecodeAddSubImm(Instr* instr) {
switch (instr->Bit(30)) {
case 0: {
@@ -849,6 +873,11 @@
void ARM64Decoder::DecodeSystem(Instr* instr) {
+ if (instr->InstructionBits() == CLREX) {
+ Format(instr, "clrex");
+ return;
+ }
+
if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) &&
(instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) &&
(instr->Bit(21) == 0)) {
@@ -950,6 +979,8 @@
DecodeLoadStoreRegPair(instr);
} else if (instr->IsLoadRegLiteralOp()) {
DecodeLoadRegLiteral(instr);
+ } else if (instr->IsLoadStoreExclusiveOp()) {
+ DecodeLoadStoreExclusive(instr);
} else {
Unknown(instr);
}
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index a6195fb..b9e0987 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -712,6 +712,10 @@
Format(instr, "lui 'rt, 'immu");
break;
}
+ case LL: {
+ Format(instr, "ll 'rt, 'imms('rs)");
+ break;
+ }
case LW: {
Format(instr, "lw 'rt, 'imms('rs)");
break;
@@ -728,6 +732,10 @@
Format(instr, "sb 'rt, 'imms('rs)");
break;
}
+ case SC: {
+ Format(instr, "sc 'rt, 'imms('rs)");
+ break;
+ }
case SLTI: {
Format(instr, "slti 'rt, 'rs, 'imms");
break;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 800a802..84ca377 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -64,7 +64,8 @@
public:
explicit PreallocatedStacktraceBuilder(const Instance& stacktrace)
: stacktrace_(Stacktrace::Cast(stacktrace)),
- cur_index_(0) {
+ cur_index_(0),
+ dropped_frames_(0) {
ASSERT(stacktrace_.raw() ==
Isolate::Current()->object_store()->preallocated_stack_trace());
}
@@ -77,6 +78,7 @@
const Stacktrace& stacktrace_;
intptr_t cur_index_;
+ intptr_t dropped_frames_;
DISALLOW_COPY_AND_ASSIGN(PreallocatedStacktraceBuilder);
};
@@ -90,11 +92,18 @@
Smi& frame_offset = Smi::Handle();
intptr_t start = Stacktrace::kPreallocatedStackdepth - (kNumTopframes - 1);
intptr_t null_slot = start - 2;
+ // We are going to drop one frame.
+ dropped_frames_++;
// Add an empty slot to indicate the overflow so that the toString
// method can account for the overflow.
if (stacktrace_.FunctionAtFrame(null_slot) != Function::null()) {
stacktrace_.SetCodeAtFrame(null_slot, frame_code);
+ // We drop an extra frame here too.
+ dropped_frames_++;
}
+ // Encode the number of dropped frames into the pc offset.
+ frame_offset ^= Smi::New(dropped_frames_);
+ stacktrace_.SetPcOffsetAtFrame(null_slot, frame_offset);
// Move frames one slot down so that we can accomodate the new frame.
for (intptr_t i = start; i < Stacktrace::kPreallocatedStackdepth; i++) {
intptr_t prev = (i - 1);
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 4fdfb7b..35a7756 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -21,8 +21,22 @@
// R(name, product_value, type, default_value, comment)
// C(name, precompiled_value, product_value, type, default_value, comment)
#define FLAG_LIST(P, R, D, C) \
+C(allow_absolute_addresses, false, true, bool, true, \
+ "Allow embedding absolute addresses in generated code.") \
+C(always_megamorphic_calls, true, false, bool, false, \
+ "Instance call always as megamorphic.") \
+C(background_compilation, false, false, bool, false, \
+ "Run optimizing compilation in background") \
+C(collect_code, false, true, bool, true, \
+ "Attempt to GC infrequently used code.") \
+C(collect_dynamic_function_names, true, false, bool, false, \
+ "Collects all dynamic function names to identify unique targets") \
R(dedup_instructions, true, bool, false, \
"Canonicalize instructions when precompiling.") \
+C(deoptimize_alot, false, false, bool, false, \
+ "Deoptimizes we are about to return to Dart code from native entries.") \
+C(deoptimize_every, 0, 0, int, 0, \
+ "Deoptimize on every N stack overflow checks") \
R(disable_alloc_stubs_after_gc, false, bool, false, \
"Stress testing flag.") \
R(disassemble, false, bool, false, \
@@ -31,16 +45,38 @@
"Disassemble optimized code.") \
R(dump_symbol_stats, false, bool, false, \
"Dump symbol table statistics") \
-R(enable_mirrors, false, bool, true, \
+C(emit_edge_counters, false, true, bool, true, \
+ "Emit edge counters") \
+R(enable_asserts, false, bool, false, \
+ "Enable assert statements.") \
+C(enable_mirrors, false, false, bool, true, \
"Disable to make importing dart:mirrors an error.") \
+R(enable_type_checks, false, bool, false, \
+ "Enable type checks.") \
+R(error_on_bad_override, false, bool, false, \
+ "Report error for bad overrides.") \
+R(error_on_bad_type, false, bool, false, \
+ "Report error for malformed types.") \
+C(fields_may_be_reset, true, false, bool, false, \
+ "Don't optimize away static field initialization") \
+C(force_clone_compiler_objects, false, false, bool, false, \
+ "Force cloning of objects needed in compiler (ICData and Field).") \
R(gc_at_alloc, false, bool, false, \
"GC at every allocation.") \
P(getter_setter_ratio, int, 13, \
"Ratio of getter/setter usage used for double field unboxing heuristics") \
P(guess_icdata_cid, bool, true, \
"Artificially create type feedback for arithmetic etc. operations") \
+C(ic_range_profiling, false, true, bool, true, \
+ "Generate special IC stubs collecting range information ") \
+C(interpret_irregexp, true, false, bool, false, \
+ "Use irregexp bytecode interpreter") \
C(lazy_dispatchers, false, true, bool, true, \
"Generate dispatchers lazily") \
+C(link_natives_lazily, true, false, bool, false, \
+ "Link native calls lazily") \
+C(load_deferred_eagerly, true, true, bool, false, \
+ "Load deferred libraries eagerly.") \
P(max_polymorphic_checks, int, 4, \
"Maximum number of polymorphic check, otherwise it is megamorphic.") \
P(max_equality_polymorphic_checks, int, 32, \
@@ -49,14 +85,20 @@
"Merge sin/cos into sincos") \
P(new_gen_ext_limit, int, 64, \
"maximum total external size (MB) in new gen before triggering GC") \
+C(optimization_counter_threshold, -1, 30000, int, 30000, \
+ "Function's usage-counter value before it is optimized, -1 means never") \
C(polymorphic_with_deopt, false, true, bool, true, \
- "Polymorphic calls with deoptimization / megamorphic call") \
+ "Polymorphic calls with deoptimization / megamorphic call") \
+C(precompiled_mode, true, false, bool, false, \
+ "Precompilation compiler/runtime mode") \
R(pretenure_all, false, bool, false, \
"Global pretenuring (for testing).") \
P(pretenure_interval, int, 10, \
"Back off pretenuring after this many cycles.") \
P(pretenure_threshold, int, 98, \
"Trigger pretenuring when this many percent are promoted.") \
+C(print_stop_message, false, false, bool, false, \
+ "Print stop message.") \
R(profiler, false, bool, true, \
"Enable the profiler.") \
R(support_ast_printer, false, bool, true, \
@@ -89,6 +131,10 @@
"Optimize left shift to truncate if possible") \
C(use_cha_deopt, false, true, bool, true, \
"Use class hierarchy analysis even if it can cause deoptimization.") \
+C(use_field_guards, false, true, bool, true, \
+ "Use field guards and track field types") \
+C(use_osr, false, true, bool, true, \
+ "Use OSR") \
P(verbose_gc, bool, false, \
"Enables verbose GC.") \
P(verbose_gc_hdr, int, 40, \
@@ -98,5 +144,4 @@
R(verify_before_gc, false, bool, false, \
"Enables heap verification before GC.") \
-
#endif // VM_FLAG_LIST_H_
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index ee7d702..cb76c91 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -80,6 +80,7 @@
#undef PRODUCT_FLAG_MARCO
#undef PRECOMPILE_FLAG_MARCO
+
bool Flags::initialized_ = false;
// List of registered flags.
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index b7b59cd..3296e09 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -19,7 +19,6 @@
DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass.");
#endif
DEFINE_FLAG(bool, prune_dead_locals, true, "optimize dead locals away");
-DECLARE_FLAG(bool, emit_edge_counters);
DECLARE_FLAG(bool, reorder_basic_blocks);
DECLARE_FLAG(bool, verify_compiler);
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 736efc6..c5460be 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -39,9 +39,7 @@
DEFINE_FLAG(bool, trace_type_check_elimination, false,
"Trace type check elimination at compile time.");
-DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, profile_vm);
-DECLARE_FLAG(bool, use_field_guards);
// Quick access to the locally defined zone() method.
#define Z (zone())
@@ -995,7 +993,7 @@
void TestGraphVisitor::ReturnValue(Value* value) {
Isolate* isolate = Isolate::Current();
- if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+ if (isolate->type_checks() || isolate->asserts()) {
value = Bind(new(Z) AssertBooleanInstr(condition_token_pos(), value));
}
Value* constant_true = Bind(new(Z) ConstantInstr(Bool::True()));
@@ -1030,7 +1028,7 @@
false)); // No number check.
} else {
branch = new(Z) BranchInstr(comp);
- branch->set_is_checked(Isolate::Current()->flags().type_checks());
+ branch->set_is_checked(Isolate::Current()->type_checks());
}
AddInstruction(branch);
CloseFragment();
@@ -1040,7 +1038,7 @@
void TestGraphVisitor::MergeBranchWithNegate(BooleanNegateInstr* neg) {
- ASSERT(!Isolate::Current()->flags().type_checks());
+ ASSERT(!Isolate::Current()->type_checks());
Value* constant_true = Bind(new(Z) ConstantInstr(Bool::True()));
StrictCompareInstr* comp =
new(Z) StrictCompareInstr(condition_token_pos(),
@@ -1062,7 +1060,7 @@
MergeBranchWithComparison(comp);
return;
}
- if (!Isolate::Current()->flags().type_checks()) {
+ if (!Isolate::Current()->type_checks()) {
BooleanNegateInstr* neg = definition->AsBooleanNegate();
if (neg != NULL) {
MergeBranchWithNegate(neg);
@@ -1155,7 +1153,7 @@
return_value = Bind(BuildLoadLocal(*temp, node->token_pos()));
}
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
const bool is_implicit_dynamic_getter =
(!function.is_static() &&
((function.kind() == RawFunction::kImplicitGetter) ||
@@ -1356,7 +1354,7 @@
node->left()->Visit(&for_left);
EffectGraphVisitor empty(owner());
Isolate* isolate = Isolate::Current();
- if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+ if (isolate->type_checks() || isolate->asserts()) {
ValueGraphVisitor for_right(owner());
node->right()->Visit(&for_right);
Value* right_value = for_right.value();
@@ -1423,7 +1421,7 @@
node->right()->Visit(&for_right);
Value* right_value = for_right.value();
Isolate* isolate = Isolate::Current();
- if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+ if (isolate->type_checks() || isolate->asserts()) {
right_value =
for_right.Bind(new(Z) AssertBooleanInstr(node->right()->token_pos(),
right_value));
@@ -1802,7 +1800,7 @@
owner()->ic_data_array());
if (node->kind() == Token::kNE) {
Isolate* isolate = Isolate::Current();
- if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+ if (isolate->type_checks() || isolate->asserts()) {
Value* value = Bind(result);
result = new(Z) AssertBooleanInstr(node->token_pos(), value);
}
@@ -1849,7 +1847,7 @@
Append(for_value);
Value* value = for_value.value();
Isolate* isolate = Isolate::Current();
- if (isolate->flags().type_checks() || isolate->flags().asserts()) {
+ if (isolate->type_checks() || isolate->asserts()) {
value =
Bind(new(Z) AssertBooleanInstr(node->operand()->token_pos(), value));
}
@@ -2772,7 +2770,8 @@
void EffectGraphVisitor::VisitInitStaticFieldNode(InitStaticFieldNode* node) {
- Value* field = Bind(new(Z) ConstantInstr(node->field()));
+ Value* field = Bind(new(Z) ConstantInstr(
+ Field::ZoneHandle(Z, node->field().Original())));
AddInstruction(new(Z) InitStaticFieldInstr(field, node->field()));
}
@@ -3644,7 +3643,7 @@
node->value()->Visit(&for_value);
Append(for_value);
Value* store_value = for_value.value();
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
store_value = BuildAssignableValue(node->value()->token_pos(),
store_value,
node->local().type(),
@@ -3688,7 +3687,7 @@
node->value()->Visit(&for_value);
Append(for_value);
Value* store_value = for_value.value();
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
const AbstractType& type =
AbstractType::ZoneHandle(Z, node->field().type());
const String& dst_name = String::ZoneHandle(Z, node->field().name());
@@ -3735,7 +3734,8 @@
Instance::ZoneHandle(Z, node->field().StaticValue()), token_pos);
return ReturnDefinition(result);
}
- Value* field_value = Bind(new(Z) ConstantInstr(node->field(), token_pos));
+ Value* field_value = Bind(new(Z) ConstantInstr(
+ Field::ZoneHandle(Z, node->field().Original()), token_pos));
LoadStaticFieldInstr* load =
new(Z) LoadStaticFieldInstr(field_value, token_pos);
ReturnDefinition(load);
@@ -4118,7 +4118,7 @@
}
}
- if (Isolate::Current()->flags().type_checks() && is_top_level_sequence) {
+ if (Isolate::Current()->type_checks() && is_top_level_sequence) {
const int num_params = function.NumParameters();
int pos = 0;
if (function.IsFactory() ||
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index d646909..5bc26af 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -30,10 +30,6 @@
namespace dart {
-DEFINE_FLAG(bool, allow_absolute_addresses, true,
- "Allow embedding absolute addresses in generated code.");
-DEFINE_FLAG(bool, always_megamorphic_calls, false,
- "Instance call always as megamorphic.");
DEFINE_FLAG(bool, enable_simd_inline, true,
"Enable inlining of SIMD related method calls.");
DEFINE_FLAG(int, min_optimization_counter_threshold, 5000,
@@ -45,28 +41,14 @@
"Inlining interval diagnostics");
DEFINE_FLAG(bool, use_megamorphic_stub, true, "Out of line megamorphic lookup");
-DECLARE_FLAG(bool, background_compilation);
DECLARE_FLAG(bool, code_comments);
-DECLARE_FLAG(bool, collect_dynamic_function_names);
-DECLARE_FLAG(bool, deoptimize_alot);
-DECLARE_FLAG(int, deoptimize_every);
DECLARE_FLAG(charp, deoptimize_filter);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(bool, fields_may_be_reset);
-DECLARE_FLAG(bool, ic_range_profiling);
DECLARE_FLAG(bool, intrinsify);
-DECLARE_FLAG(bool, load_deferred_eagerly);
-DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, propagate_ic_data);
DECLARE_FLAG(int, regexp_optimization_counter_threshold);
DECLARE_FLAG(int, reoptimization_counter_threshold);
DECLARE_FLAG(int, stacktrace_every);
DECLARE_FLAG(charp, stacktrace_filter);
-DECLARE_FLAG(bool, use_field_guards);
-DECLARE_FLAG(bool, use_osr);
-DECLARE_FLAG(bool, print_stop_message);
-DECLARE_FLAG(bool, interpret_irregexp);
-DECLARE_FLAG(bool, link_natives_lazily);
DECLARE_FLAG(bool, trace_compiler);
DECLARE_FLAG(int, inlining_hotness);
DECLARE_FLAG(int, inlining_size_threshold);
@@ -77,39 +59,19 @@
DECLARE_FLAG(int, inlining_constant_arguments_max_size_threshold);
DECLARE_FLAG(int, inlining_constant_arguments_min_size_threshold);
-bool FLAG_precompilation = false;
+#if !defined(DART_PRECOMPILED_RUNTIME)
static void PrecompilationModeHandler(bool value) {
if (value) {
#if defined(TARGET_ARCH_IA32)
FATAL("Precompilation not supported on IA32");
#endif
- FLAG_precompilation = true;
- FLAG_always_megamorphic_calls = true;
- FLAG_optimization_counter_threshold = -1;
- FLAG_use_field_guards = false;
- FLAG_use_osr = false;
- FLAG_emit_edge_counters = false;
-#ifndef PRODUCT
+#if defined(PRODUCT)
+ FATAL("dart_noopt not supported in product mode");
+#else
FLAG_support_debugger = false;
-#endif // !PRODUCT
- FLAG_ic_range_profiling = false;
- FLAG_collect_code = false;
- FLAG_load_deferred_eagerly = true;
- FLAG_deoptimize_alot = false; // Used in some tests.
- FLAG_deoptimize_every = 0; // Used in some tests.
- // Calling the PrintStopMessage stub is not supported in precompiled code
- // since it is done at places where no pool pointer is loaded.
- FLAG_print_stop_message = false;
- FLAG_interpret_irregexp = true;
-#ifndef PRODUCT
- FLAG_enable_mirrors = false;
-#endif // !PRODUCT
- FLAG_link_natives_lazily = true;
- FLAG_fields_may_be_reset = true;
- FLAG_allow_absolute_addresses = false;
-
+ // Flags affecting compilation only:
// There is no counter feedback in precompilation, so ignore the counter
// when making inlining decisions.
FLAG_inlining_hotness = 0;
@@ -120,39 +82,66 @@
FLAG_inlining_callee_size_threshold = 20;
FLAG_inlining_depth_threshold = 2;
FLAG_inlining_caller_size_threshold = 1000;
-
FLAG_inlining_constant_arguments_max_size_threshold = 100;
FLAG_inlining_constant_arguments_min_size_threshold = 30;
- // Background compilation relies on two-stage compilation pipeline,
- // while precompilation has only one.
+ FLAG_allow_absolute_addresses = false;
+ FLAG_always_megamorphic_calls = true;
FLAG_background_compilation = false;
+ FLAG_collect_code = false;
FLAG_collect_dynamic_function_names = true;
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(PRODUCT)
+ FLAG_deoptimize_alot = false; // Used in some tests.
+ FLAG_deoptimize_every = 0; // Used in some tests.
+ FLAG_emit_edge_counters = false;
+ FLAG_enable_mirrors = false;
+ FLAG_fields_may_be_reset = true;
+ FLAG_ic_range_profiling = false;
+ FLAG_interpret_irregexp = true;
FLAG_lazy_dispatchers = false;
+ FLAG_link_natives_lazily = true;
+ FLAG_load_deferred_eagerly = true;
+ FLAG_optimization_counter_threshold = -1;
FLAG_polymorphic_with_deopt = false;
- // Precompilation finalizes all classes and thus allows CHA optimizations.
- // Do not require CHA triggered deoptimization.
+ FLAG_precompiled_mode = true;
+ FLAG_print_stop_message = false;
FLAG_use_cha_deopt = false;
-#elif defined(DART_PRECOMPILED_RUNTIME)
- // Precompiled product and release mode.
- COMPILE_ASSERT(!FLAG_lazy_dispatchers);
- COMPILE_ASSERT(!FLAG_polymorphic_with_deopt);
- COMPILE_ASSERT(!FLAG_use_cha_deopt);
-#elif defined(PRODUCT)
- // Jit product and release mode.
- COMPILE_ASSERT(FLAG_lazy_dispatchers);
- COMPILE_ASSERT(FLAG_polymorphic_with_deopt);
- COMPILE_ASSERT(FLAG_use_cha_deopt);
-#endif
+ FLAG_use_field_guards = false;
+ FLAG_use_osr = false;
+#endif // PRODUCT
}
}
-
DEFINE_FLAG_HANDLER(PrecompilationModeHandler,
precompilation,
"Precompilation mode");
+#else // DART_PRECOMPILED_RUNTIME
+
+COMPILE_ASSERT(!FLAG_allow_absolute_addresses);
+COMPILE_ASSERT(!FLAG_background_compilation);
+COMPILE_ASSERT(!FLAG_collect_code);
+COMPILE_ASSERT(!FLAG_deoptimize_alot); // Used in some tests.
+COMPILE_ASSERT(!FLAG_emit_edge_counters);
+COMPILE_ASSERT(!FLAG_enable_mirrors);
+COMPILE_ASSERT(!FLAG_ic_range_profiling);
+COMPILE_ASSERT(!FLAG_lazy_dispatchers);
+COMPILE_ASSERT(!FLAG_polymorphic_with_deopt);
+COMPILE_ASSERT(!FLAG_print_stop_message);
+COMPILE_ASSERT(!FLAG_use_cha_deopt);
+COMPILE_ASSERT(!FLAG_use_field_guards);
+COMPILE_ASSERT(!FLAG_use_osr);
+COMPILE_ASSERT(FLAG_always_megamorphic_calls);
+COMPILE_ASSERT(FLAG_collect_dynamic_function_names);
+COMPILE_ASSERT(FLAG_deoptimize_every == 0); // Used in some tests.
+COMPILE_ASSERT(FLAG_fields_may_be_reset);
+COMPILE_ASSERT(FLAG_interpret_irregexp);
+COMPILE_ASSERT(FLAG_link_natives_lazily);
+COMPILE_ASSERT(FLAG_load_deferred_eagerly);
+COMPILE_ASSERT(FLAG_optimization_counter_threshold == -1);
+COMPILE_ASSERT(FLAG_precompiled_mode);
+
+#endif // DART_PRECOMPILED_RUNTIME
+
// Assign locations to incoming arguments, i.e., values pushed above spill slots
// with PushArgument. Recursively allocates from outermost to innermost
@@ -190,6 +179,7 @@
const ParsedFunction& parsed_function,
bool is_optimizing,
const GrowableArray<const Function*>& inline_id_to_function,
+ const GrowableArray<TokenPosition>& inline_id_to_token_pos,
const GrowableArray<intptr_t>& caller_inline_id)
: thread_(Thread::Current()),
zone_(Thread::Current()->zone()),
@@ -201,6 +191,8 @@
exception_handlers_list_(NULL),
pc_descriptors_list_(NULL),
stackmap_table_builder_(NULL),
+ code_source_map_builder_(NULL),
+ saved_code_size_(0),
block_info_(block_order_.length()),
deopt_infos_(),
static_calls_target_table_(),
@@ -227,6 +219,7 @@
edge_counters_array_(Array::ZoneHandle()),
inlined_code_intervals_(Array::ZoneHandle(Object::empty_array().raw())),
inline_id_to_function_(inline_id_to_function),
+ inline_id_to_token_pos_(inline_id_to_token_pos),
caller_inline_id_(caller_inline_id) {
ASSERT(flow_graph->parsed_function().function().raw() ==
parsed_function.function().raw());
@@ -285,9 +278,7 @@
block_info_.Clear();
// Conservative detection of leaf routines used to remove the stack check
// on function entry.
- bool is_leaf = !parsed_function().function().IsClosureFunction()
- && is_optimizing()
- && !flow_graph().IsCompiledForOsr();
+ bool is_leaf = is_optimizing() && !flow_graph().IsCompiledForOsr();
// Initialize block info and search optimized (non-OSR) code for calls
// indicating a non-leaf routine and calls without IC data indicating
// possible reoptimization.
@@ -488,12 +479,16 @@
// We collect intervals while generating code.
struct IntervalStruct {
- // 'start' and 'end' are pc-offsets.
+ // 'start' is the pc-offsets where the inlined code started.
+ // 'pos' is the token position where the inlined call occured.
intptr_t start;
+ TokenPosition pos;
intptr_t inlining_id;
- IntervalStruct(intptr_t s, intptr_t id) : start(s), inlining_id(id) {}
+ IntervalStruct(intptr_t s, TokenPosition tp, intptr_t id)
+ : start(s), pos(tp), inlining_id(id) {}
void Dump() {
- THR_Print("start: 0x%" Px " iid: %" Pd " ", start, inlining_id);
+ THR_Print("start: 0x%" Px " iid: %" Pd " pos: %s",
+ start, inlining_id, pos.ToCString());
}
};
@@ -511,6 +506,7 @@
GrowableArray<IntervalStruct> intervals;
intptr_t prev_offset = 0;
intptr_t prev_inlining_id = 0;
+ TokenPosition prev_inlining_pos = parsed_function_.function().token_pos();
intptr_t max_inlining_id = 0;
for (intptr_t i = 0; i < block_order().length(); ++i) {
// Compile the block entry.
@@ -531,16 +527,20 @@
LoopInfoComment(assembler(), *entry, *loop_headers);
entry->set_offset(assembler()->CodeSize());
+ BeginCodeSourceRange();
entry->EmitNativeCode(this);
+ EndCodeSourceRange(entry->token_pos());
// Compile all successors until an exit, branch, or a block entry.
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
Instruction* instr = it.Current();
// Compose intervals.
if (instr->has_inlining_id() && is_optimizing()) {
if (prev_inlining_id != instr->inlining_id()) {
- intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
+ intervals.Add(
+ IntervalStruct(prev_offset, prev_inlining_pos, prev_inlining_id));
prev_offset = assembler()->CodeSize();
prev_inlining_id = instr->inlining_id();
+ prev_inlining_pos = inline_id_to_token_pos_[prev_inlining_id];
if (prev_inlining_id > max_inlining_id) {
max_inlining_id = prev_inlining_id;
}
@@ -556,12 +556,14 @@
if (instr->IsParallelMove()) {
parallel_move_resolver_.EmitNativeCode(instr->AsParallelMove());
} else {
+ BeginCodeSourceRange();
EmitInstructionPrologue(instr);
ASSERT(pending_deoptimization_env_ == NULL);
pending_deoptimization_env_ = instr->env();
instr->EmitNativeCode(this);
pending_deoptimization_env_ = NULL;
EmitInstructionEpilogue(instr);
+ EndCodeSourceRange(instr->token_pos());
}
#if defined(DEBUG)
@@ -578,7 +580,8 @@
if (is_optimizing()) {
LogBlock lb;
- intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
+ intervals.Add(
+ IntervalStruct(prev_offset, prev_inlining_pos, prev_inlining_id));
inlined_code_intervals_ =
Array::New(intervals.length() * Code::kInlIntNumEntries, Heap::kOld);
Smi& start_h = Smi::Handle();
@@ -738,10 +741,14 @@
void FlowGraphCompiler::GenerateDeferredCode() {
for (intptr_t i = 0; i < slow_path_code_.length(); i++) {
+ BeginCodeSourceRange();
slow_path_code_[i]->GenerateCode(this);
+ EndCodeSourceRange(TokenPosition::kDeferredSlowPath);
}
for (intptr_t i = 0; i < deopt_infos_.length(); i++) {
+ BeginCodeSourceRange();
deopt_infos_[i]->GenerateCode(this, i);
+ EndCodeSourceRange(TokenPosition::kDeferredDeoptInfo);
}
}
@@ -942,8 +949,8 @@
return &intrinsic_slow_path_label_;
}
- // No deoptimization allowed when 'FLAG_precompilation' is set.
- if (FLAG_precompilation) {
+ // No deoptimization allowed when 'FLAG_precompiled_mode' is set.
+ if (FLAG_precompiled_mode) {
if (FLAG_trace_compiler) {
THR_Print(
"Retrying compilation %s, suppressing inlining of deopt_id:%" Pd "\n",
@@ -991,7 +998,7 @@
RawArray* FlowGraphCompiler::CreateDeoptInfo(Assembler* assembler) {
// No deopt information if we precompile (no deoptimization allowed).
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
return Array::empty_array().raw();
}
// For functions with optional arguments, all incoming arguments are copied
@@ -1091,7 +1098,7 @@
bool FlowGraphCompiler::TryIntrinsify() {
// Intrinsification skips arguments checks, therefore disable if in checked
// mode.
- if (FLAG_intrinsify && !isolate()->flags().type_checks()) {
+ if (FLAG_intrinsify && !isolate()->type_checks()) {
if (parsed_function().function().kind() == RawFunction::kImplicitGetter) {
// An implicit getter must have a specific AST structure.
const SequenceNode& sequence_node = *parsed_function().node_sequence();
@@ -1148,7 +1155,7 @@
LocationSummary* locs,
const ICData& ic_data_in) {
const ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original());
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
EmitSwitchableInstanceCall(ic_data, argument_count,
deopt_id, token_pos, locs);
return;
@@ -1438,7 +1445,9 @@
const MoveOperands& move = *moves_[i];
if (!move.IsEliminated()) {
ASSERT(move.src().IsConstant());
+ compiler_->BeginCodeSourceRange();
EmitMove(i);
+ compiler_->EndCodeSourceRange(TokenPosition::kParallelMove);
}
}
@@ -1514,13 +1523,17 @@
const MoveOperands& other_move = *moves_[i];
if (other_move.Blocks(destination)) {
ASSERT(other_move.IsPending());
+ compiler_->BeginCodeSourceRange();
EmitSwap(index);
+ compiler_->EndCodeSourceRange(TokenPosition::kParallelMove);
return;
}
}
// This move is not blocked.
+ compiler_->BeginCodeSourceRange();
EmitMove(index);
+ compiler_->EndCodeSourceRange(TokenPosition::kParallelMove);
}
@@ -1763,6 +1776,21 @@
}
+RawArray* FlowGraphCompiler::InliningIdToTokenPos() const {
+ if (inline_id_to_token_pos_.length() == 0) {
+ return Object::empty_array().raw();
+ }
+ const Array& res = Array::Handle(zone(),
+ Array::New(inline_id_to_token_pos_.length(), Heap::kOld));
+ Smi& smi = Smi::Handle(zone());
+ for (intptr_t i = 0; i < inline_id_to_token_pos_.length(); i++) {
+ smi = Smi::New(inline_id_to_token_pos_[i].value());
+ res.SetAt(i, smi);
+ }
+ return res.raw();
+}
+
+
RawArray* FlowGraphCompiler::CallerInliningIdMap() const {
if (caller_inline_id_.length() == 0) {
return Object::empty_array().raw();
@@ -1778,6 +1806,30 @@
}
+void FlowGraphCompiler::BeginCodeSourceRange() {
+NOT_IN_PRODUCT(
+ // Remember how many bytes of code we emitted so far. This function
+ // is called before we call into an instruction's EmitNativeCode.
+ saved_code_size_ = assembler()->CodeSize();
+);
+}
+
+
+bool FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) {
+NOT_IN_PRODUCT(
+ // This function is called after each instructions' EmitNativeCode.
+ if (saved_code_size_ < assembler()->CodeSize()) {
+ // We emitted more code, now associate the emitted code chunk with
+ // |token_pos|.
+ code_source_map_builder()->AddEntry(saved_code_size_, token_pos);
+ BeginCodeSourceRange();
+ return true;
+ }
+);
+ return false;
+}
+
+
void FlowGraphCompiler::EmitPolymorphicInstanceCall(
const ICData& ic_data,
intptr_t argument_count,
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 7a1e156..60ce384 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -302,6 +302,7 @@
const ParsedFunction& parsed_function,
bool is_optimizing,
const GrowableArray<const Function*>& inline_id_to_function,
+ const GrowableArray<TokenPosition>& inline_id_to_token_pos,
const GrowableArray<intptr_t>& caller_inline_id);
~FlowGraphCompiler();
@@ -382,6 +383,12 @@
const StubEntry& stub_entry,
RawPcDescriptors::Kind kind,
LocationSummary* locs);
+ void GenerateStaticDartCall(intptr_t deopt_id,
+ TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs,
+ const Function& target);
void GenerateAssertAssignable(TokenPosition token_pos,
intptr_t deopt_id,
@@ -584,9 +591,20 @@
}
RawArray* InliningIdToFunction() const;
-
+ RawArray* InliningIdToTokenPos() const;
RawArray* CallerInliningIdMap() const;
+ CodeSourceMapBuilder* code_source_map_builder() {
+ if (code_source_map_builder_ == NULL) {
+ code_source_map_builder_ = new CodeSourceMapBuilder();
+ }
+ ASSERT(code_source_map_builder_ != NULL);
+ return code_source_map_builder_;
+ }
+
+ void BeginCodeSourceRange();
+ bool EndCodeSourceRange(TokenPosition token_pos);
+
private:
friend class CheckStackOverflowSlowPath; // For pending_deoptimization_env_.
@@ -744,6 +762,8 @@
ExceptionHandlerList* exception_handlers_list_;
DescriptorList* pc_descriptors_list_;
StackmapTableBuilder* stackmap_table_builder_;
+ CodeSourceMapBuilder* code_source_map_builder_;
+ intptr_t saved_code_size_;
GrowableArray<BlockInfo*> block_info_;
GrowableArray<CompilerDeoptInfo*> deopt_infos_;
GrowableArray<SlowPathCode*> slow_path_code_;
@@ -781,6 +801,7 @@
Array& inlined_code_intervals_;
const GrowableArray<const Function*>& inline_id_to_function_;
+ const GrowableArray<TokenPosition>& inline_id_to_token_pos_;
const GrowableArray<intptr_t>& caller_inline_id_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphCompiler);
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 2b14545..8d6816a 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -29,7 +29,6 @@
DEFINE_FLAG(bool, unbox_doubles, true, "Optimize double arithmetic.");
DECLARE_FLAG(bool, enable_simd_inline);
DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1128,13 +1127,15 @@
}
}
+ EndCodeSourceRange(TokenPosition::kDartCodePrologue);
VisitBlocks();
__ bkpt(0);
ASSERT(assembler()->constant_pool_allowed());
GenerateDeferredCode();
- if (is_optimizing() && !FLAG_precompilation) {
+ BeginCodeSourceRange();
+ if (is_optimizing() && !FLAG_precompiled_mode) {
// Leave enough space for patching in case of lazy deoptimization from
// deferred code.
for (intptr_t i = 0;
@@ -1145,6 +1146,7 @@
lazy_deopt_pc_offset_ = assembler()->CodeSize();
__ Branch(*StubCode::DeoptimizeLazy_entry());
}
+ EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
}
@@ -1180,6 +1182,35 @@
}
+void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
+ TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs,
+ const Function& target) {
+ // Call sites to the same target can share object pool entries. These
+ // call sites are never patched for breakpoints: the function is deoptimized
+ // and the unoptimized code with IC calls for static calls is patched instead.
+ ASSERT(is_optimizing());
+ __ BranchLinkWithEquivalence(stub_entry, target);
+
+ AddCurrentDescriptor(kind, deopt_id, token_pos);
+ RecordSafepoint(locs);
+ // Marks either the continuation point in unoptimized code or the
+ // deoptimization point in optimized code, after call.
+ const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
+ if (is_optimizing()) {
+ AddDeoptIndexAtCall(deopt_id_after, token_pos);
+ } else {
+ // Add deoptimization continuation point after the call and before the
+ // arguments are removed.
+ AddCurrentDescriptor(RawPcDescriptors::kDeopt,
+ deopt_id_after, token_pos);
+ }
+ AddStaticCallTarget(target);
+}
+
+
void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
intptr_t deopt_id,
const RuntimeEntry& entry,
@@ -1298,7 +1329,7 @@
RecordSafepoint(locs);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
// Megamorphic calls may occur in slow path stubs.
// If valid use try_index argument.
if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1393,12 +1424,12 @@
__ LoadObject(R4, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_pos,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_pos,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
}
@@ -1591,14 +1622,14 @@
}
// Do not use the code from the function, but let the code be patched so
// that we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_index,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
const Function& function = Function::ZoneHandle(
zone(), ic_data.GetTargetAt(0));
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_index,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
if (kNumChecks > 1) {
__ b(match_found);
@@ -1633,13 +1664,13 @@
}
// Do not use the code from the function, but let the code be patched so
// that we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_index,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
const Function& function = *sorted[i].target;
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_index,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
if (!kIsLastCheck) {
__ b(match_found);
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 30e4211..618e60d 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -26,7 +26,6 @@
DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
DECLARE_FLAG(bool, enable_simd_inline);
DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1121,13 +1120,15 @@
}
}
+ EndCodeSourceRange(TokenPosition::kDartCodePrologue);
VisitBlocks();
__ brk(0);
ASSERT(assembler()->constant_pool_allowed());
GenerateDeferredCode();
- if (is_optimizing() && !FLAG_precompilation) {
+ BeginCodeSourceRange();
+ if (is_optimizing() && !FLAG_precompiled_mode) {
// Leave enough space for patching in case of lazy deoptimization from
// deferred code.
for (intptr_t i = 0;
@@ -1136,8 +1137,9 @@
__ orr(R0, ZR, Operand(R0)); // nop
}
lazy_deopt_pc_offset_ = assembler()->CodeSize();
- __ BranchPatchable(*StubCode::DeoptimizeLazy_entry());
+ __ BranchPatchable(*StubCode::DeoptimizeLazy_entry());
}
+ EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
}
@@ -1172,6 +1174,34 @@
}
+void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
+ TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs,
+ const Function& target) {
+ // Call sites to the same target can share object pool entries. These
+ // call sites are never patched for breakpoints: the function is deoptimized
+ // and the unoptimized code with IC calls for static calls is patched instead.
+ ASSERT(is_optimizing());
+ __ BranchLinkWithEquivalence(stub_entry, target);
+
+ AddCurrentDescriptor(kind, deopt_id, token_pos);
+ RecordSafepoint(locs);
+ // Marks either the continuation point in unoptimized code or the
+ // deoptimization point in optimized code, after call.
+ const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
+ if (is_optimizing()) {
+ AddDeoptIndexAtCall(deopt_id_after, token_pos);
+ } else {
+ // Add deoptimization continuation point after the call and before the
+ // arguments are removed.
+ AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
+ }
+ AddStaticCallTarget(target);
+}
+
+
void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
intptr_t deopt_id,
const RuntimeEntry& entry,
@@ -1280,7 +1310,7 @@
RecordSafepoint(locs);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
// Megamorphic calls may occur in slow path stubs.
// If valid use try_index argument.
if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1374,12 +1404,12 @@
__ LoadObject(R4, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_pos,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_pos,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
}
@@ -1548,14 +1578,14 @@
}
// Do not use the code from the function, but let the code be patched so
// that we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_index,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
const Function& function = Function::ZoneHandle(
zone(), ic_data.GetTargetAt(0));
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_index,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
if (kNumChecks > 1) {
__ b(match_found);
@@ -1590,13 +1620,13 @@
}
// Do not use the code from the function, but let the code be patched so
// that we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_index,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
const Function& function = *sorted[i].target;
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_index,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
if (!kIsLastCheck) {
__ b(match_found);
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 3ae8998..2ede9e0 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -31,7 +31,6 @@
DECLARE_FLAG(bool, enable_simd_inline);
DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1139,19 +1138,22 @@
}
}
+ EndCodeSourceRange(TokenPosition::kDartCodePrologue);
ASSERT(!block_order().is_empty());
VisitBlocks();
__ int3();
GenerateDeferredCode();
- if (is_optimizing() && !FLAG_precompilation) {
+ BeginCodeSourceRange();
+ if (is_optimizing() && !FLAG_precompiled_mode) {
// Leave enough space for patching in case of lazy deoptimization from
// deferred code.
__ nop(CallPattern::pattern_length_in_bytes());
lazy_deopt_pc_offset_ = assembler()->CodeSize();
__ Jmp(*StubCode::DeoptimizeLazy_entry());
}
+ EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
}
@@ -1311,7 +1313,7 @@
RecordSafepoint(locs);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
// Precompilation not implemented on ia32 platform.
- ASSERT(!FLAG_precompilation);
+ ASSERT(!FLAG_precompiled_mode);
if (is_optimizing()) {
AddDeoptIndexAtCall(deopt_id_after, token_pos);
} else {
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 273a0e0..8f51f86 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -24,7 +24,6 @@
DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1142,12 +1141,14 @@
}
}
+ EndCodeSourceRange(TokenPosition::kDartCodePrologue);
VisitBlocks();
__ break_(0);
GenerateDeferredCode();
- if (is_optimizing() && !FLAG_precompilation) {
+ BeginCodeSourceRange();
+ if (is_optimizing() && !FLAG_precompiled_mode) {
// Leave enough space for patching in case of lazy deoptimization from
// deferred code.
for (intptr_t i = 0;
@@ -1158,6 +1159,7 @@
lazy_deopt_pc_offset_ = assembler()->CodeSize();
__ Branch(*StubCode::DeoptimizeLazy_entry());
}
+ EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
}
@@ -1194,6 +1196,36 @@
}
+void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
+ TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs,
+ const Function& target) {
+ // Call sites to the same target can share object pool entries. These
+ // call sites are never patched for breakpoints: the function is deoptimized
+ // and the unoptimized code with IC calls for static calls is patched instead.
+ ASSERT(is_optimizing());
+ __ BranchLinkWithEquivalence(stub_entry, target);
+
+ AddCurrentDescriptor(kind, deopt_id, token_pos);
+ RecordSafepoint(locs);
+ // Marks either the continuation point in unoptimized code or the
+ // deoptimization point in optimized code, after call.
+ const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
+ if (is_optimizing()) {
+ AddDeoptIndexAtCall(deopt_id_after, token_pos);
+ } else {
+ // Add deoptimization continuation point after the call and before the
+ // arguments are removed.
+ AddCurrentDescriptor(RawPcDescriptors::kDeopt,
+ deopt_id_after,
+ token_pos);
+ }
+ AddStaticCallTarget(target);
+}
+
+
void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
intptr_t deopt_id,
const RuntimeEntry& entry,
@@ -1305,7 +1337,7 @@
RecordSafepoint(locs);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
// Megamorphic calls may occur in slow path stubs.
// If valid use try_index argument.
if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1400,12 +1432,12 @@
__ LoadObject(S4, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_pos,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_pos,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
}
@@ -1614,14 +1646,14 @@
}
// Do not use the code from the function, but let the code be patched so
// that we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_index,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
const Function& function = Function::ZoneHandle(
zone(), ic_data.GetTargetAt(0));
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_index,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
if (kNumChecks > 1) {
__ b(match_found);
@@ -1655,13 +1687,13 @@
}
// Do not use the code from the function, but let the code be patched so
// that we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_index,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
const Function& function = *sorted[i].target;
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_index,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count);
if (!kIsLastCheck) {
__ b(match_found);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 49aeed8..800e1dc 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -27,7 +27,6 @@
DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
DECLARE_FLAG(bool, enable_simd_inline);
DECLARE_FLAG(bool, use_megamorphic_stub);
-DECLARE_FLAG(bool, precompilation);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
Assembler* assembler = compiler->assembler();
@@ -1137,6 +1136,7 @@
}
}
+ EndCodeSourceRange(TokenPosition::kDartCodePrologue);
ASSERT(!block_order().is_empty());
VisitBlocks();
@@ -1146,13 +1146,15 @@
// Emit function patching code. This will be swapped with the first 13 bytes
// at entry point.
- if (is_optimizing() && !FLAG_precompilation) {
+ BeginCodeSourceRange();
+ if (is_optimizing() && !FLAG_precompiled_mode) {
// Leave enough space for patching in case of lazy deoptimization from
// deferred code.
__ nop(ShortCallPattern::pattern_length_in_bytes());
lazy_deopt_pc_offset_ = assembler()->CodeSize();
__ Jmp(*StubCode::DeoptimizeLazy_entry(), PP);
}
+ EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
}
@@ -1187,6 +1189,34 @@
}
+void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
+ TokenPosition token_pos,
+ const StubEntry& stub_entry,
+ RawPcDescriptors::Kind kind,
+ LocationSummary* locs,
+ const Function& target) {
+ // Call sites to the same target can share object pool entries. These
+ // call sites are never patched for breakpoints: the function is deoptimized
+ // and the unoptimized code with IC calls for static calls is patched instead.
+ ASSERT(is_optimizing());
+ __ CallWithEquivalence(stub_entry, target);
+
+ AddCurrentDescriptor(kind, deopt_id, token_pos);
+ RecordSafepoint(locs);
+ // Marks either the continuation point in unoptimized code or the
+ // deoptimization point in optimized code, after call.
+ const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
+ if (is_optimizing()) {
+ AddDeoptIndexAtCall(deopt_id_after, token_pos);
+ } else {
+ // Add deoptimization continuation point after the call and before the
+ // arguments are removed.
+ AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
+ }
+ AddStaticCallTarget(target);
+}
+
+
void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
intptr_t deopt_id,
const RuntimeEntry& entry,
@@ -1310,7 +1340,7 @@
RecordSafepoint(locs);
const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
// Megamorphic calls may occur in slow path stubs.
// If valid use try_index argument.
if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1386,12 +1416,12 @@
__ LoadObject(R10, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_pos,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_pos,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count, RCX);
}
@@ -1531,14 +1561,14 @@
}
// Do not use the code from the function, but let the code be patched so
// that we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_index,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
const Function& function = Function::ZoneHandle(
zone(), ic_data.GetTargetAt(0));
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_index,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count, RCX);
if (kNumChecks > 1) {
__ jmp(match_found);
@@ -1573,13 +1603,13 @@
}
// Do not use the code from the function, but let the code be patched so
// that we can record the outgoing edges to other code.
- GenerateDartCall(deopt_id,
- token_index,
- *StubCode::CallStaticFunction_entry(),
- RawPcDescriptors::kOther,
- locs);
const Function& function = *sorted[i].target;
- AddStaticCallTarget(function);
+ GenerateStaticDartCall(deopt_id,
+ token_index,
+ *StubCode::CallStaticFunction_entry(),
+ RawPcDescriptors::kOther,
+ locs,
+ function);
__ Drop(argument_count, RCX);
if (!kIsLastCheck) {
__ jmp(match_found);
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 9956af3..95a1c9f 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -12,10 +12,10 @@
#include "vm/flow_graph.h"
#include "vm/flow_graph_builder.h"
#include "vm/flow_graph_compiler.h"
-#include "vm/flow_graph_optimizer.h"
#include "vm/flow_graph_type_propagator.h"
#include "vm/il_printer.h"
#include "vm/intrinsifier.h"
+#include "vm/jit_optimizer.h"
#include "vm/longjump.h"
#include "vm/object.h"
#include "vm/object_store.h"
@@ -62,7 +62,6 @@
DECLARE_FLAG(bool, compiler_stats);
DECLARE_FLAG(int, max_deoptimization_counter_threshold);
-DECLARE_FLAG(bool, precompilation);
DECLARE_FLAG(bool, print_flow_graph);
DECLARE_FLAG(bool, print_flow_graph_optimized);
DECLARE_FLAG(bool, verify_compiler);
@@ -632,7 +631,7 @@
// Function has no type feedback. With precompilation we don't rely on
// type feedback.
- if (!FLAG_precompilation &&
+ if (!FLAG_precompiled_mode &&
function.ic_data_array() == Object::null()) {
TRACE_INLINING(THR_Print(" Bailout: not compiled yet\n"));
PRINT_INLINING_TREE("Not compiled",
@@ -790,7 +789,7 @@
CSTAT_TIMER_SCOPE(thread(), graphinliner_opt_timer);
// TODO(fschneider): Improve suppression of speculative inlining.
// Deopt-ids overlap between caller and callee.
- if (FLAG_precompilation) {
+ if (FLAG_precompiled_mode) {
AotOptimizer optimizer(callee_graph,
inliner_->use_speculative_inlining_,
inliner_->inlining_black_list_);
@@ -810,9 +809,7 @@
optimizer.TryOptimizePatterns();
DEBUG_ASSERT(callee_graph->VerifyUseLists());
} else {
- FlowGraphOptimizer optimizer(callee_graph,
- inliner_->use_speculative_inlining_,
- inliner_->inlining_black_list_);
+ JitOptimizer optimizer(callee_graph);
optimizer.ApplyICData();
DEBUG_ASSERT(callee_graph->VerifyUseLists());
@@ -906,6 +903,7 @@
FlowGraphInliner::SetInliningId(callee_graph,
inliner_->NextInlineId(callee_graph->function(),
+ call_data->call->token_pos(),
call_data->caller_inlining_id_));
TRACE_INLINING(THR_Print(" Success\n"));
PRINT_INLINING_TREE(NULL,
@@ -932,7 +930,7 @@
// Propagate a compile-time error. Only in precompilation do we attempt to
// inline functions that have never been compiled before; when JITing we
// should only see compile-time errors in unoptimized compilation.
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
Thread::Current()->long_jump_base()->Jump(1, error);
UNREACHABLE();
return false;
@@ -1827,11 +1825,13 @@
FlowGraphInliner::FlowGraphInliner(
FlowGraph* flow_graph,
GrowableArray<const Function*>* inline_id_to_function,
+ GrowableArray<TokenPosition>* inline_id_to_token_pos,
GrowableArray<intptr_t>* caller_inline_id,
bool use_speculative_inlining,
GrowableArray<intptr_t>* inlining_black_list)
: flow_graph_(flow_graph),
inline_id_to_function_(inline_id_to_function),
+ inline_id_to_token_pos_(inline_id_to_token_pos),
caller_inline_id_(caller_inline_id),
trace_inlining_(ShouldTraceInlining(flow_graph)),
use_speculative_inlining_(use_speculative_inlining),
@@ -1952,9 +1952,15 @@
intptr_t FlowGraphInliner::NextInlineId(const Function& function,
+ TokenPosition tp,
intptr_t parent_id) {
const intptr_t id = inline_id_to_function_->length();
+ // TODO(johnmccutchan): Do not allow IsNoSource once all nodes have proper
+ // source positions.
+ ASSERT(tp.IsReal() || tp.IsSynthetic() || tp.IsNoSource());
inline_id_to_function_->Add(&function);
+ inline_id_to_token_pos_->Add(tp);
+ ASSERT(inline_id_to_token_pos_->length() == inline_id_to_function_->length());
caller_inline_id_->Add(parent_id);
return id;
}
@@ -2231,7 +2237,7 @@
call->GetBlock()->try_index());
(*entry)->InheritDeoptTarget(Z, call);
Instruction* cursor = *entry;
- if (flow_graph->isolate()->flags().type_checks()) {
+ if (flow_graph->isolate()->type_checks()) {
// Only type check for the value. A type check for the index is not
// needed here because we insert a deoptimizing smi-check for the case
// the index is not a smi.
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index c4d8ca2..ade98b5 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -21,6 +21,7 @@
public:
FlowGraphInliner(FlowGraph* flow_graph,
GrowableArray<const Function*>* inline_id_to_function,
+ GrowableArray<TokenPosition>* inline_id_to_token_pos,
GrowableArray<intptr_t>* caller_inline_id,
bool use_speculative_inlining,
GrowableArray<intptr_t>* inlining_black_list);
@@ -35,7 +36,9 @@
bool AlwaysInline(const Function& function);
FlowGraph* flow_graph() const { return flow_graph_; }
- intptr_t NextInlineId(const Function& function, intptr_t caller_id);
+ intptr_t NextInlineId(const Function& function,
+ TokenPosition tp,
+ intptr_t caller_id);
bool trace_inlining() const { return trace_inlining_; }
@@ -54,6 +57,7 @@
FlowGraph* flow_graph_;
GrowableArray<const Function*>* inline_id_to_function_;
+ GrowableArray<TokenPosition>* inline_id_to_token_pos_;
GrowableArray<intptr_t>* caller_inline_id_;
const bool trace_inlining_;
const bool use_speculative_inlining_;
diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
index f9840c6..18eaa36 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -14,7 +14,6 @@
DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress");
DEFINE_FLAG(bool, trace_integer_ir_selection, false,
"Print integer IR selection optimization pass.");
-DECLARE_FLAG(bool, precompilation);
DECLARE_FLAG(bool, trace_constant_propagation);
// Quick access to the locally defined isolate() and zone() methods.
@@ -1534,7 +1533,7 @@
// optimistic hoisting of checks possible)
const bool try_generalization =
function.allows_bounds_check_generalization() &&
- !FLAG_precompilation;
+ !FLAG_precompiled_mode;
BoundsCheckGeneralizer generalizer(this, flow_graph_);
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 9807bcf..df32f54 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -15,7 +15,6 @@
"Trace flow graph type propagation");
DECLARE_FLAG(bool, propagate_types);
-DECLARE_FLAG(bool, fields_may_be_reset);
void FlowGraphTypePropagator::Propagate(FlowGraph* flow_graph) {
@@ -46,7 +45,7 @@
types_.Add(NULL);
}
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
asserts_ = new ZoneGrowableArray<AssertAssignableInstr*>(
flow_graph->current_ssa_temp_index());
for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
@@ -128,7 +127,7 @@
const intptr_t rollback_point = rollback_.length();
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
StrengthenAsserts(block);
}
@@ -891,7 +890,7 @@
return CompileType::FromCid(result_cid_);
}
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
// Void functions are known to return null, which is checked at the return
// from the function.
const AbstractType& result_type =
@@ -906,7 +905,7 @@
CompileType LoadLocalInstr::ComputeType() const {
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
return CompileType::FromAbstractType(local().type());
}
return CompileType::Dynamic();
@@ -950,7 +949,7 @@
intptr_t cid = kDynamicCid;
AbstractType* abstract_type = NULL;
const Field& field = this->StaticField();
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
cid = kIllegalCid;
abstract_type = &AbstractType::ZoneHandle(field.type());
}
@@ -1009,7 +1008,7 @@
}
const AbstractType* abstract_type = NULL;
- if (Isolate::Current()->flags().type_checks() &&
+ if (Isolate::Current()->type_checks() &&
type().HasResolvedTypeClass() &&
!Field::IsExternalizableCid(Class::Handle(type().type_class()).id())) {
abstract_type = &type();
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 207167c..b3e48f1 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -171,7 +171,7 @@
if ((cid_ != kIllegalCid) && (cid_ != kDynamicCid)) {
const Class& cls =
Class::Handle(Isolate::Current()->class_table()->At(cid_));
- type_name = String::Handle(cls.PrettyName()).ToCString();
+ type_name = String::Handle(cls.ScrubbedName()).ToCString();
} else if (type_ != NULL &&
!type_->Equals(Type::Handle(Type::DynamicType()))) {
type_name = type_->ToCString();
@@ -447,6 +447,9 @@
PushArgumentAt(i)->value()->PrintTo(f);
}
PrintICDataHelper(f, ic_data());
+ if (with_checks()) {
+ f->Print(" WITH CHECKS");
+ }
}
@@ -565,7 +568,7 @@
void AllocateObjectInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print("%s", String::Handle(cls().PrettyName()).ToCString());
+ f->Print("%s", String::Handle(cls().ScrubbedName()).ToCString());
for (intptr_t i = 0; i < ArgumentCount(); i++) {
f->Print(", ");
PushArgumentAt(i)->value()->PrintTo(f);
@@ -578,7 +581,7 @@
void MaterializeObjectInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print("%s", String::Handle(cls_.PrettyName()).ToCString());
+ f->Print("%s", String::Handle(cls_.ScrubbedName()).ToCString());
for (intptr_t i = 0; i < InputCount(); i++) {
f->Print(", ");
f->Print("%s: ", slots_[i]->ToCString());
@@ -926,7 +929,7 @@
const Class& cls =
Class::Handle(Isolate::Current()->class_table()->At(cid()));
- f->Print(", %s", String::Handle(cls.PrettyName()).ToCString());
+ f->Print(", %s", String::Handle(cls.ScrubbedName()).ToCString());
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index b2b4df6..4f4032f 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -13,7 +13,6 @@
#include "vm/flow_graph_allocator.h"
#include "vm/flow_graph_builder.h"
#include "vm/flow_graph_compiler.h"
-#include "vm/flow_graph_optimizer.h"
#include "vm/flow_graph_range_analysis.h"
#include "vm/locations.h"
#include "vm/method_recognizer.h"
@@ -30,19 +29,23 @@
namespace dart {
-DEFINE_FLAG(bool, ic_range_profiling, true,
- "Generate special IC stubs collecting range information "
- "for binary and unary arithmetic operations");
DEFINE_FLAG(bool, propagate_ic_data, true,
"Propagate IC data from unoptimized to optimized IC calls.");
DEFINE_FLAG(bool, two_args_smi_icd, true,
"Generate special IC stubs for two args Smi operations");
DEFINE_FLAG(bool, unbox_numeric_fields, true,
"Support unboxed double and float32x4 fields.");
-DEFINE_FLAG(bool, fields_may_be_reset, false,
- "Don't optimize away static field initialization");
DECLARE_FLAG(bool, eliminate_type_checks);
+
+#if defined(DEBUG)
+void Instruction::CheckField(const Field& field) const {
+ ASSERT(field.IsZoneHandle());
+ ASSERT(!Compiler::IsBackgroundCompilation() || !field.IsOriginal());
+}
+#endif // DEBUG
+
+
Definition::Definition(intptr_t deopt_id)
: Instruction(deopt_id),
range_(NULL),
@@ -412,7 +415,7 @@
const Field& LoadStaticFieldInstr::StaticField() const {
- Field& field = Field::Handle();
+ Field& field = Field::ZoneHandle();
field ^= field_value()->BoundConstant().raw();
return field;
}
@@ -425,6 +428,7 @@
ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoSmi());
ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoInt64());
ASSERT(!value.IsMint() || !Smi::IsValid(Mint::Cast(value).AsInt64Value()));
+ ASSERT(!value.IsField() || Field::Cast(value).IsOriginal());
}
@@ -2075,7 +2079,7 @@
Definition* InstantiateTypeArgumentsInstr::Canonicalize(FlowGraph* flow_graph) {
- return (Isolate::Current()->flags().type_checks() || HasUses()) ? this : NULL;
+ return (Isolate::Current()->type_checks() || HasUses()) ? this : NULL;
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 8677ac9..f424c99 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -714,6 +714,16 @@
virtual const char* DebugName() const = 0;
+#if defined(DEBUG)
+ // Checks that the field stored in an instruction has proper form:
+ // - must be a zone-handle
+ // - In background compilation, must be cloned.
+ // Aborts if field is not OK.
+ void CheckField(const Field& field) const;
+#else
+ void CheckField(const Field& field) const {}
+#endif // DEBUG
+
// Printing support.
const char* ToCString() const;
#ifndef PRODUCT
@@ -2842,7 +2852,7 @@
PRINT_OPERANDS_TO_SUPPORT
protected:
- friend class FlowGraphOptimizer;
+ friend class JitOptimizer;
void set_ic_data(ICData* value) { ic_data_ = value; }
private:
@@ -3550,6 +3560,7 @@
is_object_reference_initialization_(false) {
SetInputAt(kInstancePos, instance);
SetInputAt(kValuePos, value);
+ CheckField(field);
}
StoreInstanceFieldInstr(intptr_t offset_in_bytes,
@@ -3620,7 +3631,7 @@
PRINT_OPERANDS_TO_SUPPORT
private:
- friend class FlowGraphOptimizer; // For ASSERT(initialization_).
+ friend class JitOptimizer; // For ASSERT(initialization_).
bool CanValueBeSmi() const {
const intptr_t cid = value()->Type()->ToNullableCid();
@@ -3651,6 +3662,7 @@
: TemplateInstruction(deopt_id),
field_(field) {
SetInputAt(0, value);
+ CheckField(field);
}
Value* value() const { return inputs_[0]; }
@@ -3677,7 +3689,9 @@
GuardFieldClassInstr(Value* value,
const Field& field,
intptr_t deopt_id)
- : GuardFieldInstr(value, field, deopt_id) { }
+ : GuardFieldInstr(value, field, deopt_id) {
+ CheckField(field);
+ }
DECLARE_INSTRUCTION(GuardFieldClass)
@@ -3695,7 +3709,9 @@
GuardFieldLengthInstr(Value* value,
const Field& field,
intptr_t deopt_id)
- : GuardFieldInstr(value, field, deopt_id) { }
+ : GuardFieldInstr(value, field, deopt_id) {
+ CheckField(field);
+ }
DECLARE_INSTRUCTION(GuardFieldLength)
@@ -3750,6 +3766,7 @@
token_pos_(token_pos) {
ASSERT(field.IsZoneHandle());
SetInputAt(kValuePos, value);
+ CheckField(field);
}
enum {
@@ -4641,6 +4658,7 @@
: TemplateInstruction(Thread::Current()->GetNextDeoptId()),
field_(field) {
SetInputAt(0, input);
+ CheckField(field);
}
virtual TokenPosition token_pos() const {
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 93619bc..df31e31 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -22,15 +22,10 @@
#include "vm/symbols.h"
#define __ compiler->assembler()->
+#define Z (compiler->zone())
namespace dart {
-DECLARE_FLAG(bool, allow_absolute_addresses);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, precompilation);
-DECLARE_FLAG(bool, use_osr);
-
// Generic summary for call instructions that have all arguments pushed
// on the stack and return the result in a fixed register R0.
LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -379,13 +374,13 @@
ASSERT(locs->always_calls());
Label done;
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
__ CompareObject(reg, Bool::True());
__ b(&done, EQ);
__ CompareObject(reg, Bool::False());
__ b(&done, EQ);
} else {
- ASSERT(Isolate::Current()->flags().asserts());
+ ASSERT(Isolate::Current()->asserts());
__ CompareObject(reg, Object::null_instance());
__ b(&done, NE);
}
@@ -1616,7 +1611,7 @@
Label* fail = (deopt != NULL) ? deopt : &fail_label;
if (emit_full_guard) {
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
@@ -1763,7 +1758,7 @@
Label ok;
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
__ ldrsb(offset_reg, FieldAddress(field_reg,
Field::guarded_list_length_in_object_offset_offset()));
@@ -1823,7 +1818,7 @@
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
instruction_->DebugName(),
- String::Handle(cls_.PrettyName()).ToCString());
+ String::Handle(cls_.ScrubbedName()).ToCString());
}
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(
@@ -2120,7 +2115,7 @@
Label store_float32x4;
Label store_float64x2;
- __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
__ ldrh(temp2, FieldAddress(temp, Field::is_nullable_offset()));
__ CompareImmediate(temp2, kNullCid);
@@ -2260,7 +2255,7 @@
const Register value = locs()->in(0).reg();
const Register temp = locs()->temp(0).reg();
- __ LoadObject(temp, field());
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
if (this->value()->NeedsStoreBuffer()) {
__ StoreIntoObject(temp,
FieldAddress(temp, Field::static_value_offset()),
@@ -2378,7 +2373,7 @@
ASSERT(locs()->in(kLengthPos).reg() == kLengthReg);
if (compiler->is_optimizing() &&
- !FLAG_precompilation &&
+ !FLAG_precompiled_mode &&
num_elements()->BindsToConstant() &&
num_elements()->BoundConstant().IsSmi()) {
const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2482,7 +2477,7 @@
Label load_float32x4;
Label load_float64x2;
- __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
+ __ LoadObject(result_reg, Field::ZoneHandle(field()->Original()));
FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(result_reg,
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 0627f74..79296b3 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -21,15 +21,10 @@
#include "vm/symbols.h"
#define __ compiler->assembler()->
+#define Z (compiler->zone())
namespace dart {
-DECLARE_FLAG(bool, allow_absolute_addresses);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, precompilation);
-DECLARE_FLAG(bool, use_osr);
-
// Generic summary for call instructions that have all arguments pushed
// on the stack and return the result in a fixed register R0.
LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -367,13 +362,13 @@
ASSERT(locs->always_calls());
Label done;
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
__ CompareObject(reg, Bool::True());
__ b(&done, EQ);
__ CompareObject(reg, Bool::False());
__ b(&done, EQ);
} else {
- ASSERT(Isolate::Current()->flags().asserts());
+ ASSERT(Isolate::Current()->asserts());
__ CompareObject(reg, Object::null_instance());
__ b(&done, NE);
}
@@ -1473,7 +1468,7 @@
Label* fail = (deopt != NULL) ? deopt : &fail_label;
if (emit_full_guard) {
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
FieldAddress field_cid_operand(
field_reg, Field::guarded_cid_offset(), kUnsignedWord);
@@ -1617,7 +1612,7 @@
Label ok;
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
__ ldr(offset_reg,
FieldAddress(field_reg,
@@ -1675,7 +1670,7 @@
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
instruction_->DebugName(),
- String::Handle(cls_.PrettyName()).ToCString());
+ String::Handle(cls_.ScrubbedName()).ToCString());
}
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(compiler->zone(),
@@ -1843,7 +1838,7 @@
Label store_float32x4;
Label store_float64x2;
- __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
__ LoadFieldFromOffset(temp2, temp, Field::is_nullable_offset(),
kUnsignedWord);
@@ -1981,7 +1976,7 @@
const Register value = locs()->in(0).reg();
const Register temp = locs()->temp(0).reg();
- __ LoadObject(temp, field());
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
if (this->value()->NeedsStoreBuffer()) {
__ StoreIntoObjectOffset(
temp, Field::static_value_offset(), value, CanValueBeSmi());
@@ -2101,7 +2096,7 @@
ASSERT(locs()->in(kLengthPos).reg() == kLengthReg);
if (compiler->is_optimizing() &&
- !FLAG_precompilation &&
+ !FLAG_precompiled_mode &&
num_elements()->BindsToConstant() &&
num_elements()->BoundConstant().IsSmi()) {
const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2193,7 +2188,7 @@
Label load_float32x4;
Label load_float64x2;
- __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
+ __ LoadObject(result_reg, Field::ZoneHandle(field()->Original()));
FieldAddress field_cid_operand(
result_reg, Field::guarded_cid_offset(), kUnsignedWord);
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 8933848..bebb561 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -20,13 +20,10 @@
#include "vm/symbols.h"
#define __ compiler->assembler()->
+#define Z (compiler->zone())
namespace dart {
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, use_osr);
-
// Generic summary for call instructions that have all arguments pushed
// on the stack and return the result in a fixed register EAX.
LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -251,13 +248,13 @@
ASSERT(locs->always_calls());
Label done;
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
__ CompareObject(reg, Bool::True());
__ j(EQUAL, &done, Assembler::kNearJump);
__ CompareObject(reg, Bool::False());
__ j(EQUAL, &done, Assembler::kNearJump);
} else {
- ASSERT(Isolate::Current()->flags().asserts());
+ ASSERT(Isolate::Current()->asserts());
__ CompareObject(reg, Object::null_instance());
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
}
@@ -1445,7 +1442,7 @@
Label* fail = (deopt != NULL) ? deopt : &fail_label;
if (emit_full_guard) {
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
@@ -1593,7 +1590,7 @@
Label ok;
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
__ movsxb(offset_reg, FieldAddress(field_reg,
Field::guarded_list_length_in_object_offset_offset()));
@@ -1648,7 +1645,7 @@
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
instruction_->DebugName(),
- String::Handle(cls_.PrettyName()).ToCString());
+ String::Handle(cls_.ScrubbedName()).ToCString());
}
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(
@@ -1833,7 +1830,7 @@
Label store_float32x4;
Label store_float64x2;
- __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
__ cmpw(FieldAddress(temp, Field::is_nullable_offset()),
Immediate(kNullCid));
@@ -1979,7 +1976,7 @@
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
- __ LoadObject(temp, field());
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
if (this->value()->NeedsStoreBuffer()) {
__ StoreIntoObject(temp,
FieldAddress(temp, Field::static_value_offset()),
@@ -2202,7 +2199,7 @@
Label load_float32x4;
Label load_float64x2;
- __ LoadObject(result, Field::ZoneHandle(field()->raw()));
+ __ LoadObject(result, Field::ZoneHandle(field()->Original()));
FieldAddress field_cid_operand(result, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(result, Field::is_nullable_offset());
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 93e720c..f4b8032 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -21,15 +21,10 @@
#include "vm/symbols.h"
#define __ compiler->assembler()->
+#define Z (compiler->zone())
namespace dart {
-DECLARE_FLAG(bool, allow_absolute_addresses);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, precompilation);
-DECLARE_FLAG(bool, use_osr);
-
// Generic summary for call instructions that have all arguments pushed
// on the stack and return the result in a fixed register V0.
LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -428,11 +423,11 @@
ASSERT(locs->always_calls());
Label done;
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
__ BranchEqual(reg, Bool::True(), &done);
__ BranchEqual(reg, Bool::False(), &done);
} else {
- ASSERT(Isolate::Current()->flags().asserts());
+ ASSERT(Isolate::Current()->asserts());
__ BranchNotEqual(reg, Object::null_instance(), &done);
}
@@ -1647,7 +1642,7 @@
Label* fail = (deopt != NULL) ? deopt : &fail_label;
if (emit_full_guard) {
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
@@ -1792,7 +1787,7 @@
Label ok;
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
__ lb(CMPRES1, FieldAddress(field_reg,
Field::guarded_list_length_in_object_offset_offset()));
@@ -1849,7 +1844,7 @@
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
instruction_->DebugName(),
- String::Handle(cls_.PrettyName()).ToCString());
+ String::Handle(cls_.ScrubbedName()).ToCString());
}
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(
@@ -2007,7 +2002,7 @@
Label store_pointer;
Label store_double;
- __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
__ lhu(temp2, FieldAddress(temp, Field::is_nullable_offset()));
__ BranchEqual(temp2, Immediate(kNullCid), &store_pointer);
@@ -2113,7 +2108,7 @@
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
- __ LoadObject(temp, field());
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
if (this->value()->NeedsStoreBuffer()) {
__ StoreIntoObject(temp,
FieldAddress(temp, Field::static_value_offset()),
@@ -2232,7 +2227,7 @@
Label slow_path, done;
if (compiler->is_optimizing() &&
- !FLAG_precompilation &&
+ !FLAG_precompiled_mode &&
num_elements()->BindsToConstant() &&
num_elements()->BoundConstant().IsSmi()) {
const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2323,7 +2318,7 @@
Label load_pointer;
Label load_double;
- __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
+ __ LoadObject(result_reg, Field::ZoneHandle(field()->Original()));
FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(result_reg,
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 2fdf93e..ec108a8 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -20,15 +20,10 @@
#include "vm/symbols.h"
#define __ compiler->assembler()->
+#define Z (compiler->zone())
namespace dart {
-DECLARE_FLAG(bool, allow_absolute_addresses);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, use_osr);
-DECLARE_FLAG(bool, precompilation);
-
// Generic summary for call instructions that have all arguments pushed
// on the stack and return the result in a fixed register RAX.
LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -338,13 +333,13 @@
ASSERT(locs->always_calls());
Label done;
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
__ CompareObject(reg, Bool::True());
__ j(EQUAL, &done, Assembler::kNearJump);
__ CompareObject(reg, Bool::False());
__ j(EQUAL, &done, Assembler::kNearJump);
} else {
- ASSERT(Isolate::Current()->flags().asserts());
+ ASSERT(Isolate::Current()->asserts());
__ CompareObject(reg, Object::null_instance());
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
}
@@ -1489,7 +1484,7 @@
Label* fail = (deopt != NULL) ? deopt : &fail_label;
if (emit_full_guard) {
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
@@ -1623,7 +1618,7 @@
Label ok;
- __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+ __ LoadObject(field_reg, Field::ZoneHandle(field().Original()));
__ movsxb(offset_reg, FieldAddress(field_reg,
Field::guarded_list_length_in_object_offset_offset()));
@@ -1679,7 +1674,7 @@
if (Assembler::EmittingComments()) {
__ Comment("%s slow path allocation of %s",
instruction_->DebugName(),
- String::Handle(cls_.PrettyName()).ToCString());
+ String::Handle(cls_.ScrubbedName()).ToCString());
}
__ Bind(entry_label());
const Code& stub = Code::ZoneHandle(compiler->zone(),
@@ -1861,7 +1856,7 @@
Label store_float32x4;
Label store_float64x2;
- __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
__ cmpl(FieldAddress(temp, Field::is_nullable_offset()),
Immediate(kNullCid));
@@ -2003,7 +1998,7 @@
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
- __ LoadObject(temp, field());
+ __ LoadObject(temp, Field::ZoneHandle(Z, field().Original()));
if (this->value()->NeedsStoreBuffer()) {
__ StoreIntoObject(temp,
FieldAddress(temp, Field::static_value_offset()),
@@ -2121,7 +2116,7 @@
Label slow_path, done;
if (compiler->is_optimizing() &&
- !FLAG_precompilation &&
+ !FLAG_precompiled_mode &&
num_elements()->BindsToConstant() &&
num_elements()->BoundConstant().IsSmi()) {
const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2221,7 +2216,7 @@
Label load_float32x4;
Label load_float64x2;
- __ LoadObject(result, Field::ZoneHandle(field()->raw()));
+ __ LoadObject(result, Field::ZoneHandle(field()->Original()));
__ cmpl(FieldAddress(result, Field::is_nullable_offset()),
Immediate(kNullCid));
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 193dba4..af15e7a 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -770,7 +770,7 @@
bool Intrinsifier::Build_GrowableArraySetIndexed(FlowGraph* flow_graph) {
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
return false;
}
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 1b49169..0487fea 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -18,8 +18,6 @@
namespace dart {
-DECLARE_FLAG(bool, interpret_irregexp);
-
// When entering intrinsics code:
// R4: Arguments descriptor
// LR: Return address
@@ -37,7 +35,7 @@
// Intrinsify only for Smi value and index. Non-smi values need a store buffer
// update. Array length is always a Smi.
void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
return;
}
@@ -111,7 +109,7 @@
// On stack: growable array (+1), value (+0).
void Intrinsifier::GrowableArray_add(Assembler* assembler) {
// In checked mode we need to type-check the incoming argument.
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
return;
}
Label fall_through;
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 3c28ec1..f12ea8d 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -17,8 +17,6 @@
namespace dart {
-DECLARE_FLAG(bool, interpret_irregexp);
-
// When entering intrinsics code:
// R4: Arguments descriptor
// LR: Return address
@@ -36,7 +34,7 @@
// Intrinsify only for Smi value and index. Non-smi values need a store buffer
// update. Array length is always a Smi.
void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
return;
}
@@ -109,7 +107,7 @@
// On stack: growable array (+1), value (+0).
void Intrinsifier::GrowableArray_add(Assembler* assembler) {
// In checked mode we need to type-check the incoming argument.
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
return;
}
Label fall_through;
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 9f4c622..29870b2 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -24,8 +24,6 @@
namespace dart {
-DECLARE_FLAG(bool, interpret_irregexp);
-
// When entering intrinsics code:
// ECX: IC Data
// EDX: Arguments descriptor
@@ -57,7 +55,7 @@
// update. Array length is always a Smi.
void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
Label fall_through;
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
const intptr_t type_args_field_offset =
ComputeObjectArrayTypeArgumentsOffset();
// Inline simple tests (Smi, null), fallthrough if not positive.
@@ -158,7 +156,7 @@
// On stack: growable array (+2), value (+1), return-address (+0).
void Intrinsifier::GrowableArray_add(Assembler* assembler) {
// In checked mode we need to type-check the incoming argument.
- if (Isolate::Current()->flags().type_checks()) return;
+ if (Isolate::Current()->type_checks()) return;
Label fall_through;
__ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 1e289cc..57cb4d6 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -17,8 +17,6 @@
namespace dart {
-DECLARE_FLAG(bool, interpret_irregexp);
-
// When entering intrinsics code:
// S4: Arguments descriptor
// RA: Return address
@@ -36,7 +34,7 @@
// Intrinsify only for Smi value and index. Non-smi values need a store buffer
// update. Array length is always a Smi.
void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
return;
}
@@ -108,7 +106,7 @@
// On stack: growable array (+1), value (+0).
void Intrinsifier::GrowableArray_add(Assembler* assembler) {
// In checked mode we need to type-check the incoming argument.
- if (Isolate::Current()->flags().type_checks()) return;
+ if (Isolate::Current()->type_checks()) return;
Label fall_through;
__ lw(T0, Address(SP, 1 * kWordSize)); // Array.
__ lw(T1, FieldAddress(T0, GrowableObjectArray::length_offset()));
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index d9eb08b..e98777f 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -17,8 +17,6 @@
namespace dart {
-DECLARE_FLAG(bool, interpret_irregexp);
-
// When entering intrinsics code:
// R10: Arguments descriptor
// TOS: Return address
@@ -34,7 +32,7 @@
void Intrinsifier::ObjectArraySetIndexed(Assembler* assembler) {
- if (Isolate::Current()->flags().type_checks()) {
+ if (Isolate::Current()->type_checks()) {
return;
}
@@ -104,7 +102,7 @@
// On stack: growable array (+2), value (+1), return-address (+0).
void Intrinsifier::GrowableArray_add(Assembler* assembler) {
// In checked mode we need to check the incoming argument.
- if (Isolate::Current()->flags().type_checks()) return;
+ if (Isolate::Current()->type_checks()) return;
Label fall_through;
__ movq(RAX, Address(RSP, + 2 * kWordSize)); // Array.
__ movq(RCX, FieldAddress(RAX, GrowableObjectArray::length_offset()));
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 3758c21..3fc7780 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -77,18 +77,9 @@
"Max total size of external allocations in MB, or 0 for unlimited,"
"e.g: --external_max_size=1024 allows up to 1024MB of externals");
-// TODO(iposva): Make these isolate specific flags inaccessible using the
-// regular FLAG_xyz pattern.
-// These flags are per-isolate and only influence the defaults.
-DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements.");
-DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks.");
-DEFINE_FLAG(bool, error_on_bad_override, false,
- "Report error for bad overrides.");
-DEFINE_FLAG(bool, error_on_bad_type, false,
- "Report error for malformed types.");
-
DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
+NOT_IN_PRODUCT(
static void CheckedModeHandler(bool value) {
FLAG_enable_asserts = value;
FLAG_enable_type_checks = value;
@@ -103,6 +94,7 @@
DEFINE_FLAG_HANDLER(CheckedModeHandler,
checked,
"Enable checked mode.");
+)
// Quick access to the locally defined thread() and isolate() methods.
@@ -655,20 +647,6 @@
MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
const Error& result) {
- // Notify the debugger about specific unhandled exceptions which are withheld
- // when being thrown.
- if (result.IsUnhandledException()) {
- const UnhandledException& error = UnhandledException::Cast(result);
- RawInstance* exception = error.exception();
- if ((exception == I->object_store()->out_of_memory()) ||
- (exception == I->object_store()->stack_overflow())) {
- // We didn't notify the debugger when the stack was full. Do it now.
- if (FLAG_support_debugger) {
- I->debugger()->SignalExceptionThrown(Instance::Handle(exception));
- }
- }
- }
-
// Generate the error and stacktrace strings for the error message.
String& exc_str = String::Handle(T->zone());
String& stacktrace_str = String::Handle(T->zone());
@@ -704,6 +682,21 @@
} else {
T->set_sticky_error(result);
}
+ // Notify the debugger about specific unhandled exceptions which are
+ // withheld when being thrown. Do this after setting the sticky error
+ // so the isolate has an error set when paused with the unhandled
+ // exception.
+ if (result.IsUnhandledException()) {
+ const UnhandledException& error = UnhandledException::Cast(result);
+ RawInstance* exception = error.exception();
+ if ((exception == I->object_store()->out_of_memory()) ||
+ (exception == I->object_store()->stack_overflow())) {
+ // We didn't notify the debugger when the stack was full. Do it now.
+ if (FLAG_support_debugger) {
+ I->debugger()->SignalExceptionThrown(Instance::Handle(exception));
+ }
+ }
+ }
return kError;
}
}
@@ -711,31 +704,16 @@
}
-Isolate::Flags::Flags()
- : type_checks_(FLAG_enable_type_checks),
- asserts_(FLAG_enable_asserts),
- error_on_bad_type_(FLAG_error_on_bad_type),
- error_on_bad_override_(FLAG_error_on_bad_override) {}
-
-
-void Isolate::Flags::CopyFrom(const Flags& orig) {
- type_checks_ = orig.type_checks();
- asserts_ = orig.asserts();
- error_on_bad_type_ = orig.error_on_bad_type();
- error_on_bad_override_ = orig.error_on_bad_override();
+void Isolate::FlagsInitialize(Dart_IsolateFlags* api_flags) {
+ api_flags->version = DART_FLAGS_CURRENT_VERSION;
+ api_flags->enable_type_checks = FLAG_enable_type_checks;
+ api_flags->enable_asserts = FLAG_enable_asserts;
+ api_flags->enable_error_on_bad_type = FLAG_error_on_bad_type;
+ api_flags->enable_error_on_bad_override = FLAG_error_on_bad_override;
}
-void Isolate::Flags::CopyFrom(const Dart_IsolateFlags& api_flags) {
- type_checks_ = api_flags.enable_type_checks;
- asserts_ = api_flags.enable_asserts;
- error_on_bad_type_ = api_flags.enable_error_on_bad_type;
- error_on_bad_override_ = api_flags.enable_error_on_bad_override;
- // Leave others at defaults.
-}
-
-
-void Isolate::Flags::CopyTo(Dart_IsolateFlags* api_flags) const {
+void Isolate::FlagsCopyTo(Dart_IsolateFlags* api_flags) const {
api_flags->version = DART_FLAGS_CURRENT_VERSION;
api_flags->enable_type_checks = type_checks();
api_flags->enable_asserts = asserts();
@@ -744,7 +722,17 @@
}
-#if defined(DEBUG)
+NOT_IN_PRODUCT(
+void Isolate::FlagsCopyFrom(const Dart_IsolateFlags& api_flags) {
+ type_checks_ = api_flags.enable_type_checks;
+ asserts_ = api_flags.enable_asserts;
+ error_on_bad_type_ = api_flags.enable_error_on_bad_type;
+ error_on_bad_override_ = api_flags.enable_error_on_bad_override;
+ // Leave others at defaults.
+})
+
+
+DEBUG_ONLY(
// static
void BaseIsolate::AssertCurrent(BaseIsolate* isolate) {
ASSERT(isolate == Isolate::Current());
@@ -754,7 +742,7 @@
ASSERT(Isolate::Current() == this);
ASSERT(Thread::Current()->IsMutatorThread());
}
-#endif // defined(DEBUG)
+)
#if defined(DEBUG)
#define REUSABLE_HANDLE_SCOPE_INIT(object) \
@@ -798,11 +786,11 @@
resume_request_(false),
last_resume_timestamp_(OS::GetCurrentTimeMillis()),
has_compiled_code_(false),
- flags_(),
random_(),
simulator_(NULL),
mutex_(new Mutex()),
symbols_mutex_(new Mutex()),
+ type_canonicalization_mutex_(new Mutex()),
saved_stack_limit_(0),
deferred_interrupts_mask_(0),
deferred_interrupts_(0),
@@ -835,11 +823,11 @@
cha_invalidation_gen_(kInvalidGen),
field_invalidation_gen_(kInvalidGen),
prefix_invalidation_gen_(kInvalidGen),
- boxed_field_list_monitor_(new Monitor()),
+ boxed_field_list_mutex_(new Mutex()),
boxed_field_list_(GrowableObjectArray::null()),
spawn_count_monitor_(new Monitor()),
spawn_count_(0) {
- flags_.CopyFrom(api_flags);
+ NOT_IN_PRODUCT(FlagsCopyFrom(api_flags));
// TODO(asiva): A Thread is not available here, need to figure out
// how the vm_tag (kEmbedderTagId) can be set, these tags need to
// move to the OSThread structure.
@@ -866,6 +854,8 @@
mutex_ = NULL; // Fail fast if interrupts are scheduled on a dead isolate.
delete symbols_mutex_;
symbols_mutex_ = NULL;
+ delete type_canonicalization_mutex_;
+ type_canonicalization_mutex_ = NULL;
delete message_handler_;
message_handler_ = NULL; // Fail fast if we send messages to a dead isolate.
ASSERT(deopt_context_ == NULL); // No deopt in progress when isolate deleted.
@@ -876,8 +866,8 @@
object_id_ring_ = NULL;
delete pause_loop_monitor_;
pause_loop_monitor_ = NULL;
- delete boxed_field_list_monitor_;
- boxed_field_list_monitor_ = NULL;
+ delete boxed_field_list_mutex_;
+ boxed_field_list_mutex_ = NULL;
ASSERT(spawn_count_ == 0);
delete spawn_count_monitor_;
if (compiler_stats_ != NULL) {
@@ -1882,7 +1872,7 @@
// Visit the boxed_field_list.
// 'boxed_field_list_' access via mutator and background compilation threads
// is guarded with a monitor. This means that we can visit it only
- // when at safepoint or the boxed_field_list_monitor_ lock has been taken.
+ // when at safepoint or the boxed_field_list_mutex_ lock has been taken.
visitor->VisitPointer(reinterpret_cast<RawObject**>(&boxed_field_list_));
// Visit objects in the debugger.
@@ -2095,7 +2085,10 @@
void Isolate::AddDeoptimizingBoxedField(const Field& field) {
- MonitorLocker ml(boxed_field_list_monitor_);
+ ASSERT(field.IsOriginal());
+ // The enclosed code allocates objects and can potentially trigger a GC,
+ // ensure that we account for safepoints when grabbing the lock.
+ SafepointMutexLocker ml(boxed_field_list_mutex_);
if (boxed_field_list_ == GrowableObjectArray::null()) {
boxed_field_list_ = GrowableObjectArray::New(Heap::kOld);
}
@@ -2106,7 +2099,7 @@
RawField* Isolate::GetDeoptimizingBoxedField() {
- MonitorLocker ml(boxed_field_list_monitor_);
+ MutexLocker ml(boxed_field_list_mutex_);
if (boxed_field_list_ == GrowableObjectArray::null()) {
return Field::null();
}
@@ -2329,9 +2322,9 @@
// Handle all available vm service messages, up to a resume
// request.
while (!resume && Dart_HasServiceMessages()) {
- pause_loop_monitor_->Exit();
+ ml.Exit();
resume = Dart_HandleServiceMessages();
- pause_loop_monitor_->Enter();
+ ml.Enter();
}
if (resume) {
break;
@@ -2350,7 +2343,9 @@
if (visitor == NULL) {
return;
}
- MonitorLocker ml(isolates_list_monitor_);
+ // The visitor could potentially run code that could safepoint so use
+ // SafepointMonitorLocker to ensure the lock has safepoint checks.
+ SafepointMonitorLocker ml(isolates_list_monitor_);
Isolate* current = isolates_list_head_;
while (current) {
visitor->VisitIsolate(current);
@@ -2540,7 +2535,12 @@
Thread* thread = NULL;
OSThread* os_thread = OSThread::Current();
if (os_thread != NULL) {
- MonitorLocker ml(threads_lock());
+ // We are about to associate the thread with an isolate and it would
+ // not be possible to correctly track no_safepoint_scope_depth for the
+ // thread in the constructor/destructor of MonitorLocker,
+ // so we create a MonitorLocker object which does not do any
+ // no_safepoint_scope_depth increments/decrements.
+ MonitorLocker ml(threads_lock(), false);
// If a safepoint operation is in progress wait for it
// to finish before scheduling this thread in.
@@ -2560,6 +2560,7 @@
ASSERT(thread->execution_state() == Thread::kThreadInVM);
thread->set_safepoint_state(0);
thread->set_vm_tag(VMTag::kVMTagId);
+ ASSERT(thread->no_safepoint_scope_depth() == 0);
os_thread->set_thread(thread);
if (is_mutator) {
mutator_thread_ = thread;
@@ -2576,7 +2577,12 @@
bool bypass_safepoint) {
// Disassociate the 'Thread' structure and unschedule the thread
// from this isolate.
- MonitorLocker ml(threads_lock());
+ // We are disassociating the thread from an isolate and it would
+ // not be possible to correctly track no_safepoint_scope_depth for the
+ // thread in the constructor/destructor of MonitorLocker,
+ // so we create a MonitorLocker object which does not do any
+ // no_safepoint_scope_depth increments/decrements.
+ MonitorLocker ml(threads_lock(), false);
if (!bypass_safepoint) {
// Ensure that the thread reports itself as being at a safepoint.
thread->EnterSafepoint();
@@ -2594,6 +2600,7 @@
thread->set_os_thread(NULL);
thread->set_execution_state(Thread::kThreadInVM);
thread->set_safepoint_state(0);
+ ASSERT(thread->no_safepoint_scope_depth() == 0);
// Return thread structure.
thread_registry()->ReturnThreadLocked(is_mutator, thread);
}
@@ -2655,7 +2662,6 @@
serialized_message_len_(0),
spawn_count_monitor_(spawn_count_monitor),
spawn_count_(spawn_count),
- isolate_flags_(),
paused_(paused),
errors_are_fatal_(errors_are_fatal) {
const Class& cls = Class::Handle(func.Owner());
@@ -2675,7 +2681,7 @@
&serialized_message_len_,
can_send_any_object);
// Inherit flags from spawning isolate.
- isolate_flags()->CopyFrom(Isolate::Current()->flags());
+ Isolate::Current()->FlagsCopyTo(isolate_flags());
}
@@ -2725,7 +2731,7 @@
can_send_any_object);
// By default inherit flags from spawning isolate. These can be overridden
// from the calling code.
- isolate_flags()->CopyFrom(Isolate::Current()->flags());
+ Isolate::Current()->FlagsCopyTo(isolate_flags());
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index e9c255b..9d6aa28 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -319,6 +319,9 @@
Mutex* mutex() const { return mutex_; }
Mutex* symbols_mutex() const { return symbols_mutex_; }
+ Mutex* type_canonicalization_mutex() const {
+ return type_canonicalization_mutex_;
+ }
Debugger* debugger() const {
if (!FLAG_support_debugger) {
@@ -337,42 +340,6 @@
void set_has_compiled_code(bool value) { has_compiled_code_ = value; }
bool has_compiled_code() const { return has_compiled_code_; }
- // TODO(iposva): Evaluate whether two different isolate flag structures are
- // needed. Currently it serves as a separation between publicly visible flags
- // and VM internal flags.
- class Flags : public ValueObject {
- public:
- // Construct default flags as specified by the options.
- Flags();
-
- bool type_checks() const { return type_checks_; }
- bool asserts() const { return asserts_; }
- bool error_on_bad_type() const { return error_on_bad_type_; }
- bool error_on_bad_override() const { return error_on_bad_override_; }
-
- void set_checked(bool val) {
- type_checks_ = val;
- asserts_ = val;
- }
-
- void CopyFrom(const Flags& orig);
- void CopyFrom(const Dart_IsolateFlags& api_flags);
- void CopyTo(Dart_IsolateFlags* api_flags) const;
-
- private:
- bool type_checks_;
- bool asserts_;
- bool error_on_bad_type_;
- bool error_on_bad_override_;
-
- friend class Isolate;
-
- DISALLOW_ALLOCATION();
- DISALLOW_COPY_AND_ASSIGN(Flags);
- };
-
- const Flags& flags() const { return flags_; }
-
// Lets the embedder know that a service message resulted in a resume request.
void SetResumeRequest() {
resume_request_ = true;
@@ -672,6 +639,23 @@
bool is_service_isolate() const { return is_service_isolate_; }
+ // Isolate-specific flag handling.
+ static void FlagsInitialize(Dart_IsolateFlags* api_flags);
+ void FlagsCopyTo(Dart_IsolateFlags* api_flags) const;
+ void FlagsCopyFrom(const Dart_IsolateFlags& api_flags);
+
+#if defined(PRODUCT)
+ bool type_checks() const { return FLAG_enable_type_checks; }
+ bool asserts() const { return FLAG_enable_asserts; }
+ bool error_on_bad_type() const { return FLAG_error_on_bad_type; }
+ bool error_on_bad_override() const { return FLAG_error_on_bad_override; }
+#else // defined(PRODUCT)
+ bool type_checks() const { return type_checks_; }
+ bool asserts() const { return asserts_; }
+ bool error_on_bad_type() const { return error_on_bad_type_; }
+ bool error_on_bad_override() const { return error_on_bad_override_; }
+#endif // defined(PRODUCT)
+
static void KillAllIsolates(LibMsgId msg_id);
static void KillIfExists(Isolate* isolate, LibMsgId msg_id);
@@ -769,11 +753,11 @@
bool resume_request_;
int64_t last_resume_timestamp_;
bool has_compiled_code_; // Can check that no compilation occured.
- Flags flags_;
Random random_;
Simulator* simulator_;
- Mutex* mutex_; // protects stack_limit_, saved_stack_limit_, compiler stats.
- Mutex* symbols_mutex_; // Protects concurrent access to teh symbol table.
+ Mutex* mutex_; // Protects stack_limit_, saved_stack_limit_, compiler stats.
+ Mutex* symbols_mutex_; // Protects concurrent access to the symbol table.
+ Mutex* type_canonicalization_mutex_; // Protects type canonicalization.
uword saved_stack_limit_;
uword deferred_interrupts_mask_;
uword deferred_interrupts_;
@@ -791,6 +775,14 @@
bool is_service_isolate_;
+ // Isolate-specific flags.
+ NOT_IN_PRODUCT(
+ bool type_checks_;
+ bool asserts_;
+ bool error_on_bad_type_;
+ bool error_on_bad_override_;
+ )
+
// Status support.
char* stacktrace_;
intptr_t stack_frame_index_;
@@ -849,7 +841,7 @@
uint32_t prefix_invalidation_gen_;
// Protect access to boxed_field_list_.
- Monitor* boxed_field_list_monitor_;
+ Mutex* boxed_field_list_mutex_;
// List of fields that became boxed and that trigger deoptimization.
RawGrowableObjectArray* boxed_field_list_;
@@ -997,7 +989,7 @@
bool is_spawn_uri() const { return library_url_ == NULL; }
bool paused() const { return paused_; }
bool errors_are_fatal() const { return errors_are_fatal_; }
- Isolate::Flags* isolate_flags() { return &isolate_flags_; }
+ Dart_IsolateFlags* isolate_flags() { return &isolate_flags_; }
RawObject* ResolveFunction();
RawInstance* BuildArgs(Thread* thread);
@@ -1028,7 +1020,7 @@
Monitor* spawn_count_monitor_;
intptr_t* spawn_count_;
- Isolate::Flags isolate_flags_;
+ Dart_IsolateFlags isolate_flags_;
bool paused_;
bool errors_are_fatal_;
};
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/jit_optimizer.cc
similarity index 90%
rename from runtime/vm/flow_graph_optimizer.cc
rename to runtime/vm/jit_optimizer.cc
index fa5649f..f5f2211 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/jit_optimizer.cc
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-#include "vm/flow_graph_optimizer.h"
+#include "vm/jit_optimizer.h"
#include "vm/bit_vector.h"
#include "vm/branch_optimizer.h"
@@ -47,7 +47,7 @@
// Optimize instance calls using ICData.
-void FlowGraphOptimizer::ApplyICData() {
+void JitOptimizer::ApplyICData() {
VisitBlocks();
}
@@ -58,7 +58,7 @@
// have no runtime type feedback collected.
// Attempts to convert an instance call (IC call) using propagated class-ids,
// e.g., receiver class id, guarded-cid, or by guessing cid-s.
-void FlowGraphOptimizer::ApplyClassIds() {
+void JitOptimizer::ApplyClassIds() {
ASSERT(current_iterator_ == NULL);
for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
!block_it.Done();
@@ -89,7 +89,7 @@
}
-bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
+bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) {
ASSERT(call->HasICData());
if (call->ic_data()->NumberOfUsedChecks() > 0) {
// This occurs when an instance call has too many checks, will be converted
@@ -198,8 +198,8 @@
}
-const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data,
- intptr_t cid) {
+const ICData& JitOptimizer::TrySpecializeICData(const ICData& ic_data,
+ intptr_t cid) {
ASSERT(ic_data.NumArgsTested() == 1);
if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
@@ -226,7 +226,7 @@
}
-void FlowGraphOptimizer::SpecializePolymorphicInstanceCall(
+void JitOptimizer::SpecializePolymorphicInstanceCall(
PolymorphicInstanceCallInstr* call) {
if (!FLAG_polymorphic_with_deopt) {
// Specialization adds receiver checks which can lead to deoptimization.
@@ -275,7 +275,7 @@
}
-void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp(
+void JitOptimizer::OptimizeLeftShiftBitAndSmiOp(
Definition* bit_and_instr,
Definition* left_instr,
Definition* right_instr) {
@@ -313,10 +313,10 @@
}
-void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
- intptr_t index,
- Representation rep,
- intptr_t cid) {
+void JitOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
+ intptr_t index,
+ Representation rep,
+ intptr_t cid) {
ExtractNthOutputInstr* extract =
new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
instr->ReplaceUsesWith(extract);
@@ -341,7 +341,7 @@
// v7 <- +(v5, v6)
// Because of the environment it is important that merged instruction replaces
// first original instruction encountered.
-void FlowGraphOptimizer::TryMergeTruncDivMod(
+void JitOptimizer::TryMergeTruncDivMod(
GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
if (merge_candidates->length() < 2) {
// Need at least a TRUNCDIV and a MOD.
@@ -402,7 +402,7 @@
// Tries to merge MathUnary operations, in this case sinus and cosinus.
-void FlowGraphOptimizer::TryMergeMathUnary(
+void JitOptimizer::TryMergeMathUnary(
GrowableArray<MathUnaryInstr*>* merge_candidates) {
if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
!FLAG_merge_sin_cos) {
@@ -463,7 +463,7 @@
// Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
// shift can be a truncating Smi shift-left and result is always Smi.
// Merging occurs only per basic-block.
-void FlowGraphOptimizer::TryOptimizePatterns() {
+void JitOptimizer::TryOptimizePatterns() {
if (!FLAG_truncating_left_shift) return;
ASSERT(current_iterator_ == NULL);
GrowableArray<BinarySmiOpInstr*> div_mod_merge;
@@ -649,8 +649,8 @@
}
-void FlowGraphOptimizer::ReplaceCall(Definition* call,
- Definition* replacement) {
+void JitOptimizer::ReplaceCall(Definition* call,
+ Definition* replacement) {
// Remove the original push arguments.
for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
PushArgumentInstr* push = call->PushArgumentAt(i);
@@ -661,10 +661,10 @@
}
-void FlowGraphOptimizer::AddCheckSmi(Definition* to_check,
- intptr_t deopt_id,
- Environment* deopt_environment,
- Instruction* insert_before) {
+void JitOptimizer::AddCheckSmi(Definition* to_check,
+ intptr_t deopt_id,
+ Environment* deopt_environment,
+ Instruction* insert_before) {
if (to_check->Type()->ToCid() != kSmiCid) {
InsertBefore(insert_before,
new(Z) CheckSmiInstr(new(Z) Value(to_check),
@@ -676,10 +676,10 @@
}
-Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check,
- const ICData& unary_checks,
- intptr_t deopt_id,
- TokenPosition token_pos) {
+Instruction* JitOptimizer::GetCheckClass(Definition* to_check,
+ const ICData& unary_checks,
+ intptr_t deopt_id,
+ TokenPosition token_pos) {
if ((unary_checks.NumberOfUsedChecks() == 1) &&
unary_checks.HasReceiverClassId(kSmiCid)) {
return new(Z) CheckSmiInstr(new(Z) Value(to_check),
@@ -691,11 +691,11 @@
}
-void FlowGraphOptimizer::AddCheckClass(Definition* to_check,
- const ICData& unary_checks,
- intptr_t deopt_id,
- Environment* deopt_environment,
- Instruction* insert_before) {
+void JitOptimizer::AddCheckClass(Definition* to_check,
+ const ICData& unary_checks,
+ intptr_t deopt_id,
+ Environment* deopt_environment,
+ Instruction* insert_before) {
// Type propagation has not run yet, we cannot eliminate the check.
Instruction* check = GetCheckClass(
to_check, unary_checks, deopt_id, insert_before->token_pos());
@@ -703,7 +703,7 @@
}
-void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
+void JitOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
AddCheckClass(call->ArgumentAt(0),
ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
call->deopt_id(),
@@ -729,7 +729,7 @@
}
-bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
+bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
// Check for monomorphic IC data.
if (!call->HasICData()) return false;
const ICData& ic_data =
@@ -761,8 +761,8 @@
// comparison. Conversion is only possible for strings of length one.
// E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
// TODO(srdjan): Expand for two-byte and external strings.
-bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
- Token::Kind op_kind) {
+bool JitOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
+ Token::Kind op_kind) {
ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
// Check that left and right are length one strings (either string constants
// or results of string-from-char-code.
@@ -848,8 +848,8 @@
static bool SmiFitsInDouble() { return kSmiBits < 53; }
-bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
+ Token::Kind op_kind) {
const ICData& ic_data = *call->ic_data();
ASSERT(ic_data.NumArgsTested() == 2);
@@ -957,8 +957,8 @@
}
-bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
+ Token::Kind op_kind) {
const ICData& ic_data = *call->ic_data();
ASSERT(ic_data.NumArgsTested() == 2);
@@ -1019,8 +1019,8 @@
}
-bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
+ Token::Kind op_kind) {
intptr_t operands_type = kIllegalCid;
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
@@ -1228,8 +1228,8 @@
}
-bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
+ Token::Kind op_kind) {
ASSERT(call->ArgumentCount() == 1);
Definition* input = call->ArgumentAt(0);
Definition* unary_op = NULL;
@@ -1262,15 +1262,20 @@
}
-// Using field class
-RawField* FlowGraphOptimizer::GetField(intptr_t class_id,
- const String& field_name) {
+// Using field class.
+RawField* JitOptimizer::GetField(intptr_t class_id,
+ const String& field_name) {
Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
Field& field = Field::Handle(Z);
while (!cls.IsNull()) {
field = cls.LookupInstanceField(field_name);
if (!field.IsNull()) {
- return field.raw();
+ if (Compiler::IsBackgroundCompilation() ||
+ FLAG_force_clone_compiler_objects) {
+ return field.CloneFromOriginal();
+ } else {
+ return field.raw();
+ }
}
cls = cls.SuperClass();
}
@@ -1281,7 +1286,7 @@
// Use CHA to determine if the call needs a class check: if the callee's
// receiver is the same as the caller's receiver and there are no overriden
// callee functions, then no class check is needed.
-bool FlowGraphOptimizer::InstanceCallNeedsClassCheck(
+bool JitOptimizer::InstanceCallNeedsClassCheck(
InstanceCallInstr* call, RawFunction::Kind kind) const {
if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) {
// Even if class or function are private, lazy class finalization
@@ -1312,8 +1317,7 @@
}
-bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
- bool allow_check) {
+bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
ASSERT(ic_data.HasOneTarget());
@@ -1328,9 +1332,6 @@
ASSERT(!field.IsNull());
if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) {
- if (!allow_check) {
- return false;
- }
AddReceiverCheck(call);
}
LoadFieldInstr* load = new(Z) LoadFieldInstr(
@@ -1363,8 +1364,8 @@
}
-bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
- MethodRecognizer::Kind getter) {
+bool JitOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
+ MethodRecognizer::Kind getter) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1438,8 +1439,8 @@
}
-bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
- MethodRecognizer::Kind getter) {
+bool JitOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
+ MethodRecognizer::Kind getter) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1464,8 +1465,8 @@
}
-bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
- MethodRecognizer::Kind getter) {
+bool JitOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
+ MethodRecognizer::Kind getter) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1539,8 +1540,8 @@
}
-bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
+ Token::Kind op_kind) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1572,8 +1573,8 @@
}
-bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
+ Token::Kind op_kind) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1604,8 +1605,8 @@
}
-bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
- Token::Kind op_kind) {
+bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
+ Token::Kind op_kind) {
if (!ShouldInlineSimd()) {
return false;
}
@@ -1637,9 +1638,7 @@
// Only unique implicit instance getters can be currently handled.
-// Returns false if 'allow_check' is false and a check is needed.
-bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call,
- bool allow_check) {
+bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
if (ic_data.NumberOfUsedChecks() == 0) {
@@ -1659,11 +1658,11 @@
// inlining in FlowGraphInliner.
return false;
}
- return InlineImplicitInstanceGetter(call, allow_check);
+ return InlineImplicitInstanceGetter(call);
}
-bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline(
+bool JitOptimizer::TryReplaceInstanceCallWithInline(
InstanceCallInstr* call) {
Function& target = Function::Handle(Z);
GrowableArray<intptr_t> class_ids;
@@ -1707,7 +1706,7 @@
}
-void FlowGraphOptimizer::ReplaceWithMathCFunction(
+void JitOptimizer::ReplaceWithMathCFunction(
InstanceCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
AddReceiverCheck(call);
@@ -1748,7 +1747,7 @@
// Inline only simple, frequently called core library methods.
-bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
+bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
@@ -1981,7 +1980,7 @@
}
-bool FlowGraphOptimizer::TryInlineFloat32x4Constructor(
+bool JitOptimizer::TryInlineFloat32x4Constructor(
StaticCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
if (!ShouldInlineSimd()) {
@@ -2024,7 +2023,7 @@
}
-bool FlowGraphOptimizer::TryInlineFloat64x2Constructor(
+bool JitOptimizer::TryInlineFloat64x2Constructor(
StaticCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
if (!ShouldInlineSimd()) {
@@ -2059,7 +2058,7 @@
}
-bool FlowGraphOptimizer::TryInlineInt32x4Constructor(
+bool JitOptimizer::TryInlineInt32x4Constructor(
StaticCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
if (!ShouldInlineSimd()) {
@@ -2096,7 +2095,7 @@
}
-bool FlowGraphOptimizer::TryInlineFloat32x4Method(
+bool JitOptimizer::TryInlineFloat32x4Method(
InstanceCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
if (!ShouldInlineSimd()) {
@@ -2260,7 +2259,7 @@
}
-bool FlowGraphOptimizer::TryInlineFloat64x2Method(
+bool JitOptimizer::TryInlineFloat64x2Method(
InstanceCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
if (!ShouldInlineSimd()) {
@@ -2319,7 +2318,7 @@
}
-bool FlowGraphOptimizer::TryInlineInt32x4Method(
+bool JitOptimizer::TryInlineInt32x4Method(
InstanceCallInstr* call,
MethodRecognizer::Kind recognized_kind) {
if (!ShouldInlineSimd()) {
@@ -2390,7 +2389,7 @@
// If no mapping is possible, 'results' is empty.
// An instance-of test returning all same results can be converted to a class
// check.
-RawBool* FlowGraphOptimizer::InstanceOfAsBool(
+RawBool* JitOptimizer::InstanceOfAsBool(
const ICData& ic_data,
const AbstractType& type,
ZoneGrowableArray<intptr_t>* results) const {
@@ -2449,7 +2448,7 @@
// Returns true if checking against this type is a direct class id comparison.
-bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
+bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
// Requires CHA.
if (!type.IsInstantiated()) return false;
@@ -2553,7 +2552,7 @@
// TODO(srdjan): Use ICData to check if always true or false.
-void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
+void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
ASSERT(Token::IsTypeTestOperator(call->token_kind()));
Definition* left = call->ArgumentAt(0);
Definition* type_args = NULL;
@@ -2661,7 +2660,7 @@
// TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
-void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
+void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
ASSERT(Token::IsTypeCastOperator(call->token_kind()));
Definition* left = call->ArgumentAt(0);
Definition* type_args = call->ArgumentAt(1);
@@ -2704,154 +2703,9 @@
}
-bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) {
- for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) {
- if ((*inlining_black_list_)[i] == call_deopt_id) return true;
- }
- return false;
-}
-
-// Special optimizations when running in --noopt mode.
-void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) {
- // TODO(srdjan): Investigate other attempts, as they are not allowed to
- // deoptimize.
-
- // Type test is special as it always gets converted into inlined code.
- const Token::Kind op_kind = instr->token_kind();
- if (Token::IsTypeTestOperator(op_kind)) {
- ReplaceWithInstanceOf(instr);
- return;
- }
- if (Token::IsTypeCastOperator(op_kind)) {
- ReplaceWithTypeCast(instr);
- return;
- }
-
- if ((op_kind == Token::kGET) &&
- TryInlineInstanceGetter(instr, false /* no checks allowed */)) {
- return;
- }
- const ICData& unary_checks =
- ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
- if ((unary_checks.NumberOfChecks() > 0) &&
- (op_kind == Token::kSET) &&
- TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) {
- return;
- }
-
- if (use_speculative_inlining_ &&
- !IsBlackListedForInlining(instr->deopt_id()) &&
- (unary_checks.NumberOfChecks() > 0)) {
- if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
- return;
- }
- if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
- return;
- }
- if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) {
- return;
- }
-
- if (Token::IsRelationalOperator(op_kind) &&
- TryReplaceWithRelationalOp(instr, op_kind)) {
- return;
- }
-
- if (Token::IsBinaryOperator(op_kind) &&
- TryReplaceWithBinaryOp(instr, op_kind)) {
- return;
- }
- if (Token::IsUnaryOperator(op_kind) &&
- TryReplaceWithUnaryOp(instr, op_kind)) {
- return;
- }
- }
-
- bool has_one_target =
- (unary_checks.NumberOfChecks() > 0) && unary_checks.HasOneTarget();
- if (has_one_target) {
- // Check if the single target is a polymorphic target, if it is,
- // we don't have one target.
- const Function& target =
- Function::Handle(Z, unary_checks.GetTargetAt(0));
- const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
- has_one_target = !polymorphic_target;
- }
-
- if (has_one_target) {
- RawFunction::Kind function_kind =
- Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
- if (!InstanceCallNeedsClassCheck(instr, function_kind)) {
- PolymorphicInstanceCallInstr* call =
- new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
- /* with_checks = */ false);
- instr->ReplaceWith(call, current_iterator());
- return;
- }
- }
-
- // More than one targets. Generate generic polymorphic call without
- // deoptimization.
- if (instr->ic_data()->NumberOfUsedChecks() > 0) {
- ASSERT(!FLAG_polymorphic_with_deopt);
- // OK to use checks with PolymorphicInstanceCallInstr since no
- // deoptimization is allowed.
- PolymorphicInstanceCallInstr* call =
- new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
- /* with_checks = */ true);
- instr->ReplaceWith(call, current_iterator());
- return;
- }
-
- // No IC data checks. Try resolve target using the propagated type.
- // If the propagated type has a method with the target name and there are
- // no overrides with that name according to CHA, call the method directly.
- const intptr_t receiver_cid =
- instr->PushArgumentAt(0)->value()->Type()->ToCid();
- if (receiver_cid == kDynamicCid) return;
- const Class& receiver_class = Class::Handle(Z,
- isolate()->class_table()->At(receiver_cid));
-
- const Array& args_desc_array = Array::Handle(Z,
- ArgumentsDescriptor::New(instr->ArgumentCount(),
- instr->argument_names()));
- ArgumentsDescriptor args_desc(args_desc_array);
- const Function& function = Function::Handle(Z,
- Resolver::ResolveDynamicForReceiverClass(
- receiver_class,
- instr->function_name(),
- args_desc));
- if (function.IsNull()) {
- return;
- }
- if (!thread()->cha()->HasOverride(receiver_class, instr->function_name())) {
- if (FLAG_trace_cha) {
- THR_Print(" **(CHA) Instance call needs no check, "
- "no overrides of '%s' '%s'\n",
- instr->function_name().ToCString(), receiver_class.ToCString());
- }
- thread()->cha()->AddToLeafClasses(receiver_class);
-
- // Create fake IC data with the resolved target.
- const ICData& ic_data = ICData::Handle(
- ICData::New(flow_graph_->function(),
- instr->function_name(),
- args_desc_array,
- Thread::kNoDeoptId,
- /* args_tested = */ 1));
- ic_data.AddReceiverCheck(receiver_class.id(), function);
- PolymorphicInstanceCallInstr* call =
- new(Z) PolymorphicInstanceCallInstr(instr, ic_data,
- /* with_checks = */ false);
- instr->ReplaceWith(call, current_iterator());
- return;
- }
-}
-
-
// Tries to optimize instance call by replacing it with a faster instruction
// (e.g, binary op, field load, ..).
-void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
+void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
return;
}
@@ -2957,7 +2811,7 @@
}
-void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
+void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
if (!CanUnboxDouble()) {
return;
}
@@ -3130,7 +2984,7 @@
}
-void FlowGraphOptimizer::VisitStoreInstanceField(
+void JitOptimizer::VisitStoreInstanceField(
StoreInstanceFieldInstr* instr) {
if (instr->IsUnboxedStore()) {
ASSERT(instr->is_potential_unboxed_initialization_);
@@ -3139,9 +2993,9 @@
// usage count of at least 1/kGetterSetterRatio of the getter usage count.
// This is to avoid unboxing fields where the setter is never or rarely
// executed.
- const Field& field = Field::ZoneHandle(Z, instr->field().raw());
+ const Field& field = Field::ZoneHandle(Z, instr->field().Original());
const String& field_name = String::Handle(Z, field.name());
- const Class& owner = Class::Handle(Z, field.owner());
+ const Class& owner = Class::Handle(Z, field.Owner());
const Function& getter =
Function::Handle(Z, owner.LookupGetterFunction(field_name));
const Function& setter =
@@ -3184,7 +3038,7 @@
}
-void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
+void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
// Replace generic allocation with a sequence of inlined allocation and
// explicit initalizing stores.
AllocateUninitializedContextInstr* replacement =
@@ -3219,7 +3073,7 @@
}
-void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
+void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
// TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
if (!instr->can_pack_into_smi())
@@ -3228,12 +3082,11 @@
}
-bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
- const ICData& unary_ic_data,
- bool allow_checks) {
+bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
+ const ICData& unary_ic_data) {
ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
(unary_ic_data.NumArgsTested() == 1));
- if (I->flags().type_checks()) {
+ if (I->type_checks()) {
// Checked mode setters are inlined like normal methods by conventional
// inlining.
return false;
@@ -3264,15 +3117,9 @@
ASSERT(!field.IsNull());
if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) {
- if (!allow_checks) {
- return false;
- }
AddReceiverCheck(instr);
}
if (field.guarded_cid() != kDynamicCid) {
- if (!allow_checks) {
- return false;
- }
InsertBefore(instr,
new(Z) GuardFieldClassInstr(
new(Z) Value(instr->ArgumentAt(1)),
@@ -3283,9 +3130,6 @@
}
if (field.needs_length_check()) {
- if (!allow_checks) {
- return false;
- }
InsertBefore(instr,
new(Z) GuardFieldLengthInstr(
new(Z) Value(instr->ArgumentAt(1)),
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/jit_optimizer.h
similarity index 85%
rename from runtime/vm/flow_graph_optimizer.h
rename to runtime/vm/jit_optimizer.h
index 544d7de..ebddc78 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/jit_optimizer.h
@@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-#ifndef VM_FLOW_GRAPH_OPTIMIZER_H_
-#define VM_FLOW_GRAPH_OPTIMIZER_H_
+#ifndef VM_JIT_OPTIMIZER_H_
+#define VM_JIT_OPTIMIZER_H_
#include "vm/intermediate_language.h"
#include "vm/flow_graph.h"
@@ -14,19 +14,13 @@
template <typename T> class GrowableArray;
class ParsedFunction;
-class FlowGraphOptimizer : public FlowGraphVisitor {
+class JitOptimizer : public FlowGraphVisitor {
public:
- FlowGraphOptimizer(
- FlowGraph* flow_graph,
- bool use_speculative_inlining,
- GrowableArray<intptr_t>* inlining_black_list)
+ explicit JitOptimizer(FlowGraph* flow_graph)
: FlowGraphVisitor(flow_graph->reverse_postorder()),
- flow_graph_(flow_graph),
- use_speculative_inlining_(use_speculative_inlining),
- inlining_black_list_(inlining_black_list) {
- ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
- }
- virtual ~FlowGraphOptimizer() {}
+ flow_graph_(flow_graph) { }
+
+ virtual ~JitOptimizer() {}
FlowGraph* flow_graph() const { return flow_graph_; }
@@ -70,11 +64,9 @@
bool TryReplaceWithEqualityOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
- bool TryInlineInstanceGetter(InstanceCallInstr* call,
- bool allow_check = true);
+ bool TryInlineInstanceGetter(InstanceCallInstr* call);
bool TryInlineInstanceSetter(InstanceCallInstr* call,
- const ICData& unary_ic_data,
- bool allow_check = true);
+ const ICData& unary_ic_data);
bool TryInlineInstanceMethod(InstanceCallInstr* call);
bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
@@ -138,7 +130,7 @@
Token::Kind op_kind);
bool InlineFloat64x2BinaryOp(InstanceCallInstr* call,
Token::Kind op_kind);
- bool InlineImplicitInstanceGetter(InstanceCallInstr* call, bool allow_check);
+ bool InlineImplicitInstanceGetter(InstanceCallInstr* call);
RawBool* InstanceOfAsBool(const ICData& ic_data,
const AbstractType& type,
@@ -157,8 +149,6 @@
Representation rep, intptr_t cid);
bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
- void InstanceCallNoopt(InstanceCallInstr* instr);
-
RawField* GetField(intptr_t class_id, const String& field_name);
Thread* thread() const { return flow_graph_->thread(); }
@@ -167,18 +157,12 @@
const Function& function() const { return flow_graph_->function(); }
- bool IsBlackListedForInlining(intptr_t deopt_id);
-
FlowGraph* flow_graph_;
- const bool use_speculative_inlining_;
-
- GrowableArray<intptr_t>* inlining_black_list_;
-
- DISALLOW_COPY_AND_ASSIGN(FlowGraphOptimizer);
+ DISALLOW_COPY_AND_ASSIGN(JitOptimizer);
};
} // namespace dart
-#endif // VM_FLOW_GRAPH_OPTIMIZER_H_
+#endif // VM_JIT_OPTIMIZER_H_
diff --git a/runtime/vm/lockers.cc b/runtime/vm/lockers.cc
index 839d40c..2efe245 100644
--- a/runtime/vm/lockers.cc
+++ b/runtime/vm/lockers.cc
@@ -9,6 +9,23 @@
namespace dart {
+static void updateThreadState(Thread* thread) {
+ // First try a fast update of the thread state to indicate it is not at a
+ // safepoint anymore.
+ uword old_state = Thread::SetAtSafepoint(true, 0);
+ uword addr =
+ reinterpret_cast<uword>(thread) + Thread::safepoint_state_offset();
+ if (AtomicOperations::CompareAndSwapWord(
+ reinterpret_cast<uword*>(addr), old_state, 0) != old_state) {
+ // Fast update failed which means we could potentially be in the middle
+ // of a safepoint operation and need to block for it.
+ SafepointHandler* handler = thread->isolate()->safepoint_handler();
+ handler->ExitSafepointUsingLock(thread);
+ }
+ thread->set_execution_state(Thread::kThreadInVM);
+}
+
+
Monitor::WaitResult MonitorLocker::WaitWithSafepointCheck(Thread* thread,
int64_t millis) {
ASSERT(thread == Thread::Current());
@@ -40,9 +57,45 @@
// We did not get the lock and could potentially block, so transition
// accordingly.
Thread* thread = Thread::Current();
+ if (thread != NULL) {
+ thread->set_execution_state(Thread::kThreadInBlockedState);
+ thread->EnterSafepoint();
+ mutex->Lock();
+ // Update thread state and block if a safepoint operation is in progress.
+ updateThreadState(thread);
+ } else {
+ mutex->Lock();
+ }
+ }
+}
+
+
+SafepointMonitorLocker::SafepointMonitorLocker(Monitor* monitor)
+ : monitor_(monitor) {
+ ASSERT(monitor_ != NULL);
+ if (!monitor_->TryEnter()) {
+ // We did not get the lock and could potentially block, so transition
+ // accordingly.
+ Thread* thread = Thread::Current();
+ if (thread != NULL) {
+ thread->set_execution_state(Thread::kThreadInBlockedState);
+ thread->EnterSafepoint();
+ monitor_->Enter();
+ // Update thread state and block if a safepoint operation is in progress.
+ updateThreadState(thread);
+ } else {
+ monitor_->Enter();
+ }
+ }
+}
+
+
+Monitor::WaitResult SafepointMonitorLocker::Wait(int64_t millis) {
+ Thread* thread = Thread::Current();
+ if (thread != NULL) {
thread->set_execution_state(Thread::kThreadInBlockedState);
thread->EnterSafepoint();
- mutex->Lock();
+ Monitor::WaitResult result = monitor_->Wait(millis);
// First try a fast update of the thread state to indicate it is not at a
// safepoint anymore.
uword old_state = Thread::SetAtSafepoint(true, 0);
@@ -52,10 +105,15 @@
reinterpret_cast<uword*>(addr), old_state, 0) != old_state) {
// Fast update failed which means we could potentially be in the middle
// of a safepoint operation and need to block for it.
+ monitor_->Exit();
SafepointHandler* handler = thread->isolate()->safepoint_handler();
handler->ExitSafepointUsingLock(thread);
+ monitor_->Enter();
}
thread->set_execution_state(Thread::kThreadInVM);
+ return result;
+ } else {
+ return monitor_->Wait(millis);
}
}
diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h
index fd324f4..a0b1a17 100644
--- a/runtime/vm/lockers.h
+++ b/runtime/vm/lockers.h
@@ -13,37 +13,156 @@
namespace dart {
+const bool kNoSafepointScope = true;
+const bool kDontAssertNoSafepointScope = false;
+
+/*
+ * Normal mutex locker :
+ * This locker abstraction should only be used when the enclosing code can
+ * not trigger a safepoint. In debug mode this class increments the
+ * no_safepoint_scope_depth variable for the current thread when the lock is
+ * taken and decrements it when the lock is released. NOTE: please do not use
+ * the passed in mutex object independent of the locker class, For example the
+ * code below will not assert correctly:
+ * {
+ * MutexLocker ml(m);
+ * ....
+ * m->Exit();
+ * ....
+ * m->Enter();
+ * ...
+ * }
+ * Always use the locker object even when the lock needs to be released
+ * temporarily, e.g:
+ * {
+ * MutexLocker ml(m);
+ * ....
+ * ml.Exit();
+ * ....
+ * ml.Enter();
+ * ...
+ * }
+ */
class MutexLocker : public ValueObject {
public:
- explicit MutexLocker(Mutex* mutex) : mutex_(mutex) {
+ explicit MutexLocker(Mutex* mutex, bool no_safepoint_scope = true)
+ : mutex_(mutex), no_safepoint_scope_(no_safepoint_scope) {
ASSERT(mutex != NULL);
- // TODO(iposva): Consider adding a no GC scope here.
+#if defined(DEBUG)
+ if (no_safepoint_scope_) {
+ Thread* thread = Thread::Current();
+ if (thread != NULL) {
+ thread->IncrementNoSafepointScopeDepth();
+ } else {
+ no_safepoint_scope_ = false;
+ }
+ }
+#endif
mutex_->Lock();
}
virtual ~MutexLocker() {
mutex_->Unlock();
- // TODO(iposva): Consider decrementing the no GC scope here.
+#if defined(DEBUG)
+ if (no_safepoint_scope_) {
+ Thread::Current()->DecrementNoSafepointScopeDepth();
+ }
+#endif
+ }
+
+ void Lock() const {
+#if defined(DEBUG)
+ if (no_safepoint_scope_) {
+ Thread::Current()->IncrementNoSafepointScopeDepth();
+ }
+#endif
+ mutex_->Lock();
+ }
+ void Unlock() const {
+ mutex_->Unlock();
+#if defined(DEBUG)
+ if (no_safepoint_scope_) {
+ Thread::Current()->DecrementNoSafepointScopeDepth();
+ }
+#endif
}
private:
Mutex* const mutex_;
+ bool no_safepoint_scope_;
DISALLOW_COPY_AND_ASSIGN(MutexLocker);
};
-
+/*
+ * Normal monitor locker :
+ * This locker abstraction should only be used when the enclosing code can
+ * not trigger a safepoint. In debug mode this class increments the
+ * no_safepoint_scope_depth variable for the current thread when the lock is
+ * taken and decrements it when the lock is released. NOTE: please do not use
+ * the passed in mutex object independent of the locker class, For example the
+ * code below will not assert correctly:
+ * {
+ * MonitorLocker ml(m);
+ * ....
+ * m->Exit();
+ * ....
+ * m->Enter();
+ * ...
+ * }
+ * Always use the locker object even when the lock needs to be released
+ * temporarily, e.g:
+ * {
+ * MonitorLocker ml(m);
+ * ....
+ * ml.Exit();
+ * ....
+ * ml.Enter();
+ * ...
+ * }
+ */
class MonitorLocker : public ValueObject {
public:
- explicit MonitorLocker(Monitor* monitor) : monitor_(monitor) {
+ explicit MonitorLocker(Monitor* monitor, bool no_safepoint_scope = true)
+ : monitor_(monitor), no_safepoint_scope_(no_safepoint_scope) {
ASSERT(monitor != NULL);
- // TODO(iposva): Consider adding a no GC scope here.
+#if defined(DEBUG)
+ if (no_safepoint_scope_) {
+ Thread* thread = Thread::Current();
+ if (thread != NULL) {
+ thread->IncrementNoSafepointScopeDepth();
+ } else {
+ no_safepoint_scope_ = false;
+ }
+ }
+#endif
monitor_->Enter();
}
virtual ~MonitorLocker() {
monitor_->Exit();
- // TODO(iposva): Consider decrementing the no GC scope here.
+#if defined(DEBUG)
+ if (no_safepoint_scope_) {
+ Thread::Current()->DecrementNoSafepointScopeDepth();
+ }
+#endif
+ }
+
+ void Enter() const {
+#if defined(DEBUG)
+ if (no_safepoint_scope_) {
+ Thread::Current()->IncrementNoSafepointScopeDepth();
+ }
+#endif
+ monitor_->Enter();
+ }
+ void Exit() const {
+ monitor_->Exit();
+#if defined(DEBUG)
+ if (no_safepoint_scope_) {
+ Thread::Current()->DecrementNoSafepointScopeDepth();
+ }
+#endif
}
Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout) {
@@ -67,16 +186,29 @@
private:
Monitor* const monitor_;
+ bool no_safepoint_scope_;
DISALLOW_COPY_AND_ASSIGN(MonitorLocker);
};
-
-// SafepointMutexLocker objects are used in code where the locks are
-// more coarse grained and a safepoint operation could be potentially
-// triggered while holding this lock. This ensures that other threads
-// which try to acquire the same lock will be marked as being at a
-// safepoint when they are blocked.
+/*
+ * Safepoint mutex locker :
+ * This locker abstraction should be used when the enclosing code could
+ * potentially trigger a safepoint.
+ * This locker ensures that other threads that try to acquire the same lock
+ * will be marked as being at a safepoint if they get blocked trying to
+ * acquire the lock.
+ * NOTE: please do not use the passed in mutex object independent of the locker
+ * class, For example the code below will not work correctly:
+ * {
+ * SafepointMutexLocker ml(m);
+ * ....
+ * m->Exit();
+ * ....
+ * m->Enter();
+ * ...
+ * }
+ */
class SafepointMutexLocker : public ValueObject {
public:
explicit SafepointMutexLocker(Mutex* mutex);
@@ -90,6 +222,39 @@
DISALLOW_COPY_AND_ASSIGN(SafepointMutexLocker);
};
+/*
+ * Safepoint monitor locker :
+ * This locker abstraction should be used when the enclosing code could
+ * potentially trigger a safepoint.
+ * This locker ensures that other threads that try to acquire the same lock
+ * will be marked as being at a safepoint if they get blocked trying to
+ * acquire the lock.
+ * NOTE: please do not use the passed in monitor object independent of the
+ * locker class, For example the code below will not work correctly:
+ * {
+ * SafepointMonitorLocker ml(m);
+ * ....
+ * m->Exit();
+ * ....
+ * m->Enter();
+ * ...
+ * }
+ */
+class SafepointMonitorLocker : public ValueObject {
+ public:
+ explicit SafepointMonitorLocker(Monitor* monitor);
+ virtual ~SafepointMonitorLocker() {
+ monitor_->Exit();
+ }
+
+ Monitor::WaitResult Wait(int64_t millis = Monitor::kNoTimeout);
+
+ private:
+ Monitor* const monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(SafepointMonitorLocker);
+};
+
} // namespace dart
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index 062941e..6c4ccf1 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -16,7 +16,7 @@
const String& name,
const Array& descriptor) {
// Multiple compilation threads could access this lookup.
- MutexLocker ml(isolate->mutex());
+ SafepointMutexLocker ml(isolate->mutex());
ASSERT(name.IsSymbol());
// TODO(rmacnak): ASSERT(descriptor.IsCanonical());
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index e64a05a..c1a9980 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -176,6 +176,7 @@
MessageHandler::MessageStatus MessageHandler::HandleMessages(
+ MonitorLocker* ml,
bool allow_normal_messages,
bool allow_multiple_normal_messages) {
// TODO(turnidge): Add assert that monitor_ is held here.
@@ -200,7 +201,7 @@
// Release the monitor_ temporarily while we handle the message.
// The monitor was acquired in MessageHandler::TaskCallback().
- monitor_.Exit();
+ ml->Exit();
Message::Priority saved_priority = message->priority();
Dart_Port saved_dest_port = message->dest_port();
MessageStatus status = HandleMessage(message);
@@ -208,7 +209,7 @@
max_status = status;
}
message = NULL; // May be deleted by now.
- monitor_.Enter();
+ ml->Enter();
if (FLAG_trace_isolates) {
OS::Print("[.] Message handled (%s):\n"
"\tlen: %" Pd "\n"
@@ -254,7 +255,7 @@
#if defined(DEBUG)
CheckAccess();
#endif
- return HandleMessages(true, false);
+ return HandleMessages(&ml, true, false);
}
@@ -266,7 +267,7 @@
#if defined(DEBUG)
CheckAccess();
#endif
- return HandleMessages(true, true);
+ return HandleMessages(&ml, true, true);
}
@@ -278,7 +279,7 @@
#if defined(DEBUG)
CheckAccess();
#endif
- return HandleMessages(false, false);
+ return HandleMessages(&ml, false, false);
}
@@ -327,7 +328,7 @@
PausedOnStartLocked(true);
}
// More messages may have come in before we (re)acquired the monitor.
- status = HandleMessages(false, false);
+ status = HandleMessages(&ml, false, false);
if (ShouldPauseOnStart(status)) {
// Still paused.
ASSERT(oob_queue_->IsEmpty());
@@ -345,16 +346,16 @@
// main() function.
//
// Release the monitor_ temporarily while we call the start callback.
- monitor_.Exit();
+ ml.Exit();
status = start_callback_(callback_data_);
ASSERT(Isolate::Current() == NULL);
start_callback_ = NULL;
- monitor_.Enter();
+ ml.Enter();
}
// Handle any pending messages for this message handler.
if (status != kShutdown) {
- status = HandleMessages((status == kOK), true);
+ status = HandleMessages(&ml, (status == kOK), true);
}
}
@@ -369,7 +370,7 @@
}
PausedOnExitLocked(true);
// More messages may have come in while we released the monitor.
- status = HandleMessages(false, false);
+ status = HandleMessages(&ml, false, false);
}
if (ShouldPauseOnExit(status)) {
// Still paused.
diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h
index 47dfa99..6f01328 100644
--- a/runtime/vm/message_handler.h
+++ b/runtime/vm/message_handler.h
@@ -12,6 +12,9 @@
namespace dart {
+// Forward declarations.
+class MonitorLocker;
+
// A MessageHandler is an entity capable of accepting messages.
class MessageHandler {
protected:
@@ -225,7 +228,8 @@
void ClearOOBQueue();
// Handles any pending messages.
- MessageStatus HandleMessages(bool allow_normal_messages,
+ MessageStatus HandleMessages(MonitorLocker* ml,
+ bool allow_normal_messages,
bool allow_multiple_normal_messages);
Monitor monitor_; // Protects all fields in MessageHandler.
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 5547282..87a524e 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -13,310 +13,307 @@
// When adding a new function add a 0 as fingerprint, build and run to get the
// correct fingerprint from the mismatch error.
#define OTHER_RECOGNIZED_LIST(V) \
- V(::, identical, ObjectIdentical, 554128144) \
- V(ClassID, getID, ClassIDgetID, 535124072) \
- V(Object, Object., ObjectConstructor, 1852396454) \
- V(_List, ., ObjectArrayAllocate, 850375012) \
- V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 1541411498) \
- V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1032404349) \
- V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 381073990) \
- V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1142676276) \
- V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 330269934) \
- V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 59490554) \
- V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 322272622) \
- V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 393003933) \
- V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1792407200) \
- V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1338379857) \
- V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 1469917805) \
- V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 1892735922) \
- V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 1608794041) \
- V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 117380972) \
- V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 200484754) \
- V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1020151991) \
- V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1175056602) \
- V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 784983863) \
- V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 460607665) \
- V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 284787790) \
- V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 262426120) \
- V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 613041888) \
- V(_StringBase, _interpolate, StringBaseInterpolate, 1214901263) \
- V(_IntegerImplementation, toDouble, IntegerToDouble, 826404440) \
+ V(::, identical, ObjectIdentical, 317103244) \
+ V(ClassID, getID, ClassIDgetID, 1385157717) \
+ V(Object, Object., ObjectConstructor, 1746278398) \
+ V(_List, ., ObjectArrayAllocate, 184405219) \
+ V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 187609847) \
+ V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1826086346) \
+ V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 1174755987) \
+ V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1936358273) \
+ V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 1123951931) \
+ V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 853172551) \
+ V(_TypedList, _getInt64, ByteArrayBaseGetInt64, 1115954619) \
+ V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 165422183) \
+ V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1564825450) \
+ V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1123952315) \
+ V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 831892409) \
+ V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 2043203289) \
+ V(_TypedList, _setUint8, ByteArrayBaseSetUint8, 1759261408) \
+ V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 267848339) \
+ V(_TypedList, _setUint16, ByteArrayBaseSetUint16, 350952121) \
+ V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1170619358) \
+ V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1325523969) \
+ V(_TypedList, _setInt64, ByteArrayBaseSetInt64, 935451230) \
+ V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 541136999) \
+ V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 365317124) \
+ V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 1766802707) \
+ V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 2075229300) \
+ V(_StringBase, _interpolate, StringBaseInterpolate, 1597087225) \
+ V(_IntegerImplementation, toDouble, IntegerToDouble, 150718448) \
V(_IntegerImplementation, _leftShiftWithMask32, \
- IntegerLeftShiftWithMask32, 598958097) \
- V(_Double, truncateToDouble, DoubleTruncate, 2117801967) \
- V(_Double, roundToDouble, DoubleRound, 2124216110) \
- V(_Double, floorToDouble, DoubleFloor, 968600699) \
- V(_Double, ceilToDouble, DoubleCeil, 1779929274) \
- V(_Double, _modulo, DoubleMod, 1473971007) \
- V(_Double, _add, DoubleAdd, 1570715125) \
- V(_Double, _sub, DoubleSub, 1466395310) \
- V(_Double, _mul, DoubleMul, 546441193) \
- V(_Double, _div, DoubleDiv, 1201505037) \
- V(::, sin, MathSin, 1741396147) \
- V(::, cos, MathCos, 1951197905) \
- V(::, tan, MathTan, 982072809) \
- V(::, asin, MathAsin, 1651042633) \
- V(::, acos, MathAcos, 1139647090) \
- V(::, atan, MathAtan, 1668754384) \
- V(::, atan2, MathAtan2, 1931713076) \
- V(::, min, MathMin, 478627534) \
- V(::, max, MathMax, 212291192) \
- V(::, _doublePow, MathDoublePow, 1286501289) \
- V(Float32x4, Float32x4., Float32x4Constructor, 1413513587) \
- V(Float32x4, Float32x4.zero, Float32x4Zero, 865663495) \
- V(Float32x4, Float32x4.splat, Float32x4Splat, 964312836) \
- V(Float32x4, Float32x4.fromInt32x4Bits, Float32x4FromInt32x4Bits, 688177588) \
- V(Float32x4, Float32x4.fromFloat64x2, Float32x4FromFloat64x2, 1327692716) \
- V(_Float32x4, shuffle, Float32x4Shuffle, 1636488139) \
- V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 654814229) \
- V(_Float32x4, get:signMask, Float32x4GetSignMask, 630880675) \
- V(_Float32x4, _cmpequal, Float32x4Equal, 571062952) \
- V(_Float32x4, _cmpgt, Float32x4GreaterThan, 1613543295) \
- V(_Float32x4, _cmpgte, Float32x4GreaterThanOrEqual, 589402909) \
- V(_Float32x4, _cmplt, Float32x4LessThan, 1502332656) \
- V(_Float32x4, _cmplte, Float32x4LessThanOrEqual, 1069848031) \
- V(_Float32x4, _cmpnequal, Float32x4NotEqual, 1334574472) \
- V(_Float32x4, _min, Float32x4Min, 2036349551) \
- V(_Float32x4, _max, Float32x4Max, 571688115) \
- V(_Float32x4, _scale, Float32x4Scale, 1311297761) \
- V(_Float32x4, _sqrt, Float32x4Sqrt, 1709659395) \
- V(_Float32x4, _reciprocalSqrt, Float32x4ReciprocalSqrt, 2043980962) \
- V(_Float32x4, _reciprocal, Float32x4Reciprocal, 739405237) \
- V(_Float32x4, _negate, Float32x4Negate, 445839777) \
- V(_Float32x4, _abs, Float32x4Absolute, 1152777608) \
- V(_Float32x4, _clamp, Float32x4Clamp, 410673744) \
- V(_Float32x4, withX, Float32x4WithX, 1446546696) \
- V(_Float32x4, withY, Float32x4WithY, 309844761) \
- V(_Float32x4, withZ, Float32x4WithZ, 971921505) \
- V(_Float32x4, withW, Float32x4WithW, 1759699726) \
- V(Float64x2, Float64x2., Float64x2Constructor, 1047027504) \
- V(Float64x2, Float64x2.zero, Float64x2Zero, 1208364703) \
- V(Float64x2, Float64x2.splat, Float64x2Splat, 987392531) \
- V(Float64x2, Float64x2.fromFloat32x4, Float64x2FromFloat32x4, 1547827778) \
- V(_Float64x2, get:x, Float64x2GetX, 261163258) \
- V(_Float64x2, get:y, Float64x2GetY, 1942377050) \
- V(_Float64x2, _negate, Float64x2Negate, 2133212774) \
- V(_Float64x2, abs, Float64x2Abs, 1224776282) \
- V(_Float64x2, sqrt, Float64x2Sqrt, 1037569520) \
- V(_Float64x2, get:signMask, Float64x2GetSignMask, 253055964) \
- V(_Float64x2, scale, Float64x2Scale, 1199438744) \
- V(_Float64x2, withX, Float64x2WithX, 1042725932) \
- V(_Float64x2, withY, Float64x2WithY, 1496958947) \
- V(_Float64x2, min, Float64x2Min, 485240583) \
- V(_Float64x2, max, Float64x2Max, 2146148204) \
- V(Int32x4, Int32x4., Int32x4Constructor, 323626792) \
- V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 637206368) \
- V(Int32x4, Int32x4.fromFloat32x4Bits, Int32x4FromFloat32x4Bits, 420618790) \
- V(_Int32x4, get:flagX, Int32x4GetFlagX, 1077674402) \
- V(_Int32x4, get:flagY, Int32x4GetFlagY, 779279448) \
- V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 182031447) \
- V(_Int32x4, get:flagW, Int32x4GetFlagW, 977794698) \
- V(_Int32x4, get:signMask, Int32x4GetSignMask, 1929391078) \
- V(_Int32x4, shuffle, Int32x4Shuffle, 1870018702) \
- V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 1024903172) \
- V(_Int32x4, select, Int32x4Select, 1638081645) \
- V(_Int32x4, withFlagX, Int32x4WithFlagX, 467852789) \
- V(_Int32x4, withFlagY, Int32x4WithFlagY, 1903359978) \
- V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 862460960) \
- V(_Int32x4, withFlagW, Int32x4WithFlagW, 1095242907) \
- V(_Float32Array, [], Float32ArrayGetIndexed, 321832479) \
- V(_Float32Array, []=, Float32ArraySetIndexed, 979306169) \
- V(_Int8Array, [], Int8ArrayGetIndexed, 1390782783) \
- V(_Int8Array, []=, Int8ArraySetIndexed, 1774152196) \
- V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 1297457028) \
- V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 2018722539) \
- V(_ExternalUint8ClampedArray, [], \
- ExternalUint8ClampedArrayGetIndexed, 1871828532) \
- V(_ExternalUint8ClampedArray, []=, \
- ExternalUint8ClampedArraySetIndexed, 1746834469) \
- V(_Int16Array, [], Int16ArrayGetIndexed, 1699340532) \
- V(_Int16Array, []=, Int16ArraySetIndexed, 799870496) \
- V(_Uint16Array, [], Uint16ArrayGetIndexed, 452576118) \
- V(_Uint16Array, []=, Uint16ArraySetIndexed, 1594961463) \
- V(_Int32Array, [], Int32ArrayGetIndexed, 2052925823) \
- V(_Int32Array, []=, Int32ArraySetIndexed, 504626978) \
- V(_Int64Array, [], Int64ArrayGetIndexed, 297668331) \
- V(_Int64Array, []=, Int64ArraySetIndexed, 36465128) \
- V(_Float32x4Array, [], Float32x4ArrayGetIndexed, 35821240) \
- V(_Float32x4Array, []=, Float32x4ArraySetIndexed, 428758949) \
- V(_Int32x4Array, [], Int32x4ArrayGetIndexed, 1830534333) \
- V(_Int32x4Array, []=, Int32x4ArraySetIndexed, 1631676655) \
- V(_Float64x2Array, [], Float64x2ArrayGetIndexed, 1860837505) \
- V(_Float64x2Array, []=, Float64x2ArraySetIndexed, 821269609) \
- V(_Bigint, get:_neg, Bigint_getNeg, 1151633263) \
- V(_Bigint, get:_used, Bigint_getUsed, 1308648707) \
- V(_Bigint, get:_digits, Bigint_getDigits, 1408181836) \
- V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 1431607529) \
- V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 2007926178) \
- V(_HashVMBase, get:_data, LinkedHashMap_getData, 958070909) \
- V(_HashVMBase, set:_data, LinkedHashMap_setData, 1134236592) \
- V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 421669312) \
- V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 1152062737) \
- V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 969476186) \
- V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 1781420082) \
- V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 63633039) \
- V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 2079107858) \
+ IntegerLeftShiftWithMask32, 1634465017) \
+ V(_Double, truncateToDouble, DoubleTruncate, 791143891) \
+ V(_Double, roundToDouble, DoubleRound, 797558034) \
+ V(_Double, floorToDouble, DoubleFloor, 1789426271) \
+ V(_Double, ceilToDouble, DoubleCeil, 453271198) \
+ V(_Double, _modulo, DoubleMod, 1093862165) \
+ V(_Double, _add, DoubleAdd, 1190606283) \
+ V(_Double, _sub, DoubleSub, 1086286468) \
+ V(_Double, _mul, DoubleMul, 166332351) \
+ V(_Double, _div, DoubleDiv, 821396195) \
+ V(::, sin, MathSin, 939048573) \
+ V(::, cos, MathCos, 1148850331) \
+ V(::, tan, MathTan, 179725235) \
+ V(::, asin, MathAsin, 848695059) \
+ V(::, acos, MathAcos, 337299516) \
+ V(::, atan, MathAtan, 866406810) \
+ V(::, atan2, MathAtan2, 1901969510) \
+ V(::, min, MathMin, 1115051548) \
+ V(::, max, MathMax, 1410473322) \
+ V(::, _doublePow, MathDoublePow, 562154128) \
+ V(Float32x4, Float32x4., Float32x4Constructor, 1849420944) \
+ V(Float32x4, Float32x4.zero, Float32x4Zero, 762161262) \
+ V(Float32x4, Float32x4.splat, Float32x4Splat, 255855286) \
+ V(Float32x4, Float32x4.fromInt32x4Bits, Float32x4FromInt32x4Bits, 1718571366)\
+ V(Float32x4, Float32x4.fromFloat64x2, Float32x4FromFloat64x2, 1458098858) \
+ V(_Float32x4, shuffle, Float32x4Shuffle, 2015957023) \
+ V(_Float32x4, shuffleMix, Float32x4ShuffleMix, 1099087979) \
+ V(_Float32x4, get:signMask, Float32x4GetSignMask, 487049875) \
+ V(_Float32x4, _cmpequal, Float32x4Equal, 1069901308) \
+ V(_Float32x4, _cmpgt, Float32x4GreaterThan, 2112381651) \
+ V(_Float32x4, _cmpgte, Float32x4GreaterThanOrEqual, 1088241265) \
+ V(_Float32x4, _cmplt, Float32x4LessThan, 2001171012) \
+ V(_Float32x4, _cmplte, Float32x4LessThanOrEqual, 1568686387) \
+ V(_Float32x4, _cmpnequal, Float32x4NotEqual, 1833412828) \
+ V(_Float32x4, _min, Float32x4Min, 1194113943) \
+ V(_Float32x4, _max, Float32x4Max, 1876936155) \
+ V(_Float32x4, _scale, Float32x4Scale, 1176743640) \
+ V(_Float32x4, _sqrt, Float32x4Sqrt, 526238610) \
+ V(_Float32x4, _reciprocalSqrt, Float32x4ReciprocalSqrt, 860560177) \
+ V(_Float32x4, _reciprocal, Float32x4Reciprocal, 1703468100) \
+ V(_Float32x4, _negate, Float32x4Negate, 1409902640) \
+ V(_Float32x4, _abs, Float32x4Absolute, 2116840471) \
+ V(_Float32x4, _clamp, Float32x4Clamp, 1789892357) \
+ V(_Float32x4, withX, Float32x4WithX, 1311992575) \
+ V(_Float32x4, withY, Float32x4WithY, 175290640) \
+ V(_Float32x4, withZ, Float32x4WithZ, 837367384) \
+ V(_Float32x4, withW, Float32x4WithW, 1625145605) \
+ V(Float64x2, Float64x2., Float64x2Constructor, 1428850802) \
+ V(Float64x2, Float64x2.zero, Float64x2Zero, 29170676) \
+ V(Float64x2, Float64x2.splat, Float64x2Splat, 1077183856) \
+ V(Float64x2, Float64x2.fromFloat32x4, Float64x2FromFloat32x4, 1752000980) \
+ V(_Float64x2, get:x, Float64x2GetX, 1488958362) \
+ V(_Float64x2, get:y, Float64x2GetY, 1022688506) \
+ V(_Float64x2, _negate, Float64x2Negate, 960840275) \
+ V(_Float64x2, abs, Float64x2Abs, 52403783) \
+ V(_Float64x2, sqrt, Float64x2Sqrt, 2012680669) \
+ V(_Float64x2, get:signMask, Float64x2GetSignMask, 668856717) \
+ V(_Float64x2, scale, Float64x2Scale, 646122081) \
+ V(_Float64x2, withX, Float64x2WithX, 489409269) \
+ V(_Float64x2, withY, Float64x2WithY, 943642284) \
+ V(_Float64x2, min, Float64x2Min, 685235702) \
+ V(_Float64x2, max, Float64x2Max, 198659675) \
+ V(Int32x4, Int32x4., Int32x4Constructor, 80862812) \
+ V(Int32x4, Int32x4.bool, Int32x4BoolConstructor, 1949580252) \
+ V(Int32x4, Int32x4.fromFloat32x4Bits, Int32x4FromFloat32x4Bits, 1611205288) \
+ V(_Int32x4, get:flagX, Int32x4GetFlagX, 1446544324) \
+ V(_Int32x4, get:flagY, Int32x4GetFlagY, 1148149370) \
+ V(_Int32x4, get:flagZ, Int32x4GetFlagZ, 550901369) \
+ V(_Int32x4, get:flagW, Int32x4GetFlagW, 1346664620) \
+ V(_Int32x4, get:signMask, Int32x4GetSignMask, 740215269) \
+ V(_Int32x4, shuffle, Int32x4Shuffle, 549194518) \
+ V(_Int32x4, shuffleMix, Int32x4ShuffleMix, 1550866145) \
+ V(_Int32x4, select, Int32x4Select, 614943686) \
+ V(_Int32x4, withFlagX, Int32x4WithFlagX, 250974159) \
+ V(_Int32x4, withFlagY, Int32x4WithFlagY, 1686481348) \
+ V(_Int32x4, withFlagZ, Int32x4WithFlagZ, 645582330) \
+ V(_Int32x4, withFlagW, Int32x4WithFlagW, 878364277) \
+ V(_Float32Array, [], Float32ArrayGetIndexed, 1002307136) \
+ V(_Float32Array, []=, Float32ArraySetIndexed, 279546769) \
+ V(_Int8Array, [], Int8ArrayGetIndexed, 1141846285) \
+ V(_Int8Array, []=, Int8ArraySetIndexed, 1486839324) \
+ V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 513704632) \
+ V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 1015846567) \
+ V(_ExternalUint8ClampedArray, [], ExternalUint8ClampedArrayGetIndexed, \
+ 513704632) \
+ V(_ExternalUint8ClampedArray, []=, ExternalUint8ClampedArraySetIndexed, \
+ 1015846567) \
+ V(_Int16Array, [], Int16ArrayGetIndexed, 1826359619) \
+ V(_Int16Array, []=, Int16ArraySetIndexed, 1108689116) \
+ V(_Uint16Array, [], Uint16ArrayGetIndexed, 118958722) \
+ V(_Uint16Array, []=, Uint16ArraySetIndexed, 658824450) \
+ V(_Int32Array, [], Int32ArrayGetIndexed, 681203163) \
+ V(_Int32Array, []=, Int32ArraySetIndexed, 1786886245) \
+ V(_Int64Array, [], Int64ArrayGetIndexed, 1883155004) \
+ V(_Int64Array, []=, Int64ArraySetIndexed, 905815059) \
+ V(_Float32x4Array, [], Float32x4ArrayGetIndexed, 694822356) \
+ V(_Float32x4Array, []=, Float32x4ArraySetIndexed, 1166109127) \
+ V(_Int32x4Array, [], Int32x4ArrayGetIndexed, 668249259) \
+ V(_Int32x4Array, []=, Int32x4ArraySetIndexed, 654739449) \
+ V(_Float64x2Array, [], Float64x2ArrayGetIndexed, 196472005) \
+ V(_Float64x2Array, []=, Float64x2ArraySetIndexed, 1421858500) \
+ V(_Bigint, get:_neg, Bigint_getNeg, 1681019799) \
+ V(_Bigint, get:_used, Bigint_getUsed, 1439136438) \
+ V(_Bigint, get:_digits, Bigint_getDigits, 769722770) \
+ V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 2048715833) \
+ V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 1882796480) \
+ V(_HashVMBase, get:_data, LinkedHashMap_getData, 942992497) \
+ V(_HashVMBase, set:_data, LinkedHashMap_setData, 1410623019) \
+ V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 1698421819) \
+ V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 1858754514) \
+ V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 98745045) \
+ V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 340628211) \
+ V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 1340385546) \
+ V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 638315987) \
// List of intrinsics:
// (class-name, function-name, intrinsification method, fingerprint).
#define CORE_LIB_INTRINSIC_LIST(V) \
- V(_Smi, ~, Smi_bitNegate, 221883538) \
- V(_Smi, get:bitLength, Smi_bitLength, 870075661) \
- V(_Bigint, _lsh, Bigint_lsh, 1457834861) \
- V(_Bigint, _rsh, Bigint_rsh, 1619318930) \
- V(_Bigint, _absAdd, Bigint_absAdd, 1029882563) \
- V(_Bigint, _absSub, Bigint_absSub, 1407667556) \
- V(_Bigint, _mulAdd, Bigint_mulAdd, 1408994809) \
- V(_Bigint, _sqrAdd, Bigint_sqrAdd, 2025116181) \
- V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 919247767) \
- V(_Montgomery, _mulMod, Montgomery_mulMod, 401580778) \
- V(_Double, >, Double_greaterThan, 1329424300) \
- V(_Double, >=, Double_greaterEqualThan, 805805707) \
- V(_Double, <, Double_lessThan, 1504529159) \
- V(_Double, <=, Double_lessEqualThan, 1650247787) \
- V(_Double, ==, Double_equal, 1107327662) \
- V(_Double, +, Double_add, 957499569) \
- V(_Double, -, Double_sub, 788608394) \
- V(_Double, *, Double_mul, 645729895) \
- V(_Double, /, Double_div, 1249186273) \
- V(_Double, get:isNaN, Double_getIsNaN, 843169197) \
- V(_Double, get:isNegative, Double_getIsNegative, 1637994744) \
- V(_Double, _mulFromInteger, Double_mulFromInteger, 63390017) \
- V(_Double, .fromInteger, DoubleFromInteger, 213717920) \
- V(_List, []=, ObjectArraySetIndexed, 527521746) \
- V(_GrowableList, .withData, GrowableArray_Allocate, 2094352700) \
- V(_GrowableList, add, GrowableArray_add, 1675959698) \
- V(_JSSyntaxRegExp, _ExecuteMatch, JSRegExp_ExecuteMatch, 1711509198) \
- V(Object, ==, ObjectEquals, 409406570) \
- V(Object, get:runtimeType, ObjectRuntimeType, 2076963579) \
- V(_StringBase, get:hashCode, String_getHashCode, 2103025405) \
- V(_StringBase, get:isEmpty, StringBaseIsEmpty, 780870414) \
- V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 397735324) \
- V(_StringBase, _substringMatches, StringBaseSubstringMatches, 347814979) \
- V(_StringBase, [], StringBaseCharAt, 408544820) \
- V(_OneByteString, get:hashCode, OneByteString_getHashCode, 1111957093) \
+ V(_Smi, ~, Smi_bitNegate, 1673522705) \
+ V(_Smi, get:bitLength, Smi_bitLength, 632480332) \
+ V(_Bigint, _lsh, Bigint_lsh, 834311957) \
+ V(_Bigint, _rsh, Bigint_rsh, 333337658) \
+ V(_Bigint, _absAdd, Bigint_absAdd, 473436659) \
+ V(_Bigint, _absSub, Bigint_absSub, 1018678324) \
+ V(_Bigint, _mulAdd, Bigint_mulAdd, 571005736) \
+ V(_Bigint, _sqrAdd, Bigint_sqrAdd, 372896038) \
+ V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 540033329) \
+ V(_Montgomery, _mulMod, Montgomery_mulMod, 118781828) \
+ V(_Double, >, Double_greaterThan, 1413076759) \
+ V(_Double, >=, Double_greaterEqualThan, 1815180096) \
+ V(_Double, <, Double_lessThan, 652059836) \
+ V(_Double, <=, Double_lessEqualThan, 512138528) \
+ V(_Double, ==, Double_equal, 752327620) \
+ V(_Double, +, Double_add, 854024064) \
+ V(_Double, -, Double_sub, 685132889) \
+ V(_Double, *, Double_mul, 542254390) \
+ V(_Double, /, Double_div, 1145710768) \
+ V(_Double, get:isNaN, Double_getIsNaN, 184085483) \
+ V(_Double, get:isNegative, Double_getIsNegative, 978911030) \
+ V(_Double, _mulFromInteger, Double_mulFromInteger, 543831179) \
+ V(_Double, .fromInteger, DoubleFromInteger, 1453449234) \
+ V(_List, []=, ObjectArraySetIndexed, 886228780) \
+ V(_GrowableList, .withData, GrowableArray_Allocate, 131424500) \
+ V(_GrowableList, add, GrowableArray_add, 242296201) \
+ V(_JSSyntaxRegExp, _ExecuteMatch, JSRegExp_ExecuteMatch, 1490503678) \
+ V(Object, ==, ObjectEquals, 291909336) \
+ V(Object, get:runtimeType, ObjectRuntimeType, 15188587) \
+ V(_StringBase, get:hashCode, String_getHashCode, 2026040200) \
+ V(_StringBase, get:isEmpty, StringBaseIsEmpty, 1958879178) \
+ V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 1436590579) \
+ V(_StringBase, _substringMatches, StringBaseSubstringMatches, 1548648995) \
+ V(_StringBase, [], StringBaseCharAt, 754527301) \
+ V(_OneByteString, get:hashCode, OneByteString_getHashCode, 2026040200) \
V(_OneByteString, _substringUncheckedNative, \
- OneByteString_substringUnchecked, 1584757277) \
- V(_OneByteString, _setAt, OneByteStringSetAt, 1927993207) \
- V(_OneByteString, _allocate, OneByteString_allocate, 1248050114) \
- V(_OneByteString, ==, OneByteString_equality, 1151307249) \
- V(_TwoByteString, ==, TwoByteString_equality, 375409915) \
+ OneByteString_substringUnchecked, 2063670029) \
+ V(_OneByteString, _setAt, OneByteStringSetAt, 929822971) \
+ V(_OneByteString, _allocate, OneByteString_allocate, 1737851380) \
+ V(_OneByteString, ==, OneByteString_equality, 1062844160) \
+ V(_TwoByteString, ==, TwoByteString_equality, 1062844160) \
#define CORE_INTEGER_LIB_INTRINSIC_LIST(V) \
- V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger, \
- 438687793) \
- V(_IntegerImplementation, +, Integer_add, 6890122) \
- V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, \
- 562800077) \
- V(_IntegerImplementation, -, Integer_sub, 1325066635) \
+ V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger, 298045644)\
+ V(_IntegerImplementation, +, Integer_add, 364498398) \
+ V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, 422157928)\
+ V(_IntegerImplementation, -, Integer_sub, 1682674911) \
V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger, \
- 67891834) \
- V(_IntegerImplementation, *, Integer_mul, 1293507180) \
+ 2074733333) \
+ V(_IntegerImplementation, *, Integer_mul, 1651115456) \
V(_IntegerImplementation, _moduloFromInteger, Integer_moduloFromInteger, \
- 93478264) \
- V(_IntegerImplementation, ~/, Integer_truncDivide, 1401079912) \
- V(_IntegerImplementation, unary-, Integer_negate, 1992904169) \
- V(_IntegerImplementation, _bitAndFromInteger, \
- Integer_bitAndFromInteger, 504496713) \
- V(_IntegerImplementation, &, Integer_bitAnd, 154523381) \
- V(_IntegerImplementation, _bitOrFromInteger, \
- Integer_bitOrFromInteger, 1763728073) \
- V(_IntegerImplementation, |, Integer_bitOr, 979400883) \
- V(_IntegerImplementation, _bitXorFromInteger, \
- Integer_bitXorFromInteger, 281425907) \
- V(_IntegerImplementation, ^, Integer_bitXor, 1753100628) \
- V(_IntegerImplementation, \
- _greaterThanFromInteger, \
- Integer_greaterThanFromInt, 787426822) \
- V(_IntegerImplementation, >, Integer_greaterThan, 871319346) \
- V(_IntegerImplementation, ==, Integer_equal, 150126631) \
+ 2100319763) \
+ V(_IntegerImplementation, ~/, Integer_truncDivide, 108494012) \
+ V(_IntegerImplementation, unary-, Integer_negate, 1507648892) \
+ V(_IntegerImplementation, _bitAndFromInteger, Integer_bitAndFromInteger, \
+ 363854564) \
+ V(_IntegerImplementation, &, Integer_bitAnd, 286231290) \
+ V(_IntegerImplementation, _bitOrFromInteger, Integer_bitOrFromInteger, \
+ 1623085924) \
+ V(_IntegerImplementation, |, Integer_bitOr, 1111108792) \
+ V(_IntegerImplementation, _bitXorFromInteger, Integer_bitXorFromInteger, \
+ 140783758) \
+ V(_IntegerImplementation, ^, Integer_bitXor, 1884808537) \
+ V(_IntegerImplementation, _greaterThanFromInteger, \
+ Integer_greaterThanFromInt, 814932166) \
+ V(_IntegerImplementation, >, Integer_greaterThan, 293890061) \
+ V(_IntegerImplementation, ==, Integer_equal, 4489308) \
V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger, \
- 1790821042) \
- V(_IntegerImplementation, <, Integer_lessThan, 1997184951) \
- V(_IntegerImplementation, <=, Integer_lessEqualThan, 909274395) \
- V(_IntegerImplementation, >=, Integer_greaterEqualThan, 64832315) \
- V(_IntegerImplementation, <<, Integer_shl, 162043543) \
- V(_IntegerImplementation, >>, Integer_sar, 2140866840) \
- V(_Double, toInt, DoubleToInteger, 1547535151)
+ 1818326386) \
+ V(_IntegerImplementation, <, Integer_lessThan, 652059836) \
+ V(_IntegerImplementation, <=, Integer_lessEqualThan, 512138528) \
+ V(_IntegerImplementation, >=, Integer_greaterEqualThan, 1815180096) \
+ V(_IntegerImplementation, <<, Integer_shl, 293751452) \
+ V(_IntegerImplementation, >>, Integer_sar, 125091101) \
+ V(_Double, toInt, DoubleToInteger, 653210699)
#define MATH_LIB_INTRINSIC_LIST(V) \
- V(::, sqrt, MathSqrt, 101545548) \
- V(_Random, _nextState, Random_nextState, 170407315) \
+ V(::, sqrt, MathSqrt, 1446681622) \
+ V(_Random, _nextState, Random_nextState, 1241583299) \
#define TYPED_DATA_LIB_INTRINSIC_LIST(V) \
- V(_Int8Array, _new, TypedData_Int8Array_new, 362764911) \
- V(_Uint8Array, _new, TypedData_Uint8Array_new, 1232298852) \
- V(_Uint8ClampedArray, _new, TypedData_Uint8ClampedArray_new, 2086529408) \
- V(_Int16Array, _new, TypedData_Int16Array_new, 1092174107) \
- V(_Uint16Array, _new, TypedData_Uint16Array_new, 1549613141) \
- V(_Int32Array, _new, TypedData_Int32Array_new, 937960140) \
- V(_Uint32Array, _new, TypedData_Uint32Array_new, 1370423225) \
- V(_Int64Array, _new, TypedData_Int64Array_new, 512135010) \
- V(_Uint64Array, _new, TypedData_Uint64Array_new, 847951795) \
- V(_Float32Array, _new, TypedData_Float32Array_new, 1937854220) \
- V(_Float64Array, _new, TypedData_Float64Array_new, 2005472426) \
- V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 1956756158) \
- V(_Int32x4Array, _new, TypedData_Int32x4Array_new, 1856474973) \
- V(_Float64x2Array, _new, TypedData_Float64x2Array_new, 719608172) \
- V(_Int8Array, ., TypedData_Int8Array_factory, 439914696) \
- V(_Uint8Array, ., TypedData_Uint8Array_factory, 1442599030) \
- V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1320015159) \
- V(_Int16Array, ., TypedData_Int16Array_factory, 2132591678) \
- V(_Uint16Array, ., TypedData_Uint16Array_factory, 1704816032) \
- V(_Int32Array, ., TypedData_Int32Array_factory, 1115045147) \
- V(_Uint32Array, ., TypedData_Uint32Array_factory, 1385852190) \
- V(_Int64Array, ., TypedData_Int64Array_factory, 1193438555) \
- V(_Uint64Array, ., TypedData_Uint64Array_factory, 410766246) \
- V(_Float32Array, ., TypedData_Float32Array_factory, 1194249144) \
- V(_Float64Array, ., TypedData_Float64Array_factory, 1430631000) \
- V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 158753569) \
- V(_Int32x4Array, ., TypedData_Int32x4Array_factory, 1189213641) \
- V(_Float64x2Array, ., TypedData_Float64x2Array_factory, 1699696799) \
+ V(_Int8Array, _new, TypedData_Int8Array_new, 1025382728) \
+ V(_Uint8Array, _new, TypedData_Uint8Array_new, 1772090315) \
+ V(_Uint8ClampedArray, _new, TypedData_Uint8ClampedArray_new, 1817995920) \
+ V(_Int16Array, _new, TypedData_Int16Array_new, 857482727) \
+ V(_Uint16Array, _new, TypedData_Uint16Array_new, 224498043) \
+ V(_Int32Array, _new, TypedData_Int32Array_new, 662785062) \
+ V(_Uint32Array, _new, TypedData_Uint32Array_new, 457777042) \
+ V(_Int64Array, _new, TypedData_Int64Array_new, 11424776) \
+ V(_Uint64Array, _new, TypedData_Uint64Array_new, 580841705) \
+ V(_Float32Array, _new, TypedData_Float32Array_new, 141243383) \
+ V(_Float64Array, _new, TypedData_Float64Array_new, 2054234881) \
+ V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 1277009760) \
+ V(_Int32x4Array, _new, TypedData_Int32x4Array_new, 366994774) \
+ V(_Float64x2Array, _new, TypedData_Float64x2Array_new, 134695262) \
+ V(_Int8Array, ., TypedData_Int8Array_factory, 484088513) \
+ V(_Uint8Array, ., TypedData_Uint8Array_factory, 1830561671) \
+ V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 980532456) \
+ V(_Int16Array, ., TypedData_Int16Array_factory, 2095566414) \
+ V(_Uint16Array, ., TypedData_Uint16Array_factory, 248627537) \
+ V(_Int32Array, ., TypedData_Int32Array_factory, 836050202) \
+ V(_Uint32Array, ., TypedData_Uint32Array_factory, 102123815) \
+ V(_Int64Array, ., TypedData_Int64Array_factory, 1820730838) \
+ V(_Uint64Array, ., TypedData_Uint64Array_factory, 1668399825) \
+ V(_Float32Array, ., TypedData_Float32Array_factory, 307228626) \
+ V(_Float64Array, ., TypedData_Float64Array_factory, 1700923139) \
+ V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 1083909924) \
+ V(_Int32x4Array, ., TypedData_Int32x4Array_factory, 803703492) \
+ V(_Float64x2Array, ., TypedData_Float64x2Array_factory, 944719167) \
#define GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
- V(_Uint8Array, [], Uint8ArrayGetIndexed, 579862489) \
- V(_Uint8Array, []=, Uint8ArraySetIndexed, 447309008) \
- V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 1293647140) \
- V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 1593599192) \
- V(_Uint32Array, [], Uint32ArrayGetIndexed, 1034114777) \
- V(_Uint32Array, []=, Uint32ArraySetIndexed, 918159348) \
- V(_Float64Array, []=, Float64ArraySetIndexed, 887301703) \
- V(_Float64Array, [], Float64ArrayGetIndexed, 1959896670) \
- V(_TypedList, get:length, TypedDataLength, 522684521) \
- V(_Float32x4, get:x, Float32x4ShuffleX, 384969722) \
- V(_Float32x4, get:y, Float32x4ShuffleY, 1398121942) \
- V(_Float32x4, get:z, Float32x4ShuffleZ, 1178175605) \
- V(_Float32x4, get:w, Float32x4ShuffleW, 480951003) \
- V(_Float32x4, _mul, Float32x4Mul, 1703784673) \
- V(_Float32x4, _sub, Float32x4Sub, 1302598822) \
- V(_Float32x4, _add, Float32x4Add, 182344215) \
+ V(_Uint8Array, [], Uint8ArrayGetIndexed, 513704632) \
+ V(_Uint8Array, []=, Uint8ArraySetIndexed, 2123520783) \
+ V(_ExternalUint8Array, [], ExternalUint8ArrayGetIndexed, 513704632) \
+ V(_ExternalUint8Array, []=, ExternalUint8ArraySetIndexed, 2123520783) \
+ V(_Uint32Array, [], Uint32ArrayGetIndexed, 1179675338) \
+ V(_Uint32Array, []=, Uint32ArraySetIndexed, 1455695417) \
+ V(_Float64Array, []=, Float64ArraySetIndexed, 1929239576) \
+ V(_Float64Array, [], Float64ArrayGetIndexed, 816943529) \
+ V(_TypedList, get:length, TypedDataLength, 546364442) \
+ V(_Float32x4, get:x, Float32x4ShuffleX, 1674625343) \
+ V(_Float32x4, get:y, Float32x4ShuffleY, 540293915) \
+ V(_Float32x4, get:z, Float32x4ShuffleZ, 320347578) \
+ V(_Float32x4, get:w, Float32x4ShuffleW, 1770606624) \
+ V(_Float32x4, _mul, Float32x4Mul, 861549065) \
+ V(_Float32x4, _sub, Float32x4Sub, 460363214) \
+ V(_Float32x4, _add, Float32x4Add, 1487592255) \
#define GRAPH_CORE_INTRINSICS_LIST(V) \
- V(_List, get:length, ObjectArrayLength, 1181471893) \
- V(_List, [], ObjectArrayGetIndexed, 1839430267) \
- V(_ImmutableList, get:length, ImmutableArrayLength, 275036891) \
- V(_ImmutableList, [], ImmutableArrayGetIndexed, 886511484) \
- V(_GrowableList, get:length, GrowableArrayLength, 778624271) \
- V(_GrowableList, get:_capacity, GrowableArrayCapacity, 555259239) \
- V(_GrowableList, _setData, GrowableArraySetData, 508234257) \
- V(_GrowableList, _setLength, GrowableArraySetLength, 618179695) \
- V(_GrowableList, [], GrowableArrayGetIndexed, 1962926024) \
- V(_GrowableList, []=, GrowableArraySetIndexed, 457344024) \
- V(_StringBase, get:length, StringBaseLength, 784518792) \
- V(_Double, unary-, DoubleFlipSignBit, 2107492213)
+ V(_List, get:length, ObjectArrayLength, 630471378) \
+ V(_List, [], ObjectArrayGetIndexed, 360400496) \
+ V(_ImmutableList, get:length, ImmutableArrayLength, 630471378) \
+ V(_ImmutableList, [], ImmutableArrayGetIndexed, 360400496) \
+ V(_GrowableList, get:length, GrowableArrayLength, 417111542) \
+ V(_GrowableList, get:_capacity, GrowableArrayCapacity, 193746510) \
+ V(_GrowableList, _setData, GrowableArraySetData, 1496536873) \
+ V(_GrowableList, _setLength, GrowableArraySetLength, 32203572) \
+ V(_GrowableList, [], GrowableArrayGetIndexed, 1957529650) \
+ V(_GrowableList, []=, GrowableArraySetIndexed, 225246870) \
+ V(_StringBase, get:length, StringBaseLength, 707533587) \
+ V(_Double, unary-, DoubleFlipSignBit, 1783281169)
#define GRAPH_INTRINSICS_LIST(V) \
GRAPH_CORE_INTRINSICS_LIST(V) \
GRAPH_TYPED_DATA_INTRINSICS_LIST(V) \
#define DEVELOPER_LIB_INTRINSIC_LIST(V) \
- V(_UserTag, makeCurrent, UserTag_makeCurrent, 788201614) \
- V(::, _getDefaultTag, UserTag_defaultTag, 1080704381) \
- V(::, _getCurrentTag, Profiler_getCurrentTag, 2048029229) \
+ V(_UserTag, makeCurrent, UserTag_makeCurrent, 187721469) \
+ V(::, _getDefaultTag, UserTag_defaultTag, 1872263331) \
+ V(::, _getCurrentTag, Profiler_getCurrentTag, 692104531) \
#define ALL_INTRINSICS_NO_INTEGER_LIB_LIST(V) \
CORE_LIB_INTRINSIC_LIST(V) \
@@ -336,149 +333,149 @@
// A list of core function that should always be inlined.
#define INLINE_WHITE_LIST(V) \
- V(Object, ==, ObjectEquals, 409406570) \
- V(_List, get:length, ObjectArrayLength, 1181471893) \
- V(_ImmutableList, get:length, ImmutableArrayLength, 275036891) \
- V(_TypedList, get:length, TypedDataLength, 522684521) \
- V(_GrowableList, get:length, GrowableArrayLength, 778624271) \
- V(_GrowableList, add, GrowableListAdd, 1675959698) \
- V(_GrowableList, removeLast, GrowableListRemoveLast, 1687341910) \
- V(_StringBase, get:length, StringBaseLength, 784518792) \
- V(ListIterator, moveNext, ListIteratorMoveNext, 1698922708) \
- V(_FixedSizeArrayIterator, moveNext, FixedListIteratorMoveNext, 53548649) \
- V(_GrowableList, get:iterator, GrowableArrayIterator, 830391682) \
- V(_GrowableList, forEach, GrowableArrayForEach, 792224678) \
- V(_List, ., ObjectArrayAllocate, 850375012) \
- V(_List, [], ObjectArrayGetIndexed, 1839430267) \
- V(_List, []=, ObjectArraySetIndexed, 527521746) \
- V(ListMixin, get:isEmpty, ListMixinIsEmpty, 40656674) \
- V(_List, get:iterator, ObjectArrayIterator, 1623553799) \
- V(_List, forEach, ObjectArrayForEach, 1840334181) \
- V(_List, _slice, ObjectArraySlice, 1370223553) \
- V(_ImmutableList, get:iterator, ImmutableArrayIterator, 1527026181) \
- V(_ImmutableList, forEach, ImmutableArrayForEach, 1311466789) \
- V(_ImmutableList, [], ImmutableArrayGetIndexed, 886511484) \
- V(_GrowableList, [], GrowableArrayGetIndexed, 1962926024) \
- V(_GrowableList, []=, GrowableArraySetIndexed, 457344024) \
- V(_Float32Array, [], Float32ArrayGetIndexed, 321832479) \
- V(_Float32Array, []=, Float32ArraySetIndexed, 979306169) \
- V(_Float64Array, [], Float64ArrayGetIndexed, 1959896670) \
- V(_Float64Array, []=, Float64ArraySetIndexed, 887301703) \
- V(_Int8Array, [], Int8ArrayGetIndexed, 1390782783) \
- V(_Int8Array, []=, Int8ArraySetIndexed, 1774152196) \
- V(_Uint8Array, [], Uint8ArrayGetIndexed, 579862489) \
- V(_Uint8Array, []=, Uint8ArraySetIndexed, 447309008) \
- V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 1297457028) \
- V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 2018722539) \
- V(_Uint16Array, [], Uint16ArrayGetIndexed, 452576118) \
- V(_Uint16Array, []=, Uint16ArraySetIndexed, 1594961463) \
- V(_Int16Array, [], Int16ArrayGetIndexed, 1699340532) \
- V(_Int16Array, []=, Int16ArraySetIndexed, 799870496) \
- V(_Int32Array, [], Int32ArrayGetIndexed, 2052925823) \
- V(_Int32Array, []=, Int32ArraySetIndexed, 504626978) \
- V(_Int64Array, [], Int64ArrayGetIndexed, 297668331) \
- V(_Int64Array, []=, Int64ArraySetIndexed, 36465128) \
- V(_Uint8ArrayView, [], Uint8ArrayViewGetIndexed, 662241408) \
- V(_Uint8ArrayView, []=, Uint8ArrayViewSetIndexed, 1550171024) \
- V(_Int8ArrayView, [], Int8ArrayViewGetIndexed, 875752635) \
- V(_Int8ArrayView, []=, Int8ArrayViewSetIndexed, 689961281) \
- V(_ByteDataView, setInt8, ByteDataViewSetInt8, 1039277590) \
- V(_ByteDataView, setUint8, ByteDataViewSetUint8, 497316431) \
- V(_ByteDataView, setInt16, ByteDataViewSetInt16, 27520778) \
- V(_ByteDataView, setUint16, ByteDataViewSetUint16, 1543151983) \
- V(_ByteDataView, setInt32, ByteDataViewSetInt32, 535913934) \
- V(_ByteDataView, setUint32, ByteDataViewSetUint32, 596009393) \
- V(_ByteDataView, setInt64, ByteDataViewSetInt64, 787812783) \
- V(_ByteDataView, setUint64, ByteDataViewSetUint64, 1078002910) \
- V(_ByteDataView, setFloat32, ByteDataViewSetFloat32, 2098528020) \
- V(_ByteDataView, setFloat64, ByteDataViewSetFloat64, 659619201) \
- V(_ByteDataView, getInt8, ByteDataViewGetInt8, 2117136369) \
- V(_ByteDataView, getUint8, ByteDataViewGetUint8, 298860761) \
- V(_ByteDataView, getInt16, ByteDataViewGetInt16, 975961124) \
- V(_ByteDataView, getUint16, ByteDataViewGetUint16, 1503060990) \
- V(_ByteDataView, getInt32, ByteDataViewGetInt32, 1096620023) \
- V(_ByteDataView, getUint32, ByteDataViewGetUint32, 1698446167) \
- V(_ByteDataView, getInt64, ByteDataViewGetInt64, 1950535797) \
- V(_ByteDataView, getUint64, ByteDataViewGetUint64, 786884343) \
- V(_ByteDataView, getFloat32, ByteDataViewGetFloat32, 889064264) \
- V(_ByteDataView, getFloat64, ByteDataViewGetFloat64, 1577605354) \
- V(::, asin, MathASin, 1651042633) \
- V(::, acos, MathACos, 1139647090) \
- V(::, atan, MathATan, 1668754384) \
- V(::, atan2, MathATan2, 1931713076) \
- V(::, cos, MathCos, 1951197905) \
- V(::, exp, MathExp, 1809210829) \
- V(::, log, MathLog, 1620336448) \
- V(::, max, MathMax, 212291192) \
- V(::, min, MathMin, 478627534) \
- V(::, pow, MathPow, 582475257) \
- V(::, sin, MathSin, 1741396147) \
- V(::, sqrt, MathSqrt, 101545548) \
- V(::, tan, MathTan, 982072809) \
- V(Lists, copy, ListsCopy, 618211805) \
- V(_Bigint, get:_neg, Bigint_getNeg, 1151633263) \
- V(_Bigint, get:_used, Bigint_getUsed, 1308648707) \
- V(_Bigint, get:_digits, Bigint_getDigits, 1408181836) \
- V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 1431607529) \
- V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 2007926178) \
- V(_HashVMBase, get:_data, LinkedHashMap_getData, 958070909) \
- V(_HashVMBase, set:_data, LinkedHashMap_setData, 1134236592) \
- V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 421669312) \
- V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 1152062737) \
- V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 969476186) \
- V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 1781420082) \
- V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 63633039) \
- V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 2079107858) \
- V(Uint8List, ., Uint8ListFactory, 1844890525) \
- V(Int8List, ., Int8ListFactory, 1802068996) \
- V(Uint16List, ., Uint16ListFactory, 1923962567) \
- V(Int16List, ., Int16ListFactory, 2000007495) \
- V(Uint32List, ., Uint32ListFactory, 1836019363) \
- V(Int32List, ., Int32ListFactory, 442847136) \
- V(Uint64List, ., Uint64ListFactory, 196248223) \
- V(Int64List, ., Int64ListFactory, 1668869084) \
- V(Float32List, ., Float32ListFactory, 1367032554) \
- V(Float64List, ., Float64ListFactory, 1886443347) \
- V(Int32x4List, ., Int32x4ListFactory, 1409401969) \
- V(Float32x4List, ., Float32x4ListFactory, 556438009) \
- V(Float64x2List, ., Float64x2ListFactory, 1269752759)
+ V(Object, ==, ObjectEquals, 291909336) \
+ V(_List, get:length, ObjectArrayLength, 630471378) \
+ V(_ImmutableList, get:length, ImmutableArrayLength, 630471378) \
+ V(_TypedList, get:length, TypedDataLength, 546364442) \
+ V(_GrowableList, get:length, GrowableArrayLength, 417111542) \
+ V(_GrowableList, add, GrowableListAdd, 242296201) \
+ V(_GrowableList, removeLast, GrowableListRemoveLast, 1655383014) \
+ V(_StringBase, get:length, StringBaseLength, 707533587) \
+ V(ListIterator, moveNext, ListIteratorMoveNext, 1467737539) \
+ V(_FixedSizeArrayIterator, moveNext, FixedListIteratorMoveNext, 784200630) \
+ V(_GrowableList, get:iterator, GrowableArrayIterator, 1840323187) \
+ V(_GrowableList, forEach, GrowableArrayForEach, 620771070) \
+ V(_List, ., ObjectArrayAllocate, 184405219) \
+ V(_List, [], ObjectArrayGetIndexed, 360400496) \
+ V(_List, []=, ObjectArraySetIndexed, 886228780) \
+ V(ListMixin, get:isEmpty, ListMixinIsEmpty, 2021497798) \
+ V(_List, get:iterator, ObjectArrayIterator, 1930956161) \
+ V(_List, forEach, ObjectArrayForEach, 180150673) \
+ V(_List, _slice, ObjectArraySlice, 1785552519) \
+ V(_ImmutableList, get:iterator, ImmutableArrayIterator, 1930956161) \
+ V(_ImmutableList, forEach, ImmutableArrayForEach, 180150673) \
+ V(_ImmutableList, [], ImmutableArrayGetIndexed, 360400496) \
+ V(_GrowableList, [], GrowableArrayGetIndexed, 1957529650) \
+ V(_GrowableList, []=, GrowableArraySetIndexed, 225246870) \
+ V(_Float32Array, [], Float32ArrayGetIndexed, 1002307136) \
+ V(_Float32Array, []=, Float32ArraySetIndexed, 279546769) \
+ V(_Float64Array, [], Float64ArrayGetIndexed, 816943529) \
+ V(_Float64Array, []=, Float64ArraySetIndexed, 1929239576) \
+ V(_Int8Array, [], Int8ArrayGetIndexed, 1141846285) \
+ V(_Int8Array, []=, Int8ArraySetIndexed, 1486839324) \
+ V(_Uint8Array, [], Uint8ArrayGetIndexed, 513704632) \
+ V(_Uint8Array, []=, Uint8ArraySetIndexed, 2123520783) \
+ V(_Uint8ClampedArray, [], Uint8ClampedArrayGetIndexed, 513704632) \
+ V(_Uint8ClampedArray, []=, Uint8ClampedArraySetIndexed, 1015846567) \
+ V(_Uint16Array, [], Uint16ArrayGetIndexed, 118958722) \
+ V(_Uint16Array, []=, Uint16ArraySetIndexed, 658824450) \
+ V(_Int16Array, [], Int16ArrayGetIndexed, 1826359619) \
+ V(_Int16Array, []=, Int16ArraySetIndexed, 1108689116) \
+ V(_Int32Array, [], Int32ArrayGetIndexed, 681203163) \
+ V(_Int32Array, []=, Int32ArraySetIndexed, 1786886245) \
+ V(_Int64Array, [], Int64ArrayGetIndexed, 1883155004) \
+ V(_Int64Array, []=, Int64ArraySetIndexed, 905815059) \
+ V(_Uint8ArrayView, [], Uint8ArrayViewGetIndexed, 215420949) \
+ V(_Uint8ArrayView, []=, Uint8ArrayViewSetIndexed, 1138146450) \
+ V(_Int8ArrayView, [], Int8ArrayViewGetIndexed, 1003520035) \
+ V(_Int8ArrayView, []=, Int8ArrayViewSetIndexed, 225448326) \
+ V(_ByteDataView, setInt8, ByteDataViewSetInt8, 1091734252) \
+ V(_ByteDataView, setUint8, ByteDataViewSetUint8, 549773093) \
+ V(_ByteDataView, setInt16, ByteDataViewSetInt16, 1580120352) \
+ V(_ByteDataView, setUint16, ByteDataViewSetUint16, 948267909) \
+ V(_ByteDataView, setInt32, ByteDataViewSetInt32, 2088513508) \
+ V(_ByteDataView, setUint32, ByteDataViewSetUint32, 1125319) \
+ V(_ByteDataView, setInt64, ByteDataViewSetInt64, 192928709) \
+ V(_ByteDataView, setUint64, ByteDataViewSetUint64, 483118836) \
+ V(_ByteDataView, setFloat32, ByteDataViewSetFloat32, 1241910514) \
+ V(_ByteDataView, setFloat64, ByteDataViewSetFloat64, 1950485343) \
+ V(_ByteDataView, getInt8, ByteDataViewGetInt8, 1939363561) \
+ V(_ByteDataView, getUint8, ByteDataViewGetUint8, 121087953) \
+ V(_ByteDataView, getInt16, ByteDataViewGetInt16, 591911343) \
+ V(_ByteDataView, getUint16, ByteDataViewGetUint16, 2114157459) \
+ V(_ByteDataView, getInt32, ByteDataViewGetInt32, 712570242) \
+ V(_ByteDataView, getUint32, ByteDataViewGetUint32, 162058988) \
+ V(_ByteDataView, getInt64, ByteDataViewGetInt64, 1566486016) \
+ V(_ByteDataView, getUint64, ByteDataViewGetUint64, 1397980812) \
+ V(_ByteDataView, getFloat32, ByteDataViewGetFloat32, 1251636679) \
+ V(_ByteDataView, getFloat64, ByteDataViewGetFloat64, 1940177769) \
+ V(::, asin, MathASin, 848695059) \
+ V(::, acos, MathACos, 337299516) \
+ V(::, atan, MathATan, 866406810) \
+ V(::, atan2, MathATan2, 1901969510) \
+ V(::, cos, MathCos, 1148850331) \
+ V(::, exp, MathExp, 1006863255) \
+ V(::, log, MathLog, 817988874) \
+ V(::, max, MathMax, 1410473322) \
+ V(::, min, MathMin, 1115051548) \
+ V(::, pow, MathPow, 864430827) \
+ V(::, sin, MathSin, 939048573) \
+ V(::, sqrt, MathSqrt, 1446681622) \
+ V(::, tan, MathTan, 179725235) \
+ V(Lists, copy, ListsCopy, 564237562) \
+ V(_Bigint, get:_neg, Bigint_getNeg, 1681019799) \
+ V(_Bigint, get:_used, Bigint_getUsed, 1439136438) \
+ V(_Bigint, get:_digits, Bigint_getDigits, 769722770) \
+ V(_HashVMBase, get:_index, LinkedHashMap_getIndex, 2048715833) \
+ V(_HashVMBase, set:_index, LinkedHashMap_setIndex, 1882796480) \
+ V(_HashVMBase, get:_data, LinkedHashMap_getData, 942992497) \
+ V(_HashVMBase, set:_data, LinkedHashMap_setData, 1410623019) \
+ V(_HashVMBase, get:_usedData, LinkedHashMap_getUsedData, 1698421819) \
+ V(_HashVMBase, set:_usedData, LinkedHashMap_setUsedData, 1858754514) \
+ V(_HashVMBase, get:_hashMask, LinkedHashMap_getHashMask, 98745045) \
+ V(_HashVMBase, set:_hashMask, LinkedHashMap_setHashMask, 340628211) \
+ V(_HashVMBase, get:_deletedKeys, LinkedHashMap_getDeletedKeys, 1340385546) \
+ V(_HashVMBase, set:_deletedKeys, LinkedHashMap_setDeletedKeys, 638315987) \
+ V(Uint8List, ., Uint8ListFactory, 1885328419) \
+ V(Int8List, ., Int8ListFactory, 551286096) \
+ V(Uint16List, ., Uint16ListFactory, 2018994846) \
+ V(Int16List, ., Int16ListFactory, 1934285336) \
+ V(Uint32List, ., Uint32ListFactory, 990865607) \
+ V(Int32List, ., Int32ListFactory, 2017670015) \
+ V(Uint64List, ., Uint64ListFactory, 1593070032) \
+ V(Int64List, ., Int64ListFactory, 1071205588) \
+ V(Float32List, ., Float32ListFactory, 1015272745) \
+ V(Float64List, ., Float64ListFactory, 626315429) \
+ V(Int32x4List, ., Int32x4ListFactory, 1693091079) \
+ V(Float32x4List, ., Float32x4ListFactory, 585154381) \
+ V(Float64x2List, ., Float64x2ListFactory, 874435184)
// A list of core function that should never be inlined.
#define INLINE_BLACK_LIST(V) \
- V(_Bigint, _lsh, Bigint_lsh, 1457834861) \
- V(_Bigint, _rsh, Bigint_rsh, 1619318930) \
- V(_Bigint, _absAdd, Bigint_absAdd, 1029882563) \
- V(_Bigint, _absSub, Bigint_absSub, 1407667556) \
- V(_Bigint, _mulAdd, Bigint_mulAdd, 1408994809) \
- V(_Bigint, _sqrAdd, Bigint_sqrAdd, 2025116181) \
- V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 919247767) \
- V(_Montgomery, _mulMod, Montgomery_mulMod, 401580778) \
+ V(_Bigint, _lsh, Bigint_lsh, 834311957) \
+ V(_Bigint, _rsh, Bigint_rsh, 333337658) \
+ V(_Bigint, _absAdd, Bigint_absAdd, 473436659) \
+ V(_Bigint, _absSub, Bigint_absSub, 1018678324) \
+ V(_Bigint, _mulAdd, Bigint_mulAdd, 571005736) \
+ V(_Bigint, _sqrAdd, Bigint_sqrAdd, 372896038) \
+ V(_Bigint, _estQuotientDigit, Bigint_estQuotientDigit, 540033329) \
+ V(_Montgomery, _mulMod, Montgomery_mulMod, 118781828) \
// A list of core functions that internally dispatch based on received id.
#define POLYMORPHIC_TARGET_LIST(V) \
- V(_StringBase, [], StringBaseCharAt, 408544820) \
- V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 397735324) \
- V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 1541411498) \
- V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1032404349) \
- V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 381073990) \
- V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1142676276) \
- V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 330269934) \
- V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 59490554) \
- V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 393003933) \
- V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1792407200) \
- V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1338379857) \
- V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 1469917805) \
- V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 1892735922) \
- V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 1608794041) \
- V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 117380972) \
- V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 200484754) \
- V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1020151991) \
- V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1175056602) \
- V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 460607665) \
- V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 284787790) \
- V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 262426120) \
- V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 613041888) \
+ V(_StringBase, [], StringBaseCharAt, 754527301) \
+ V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 1436590579) \
+ V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 187609847) \
+ V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 1826086346) \
+ V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 1174755987) \
+ V(_TypedList, _getUint16, ByteArrayBaseGetUint16, 1936358273) \
+ V(_TypedList, _getInt32, ByteArrayBaseGetInt32, 1123951931) \
+ V(_TypedList, _getUint32, ByteArrayBaseGetUint32, 853172551) \
+ V(_TypedList, _getFloat32, ByteArrayBaseGetFloat32, 165422183) \
+ V(_TypedList, _getFloat64, ByteArrayBaseGetFloat64, 1564825450) \
+ V(_TypedList, _getFloat32x4, ByteArrayBaseGetFloat32x4, 1123952315) \
+ V(_TypedList, _getInt32x4, ByteArrayBaseGetInt32x4, 831892409) \
+ V(_TypedList, _setInt8, ByteArrayBaseSetInt8, 2043203289) \
+ V(_TypedList, _setUint8, ByteArrayBaseSetInt8, 1759261408) \
+ V(_TypedList, _setInt16, ByteArrayBaseSetInt16, 267848339) \
+ V(_TypedList, _setUint16, ByteArrayBaseSetInt16, 350952121) \
+ V(_TypedList, _setInt32, ByteArrayBaseSetInt32, 1170619358) \
+ V(_TypedList, _setUint32, ByteArrayBaseSetUint32, 1325523969) \
+ V(_TypedList, _setFloat32, ByteArrayBaseSetFloat32, 541136999) \
+ V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 365317124) \
+ V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 1766802707) \
+ V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 2075229300) \
// Forward declarations.
class Function;
@@ -518,21 +515,21 @@
// List of recognized list factories:
// (factory-name-symbol, result-cid, fingerprint).
#define RECOGNIZED_LIST_FACTORY_LIST(V) \
- V(_ListFactory, kArrayCid, 850375012) \
- V(_GrowableListWithData, kGrowableObjectArrayCid, 2094352700) \
- V(_GrowableListFactory, kGrowableObjectArrayCid, 1518848600) \
- V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 439914696) \
- V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 1442599030) \
- V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 1320015159) \
- V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 2132591678) \
- V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 1704816032) \
- V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 1115045147) \
- V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 1385852190) \
- V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 1193438555) \
- V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 410766246) \
- V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1430631000) \
- V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 1194249144) \
- V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 158753569) \
+ V(_ListFactory, kArrayCid, 184405219) \
+ V(_GrowableListWithData, kGrowableObjectArrayCid, 131424500) \
+ V(_GrowableListFactory, kGrowableObjectArrayCid, 664918385) \
+ V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 484088513) \
+ V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 1830561671) \
+ V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 980532456) \
+ V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 2095566414) \
+ V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 248627537) \
+ V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 836050202) \
+ V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 102123815) \
+ V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 1820730838) \
+ V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 1668399825) \
+ V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1700923139) \
+ V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 307228626) \
+ V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 1083909924) \
// Class that recognizes factories and returns corresponding result cid.
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index 1763c8c..af27a37 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -14,7 +14,6 @@
namespace dart {
-DECLARE_FLAG(bool, deoptimize_alot);
DECLARE_FLAG(bool, trace_natives);
DECLARE_FLAG(bool, verify_on_transition);
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index a28a779..a5c79d3 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -120,6 +120,12 @@
void NativeEntry::NativeCallWrapper(Dart_NativeArguments args,
Dart_NativeFunction func) {
CHECK_STACK_ALIGNMENT;
+ NativeCallWrapperNoStackCheck(args, func);
+}
+
+
+void NativeEntry::NativeCallWrapperNoStackCheck(Dart_NativeArguments args,
+ Dart_NativeFunction func) {
VERIFY_ON_TRANSITION;
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
/* Tell MemorySanitizer 'arguments' is initialized by generated code. */
@@ -281,7 +287,9 @@
// Tail-call resolved target.
if (call_through_wrapper) {
- NativeEntry::NativeCallWrapper(
+ // Because this call is within a compilation unit, Clang doesn't respect
+ // the ABI alignment here.
+ NativeEntry::NativeCallWrapperNoStackCheck(
args, reinterpret_cast<Dart_NativeFunction>(target_function));
} else {
target_function(arguments);
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index 2e90ffc..9557073 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -120,7 +120,11 @@
static uword LinkNativeCallEntry();
static void LinkNativeCall(Dart_NativeArguments args);
+
private:
+ static void NativeCallWrapperNoStackCheck(Dart_NativeArguments args,
+ Dart_NativeFunction func);
+
static bool ReturnValueIsError(NativeArguments* arguments);
static void PropagateErrors(NativeArguments* arguments);
};
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index aea7d1f..300070b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -55,14 +55,11 @@
DEFINE_FLAG(bool, show_internal_names, false,
"Show names of internal classes (e.g. \"OneByteString\") in error messages "
"instead of showing the corresponding interface names (e.g. \"String\")");
-DEFINE_FLAG(bool, use_field_guards, true, "Guard field cids.");
DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache");
DEFINE_FLAG(bool, ignore_patch_signature_mismatch, false,
"Ignore patch file member signature mismatch.");
DECLARE_FLAG(charp, coverage_dir);
-DECLARE_FLAG(bool, load_deferred_eagerly);
-DECLARE_FLAG(bool, precompilation);
DECLARE_FLAG(bool, show_invisible_frames);
DECLARE_FLAG(bool, trace_deoptimization);
DECLARE_FLAG(bool, trace_deoptimization_verbose);
@@ -216,12 +213,15 @@
// _MyClass@6328321. -> _MyClass
// _MyClass@6328321.named -> _MyClass.named
//
-RawString* String::IdentifierPrettyName(const String& name) {
+RawString* String::ScrubName(const String& name) {
Zone* zone = Thread::Current()->zone();
+
+NOT_IN_PRODUCT(
if (name.Equals(Symbols::TopLevel())) {
// Name of invisible top-level class.
return Symbols::Empty().raw();
}
+)
const char* cname = name.ToCString();
ASSERT(strlen(cname) == static_cast<size_t>(name.Length()));
@@ -266,6 +266,7 @@
unmangled_name = MergeSubStrings(zone, unmangled_segments, sum_segment_len);
}
+NOT_IN_PRODUCT(
intptr_t len = sum_segment_len;
intptr_t start = 0;
intptr_t dot_pos = -1; // Position of '.' in the name, if any.
@@ -314,12 +315,14 @@
}
unmangled_name = MergeSubStrings(zone, unmangled_segments, final_len);
+)
return Symbols::New(unmangled_name);
}
-RawString* String::IdentifierPrettyNameRetainPrivate(const String& name) {
+RawString* String::ScrubNameRetainPrivate(const String& name) {
+NOT_IN_PRODUCT(
intptr_t len = name.Length();
intptr_t start = 0;
intptr_t at_pos = -1; // Position of '@' in the name, if any.
@@ -362,6 +365,8 @@
}
return result.raw();
+)
+ return name.raw(); // In PRODUCT, return argument unchanged.
}
@@ -1097,11 +1102,11 @@
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
ASSERT(isolate == thread->isolate());
-#ifndef PRODUCT
+NOT_IN_PRODUCT(
TimelineDurationScope tds(thread,
isolate->GetIsolateStream(),
"Object::Init");
-#endif
+)
#if defined(DART_NO_SNAPSHOT)
// Object::Init version when we are running in a version of dart that does
@@ -1375,7 +1380,8 @@
ASSERT(lib.raw() == Library::MirrorsLibrary());
cls = Class::New<MirrorReference>();
- RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib));
+ RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
+)
// Pre-register the collection library so we can place the vm class
// LinkedHashMap there rather than the core library.
@@ -1917,18 +1923,17 @@
}
-RawString* Class::PrettyName() const {
- return GeneratePrettyName();
+RawString* Class::ScrubbedName() const {
+ return String::ScrubName(String::Handle(Name()));
}
RawString* Class::UserVisibleName() const {
-#if defined(PRODUCT)
- return raw_ptr()->name_;
-#else // defined(PRODUCT)
+NOT_IN_PRODUCT(
ASSERT(raw_ptr()->user_name_ != String::null());
return raw_ptr()->user_name_;
-#endif // defined(PRODUCT)
+)
+ return GenerateUserVisibleName(); // No caching in PRODUCT, regenerate.
}
@@ -3012,7 +3017,8 @@
intptr_t len = value.Length();
for (intptr_t i = 0; i < len; i++) {
field ^= value.At(i);
- ASSERT(field.owner() == raw());
+ ASSERT(field.IsOriginal());
+ ASSERT(field.Owner() == raw());
}
#endif
// The value of static fields is already initialized to null.
@@ -3161,6 +3167,7 @@
void Class::set_name(const String& value) const {
+ ASSERT(raw_ptr()->name_ == String::null());
ASSERT(value.IsSymbol());
StorePointer(&raw_ptr()->name_, value.raw());
NOT_IN_PRODUCT(
@@ -3182,16 +3189,11 @@
)
-RawString* Class::GeneratePrettyName() const {
- const String& name = String::Handle(Name());
- return String::IdentifierPrettyName(name);
-}
-
-
RawString* Class::GenerateUserVisibleName() const {
if (FLAG_show_internal_names) {
return Name();
}
+NOT_IN_PRODUCT(
switch (id()) {
case kNullCid:
return Symbols::Null().raw();
@@ -3323,11 +3325,10 @@
case kTypedDataFloat64ArrayCid:
case kExternalTypedDataFloat64ArrayCid:
return Symbols::Float64List().raw();
- default:
- const String& name = String::Handle(Name());
- return String::IdentifierPrettyName(name);
}
- UNREACHABLE();
+)
+ const String& name = String::Handle(Name());
+ return String::ScrubName(name);
}
@@ -3557,6 +3558,8 @@
ASSERT(!types.IsNull() && (types.Length() > 1));
ASSERT((types.At(0) == Object::null()) || (types.At(0) == type.raw()));
types.SetAt(0, type);
+ // Makes sure that 'canonical_types' has not changed.
+ ASSERT(types.raw() == canonical_types());
}
}
@@ -4126,6 +4129,84 @@
}
+// Returns AbstractType::null() if type not found. Modifies index to the last
+// position looked up.
+RawAbstractType* Class::LookupCanonicalType(
+ Zone* zone, const AbstractType& lookup_type, intptr_t* index) const {
+ Array& canonical_types = Array::Handle(zone);
+ canonical_types ^= this->canonical_types();
+ if (canonical_types.IsNull()) {
+ return AbstractType::null();
+ }
+ AbstractType& type = Type::Handle(zone);
+ const intptr_t length = canonical_types.Length();
+ while (*index < length) {
+ type ^= canonical_types.At(*index);
+ if (type.IsNull()) {
+ break;
+ }
+ ASSERT(type.IsFinalized());
+ if (lookup_type.Equals(type)) {
+ ASSERT(type.IsCanonical());
+ return type.raw();
+ }
+ *index = *index + 1;
+ }
+ return AbstractType::null();
+}
+
+
+// Canonicalizing the type arguments may have changed the index, may have
+// grown the table, or may even have canonicalized this type. Therefore
+// conrtinue search for canonical type at the last index visited.
+RawAbstractType* Class::LookupOrAddCanonicalType(
+ const AbstractType& lookup_type, intptr_t start_index) const {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Isolate* isolate = thread->isolate();
+ AbstractType& type = Type::Handle(zone);
+ intptr_t index = start_index;
+ type ^= LookupCanonicalType(zone, lookup_type, &index);
+
+ if (!type.IsNull()) {
+ return type.raw();
+ }
+ {
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+ // Lookup again, in case the canonicalization array changed.
+ Array& canonical_types = Array::Handle(zone);
+ canonical_types ^= this->canonical_types();
+ if (canonical_types.IsNull()) {
+ canonical_types = empty_array().raw();
+ }
+ const intptr_t length = canonical_types.Length();
+ // Start looking after previously looked up last position ('length').
+ type ^= LookupCanonicalType(zone, lookup_type, &index);
+ if (!type.IsNull()) {
+ return type.raw();
+ }
+
+ // 'lookup_type' is not canonicalized yet.
+ lookup_type.SetCanonical();
+
+ // The type needs to be added to the list. Grow the list if it is full.
+ if (index >= length) {
+ ASSERT((index == length) || ((index == 1) && (length == 0)));
+ const intptr_t new_length = (length > 64) ?
+ (length + 64) :
+ ((length == 0) ? 2 : (length * 2));
+ const Array& new_canonical_types = Array::Handle(
+ zone, Array::Grow(canonical_types, new_length, Heap::kOld));
+ new_canonical_types.SetAt(index, lookup_type);
+ this->set_canonical_types(new_canonical_types);
+ } else {
+ canonical_types.SetAt(index, lookup_type);
+ }
+ }
+ return lookup_type.raw();
+}
+
+
const char* Class::ToCString() const {
const Library& lib = Library::Handle(library());
const char* library_name = lib.IsNull() ? "" : lib.ToCString();
@@ -4920,6 +5001,22 @@
}
+RawString* TypeArguments::EnumerateURIs() const {
+ if (IsNull()) {
+ return Symbols::Empty().raw();
+ }
+ Zone* zone = Thread::Current()->zone();
+ AbstractType& type = AbstractType::Handle(zone);
+ const intptr_t num_types = Length();
+ GrowableHandlePtrArray<const String> pieces(zone, num_types);
+ for (intptr_t i = 0; i < num_types; i++) {
+ type = TypeAt(i);
+ pieces.Add(String::Handle(zone, type.EnumerateURIs()));
+ }
+ return Symbols::FromConcatAll(pieces);
+}
+
+
const char* TypeArguments::ToCString() const {
if (IsNull()) {
return "NULL TypeArguments";
@@ -5942,7 +6039,7 @@
bool Function::HasCompatibleParametersWith(const Function& other,
Error* bound_error) const {
- ASSERT(Isolate::Current()->flags().error_on_bad_override());
+ ASSERT(Isolate::Current()->error_on_bad_override());
ASSERT((bound_error != NULL) && bound_error->IsNull());
// Check that this function's signature type is a subtype of the other
// function's signature type.
@@ -6655,68 +6752,36 @@
}
-RawString* Function::PrettyName() const {
- const String& str = String::Handle(name());
- return String::IdentifierPrettyName(str);
-}
-
-
-const char* Function::QualifiedUserVisibleNameCString() const {
- const String& str = String::Handle(QualifiedUserVisibleName());
- return str.ToCString();
-}
-
-
RawString* Function::UserVisibleName() const {
- return PrettyName();
+ if (FLAG_show_internal_names) {
+ return name();
+ }
+ return String::ScrubName(String::Handle(name()));
}
-RawString* Function::QualifiedPrettyName() const {
- String& tmp = String::Handle();
- const Class& cls = Class::Handle(Owner());
-
+RawString* Function::QualifiedName(NameVisibility name_visibility) const {
+ ASSERT(name_visibility != kInternalName); // We never request it.
+ // A function's scrubbed name and its user visible name are identical.
+ String& result = String::Handle(UserVisibleName());
if (IsClosureFunction()) {
- if (IsLocalFunction() && !IsImplicitClosureFunction()) {
- const Function& parent = Function::Handle(parent_function());
- tmp = parent.QualifiedPrettyName();
- } else {
- return PrettyName();
- }
- } else {
- if (cls.IsTopLevel()) {
- return PrettyName();
- } else {
- tmp = cls.PrettyName();
+ Function& fun = Function::Handle(raw());
+ while (fun.IsLocalFunction() && !fun.IsImplicitClosureFunction()) {
+ fun = fun.parent_function();
+ result = String::Concat(Symbols::Dot(), result, Heap::kOld);
+ result = String::Concat(
+ String::Handle(fun.UserVisibleName()), result, Heap::kOld);
}
}
- tmp = String::Concat(tmp, Symbols::Dot(), Heap::kOld);
- const String& suffix = String::Handle(PrettyName());
- return String::Concat(tmp, suffix, Heap::kOld);
-}
-
-
-RawString* Function::QualifiedUserVisibleName() const {
- String& tmp = String::Handle();
const Class& cls = Class::Handle(Owner());
-
- if (IsClosureFunction()) {
- if (IsLocalFunction() && !IsImplicitClosureFunction()) {
- const Function& parent = Function::Handle(parent_function());
- tmp = parent.QualifiedUserVisibleName();
- } else {
- return UserVisibleName();
- }
- } else {
- if (cls.IsTopLevel()) {
- return UserVisibleName();
- } else {
- tmp = cls.UserVisibleName();
- }
+ if (!cls.IsTopLevel()) {
+ result = String::Concat(Symbols::Dot(), result, Heap::kOld);
+ const String& cls_name = String::Handle(
+ name_visibility == kScrubbedName ? cls.ScrubbedName()
+ : cls.UserVisibleName());
+ result = String::Concat(cls_name, result, Heap::kOld);
}
- tmp = String::Concat(tmp, Symbols::Dot());
- const String& suffix = String::Handle(UserVisibleName());
- return String::Concat(tmp, suffix);
+ return result.raw();
}
@@ -6766,9 +6831,7 @@
// Construct fingerprint from token stream. The token stream contains also
// arguments.
int32_t Function::SourceFingerprint() const {
- uint32_t result = IsImplicitClosureFunction()
- ? String::Handle(Function::Handle(parent_function()).Signature()).Hash()
- : String::Handle(Signature()).Hash();
+ uint32_t result = 0;
TokenStream::Iterator tokens_iterator(TokenStream::Handle(
Script::Handle(script()).tokens()), token_pos());
Object& obj = Object::Handle();
@@ -6818,6 +6881,9 @@
void Function::RestoreICDataMap(
ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data,
bool clone_ic_data) const {
+ if (FLAG_force_clone_compiler_objects) {
+ clone_ic_data = true;
+ }
ASSERT(deopt_id_to_ic_data->is_empty());
Zone* zone = Thread::Current()->zone();
const Array& saved_ic_data = Array::Handle(zone, ic_data_array());
@@ -7014,6 +7080,31 @@
}
+RawField* Field::CloneFromOriginal() const {
+ return this->Clone(*this);
+}
+
+
+RawField* Field::Original() const {
+ if (IsNull()) {
+ return Field::null();
+ }
+ Object& obj = Object::Handle(raw_ptr()->owner_);
+ if (obj.IsField()) {
+ return Field::RawCast(obj.raw());
+ } else {
+ return this->raw();
+ }
+}
+
+
+void Field::SetOriginal(const Field& value) const {
+ ASSERT(value.IsOriginal());
+ ASSERT(!value.IsNull());
+ StorePointer(&raw_ptr()->owner_, reinterpret_cast<RawObject*>(value.raw()));
+}
+
+
RawString* Field::GetterName(const String& field_name) {
return String::Concat(Symbols::GetterPrefix(), field_name);
}
@@ -7068,12 +7159,27 @@
void Field::set_name(const String& value) const {
ASSERT(value.IsSymbol());
+ ASSERT(IsOriginal());
StorePointer(&raw_ptr()->name_, value.raw());
}
-RawClass* Field::owner() const {
- const Object& obj = Object::Handle(raw_ptr()->owner_);
+RawObject* Field::RawOwner() const {
+ if (Original()) {
+ return raw_ptr()->owner_;
+ } else {
+ const Field& field = Field::Handle(Original());
+ ASSERT(field.IsOriginal());
+ ASSERT(!Object::Handle(field.raw_ptr()->owner_).IsField());
+ return field.raw_ptr()->owner_;
+ }
+}
+
+
+RawClass* Field::Owner() const {
+ const Field& field = Field::Handle(Original());
+ ASSERT(field.IsOriginal());
+ const Object& obj = Object::Handle(field.raw_ptr()->owner_);
if (obj.IsClass()) {
return Class::Cast(obj).raw();
}
@@ -7082,8 +7188,10 @@
}
-RawClass* Field::origin() const {
- const Object& obj = Object::Handle(raw_ptr()->owner_);
+RawClass* Field::Origin() const {
+ const Field& field = Field::Handle(Original());
+ ASSERT(field.IsOriginal());
+ const Object& obj = Object::Handle(field.raw_ptr()->owner_);
if (obj.IsClass()) {
return Class::Cast(obj).raw();
}
@@ -7092,8 +7200,10 @@
}
-RawScript* Field::script() const {
- const Object& obj = Object::Handle(raw_ptr()->owner_);
+RawScript* Field::Script() const {
+ const Field& field = Field::Handle(Original());
+ ASSERT(field.IsOriginal());
+ const Object& obj = Object::Handle(field.raw_ptr()->owner_);
if (obj.IsClass()) {
return Class::Cast(obj).script();
}
@@ -7105,6 +7215,7 @@
// Called at finalization time
void Field::SetFieldType(const AbstractType& value) const {
ASSERT(Thread::Current()->IsMutatorThread());
+ ASSERT(IsOriginal());
ASSERT(!value.IsNull());
if (value.raw() != type()) {
StorePointer(&raw_ptr()->type_, value.raw());
@@ -7191,7 +7302,7 @@
RawField* Field::Clone(const Class& new_owner) const {
Field& clone = Field::Handle();
clone ^= Object::Clone(*this, Heap::kOld);
- const Class& owner = Class::Handle(this->owner());
+ const Class& owner = Class::Handle(this->Owner());
const PatchClass& clone_owner =
PatchClass::Handle(PatchClass::New(new_owner, owner));
clone.set_owner(clone_owner);
@@ -7208,14 +7319,23 @@
}
-RawString* Field::PrettyName() const {
- const String& str = String::Handle(name());
- return String::IdentifierPrettyName(str);
+RawField* Field::Clone(const Field& original) const {
+ if (original.IsNull()) {
+ return Field::null();
+ }
+ ASSERT(original.IsOriginal());
+ Field& clone = Field::Handle();
+ clone ^= Object::Clone(*this, Heap::kOld);
+ clone.SetOriginal(original);
+ return clone.raw();
}
RawString* Field::UserVisibleName() const {
- return PrettyName();
+ if (FLAG_show_internal_names) {
+ return name();
+ }
+ return String::ScrubName(String::Handle(name()));
}
@@ -7226,6 +7346,7 @@
void Field::set_guarded_list_length(intptr_t list_length) const {
ASSERT(Thread::Current()->IsMutatorThread());
+ ASSERT(IsOriginal());
StoreSmi(&raw_ptr()->guarded_list_length_, Smi::New(list_length));
}
@@ -7238,6 +7359,7 @@
void Field::set_guarded_list_length_in_object_offset(
intptr_t list_length_offset) const {
ASSERT(Thread::Current()->IsMutatorThread());
+ ASSERT(IsOriginal());
StoreNonPointer(&raw_ptr()->guarded_list_length_in_object_offset_,
static_cast<int8_t>(list_length_offset - kHeapObjectTag));
ASSERT(guarded_list_length_in_object_offset() == list_length_offset);
@@ -7252,7 +7374,7 @@
const char* kF1 = is_final() ? " final" : "";
const char* kF2 = is_const() ? " const" : "";
const char* field_name = String::Handle(name()).ToCString();
- const Class& cls = Class::Handle(owner());
+ const Class& cls = Class::Handle(Owner());
const char* cls_name = String::Handle(cls.Name()).ToCString();
return OS::SCreate(Thread::Current()->zone(),
"Field <%s.%s>:%s%s%s", cls_name, field_name, kF0, kF1, kF2);
@@ -7264,7 +7386,7 @@
// named #f (or #f= in case of a setter).
RawInstance* Field::AccessorClosure(bool make_setter) const {
ASSERT(is_static());
- const Class& field_owner = Class::Handle(owner());
+ const Class& field_owner = Class::Handle(Owner());
String& closure_name = String::Handle(this->name());
closure_name = Symbols::FromConcat(Symbols::HashMark(), closure_name);
@@ -7334,6 +7456,7 @@
void Field::set_dependent_code(const Array& array) const {
+ ASSERT(IsOriginal());
StorePointer(&raw_ptr()->dependent_code_, array.raw());
}
@@ -7377,6 +7500,7 @@
void Field::RegisterDependentCode(const Code& code) const {
+ ASSERT(IsOriginal());
DEBUG_ASSERT(IsMutatorOrAtSafepoint());
ASSERT(code.is_optimized());
FieldDependentArray a(*this);
@@ -7385,6 +7509,7 @@
void Field::DeoptimizeDependentCode() const {
+ ASSERT(IsOriginal());
ASSERT(Thread::Current()->IsMutatorThread());
FieldDependentArray a(*this);
a.DisableCode();
@@ -7399,6 +7524,7 @@
void Field::SetPrecompiledInitializer(const Function& initializer) const {
+ ASSERT(IsOriginal());
StorePointer(&raw_ptr()->initializer_.precompiled_, initializer.raw());
}
@@ -7410,12 +7536,14 @@
void Field::SetSavedInitialStaticValue(const Instance& value) const {
+ ASSERT(IsOriginal());
ASSERT(!HasPrecompiledInitializer());
StorePointer(&raw_ptr()->initializer_.saved_value_, value.raw());
}
void Field::EvaluateInitializer() const {
+ ASSERT(IsOriginal());
ASSERT(is_static());
if (StaticValue() == Object::sentinel().raw()) {
SetStaticValue(Object::transition_sentinel());
@@ -7517,6 +7645,7 @@
void Field::InitializeGuardedListLengthInObjectOffset() const {
+ ASSERT(IsOriginal());
if (needs_length_check() &&
(guarded_list_length() != Field::kUnknownFixedLength)) {
const intptr_t offset = GetListLengthOffset(guarded_cid());
@@ -7529,6 +7658,7 @@
bool Field::UpdateGuardedCidAndLength(const Object& value) const {
+ ASSERT(IsOriginal());
const intptr_t cid = value.GetClassId();
if (guarded_cid() == kIllegalCid) {
@@ -7596,6 +7726,7 @@
void Field::RecordStore(const Object& value) const {
+ ASSERT(IsOriginal());
if (!FLAG_use_field_guards) {
return;
}
@@ -8957,7 +9088,7 @@
static RawString* MakeFieldMetaName(const Field& field) {
const String& cname =
- String::Handle(MakeClassMetaName(Class::Handle(field.origin())));
+ String::Handle(MakeClassMetaName(Class::Handle(field.Origin())));
GrowableHandlePtrArray<const String> pieces(Thread::Current()->zone(), 3);
pieces.Add(cname);
pieces.Add(Symbols::At());
@@ -8972,7 +9103,7 @@
GrowableHandlePtrArray<const String> pieces(Thread::Current()->zone(), 3);
pieces.Add(cname);
pieces.Add(Symbols::At());
- pieces.Add(String::Handle(func.QualifiedPrettyName()));
+ pieces.Add(String::Handle(func.QualifiedScrubbedName()));
return Symbols::FromConcatAll(pieces);
}
@@ -9422,7 +9553,7 @@
} else if (entry.IsFunction()) {
owner_script = Function::Cast(entry).script();
} else if (entry.IsField()) {
- owner_script = Field::Cast(entry).script();
+ owner_script = Field::Cast(entry).Script();
} else {
continue;
}
@@ -10262,6 +10393,11 @@
}
ASSERT(is_deferred_load());
ASSERT(num_imports() == 1);
+ if (Dart::IsRunningPrecompiledCode()) {
+ // The library list was tree-shaken away.
+ this->set_is_loaded();
+ return true;
+ }
// This is a prefix for a deferred library. If the library is not loaded
// yet and isn't being loaded, call the library tag handler to schedule
// loading. Once all outstanding load requests have completed, the embedder
@@ -11019,6 +11155,87 @@
}
+TokenPosition CodeSourceMap::TokenPositionForPCOffset(
+ uword pc_offset) const {
+ Iterator iterator(*this);
+
+ TokenPosition result = TokenPosition::kNoSource;
+
+ while (iterator.MoveNext()) {
+ if (iterator.PcOffset() > pc_offset) {
+ break;
+ }
+ result = iterator.TokenPos();
+ }
+
+ return result;
+}
+
+
+RawFunction* CodeSourceMap::FunctionForPCOffset(const Code& code,
+ const Function& function,
+ uword pc_offset) const {
+ GrowableArray<Function*> inlined_functions;
+ code.GetInlinedFunctionsAt(pc_offset, &inlined_functions);
+ if (inlined_functions.length() > 0) {
+ Function* inlined_function = inlined_functions[0];
+ return inlined_function->raw();
+ } else {
+ return function.raw();
+ }
+}
+
+
+RawScript* CodeSourceMap::ScriptForPCOffset(const Code& code,
+ const Function& function,
+ uword pc_offset) const {
+ const Function& func =
+ Function::Handle(FunctionForPCOffset(code, function, pc_offset));
+ return func.script();
+}
+
+
+void CodeSourceMap::Dump(const CodeSourceMap& code_source_map,
+ const Code& code,
+ const Function& function) {
+ const String& code_name = String::Handle(code.QualifiedName());
+ THR_Print("Dumping Code Source Map for %s\n", code_name.ToCString());
+ if (code_source_map.Length() == 0) {
+ THR_Print("<empty>\n");
+ return;
+ }
+
+ const int addr_width = kBitsPerWord / 4;
+
+ Iterator iterator(code_source_map);
+ Function& current_function = Function::Handle();
+ Script& current_script = Script::Handle();
+ TokenPosition tp;
+ while (iterator.MoveNext()) {
+ const uword pc_offset = iterator.PcOffset();
+ tp = code_source_map.TokenPositionForPCOffset(pc_offset);
+ current_function ^=
+ code_source_map.FunctionForPCOffset(code, function, pc_offset);
+ current_script ^=
+ code_source_map.ScriptForPCOffset(code, function, pc_offset);
+ if (current_function.IsNull() || current_script.IsNull()) {
+ THR_Print("%#-*" Px "\t%s\t%s\n", addr_width,
+ pc_offset,
+ tp.ToCString(),
+ code_name.ToCString());
+ continue;
+ }
+ const String& uri = String::Handle(current_script.url());
+ ASSERT(!uri.IsNull());
+ THR_Print("%#-*" Px "\t%s\t%s\t%s\n", addr_width,
+ pc_offset,
+ tp.ToCString(),
+ current_function.ToQualifiedCString(),
+ uri.ToCString());
+ }
+}
+
+
intptr_t CodeSourceMap::Length() const {
return raw_ptr()->length_;
}
@@ -12775,6 +12992,29 @@
}
+RawArray* Code::GetInlinedIdToTokenPos() const {
+ const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
+ if (metadata.IsNull()) {
+ return metadata.raw();
+ }
+ return reinterpret_cast<RawArray*>(
+ metadata.At(RawCode::kInlinedIdToTokenPosIndex));
+}
+
+
+void Code::SetInlinedIdToTokenPos(const Array& value) const {
+ if (raw_ptr()->inlined_metadata_ == Array::null()) {
+ StorePointer(&raw_ptr()->inlined_metadata_,
+ Array::New(RawCode::kInlinedMetadataSize, Heap::kOld));
+ }
+ const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
+ ASSERT(!metadata.IsNull());
+ ASSERT(metadata.IsOld());
+ ASSERT(value.IsOld());
+ metadata.SetAt(RawCode::kInlinedIdToTokenPosIndex, value);
+}
+
+
RawArray* Code::GetInlinedCallerIdMap() const {
const Array& metadata = Array::Handle(raw_ptr()->inlined_metadata_);
if (metadata.IsNull()) {
@@ -13032,7 +13272,6 @@
}
-// Called by disassembler.
RawString* Code::Name() const {
const Object& obj = Object::Handle(owner());
if (obj.IsNull()) {
@@ -13044,36 +13283,23 @@
} else if (obj.IsClass()) {
// Allocation stub.
const Class& cls = Class::Cast(obj);
- String& cls_name = String::Handle(cls.Name());
+ String& cls_name = String::Handle(cls.ScrubbedName());
ASSERT(!cls_name.IsNull());
return Symbols::FromConcat(Symbols::AllocationStubFor(), cls_name);
} else {
ASSERT(obj.IsFunction());
// Dart function.
- return Function::Cast(obj).name();
+ return Function::Cast(obj).UserVisibleName(); // Same as scrubbed name.
}
}
-RawString* Code::PrettyName() const {
+RawString* Code::QualifiedName() const {
const Object& obj = Object::Handle(owner());
- if (obj.IsNull()) {
- // Regular stub.
- const char* name = StubCode::NameOfStub(EntryPoint());
- ASSERT(name != NULL);
- const String& stub_name = String::Handle(String::New(name));
- return String::Concat(Symbols::StubPrefix(), stub_name);
- } else if (obj.IsClass()) {
- // Allocation stub.
- const Class& cls = Class::Cast(obj);
- String& cls_name = String::Handle(cls.Name());
- ASSERT(!cls_name.IsNull());
- return String::Concat(Symbols::AllocationStubFor(), cls_name);
- } else {
- ASSERT(obj.IsFunction());
- // Dart function.
- return Function::Cast(obj).QualifiedPrettyName();
+ if (obj.IsFunction()) {
+ return Function::Cast(obj).QualifiedScrubbedName();
}
+ return Name();
}
@@ -13254,9 +13480,16 @@
THR_Print(" %" Pd ": %s\n", i, function.ToQualifiedCString());
}
}
+ THR_Print("Inlined token pos:\n");
+ const Array& token_pos_map = Array::Handle(GetInlinedIdToTokenPos());
+ Smi& smi = Smi::Handle();
+ for (intptr_t i = 0; i < token_pos_map.Length(); i++) {
+ smi ^= token_pos_map.At(i);
+ TokenPosition tp = TokenPosition(smi.Value());
+ THR_Print(" %" Pd ": %s\n", i, tp.ToCString());
+ }
THR_Print("Caller Inlining Ids:\n");
const Array& caller_map = Array::Handle(GetInlinedCallerIdMap());
- Smi& smi = Smi::Handle();
for (intptr_t i = 0; i < caller_map.Length(); i++) {
smi ^= caller_map.At(i);
THR_Print(" iid: %" Pd " caller iid: %" Pd "\n", i, smi.Value());
@@ -14255,7 +14488,7 @@
zone, other.InstantiateFrom(other_instantiator, bound_error,
NULL, NULL, Heap::kOld));
if ((bound_error != NULL) && !bound_error->IsNull()) {
- ASSERT(Isolate::Current()->flags().type_checks());
+ ASSERT(Isolate::Current()->type_checks());
return false;
}
if (instantiated_other.IsTypeRef()) {
@@ -14311,7 +14544,7 @@
instantiated_other = other.InstantiateFrom(other_instantiator, bound_error,
NULL, NULL, Heap::kOld);
if ((bound_error != NULL) && !bound_error->IsNull()) {
- ASSERT(Isolate::Current()->flags().type_checks());
+ ASSERT(Isolate::Current()->type_checks());
return false;
}
if (instantiated_other.IsTypeRef()) {
@@ -14713,6 +14946,13 @@
}
+RawString* AbstractType::EnumerateURIs() const {
+ // AbstractType is an abstract class.
+ UNREACHABLE();
+ return NULL;
+}
+
+
RawAbstractType* AbstractType::OnlyBuddyInTrail(TrailPtr trail) const {
if (trail == NULL) {
return AbstractType::null();
@@ -14785,13 +15025,12 @@
RawString* AbstractType::BuildName(NameVisibility name_visibility) const {
+ ASSERT(name_visibility != kScrubbedName);
Zone* zone = Thread::Current()->zone();
if (IsBoundedType()) {
const AbstractType& type = AbstractType::Handle(
BoundedType::Cast(*this).type());
- if (name_visibility == kPrettyName) {
- return type.BuildName(kPrettyName);
- } else if (name_visibility == kUserVisibleName) {
+ if (name_visibility == kUserVisibleName) {
return type.BuildName(kUserVisibleName);
}
GrowableHandlePtrArray<const String> pieces(zone, 5);
@@ -14861,8 +15100,6 @@
}
if (name_visibility == kInternalName) {
class_name = cls.Name();
- } else if (name_visibility == kPrettyName) {
- class_name = cls.PrettyName();
} else {
ASSERT(name_visibility == kUserVisibleName);
// Map internal types to their corresponding public interfaces.
@@ -14912,6 +15149,29 @@
}
+// Same as user visible name, but including the URI of each occuring type.
+// Used to report errors involving types with identical names.
+//
+// e.g.
+// MyClass<String> -> MyClass<String> where
+// MyClass is from my_uri
+// String is from dart:core
+// MyClass<dynamic, T> -> MyClass<dynamic, T> where
+// MyClass is from my_uri
+// T of OtherClass is from other_uri
+// (MyClass) => int -> (MyClass) => int where
+// MyClass is from my_uri
+// int is from dart:core
+RawString* AbstractType::UserVisibleNameWithURI() const {
+ Zone* zone = Thread::Current()->zone();
+ GrowableHandlePtrArray<const String> pieces(zone, 3);
+ pieces.Add(String::Handle(zone, BuildName(kUserVisibleName)));
+ pieces.Add(Symbols::SpaceWhereNewLine());
+ pieces.Add(String::Handle(zone, EnumerateURIs()));
+ return Symbols::FromConcatAll(pieces);
+}
+
+
RawString* AbstractType::ClassName() const {
if (HasResolvedTypeClass()) {
return Class::Handle(type_class()).Name();
@@ -15007,14 +15267,14 @@
// type and/or malbounded parameter types, which will then be encountered here
// at run time.
if (IsMalbounded()) {
- ASSERT(Isolate::Current()->flags().type_checks());
+ ASSERT(Isolate::Current()->type_checks());
if ((bound_error != NULL) && bound_error->IsNull()) {
*bound_error = error();
}
return false;
}
if (other.IsMalbounded()) {
- ASSERT(Isolate::Current()->flags().type_checks());
+ ASSERT(Isolate::Current()->type_checks());
if ((bound_error != NULL) && bound_error->IsNull()) {
*bound_error = other.error();
}
@@ -15265,7 +15525,7 @@
bool Type::IsMalbounded() const {
- if (!Isolate::Current()->flags().type_checks()) {
+ if (!Isolate::Current()->type_checks()) {
return false;
}
if (raw_ptr()->error_ == LanguageError::null()) {
@@ -15285,7 +15545,7 @@
return true;
}
ASSERT(type_error.kind() == Report::kMalboundedType);
- return Isolate::Current()->flags().type_checks();
+ return Isolate::Current()->type_checks();
}
@@ -15569,9 +15829,14 @@
set_arguments(type_args);
type = cls.CanonicalType(); // May be set while canonicalizing type args.
if (type.IsNull()) {
- cls.set_canonical_types(*this);
- SetCanonical();
- return this->raw();
+ MutexLocker ml(isolate->type_canonicalization_mutex());
+ // Recheck if type exists.
+ type = cls.CanonicalType();
+ if (type.IsNull()) {
+ SetCanonical();
+ cls.set_canonical_types(*this);
+ return this->raw();
+ }
}
}
ASSERT(this->Equals(type));
@@ -15616,43 +15881,28 @@
return this->raw();
}
set_arguments(type_args);
-
- // Canonicalizing the type arguments may have changed the index, may have
- // grown the table, or may even have canonicalized this type.
- canonical_types ^= cls.canonical_types();
- if (canonical_types.IsNull()) {
- canonical_types = empty_array().raw();
- }
- length = canonical_types.Length();
- while (index < length) {
- type ^= canonical_types.At(index);
- if (type.IsNull()) {
- break;
- }
- ASSERT(type.IsFinalized());
- if (this->Equals(type)) {
- ASSERT(type.IsCanonical());
- return type.raw();
- }
- index++;
- }
-
- // The type needs to be added to the list. Grow the list if it is full.
- if (index >= length) {
- ASSERT((index == length) || ((index == 1) && (length == 0)));
- const intptr_t new_length = (length > 64) ?
- (length + 64) :
- ((length == 0) ? 2 : (length * 2));
- const Array& new_canonical_types = Array::Handle(
- zone, Array::Grow(canonical_types, new_length, Heap::kOld));
- cls.set_canonical_types(new_canonical_types);
- canonical_types = new_canonical_types.raw();
- }
- canonical_types.SetAt(index, *this);
- ASSERT(IsOld());
ASSERT(type_args.IsNull() || type_args.IsOld());
- SetCanonical();
- return this->raw();
+
+ return cls.LookupOrAddCanonicalType(*this, index);
+}
+
+
+RawString* Type::EnumerateURIs() const {
+ if (IsDynamicType()) {
+ return Symbols::Empty().raw();
+ }
+ Zone* zone = Thread::Current()->zone();
+ GrowableHandlePtrArray<const String> pieces(zone, 6);
+ const Class& cls = Class::Handle(zone, type_class());
+ pieces.Add(Symbols::TwoSpaces());
+ pieces.Add(String::Handle(zone, cls.UserVisibleName()));
+ pieces.Add(Symbols::SpaceIsFromSpace());
+ const Library& library = Library::Handle(zone, cls.library());
+ pieces.Add(String::Handle(zone, library.url()));
+ pieces.Add(Symbols::NewLine());
+ const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+ pieces.Add(String::Handle(zone, type_args.EnumerateURIs()));
+ return Symbols::FromConcatAll(pieces);
}
@@ -15772,7 +16022,7 @@
bool FunctionType::IsMalbounded() const {
- if (!Isolate::Current()->flags().type_checks()) {
+ if (!Isolate::Current()->type_checks()) {
return false;
}
if (raw_ptr()->error_ == LanguageError::null()) {
@@ -15792,7 +16042,7 @@
return true;
}
ASSERT(type_error.kind() == Report::kMalboundedType);
- return Isolate::Current()->flags().type_checks();
+ return Isolate::Current()->type_checks();
}
@@ -16107,43 +16357,31 @@
sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names()));
set_signature(sig_fun);
}
-
- // Canonicalizing the type arguments and the signature may have changed the
- // index, may have grown the table, or may even have canonicalized this type.
- canonical_types ^= scope_cls.canonical_types();
- if (canonical_types.IsNull()) {
- canonical_types = empty_array().raw();
- }
- length = canonical_types.Length();
- while (index < length) {
- type ^= canonical_types.At(index);
- if (type.IsNull()) {
- break;
- }
- ASSERT(type.IsFinalized());
- if (this->Equals(type)) {
- ASSERT(type.IsCanonical());
- return type.raw();
- }
- index++;
- }
-
- // The type needs to be added to the list. Grow the list if it is full.
- if (index >= length) {
- ASSERT((index == length) || ((index == 1) && (length == 0)));
- const intptr_t new_length = (length > 64) ?
- (length + 64) :
- ((length == 0) ? 2 : (length * 2));
- const Array& new_canonical_types = Array::Handle(
- zone, Array::Grow(canonical_types, new_length, Heap::kOld));
- scope_cls.set_canonical_types(new_canonical_types);
- canonical_types = new_canonical_types.raw();
- }
- canonical_types.SetAt(index, *this);
- ASSERT(IsOld());
ASSERT(type_args.IsNull() || type_args.IsOld());
- SetCanonical();
- return this->raw();
+
+ return scope_cls.LookupOrAddCanonicalType(*this, index);
+}
+
+
+RawString* FunctionType::EnumerateURIs() const {
+ Zone* zone = Thread::Current()->zone();
+ // The scope class and type arguments do not appear explicitly in the user
+ // visible name. The type arguments were used to instantiate the function type
+ // prior to this call.
+ const Function& sig_fun = Function::Handle(zone, signature());
+ AbstractType& type = AbstractType::Handle(zone);
+ const intptr_t num_params = sig_fun.NumParameters();
+ GrowableHandlePtrArray<const String> pieces(zone, num_params + 1);
+ for (intptr_t i = 0; i < num_params; i++) {
+ type = sig_fun.ParameterTypeAt(i);
+ pieces.Add(String::Handle(zone, type.EnumerateURIs()));
+ }
+ // Handle result type last, since it appears last in the user visible name.
+ type = sig_fun.result_type();
+ if (!type.IsDynamicType() && !type.IsVoidType()) {
+ pieces.Add(String::Handle(zone, type.EnumerateURIs()));
+ }
+ return Symbols::FromConcatAll(pieces);
}
@@ -16350,6 +16588,11 @@
}
+RawString* TypeRef::EnumerateURIs() const {
+ return Symbols::Empty().raw(); // Break cycle.
+}
+
+
intptr_t TypeRef::Hash() const {
// Do not calculate the hash of the referenced type to avoid divergence.
const uint32_t result =
@@ -16565,6 +16808,22 @@
}
+RawString* TypeParameter::EnumerateURIs() const {
+ Zone* zone = Thread::Current()->zone();
+ GrowableHandlePtrArray<const String> pieces(zone, 4);
+ pieces.Add(Symbols::TwoSpaces());
+ pieces.Add(String::Handle(zone, name()));
+ pieces.Add(Symbols::SpaceOfSpace());
+ const Class& cls = Class::Handle(zone, parameterized_class());
+ pieces.Add(String::Handle(zone, cls.UserVisibleName()));
+ pieces.Add(Symbols::SpaceIsFromSpace());
+ const Library& library = Library::Handle(zone, cls.library());
+ pieces.Add(String::Handle(zone, library.url()));
+ pieces.Add(Symbols::NewLine());
+ return Symbols::FromConcatAll(pieces);
+}
+
+
intptr_t TypeParameter::Hash() const {
ASSERT(IsFinalized());
uint32_t result = Class::Handle(parameterized_class()).id();
@@ -16735,7 +16994,7 @@
// (or instantiated) either.
// Note that instantiator_type_arguments must have the final length, though.
}
- if ((Isolate::Current()->flags().type_checks()) &&
+ if ((Isolate::Current()->type_checks()) &&
(bound_error != NULL) && bound_error->IsNull()) {
AbstractType& upper_bound = AbstractType::Handle(bound());
ASSERT(upper_bound.IsFinalized());
@@ -16817,6 +17076,12 @@
}
+RawString* BoundedType::EnumerateURIs() const {
+ // The bound does not appear in the user visible name.
+ return AbstractType::Handle(type()).EnumerateURIs();
+}
+
+
intptr_t BoundedType::Hash() const {
uint32_t result = AbstractType::Handle(type()).Hash();
// No need to include the hash of the bound, since the bound is defined by the
@@ -21059,23 +21324,6 @@
}
-static intptr_t PrintOneStacktraceNoCode(Zone* zone,
- GrowableArray<char*>* frame_strings,
- const Function& function,
- intptr_t frame_index) {
- const Script& script = Script::Handle(zone, function.script());
- const String& function_name =
- String::Handle(zone, function.QualifiedUserVisibleName());
- const String& url = String::Handle(zone, script.url());
- char* chars = NULL;
- chars = OS::SCreate(zone,
- "#%-6" Pd " %s (%s)\n",
- frame_index, function_name.ToCString(), url.ToCString());
- frame_strings->Add(chars);
- return strlen(chars);
-}
-
-
const char* Stacktrace::ToCStringInternal(intptr_t* frame_index,
intptr_t max_frames) const {
Zone* zone = Thread::Current()->zone();
@@ -21088,7 +21336,7 @@
for (intptr_t i = 0; (i < Length()) && (*frame_index < max_frames); i++) {
function = FunctionAtFrame(i);
if (function.IsNull()) {
- // Check if null function object indicates a gap in a StackOverflow or
+ // Check for a null function, which indicates a gap in a StackOverflow or
// OutOfMemory trace.
if ((i < (Length() - 1)) &&
(FunctionAtFrame(i + 1) != Function::null())) {
@@ -21098,48 +21346,29 @@
OS::SNPrint(chars, truncated_len, "%s", kTruncated);
frame_strings.Add(chars);
total_len += truncated_len;
+ ASSERT(PcOffsetAtFrame(i) != Smi::null());
+ // To account for gap frames.
+ (*frame_index) += Smi::Value(PcOffsetAtFrame(i));
}
} else {
code = CodeAtFrame(i);
ASSERT(function.raw() == code.function());
uword pc = code.EntryPoint() + Smi::Value(PcOffsetAtFrame(i));
- if (code.is_optimized() && expand_inlined()) {
+ if (code.is_optimized() && expand_inlined() && !FLAG_precompiled_mode) {
// Traverse inlined frames.
- if (!FLAG_precompilation) {
- for (InlinedFunctionsIterator it(code, pc);
- !it.Done() && (*frame_index < max_frames); it.Advance()) {
- function = it.function();
- if (function.is_visible() || FLAG_show_invisible_frames) {
- code = it.code();
- ASSERT(function.raw() == code.function());
- uword pc = it.pc();
- ASSERT(pc != 0);
- ASSERT(code.EntryPoint() <= pc);
- ASSERT(pc < (code.EntryPoint() + code.Size()));
- total_len += PrintOneStacktrace(
- zone, &frame_strings, pc, function, code, *frame_index);
- (*frame_index)++; // To account for inlined frames.
- }
- }
- } else {
- // Precompilation: we don't have deopt info, so we don't know the
- // source position of inlined functions, but we can still name them.
- intptr_t offset = Smi::Value(PcOffsetAtFrame(i));
- // The PC of frames below the top frame is a call's return address,
- // which can belong to a different inlining interval than the call.
- intptr_t effective_offset = offset - 1;
- GrowableArray<Function*> inlined_functions;
- code.GetInlinedFunctionsAt(effective_offset, &inlined_functions);
- ASSERT(inlined_functions.length() >= 1); // At least the inliner.
- for (intptr_t j = 0; j < inlined_functions.length(); j++) {
- Function* inlined_function = inlined_functions[j];
- ASSERT(inlined_function != NULL);
- ASSERT(!inlined_function->IsNull());
- if (inlined_function->is_visible() || FLAG_show_invisible_frames) {
- total_len += PrintOneStacktraceNoCode(
- zone, &frame_strings, *inlined_function, *frame_index);
- (*frame_index)++;
- }
+ for (InlinedFunctionsIterator it(code, pc);
+ !it.Done() && (*frame_index < max_frames); it.Advance()) {
+ function = it.function();
+ if (function.is_visible() || FLAG_show_invisible_frames) {
+ code = it.code();
+ ASSERT(function.raw() == code.function());
+ uword pc = it.pc();
+ ASSERT(pc != 0);
+ ASSERT(code.EntryPoint() <= pc);
+ ASSERT(pc < (code.EntryPoint() + code.Size()));
+ total_len += PrintOneStacktrace(
+ zone, &frame_strings, pc, function, code, *frame_index);
+ (*frame_index)++; // To account for inlined frames.
}
}
} else {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ee8782a..8fafabc 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -585,13 +585,13 @@
// are preserved as well.
//
// e.g.
- // private getter - get:foo@6be832b
- // private constructor - _MyClass@6b3832b.
- // private named constructor - _MyClass@6b3832b.named
- // core impl class name shown - _OneByteString
+ // private getter -> get:foo@6be832b
+ // private constructor -> _MyClass@6b3832b.
+ // private named constructor -> _MyClass@6b3832b.named
+ // core impl class name shown -> _OneByteString
kInternalName = 0,
- // Pretty names drop privacy suffixes, getter prefixes, and
+ // Scrubbed names drop privacy suffixes, getter prefixes, and
// trailing dots on unnamed constructors. These names are used in
// the vm service.
//
@@ -599,11 +599,11 @@
// get:foo@6be832b -> foo
// _MyClass@6b3832b. -> _MyClass
// _MyClass@6b3832b.named -> _MyClass.named
- // _OneByteString -> _OneByteString (not remapped)
- kPrettyName,
+ // _OneByteString -> _OneByteString (not remapped)
+ kScrubbedName,
// User visible names are appropriate for reporting type errors
- // directly to programmers. The names have been "prettied" and
+ // directly to programmers. The names have been scrubbed and
// the names of core implementation classes are remapped to their
// public interface names.
//
@@ -611,7 +611,7 @@
// get:foo@6be832b -> foo
// _MyClass@6b3832b. -> _MyClass
// _MyClass@6b3832b.named -> _MyClass.named
- // _OneByteString -> String (remapped)
+ // _OneByteString -> String (remapped)
kUserVisibleName
};
@@ -953,7 +953,7 @@
}
RawString* Name() const;
- RawString* PrettyName() const;
+ RawString* ScrubbedName() const;
RawString* UserVisibleName() const;
bool IsInFullSnapshot() const;
@@ -1417,9 +1417,7 @@
class IsAllocatedBit : public BitField<uint16_t, bool, kIsAllocatedBit, 1> {};
void set_name(const String& value) const;
- void set_pretty_name(const String& value) const;
void set_user_name(const String& value) const;
- RawString* GeneratePrettyName() const;
RawString* GenerateUserVisibleName() const;
void set_state_bits(intptr_t bits) const;
@@ -1490,6 +1488,15 @@
TrailPtr bound_trail,
Heap::Space space);
+ // Returns AbstractType::null() if type not found.
+ RawAbstractType* LookupCanonicalType(Zone* zone,
+ const AbstractType& type,
+ intptr_t* index) const;
+
+ // Returns canonical type. Thread safe.
+ RawAbstractType* LookupOrAddCanonicalType(const AbstractType& type,
+ intptr_t start_index) const;
+
FINAL_HEAP_OBJECT_IMPLEMENTATION(Class, Object);
friend class AbstractType;
friend class Instance;
@@ -1549,12 +1556,6 @@
return SubvectorName(0, Length(), kInternalName);
}
- // The name of this type argument vector, e.g. "<T, dynamic, List<T>, Smi>".
- // Names of internal classes are not mapped to their public interfaces.
- RawString* PrettyName() const {
- return SubvectorName(0, Length(), kPrettyName);
- }
-
// The name of this type argument vector, e.g. "<T, dynamic, List<T>, int>".
// Names of internal classes are mapped to their public interfaces.
RawString* UserVisibleName() const {
@@ -1644,6 +1645,9 @@
// Canonicalize only if instantiated, otherwise returns 'this'.
RawTypeArguments* Canonicalize(TrailPtr trail = NULL) const;
+ // Returns a formatted list of occuring type arguments with their URI.
+ RawString* EnumerateURIs() const;
+
// Return 'this' if this type argument vector is instantiated, i.e. if it does
// not refer to type parameters. Otherwise, return a new type argument vector
// where each reference to a type parameter is replaced with the corresponding
@@ -2108,11 +2112,13 @@
class Function : public Object {
public:
RawString* name() const { return raw_ptr()->name_; }
- RawString* PrettyName() const;
- RawString* UserVisibleName() const;
- RawString* QualifiedPrettyName() const;
- RawString* QualifiedUserVisibleName() const;
- const char* QualifiedUserVisibleNameCString() const;
+ RawString* UserVisibleName() const; // Same as scrubbed name.
+ RawString* QualifiedScrubbedName() const {
+ return QualifiedName(kScrubbedName);
+ }
+ RawString* QualifiedUserVisibleName() const {
+ return QualifiedName(kUserVisibleName);
+ }
virtual RawString* DictionaryName() const { return name(); }
RawString* GetSource() const;
@@ -2136,12 +2142,6 @@
return BuildSignature(instantiate, kInternalName, TypeArguments::Handle());
}
- RawString* PrettySignature() const {
- const bool instantiate = false;
- return BuildSignature(
- instantiate, kPrettyName, TypeArguments::Handle());
- }
-
// Build a string of the form '(T, {b: B, c: C}) => R' representing the
// user visible signature of the given function. In this example, T and R are
// type parameters of class C, the owner of the function, also called the
@@ -2798,6 +2798,8 @@
static RawFunction* New();
+ RawString* QualifiedName(NameVisibility name_visibility) const;
+
void BuildSignatureParameters(
bool instantiate,
NameVisibility name_visibility,
@@ -2891,9 +2893,22 @@
class Field : public Object {
public:
+ RawField* Original() const;
+ void SetOriginal(const Field& value) const;
+ bool IsOriginal() const {
+ if (IsNull()) {
+ return true;
+ }
+ NoSafepointScope no_safepoint;
+ return !raw_ptr()->owner_->IsField();
+ }
+
+ // Returns a field cloned from 'this'. 'this' is set as the
+ // original field of result.
+ RawField* CloneFromOriginal() const;
+
RawString* name() const { return raw_ptr()->name_; }
- RawString* PrettyName() const;
- RawString* UserVisibleName() const;
+ RawString* UserVisibleName() const; // Same as scrubbed name.
virtual RawString* DictionaryName() const { return name(); }
bool is_static() const { return StaticBit::decode(raw_ptr()->kind_bits_); }
@@ -2903,6 +2918,7 @@
return ReflectableBit::decode(raw_ptr()->kind_bits_);
}
void set_is_reflectable(bool value) const {
+ ASSERT(IsOriginal());
set_kind_bits(ReflectableBit::update(value, raw_ptr()->kind_bits_));
}
bool is_double_initialized() const {
@@ -2912,6 +2928,7 @@
// Marks fields that are initialized with a simple double constant.
void set_is_double_initialized(bool value) const {
ASSERT(Thread::Current()->IsMutatorThread());
+ ASSERT(IsOriginal());
set_kind_bits(DoubleInitializedBit::update(value, raw_ptr()->kind_bits_));
}
@@ -2923,10 +2940,10 @@
inline void SetStaticValue(const Instance& value,
bool save_initial_value = false) const;
- RawClass* owner() const;
- RawClass* origin() const; // Either mixin class, or same as owner().
- RawScript* script() const;
- RawObject* RawOwner() const { return raw_ptr()->owner_; }
+ RawClass* Owner() const;
+ RawClass* Origin() const; // Either mixin class, or same as owner().
+ RawScript* Script() const;
+ RawObject* RawOwner() const;
RawAbstractType* type() const { return raw_ptr()->type_; }
// Used by class finalizer, otherwise initialized in constructor.
@@ -2954,6 +2971,9 @@
// Allocate new field object, clone values from this field. The
// owner of the clone is new_owner.
RawField* Clone(const Class& new_owner) const;
+ // Allocate new field object, clone values from this field. The
+ // original is specified.
+ RawField* Clone(const Field& original) const;
static intptr_t instance_field_offset() {
return OFFSET_OF(RawField, value_.offset_);
@@ -2971,6 +2991,7 @@
}
// Called by parser after allocating field.
void set_has_initializer(bool has_initializer) const {
+ ASSERT(IsOriginal());
ASSERT(Thread::Current()->IsMutatorThread());
set_kind_bits(HasInitializerBit::update(has_initializer,
raw_ptr()->kind_bits_));
@@ -3021,6 +3042,7 @@
// Default 'true', set to false once optimizing compiler determines it should
// be boxed.
void set_is_unboxing_candidate(bool b) const {
+ ASSERT(IsOriginal());
set_kind_bits(UnboxingCandidateBit::update(b, raw_ptr()->kind_bits_));
}
@@ -4051,6 +4073,18 @@
// Decode SLEB128 encoded integer. Update byte_index to the next integer.
intptr_t DecodeInteger(intptr_t* byte_index) const;
+ TokenPosition TokenPositionForPCOffset(uword pc_offset) const;
+ RawFunction* FunctionForPCOffset(const Code& code,
+ const Function& function,
+ uword pc_offset) const;
+ RawScript* ScriptForPCOffset(const Code& code,
+ const Function& function,
+ uword pc_offset) const;
+
+ static void Dump(const CodeSourceMap& code_source_map,
+ const Code& code,
+ const Function& function);
+
class Iterator : ValueObject {
public:
explicit Iterator(const CodeSourceMap& code_source_map)
@@ -4428,6 +4462,9 @@
RawArray* GetInlinedIdToFunction() const;
void SetInlinedIdToFunction(const Array& value) const;
+ RawArray* GetInlinedIdToTokenPos() const;
+ void SetInlinedIdToTokenPos(const Array& value) const;
+
RawArray* GetInlinedCallerIdMap() const;
void SetInlinedCallerIdMap(const Array& value) const;
@@ -4519,7 +4556,7 @@
intptr_t GetDeoptIdForOsr(uword pc) const;
RawString* Name() const;
- RawString* PrettyName() const;
+ RawString* QualifiedName() const;
int64_t compile_timestamp() const {
return raw_ptr()->compile_timestamp_;
@@ -5319,16 +5356,19 @@
return BuildName(kInternalName);
}
- virtual RawString* PrettyName() const {
- return BuildName(kPrettyName);
- }
-
// The name of this type, including the names of its type arguments, if any.
// Names of internal classes are mapped to their public interfaces.
virtual RawString* UserVisibleName() const {
return BuildName(kUserVisibleName);
}
+ // Same as user visible name, but including the URI of each occuring type.
+ // Used to report errors involving types with identical names.
+ virtual RawString* UserVisibleNameWithURI() const;
+
+ // Returns a formatted list of occuring types with their URI.
+ virtual RawString* EnumerateURIs() const;
+
virtual intptr_t Hash() const;
// The name of this type's class, i.e. without the type argument names of this
@@ -5472,6 +5512,7 @@
const Class& new_owner,
TrailPtr trail = NULL) const;
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+ virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -5620,6 +5661,7 @@
const Class& new_owner,
TrailPtr trail = NULL) const;
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+ virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -5696,6 +5738,7 @@
const Class& new_owner,
TrailPtr trail = NULL) const;
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+ virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -5771,6 +5814,7 @@
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const {
return raw();
}
+ virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -5857,6 +5901,7 @@
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const {
return raw();
}
+ virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -6520,8 +6565,8 @@
static RawString* ToLowerCase(const String& str,
Heap::Space space = Heap::kNew);
- static RawString* IdentifierPrettyName(const String& name);
- static RawString* IdentifierPrettyNameRetainPrivate(const String& name);
+ static RawString* ScrubName(const String& name);
+ static RawString* ScrubNameRetainPrivate(const String& name);
static bool EqualsIgnoringPrivateKey(const String& str1,
const String& str2);
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 54bd965..ba63134 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -84,9 +84,9 @@
}
AddCommonObjectProperties(&jsobj, "Class", ref);
jsobj.AddFixedServiceId("classes/%" Pd "", id());
- const String& user_name = String::Handle(PrettyName());
+ const String& scrubbed_name = String::Handle(ScrubbedName());
const String& vm_name = String::Handle(Name());
- AddNameProperties(&jsobj, user_name, vm_name);
+ AddNameProperties(&jsobj, scrubbed_name, vm_name);
if (ref) {
return;
}
@@ -184,7 +184,7 @@
ASSERT(table.Length() > 0);
AddCommonObjectProperties(&jsobj, "TypeArguments", ref);
jsobj.AddServiceId(*this);
- const String& user_name = String::Handle(PrettyName());
+ const String& user_name = String::Handle(UserVisibleName());
const String& vm_name = String::Handle(Name());
AddNameProperties(&jsobj, user_name, vm_name);
if (ref) {
@@ -270,7 +270,7 @@
JSONObject jsobj(stream);
AddCommonObjectProperties(&jsobj, "Function", ref);
AddFunctionServiceId(jsobj, *this, cls);
- const String& user_name = String::Handle(PrettyName());
+ const String& user_name = String::Handle(UserVisibleName());
const String& vm_name = String::Handle(name());
AddNameProperties(&jsobj, user_name, vm_name);
const Function& parent = Function::Handle(parent_function());
@@ -334,14 +334,14 @@
void Field::PrintJSONImpl(JSONStream* stream, bool ref) const {
JSONObject jsobj(stream);
- Class& cls = Class::Handle(owner());
+ Class& cls = Class::Handle(Owner());
String& field_name = String::Handle(name());
field_name = String::EncodeIRI(field_name);
AddCommonObjectProperties(&jsobj, "Field", ref);
jsobj.AddFixedServiceId("classes/%" Pd "/fields/%s",
cls.id(), field_name.ToCString());
- const String& user_name = String::Handle(PrettyName());
+ const String& user_name = String::Handle(UserVisibleName());
const String& vm_name = String::Handle(name());
AddNameProperties(&jsobj, user_name, vm_name);
if (cls.IsTopLevel()) {
@@ -382,8 +382,8 @@
} else {
jsobj.AddProperty("_guardLength", guarded_list_length());
}
- const Class& origin_cls = Class::Handle(origin());
- const Script& script = Script::Handle(origin_cls.script());
+ const Class& origin_cls = Class::Handle(Origin());
+ const class Script& script = Script::Handle(origin_cls.script());
if (!script.IsNull()) {
jsobj.AddLocation(script, token_pos());
}
@@ -481,9 +481,8 @@
AddCommonObjectProperties(&jsobj, "Library", ref);
jsobj.AddFixedServiceId("libraries/%" Pd "", id);
const String& vm_name = String::Handle(name());
- const String& user_name =
- String::Handle(String::IdentifierPrettyName(vm_name));
- AddNameProperties(&jsobj, user_name, vm_name);
+ const String& scrubbed_name = String::Handle(String::ScrubName(vm_name));
+ AddNameProperties(&jsobj, scrubbed_name, vm_name);
const String& library_url = String::Handle(url());
jsobj.AddPropertyStr("uri", library_url);
if (ref) {
@@ -819,9 +818,9 @@
jsobj.AddFixedServiceId("code/%" Px64"-%" Px "",
compile_timestamp(),
EntryPoint());
- const String& user_name = String::Handle(PrettyName());
+ const String& qualified_name = String::Handle(QualifiedName());
const String& vm_name = String::Handle(Name());
- AddNameProperties(&jsobj, user_name, vm_name);
+ AddNameProperties(&jsobj, qualified_name, vm_name);
const bool is_stub = IsStubCode() || IsAllocationStubCode();
if (is_stub) {
jsobj.AddProperty("kind", "Stub");
@@ -848,8 +847,9 @@
JSONObject func(&jsobj, "function");
func.AddProperty("type", "@Function");
func.AddProperty("_kind", "Stub");
- func.AddProperty("name", user_name.ToCString());
- AddNameProperties(&func, user_name, vm_name);
+ ASSERT(qualified_name.Equals(vm_name));
+ func.AddProperty("name", vm_name.ToCString());
+ AddNameProperties(&func, vm_name, vm_name);
}
jsobj.AddPropertyF("_startAddress", "%" Px "", EntryPoint());
jsobj.AddPropertyF("_endAddress", "%" Px "", EntryPoint() + Size());
@@ -1122,7 +1122,7 @@
} else {
jsobj.AddServiceId(*this);
}
- const String& user_name = String::Handle(PrettyName());
+ const String& user_name = String::Handle(UserVisibleName());
const String& vm_name = String::Handle(Name());
AddNameProperties(&jsobj, user_name, vm_name);
if (ref) {
@@ -1149,7 +1149,7 @@
} else {
jsobj.AddServiceId(*this);
}
- const String& user_name = String::Handle(PrettyName());
+ const String& user_name = String::Handle(UserVisibleName());
const String& vm_name = String::Handle(Name());
AddNameProperties(&jsobj, user_name, vm_name);
if (ref) {
@@ -1167,7 +1167,7 @@
PrintSharedInstanceJSON(&jsobj, ref);
jsobj.AddProperty("kind", "TypeRef");
jsobj.AddServiceId(*this);
- const String& user_name = String::Handle(PrettyName());
+ const String& user_name = String::Handle(UserVisibleName());
const String& vm_name = String::Handle(Name());
AddNameProperties(&jsobj, user_name, vm_name);
if (ref) {
@@ -1182,7 +1182,7 @@
PrintSharedInstanceJSON(&jsobj, ref);
jsobj.AddProperty("kind", "TypeParameter");
jsobj.AddServiceId(*this);
- const String& user_name = String::Handle(PrettyName());
+ const String& user_name = String::Handle(UserVisibleName());
const String& vm_name = String::Handle(Name());
AddNameProperties(&jsobj, user_name, vm_name);
const Class& param_cls = Class::Handle(parameterized_class());
@@ -1201,7 +1201,7 @@
PrintSharedInstanceJSON(&jsobj, ref);
jsobj.AddProperty("kind", "BoundedType");
jsobj.AddServiceId(*this);
- const String& user_name = String::Handle(PrettyName());
+ const String& user_name = String::Handle(UserVisibleName());
const String& vm_name = String::Handle(Name());
AddNameProperties(&jsobj, user_name, vm_name);
if (ref) {
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index ae009ec..e793b9b 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -4034,7 +4034,11 @@
EXPECT_NE(a_test3.SourceFingerprint(), a_test4.SourceFingerprint());
EXPECT_NE(a_test4.SourceFingerprint(), a_test5.SourceFingerprint());
EXPECT_EQ(a_test5.SourceFingerprint(), b_test5.SourceFingerprint());
- EXPECT_NE(a_test6.SourceFingerprint(), b_test6.SourceFingerprint());
+ // Although a_test6's receiver type is different than b_test6's receiver type,
+ // the fingerprints are identical. The token stream does not reflect the
+ // receiver's type. This is not a problem, since we recognize functions
+ // of a given class and of a given name.
+ EXPECT_EQ(a_test6.SourceFingerprint(), b_test6.SourceFingerprint());
}
@@ -4692,7 +4696,7 @@
};
-VM_TEST_CASE(String_IdentifierPrettyName) {
+VM_TEST_CASE(String_ScrubName) {
TestResult tests[] = {
{"(dynamic, dynamic) => void", "(dynamic, dynamic) => void"},
{"_List@915557746", "_List"},
@@ -4712,7 +4716,7 @@
String& result = String::Handle();
for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
test = String::New(tests[i].in);
- result = String::IdentifierPrettyName(test);
+ result = String::ScrubName(test);
EXPECT_STREQ(tests[i].out, result.ToCString());
}
}
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index ce22b2b..2ca6a7c 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -267,7 +267,7 @@
~Mutex();
void Lock();
- bool TryLock();
+ bool TryLock(); // Returns false if lock is busy and locking failed.
void Unlock();
#if defined(DEBUG)
@@ -303,6 +303,7 @@
Monitor();
~Monitor();
+ bool TryEnter(); // Returns false if lock is busy and locking failed.
void Enter();
void Exit();
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index c02fd9a..9b93cbe 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -336,6 +336,22 @@
}
+bool Monitor::TryEnter() {
+ int result = pthread_mutex_trylock(data_.mutex());
+ // Return false if the lock is busy and locking failed.
+ if (result == EBUSY) {
+ return false;
+ }
+ ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
+#if defined(DEBUG)
+ // When running with assertions enabled we track the owner.
+ ASSERT(owner_ == OSThread::kInvalidThreadId);
+ owner_ = OSThread::GetCurrentThreadId();
+#endif // defined(DEBUG)
+ return true;
+}
+
+
void Monitor::Enter() {
int result = pthread_mutex_lock(data_.mutex());
VALIDATE_PTHREAD_RESULT(result);
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index f821233..a0e68f1 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -341,6 +341,22 @@
}
+bool Monitor::TryEnter() {
+ int result = pthread_mutex_trylock(data_.mutex());
+ // Return false if the lock is busy and locking failed.
+ if (result == EBUSY) {
+ return false;
+ }
+ ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
+#if defined(DEBUG)
+ // When running with assertions enabled we track the owner.
+ ASSERT(owner_ == OSThread::kInvalidThreadId);
+ owner_ = OSThread::GetCurrentThreadId();
+#endif // defined(DEBUG)
+ return true;
+}
+
+
void Monitor::Enter() {
int result = pthread_mutex_lock(data_.mutex());
VALIDATE_PTHREAD_RESULT(result);
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 1964f64..42dd360 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -335,6 +335,22 @@
}
+bool Monitor::TryEnter() {
+ int result = pthread_mutex_trylock(data_.mutex());
+ // Return false if the lock is busy and locking failed.
+ if ((result == EBUSY) || (result == EDEADLK)) {
+ return false;
+ }
+ ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
+#if defined(DEBUG)
+ // When running with assertions enabled we track the owner.
+ ASSERT(owner_ == OSThread::kInvalidThreadId);
+ owner_ = OSThread::GetCurrentThreadId();
+#endif // defined(DEBUG)
+ return true;
+}
+
+
void Monitor::Enter() {
int result = pthread_mutex_lock(data_.mutex());
VALIDATE_PTHREAD_RESULT(result);
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index 7a29d0d..3802a16 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -305,6 +305,21 @@
}
+bool Monitor::TryEnter() {
+ // Attempt to pass the semaphore but return immediately.
+ BOOL result = TryEnterCriticalSection(&data_.cs_);
+ if (!result) {
+ return false;
+ }
+#if defined(DEBUG)
+ // When running with assertions enabled we do track the owner.
+ ASSERT(owner_ == OSThread::kInvalidThreadId);
+ owner_ = OSThread::GetCurrentThreadId();
+#endif // defined(DEBUG)
+ return true;
+}
+
+
void Monitor::Enter() {
EnterCriticalSection(&data_.cs_);
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index ff0fa53..177b091 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -29,21 +29,14 @@
"Print free list statistics before a GC");
DEFINE_FLAG(bool, print_free_list_after_gc, false,
"Print free list statistics after a GC");
-DEFINE_FLAG(bool, collect_code, true,
- "Attempt to GC infrequently used code.");
DEFINE_FLAG(int, code_collection_interval_in_us, 30000000,
"Time between attempts to collect unused code.");
DEFINE_FLAG(bool, log_code_drop, false,
"Emit a log message when pointers to unused code are dropped.");
DEFINE_FLAG(bool, always_drop_code, false,
"Always try to drop code if the function's usage counter is >= 0");
-#if defined(TARGET_ARCH_MIPS) || defined(TARGET_ARCH_ARM64)
-DEFINE_FLAG(bool, concurrent_sweep, false,
- "Concurrent sweep for old generation.");
-#else // TARGET_ARCH_MIPS || TARGET_ARCH_ARM64
DEFINE_FLAG(bool, concurrent_sweep, true,
"Concurrent sweep for old generation.");
-#endif // TARGET_ARCH_MIPS || TARGET_ARCH_ARM64
DEFINE_FLAG(bool, log_growth, false, "Log PageSpace growth policy decisions.");
HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) {
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index 008b7cd..12b193f 100644
--- a/runtime/vm/pages.h
+++ b/runtime/vm/pages.h
@@ -15,7 +15,6 @@
namespace dart {
-DECLARE_FLAG(bool, collect_code);
DECLARE_FLAG(bool, log_code_drop);
DECLARE_FLAG(bool, always_drop_code);
DECLARE_FLAG(bool, write_protect_code);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 9571669..78ca6a5 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -41,11 +41,8 @@
namespace dart {
DEFINE_FLAG(bool, enable_debug_break, false, "Allow use of break \"message\".");
-DEFINE_FLAG(bool, load_deferred_eagerly, false,
- "Load deferred libraries eagerly.");
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef.");
-DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
DEFINE_FLAG(bool, conditional_directives, false,
"Enable conditional directives");
DEFINE_FLAG(bool, warn_super, false,
@@ -53,8 +50,8 @@
DEFINE_FLAG(bool, await_is_keyword, false,
"await and yield are treated as proper keywords in synchronous code.");
-DECLARE_FLAG(bool, load_deferred_eagerly);
DECLARE_FLAG(bool, profile_vm);
+DECLARE_FLAG(bool, trace_service);
// Quick access to the current thread, isolate and zone.
#define T (thread())
@@ -166,7 +163,7 @@
return;
}
}
- guarded_fields_->Add(field);
+ guarded_fields_->Add(&Field::ZoneHandle(Z, field->Original()));
}
@@ -1081,8 +1078,8 @@
Thread* thread = Thread::Current();
StackZone stack_zone(thread);
Zone* zone = stack_zone.GetZone();
- const Class& owner_class = Class::Handle(zone, meta_data.owner());
- const Script& script = Script::Handle(zone, meta_data.script());
+ const Class& owner_class = Class::Handle(zone, meta_data.Owner());
+ const Script& script = Script::Handle(zone, meta_data.Script());
const TokenPosition token_pos = meta_data.token_pos();
// Parsing metadata can involve following paths in the parser that are
// normally used for expressions and assume current_function is non-null,
@@ -1222,10 +1219,10 @@
String& init_name = String::Handle(zone,
Symbols::FromConcat(Symbols::InitPrefix(), field_name));
- const Script& script = Script::Handle(zone, field.script());
- Object& initializer_owner = Object::Handle(field.owner());
+ const Script& script = Script::Handle(zone, field.Script());
+ Object& initializer_owner = Object::Handle(field.Owner());
initializer_owner =
- PatchClass::New(Class::Handle(field.owner()), script);
+ PatchClass::New(Class::Handle(field.Owner()), script);
const Function& initializer = Function::ZoneHandle(zone,
Function::New(init_name,
@@ -2552,7 +2549,8 @@
if (initializers->NodeAt(i)->IsStoreInstanceFieldNode()) {
StoreInstanceFieldNode* initializer =
initializers->NodeAt(i)->AsStoreInstanceFieldNode();
- if (initializer->field().raw() == field.raw()) {
+ ASSERT(field.IsOriginal());
+ if (initializer->field().Original() == field.raw()) {
found = true;
break;
}
@@ -2570,13 +2568,13 @@
// Only use this function if the initialized field originates
// from a different class. We need to save and restore current
// class, library, and token stream (script).
- ASSERT(current_class().raw() != field.origin());
+ ASSERT(current_class().raw() != field.Origin());
const Class& saved_class = Class::Handle(Z, current_class().raw());
const Library& saved_library = Library::Handle(Z, library().raw());
const Script& saved_script = Script::Handle(Z, script().raw());
const TokenPosition saved_token_pos = TokenPos();
- set_current_class(Class::Handle(Z, field.origin()));
+ set_current_class(Class::Handle(Z, field.Origin()));
set_library(Library::Handle(Z, current_class().library()));
SetScript(Script::Handle(Z, current_class().script()), field.token_pos());
@@ -2624,7 +2622,7 @@
initialized_fields->Add(&field);
}
AstNode* init_expr = NULL;
- if (current_class().raw() != field.origin()) {
+ if (current_class().raw() != field.Origin()) {
init_expr = ParseExternalInitializedField(field);
} else {
SetPosition(field.token_pos());
@@ -2959,6 +2957,22 @@
}
+// Returns a zone allocated string.
+static char* DumpPendingFunctions(
+ Zone* zone,
+ const GrowableObjectArray& pending_functions) {
+ ASSERT(zone != NULL);
+ char* result = OS::SCreate(zone, "Pending Functions:\n");
+ for (intptr_t i = 0; i < pending_functions.Length(); i++) {
+ const Function& func =
+ Function::Handle(zone, Function::RawCast(pending_functions.At(i)));
+ const String& fname = String::Handle(zone, func.UserVisibleName());
+ result = OS::SCreate(zone, "%s%" Pd ": %s\n", result, i, fname.ToCString());
+ }
+ return result;
+}
+
+
void Parser::CheckRecursiveInvocation() {
const GrowableObjectArray& pending_functions =
GrowableObjectArray::Handle(Z, T->pending_functions());
@@ -2967,7 +2981,16 @@
if (pending_functions.At(i) == current_function().raw()) {
const String& fname =
String::Handle(Z, current_function().UserVisibleName());
- ReportError("circular dependency for function %s", fname.ToCString());
+ if (FLAG_trace_service) {
+ const char* pending_function_dump =
+ DumpPendingFunctions(Z, pending_functions);
+ ASSERT(pending_function_dump != NULL);
+ ReportError("circular dependency for function %s\n%s",
+ fname.ToCString(),
+ pending_function_dump);
+ } else {
+ ReportError("circular dependency for function %s", fname.ToCString());
+ }
}
}
ASSERT(!unregister_pending_function_);
@@ -3278,7 +3301,7 @@
// Populate function scope with the formal parameters.
AddFormalParamsToScope(¶ms, current_block_->scope);
- if (I->flags().type_checks() &&
+ if (I->type_checks() &&
(current_block_->scope->function_level() > 0)) {
// We are parsing, but not compiling, a local function.
// The instantiator may be required at run time for generic type checks.
@@ -4609,7 +4632,7 @@
SkipMetadata();
ExpectToken(Token::kENUM);
- const String& enum_name = String::Handle(Z, cls.PrettyName());
+ const String& enum_name = String::Handle(Z, cls.ScrubbedName());
ClassDesc enum_members(Z, cls, enum_name, false, cls.token_pos());
// Add instance field 'final int index'.
@@ -4707,7 +4730,7 @@
// For the user-visible name of the enumeration value, we need to
// unmangle private names.
if (enum_ident->CharAt(0) == '_') {
- *enum_ident = String::IdentifierPrettyName(*enum_ident);
+ *enum_ident = String::ScrubName(*enum_ident);
}
enum_value_name = Symbols::FromConcat(name_prefix, *enum_ident);
enum_names.Add(enum_value_name, Heap::kOld);
@@ -5799,7 +5822,7 @@
: String::Cast(valueNode->AsLiteralNode()->literal());
// Call the embedder to supply us with the environment.
const String& env_value =
- String::Handle(Api::CallEnvironmentCallback(T, key));
+ String::Handle(Api::GetEnvironmentValue(T, key));
if (!env_value.IsNull() && env_value.Equals(value)) {
condition_triggered = true;
url_literal = conditional_url_literal;
@@ -7466,7 +7489,7 @@
bool is_final = (CurrentToken() == Token::kFINAL);
bool is_const = (CurrentToken() == Token::kCONST);
const AbstractType& type = AbstractType::ZoneHandle(Z,
- ParseConstFinalVarOrType(I->flags().type_checks() ?
+ ParseConstFinalVarOrType(I->type_checks() ?
ClassFinalizer::kCanonicalize : ClassFinalizer::kIgnore));
if (!IsIdentifier()) {
ReportError("identifier expected");
@@ -8534,7 +8557,7 @@
// position, which is inside the loop body.
new_loop_var = true;
loop_var_type = ParseConstFinalVarOrType(
- I->flags().type_checks() ? ClassFinalizer::kCanonicalize :
+ I->type_checks() ? ClassFinalizer::kCanonicalize :
ClassFinalizer::kIgnore);
}
TokenPosition loop_var_pos = TokenPos();
@@ -8828,7 +8851,7 @@
// position, which is inside the loop body.
new_loop_var = true;
loop_var_type = ParseConstFinalVarOrType(
- I->flags().type_checks() ? ClassFinalizer::kCanonicalize :
+ I->type_checks() ? ClassFinalizer::kCanonicalize :
ClassFinalizer::kIgnore);
loop_var_name = ExpectIdentifier("variable name expected");
}
@@ -9047,7 +9070,7 @@
ConsumeToken(); // Consume assert keyword.
ExpectToken(Token::kLPAREN);
const TokenPosition condition_pos = TokenPos();
- if (!I->flags().asserts()) {
+ if (!I->asserts()) {
SkipExpr();
ExpectToken(Token::kRPAREN);
return NULL;
@@ -10686,7 +10709,7 @@
} else if (original->IsLoadStaticFieldNode()) {
name = original->AsLoadStaticFieldNode()->field().name();
target_cls = &Class::Handle(Z,
- original->AsLoadStaticFieldNode()->field().owner());
+ original->AsLoadStaticFieldNode()->field().Owner());
} else if ((left_ident != NULL) &&
(original->IsLiteralNode() ||
original->IsLoadLocalNode())) {
@@ -11184,7 +11207,7 @@
}
// The field is initialized.
ASSERT(field.is_static());
- const Class& field_owner = Class::ZoneHandle(Z, field.owner());
+ const Class& field_owner = Class::ZoneHandle(Z, field.Owner());
const String& field_name = String::ZoneHandle(Z, field.name());
const String& getter_name =
String::Handle(Z, Field::GetterSymbol(field_name));
@@ -12027,7 +12050,7 @@
StaticGetterNode* Parser::RunStaticFieldInitializer(
const Field& field, TokenPosition field_ref_pos) {
ASSERT(field.is_static());
- const Class& field_owner = Class::ZoneHandle(Z, field.owner());
+ const Class& field_owner = Class::ZoneHandle(Z, field.Owner());
const String& field_name = String::ZoneHandle(Z, field.name());
const String& getter_name =
String::Handle(Z, Field::GetterSymbol(field_name));
@@ -12654,7 +12677,7 @@
"include a type variable");
}
} else {
- if (I->flags().error_on_bad_type()) {
+ if (I->error_on_bad_type()) {
ReportError(type_pos,
"a list literal takes one type argument specifying "
"the element type");
@@ -12677,7 +12700,7 @@
while (CurrentToken() != Token::kRBRACK) {
const TokenPosition element_pos = TokenPos();
AstNode* element = ParseExpr(is_const, kConsumeCascades);
- if (I->flags().type_checks() &&
+ if (I->type_checks() &&
!is_const &&
!element_type.IsDynamicType()) {
element = new(Z) AssignableNode(element_pos,
@@ -12708,7 +12731,7 @@
// Arguments have been evaluated to a literal value already.
ASSERT(elem->IsLiteralNode());
ASSERT(!is_top_level_); // We cannot check unresolved types.
- if (I->flags().type_checks() &&
+ if (I->type_checks() &&
!element_type.IsDynamicType() &&
(!elem->AsLiteralNode()->literal().IsNull() &&
!elem->AsLiteralNode()->literal().IsInstanceOf(
@@ -12860,7 +12883,7 @@
"include a type variable");
}
} else {
- if (I->flags().error_on_bad_type()) {
+ if (I->error_on_bad_type()) {
ReportError(type_pos,
"a map literal takes two type arguments specifying "
"the key type and the value type");
@@ -12879,7 +12902,7 @@
const bool saved_mode = SetAllowFunctionLiterals(true);
const TokenPosition key_pos = TokenPos();
AstNode* key = ParseExpr(is_const, kConsumeCascades);
- if (I->flags().type_checks() &&
+ if (I->type_checks() &&
!is_const &&
!key_type.IsDynamicType()) {
key = new(Z) AssignableNode(
@@ -12902,7 +12925,7 @@
const TokenPosition value_pos = TokenPos();
AstNode* value = ParseExpr(is_const, kConsumeCascades);
SetAllowFunctionLiterals(saved_mode);
- if (I->flags().type_checks() &&
+ if (I->type_checks() &&
!is_const &&
!value_type.IsDynamicType()) {
value = new(Z) AssignableNode(
@@ -12934,7 +12957,7 @@
// Arguments have been evaluated to a literal value already.
ASSERT(arg->IsLiteralNode());
ASSERT(!is_top_level_); // We cannot check unresolved types.
- if (I->flags().type_checks()) {
+ if (I->type_checks()) {
if ((i % 2) == 0) {
// Check key type.
arg_type = key_type.raw();
@@ -13436,7 +13459,7 @@
}
return ThrowTypeError(redirect_type.token_pos(), redirect_type);
}
- if (I->flags().type_checks() &&
+ if (I->type_checks() &&
!redirect_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
// Additional type checking of the result is necessary.
type_bound = type.raw();
@@ -14345,11 +14368,6 @@
namespace dart {
-DEFINE_FLAG(bool, load_deferred_eagerly, false,
- "Load deferred libraries eagerly.");
-DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
-
-
void ParsedFunction::AddToGuardedFields(const Field* field) const {
UNREACHABLE();
}
diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc
index 6af2ff8..a57b93f 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -313,7 +313,7 @@
Object& msg_handler = Object::Handle();
{
JSONArray ports(&jsobj, "ports");
- MutexLocker ml(mutex_);
+ SafepointMutexLocker ml(mutex_);
for (intptr_t i = 0; i < capacity_; i++) {
if (map_[i].handler == handler) {
if (map_[i].state == kLivePort) {
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index ce5ca5e..2f876e0 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -49,9 +49,6 @@
#define Z (zone())
-DEFINE_FLAG(bool, collect_dynamic_function_names, false,
- "In precompilation collects all dynamic function names in order to"
- " identify unique targets");
DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynaic targets");
DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
DEFINE_FLAG(int, max_speculative_inlining_attempts, 1,
@@ -69,9 +66,7 @@
DECLARE_FLAG(bool, trace_bailout);
DECLARE_FLAG(bool, use_inlining);
DECLARE_FLAG(bool, verify_compiler);
-DECLARE_FLAG(bool, precompilation);
DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
-DECLARE_FLAG(bool, load_deferred_eagerly);
DECLARE_FLAG(bool, trace_failed_optimization_attempts);
DECLARE_FLAG(bool, trace_inlining_intervals);
DECLARE_FLAG(bool, trace_irregexp);
@@ -576,6 +571,34 @@
type = function.ParameterTypeAt(i);
AddType(type);
}
+ Code& code = Code::Handle(Z, function.CurrentCode());
+ if (code.IsNull()) {
+ ASSERT(function.kind() == RawFunction::kSignatureFunction);
+ } else {
+ const ExceptionHandlers& handlers =
+ ExceptionHandlers::Handle(Z, code.exception_handlers());
+ if (!handlers.IsNull()) {
+ Array& types = Array::Handle(Z);
+ for (intptr_t i = 0; i < handlers.num_entries(); i++) {
+ types = handlers.GetHandledTypes(i);
+ if (!types.IsNull()) {
+ for (intptr_t j = 0; j < types.Length(); j++) {
+ type ^= types.At(j);
+ AddType(type);
+ }
+ }
+ }
+ }
+ }
+ // A function can always be inlined and have only a nested local function
+ // remain.
+ const Function& parent = Function::Handle(Z, function.parent_function());
+ if (!parent.IsNull()) {
+ AddTypesOf(parent);
+ }
+ // A class may have all functions inlined except a local function.
+ const Class& owner = Class::Handle(Z, function.Owner());
+ AddTypesOf(owner);
}
@@ -609,6 +632,13 @@
AbstractType& type = AbstractType::Handle(Z);
type = TypeRef::Cast(abstype).type();
AddType(type);
+ } else if (abstype.IsTypeParameter()) {
+ const AbstractType& type =
+ AbstractType::Handle(Z, TypeParameter::Cast(abstype).bound());
+ AddType(type);
+ const Class& cls =
+ Class::Handle(Z, TypeParameter::Cast(abstype).parameterized_class());
+ AddTypesOf(cls);
}
}
@@ -1889,7 +1919,7 @@
// If optimized_result_code is not NULL then it is caller's responsibility
// to install code.
bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
const Function& function = parsed_function()->function();
if (optimized() && !function.IsOptimizable()) {
return false;
@@ -1971,6 +2001,8 @@
// Maps inline_id_to_function[inline_id] -> function. Top scope
// function has inline_id 0. The map is populated by the inliner.
GrowableArray<const Function*> inline_id_to_function;
+ // Token position where inlining occured.
+ GrowableArray<TokenPosition> inline_id_to_token_pos;
// For a given inlining-id(index) specifies the caller's inlining-id.
GrowableArray<intptr_t> caller_inline_id;
// Collect all instance fields that are loaded in the graph and
@@ -1983,6 +2015,7 @@
"OptimizationPasses");
#endif // !PRODUCT
inline_id_to_function.Add(&function);
+ inline_id_to_token_pos.Add(function.token_pos());
// Top scope function has no caller (-1).
caller_inline_id.Add(-1);
CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer);
@@ -2026,6 +2059,7 @@
FlowGraphInliner inliner(flow_graph,
&inline_id_to_function,
+ &inline_id_to_token_pos,
&caller_inline_id,
use_speculative_inlining,
&inlining_black_list);
@@ -2322,6 +2356,7 @@
FlowGraphCompiler graph_compiler(&assembler, flow_graph,
*parsed_function(), optimized(),
inline_id_to_function,
+ inline_id_to_token_pos,
caller_inline_id);
{
CSTAT_TIMER_SCOPE(thread(), graphcompiler_timer);
@@ -2404,7 +2439,7 @@
const Function& function,
bool optimized) {
// Check that we optimize, except if the function is not optimizable.
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
ASSERT(!function.IsOptimizable() || optimized);
ASSERT(!function.HasCode());
LongJumpScope jump;
@@ -2501,7 +2536,7 @@
CompilationPipeline* pipeline =
CompilationPipeline::New(thread->zone(), function);
- ASSERT(FLAG_precompilation);
+ ASSERT(FLAG_precompiled_mode);
const bool optimized = function.IsOptimizable(); // False for natives.
return PrecompileFunctionHelper(pipeline, function, optimized);
}
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index e4f6c8d..0b1207f 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -54,7 +54,6 @@
private:
static bool initialized_;
- static Monitor* monitor_;
static SampleBuffer* sample_buffer_;
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 8152884..3de17c8 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -553,17 +553,15 @@
function = table->GetUnknown();
} else if (kind() == kDartCode) {
ASSERT(!code_.IsNull());
+ const String& name = String::Handle(code_.QualifiedName());
const Object& obj = Object::Handle(code_.owner());
if (obj.IsFunction()) {
- const String& user_name = String::Handle(code_.PrettyName());
function = table->LookupOrAdd(Function::Cast(obj));
- SetName(user_name.ToCString());
} else {
// A stub.
- const String& user_name = String::Handle(code_.PrettyName());
- function = table->AddStub(start(), user_name.ToCString());
- SetName(user_name.ToCString());
+ function = table->AddStub(start(), name.ToCString());
}
+ SetName(name.ToCString());
} else if (kind() == kNativeCode) {
if (name() == NULL) {
// Lazily set generated name.
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 55149b2..f9ae241 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -15,7 +15,6 @@
#ifndef PRODUCT
-DECLARE_FLAG(bool, background_compilation);
DECLARE_FLAG(bool, profile_vm);
DECLARE_FLAG(int, max_profile_depth);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 76d49ed..c30823f 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -424,6 +424,9 @@
bool IsScript() {
return ((GetClassId() == kScriptCid));
}
+ bool IsField() {
+ return ((GetClassId() == kFieldCid));
+ }
bool IsFunction() {
return ((GetClassId() == kFunctionCid));
}
@@ -881,7 +884,7 @@
RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
RawString* name_;
RawObject* owner_; // Class or patch class or mixin class
- // where this field is defined.
+ // where this field is defined or original field.
RawAbstractType* type_;
union {
RawInstance* static_value_; // Value for static fields.
@@ -1052,7 +1055,8 @@
kInlinedIntervalsIndex = 0,
kInlinedIdToFunctionIndex = 1,
kInlinedCallerIdMapIndex = 2,
- kInlinedMetadataSize = 3,
+ kInlinedIdToTokenPosIndex = 3,
+ kInlinedMetadataSize = 4,
};
RAW_HEAP_OBJECT_IMPLEMENTATION(Code);
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 6b9d728..ed22fa2 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -12,9 +12,6 @@
namespace dart {
-DECLARE_FLAG(int, optimization_counter_threshold);
-DECLARE_FLAG(bool, use_field_guards);
-
#define NEW_OBJECT(type) \
((kind == Snapshot::kFull) ? reader->New##type() : type::New())
diff --git a/runtime/vm/redundancy_elimination.cc b/runtime/vm/redundancy_elimination.cc
index 266abdf..adc1319 100644
--- a/runtime/vm/redundancy_elimination.cc
+++ b/runtime/vm/redundancy_elimination.cc
@@ -19,9 +19,6 @@
DEFINE_FLAG(bool, trace_load_optimization, false,
"Print live sets for load optimization pass.");
-DECLARE_FLAG(bool, fields_may_be_reset);
-DECLARE_FLAG(bool, precompilation);
-
// Quick access to the current zone.
#define Z (zone())
@@ -484,12 +481,13 @@
}
bool SameField(const Place* other) const {
- return (kind() == kField) ? (field().raw() == other->field().raw())
- : (offset_in_bytes_ == other->offset_in_bytes_);
+ return (kind() == kField) ?
+ (field().Original() == other->field().Original()) :
+ (offset_in_bytes_ == other->offset_in_bytes_);
}
intptr_t FieldHashcode() const {
- return (kind() == kField) ? reinterpret_cast<intptr_t>(field().raw())
+ return (kind() == kField) ? reinterpret_cast<intptr_t>(field().Original())
: offset_in_bytes_;
}
@@ -1430,7 +1428,7 @@
void LICM::OptimisticallySpecializeSmiPhis() {
if (!flow_graph()->function().allows_hoisting_check_class() ||
- FLAG_precompilation) {
+ FLAG_precompiled_mode) {
// Do not hoist any: Either deoptimized on a hoisted check,
// or compiling precompiled code where we can't do optimistic
// hoisting of checks.
@@ -3088,6 +3086,8 @@
// Add a field/offset to the list of fields if it is not yet present there.
static bool AddSlot(ZoneGrowableArray<const Object*>* slots,
const Object& slot) {
+ ASSERT(slot.IsSmi() || slot.IsField());
+ ASSERT(!slot.IsField() || Field::Cast(slot).IsOriginal());
for (intptr_t i = 0; i < slots->length(); i++) {
if ((*slots)[i]->raw() == slot.raw()) {
return false;
@@ -3284,7 +3284,7 @@
StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
if ((store != NULL) && (store->instance()->definition() == alloc)) {
if (!store->field().IsNull()) {
- AddSlot(slots, store->field());
+ AddSlot(slots, Field::ZoneHandle(Z, store->field().Original()));
} else {
AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(store->offset_in_bytes())));
}
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 7cf9710..e49c3d8 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -19,8 +19,6 @@
namespace dart {
DECLARE_FLAG(bool, trace_irregexp);
-DEFINE_FLAG(bool, interpret_irregexp, false,
- "Use irregexp bytecode interpreter");
// Default to generating optimized regexp code.
static const bool kRegexpOptimization = true;
diff --git a/runtime/vm/regexp_assembler.cc b/runtime/vm/regexp_assembler.cc
index 9e01f35..c916c70 100644
--- a/runtime/vm/regexp_assembler.cc
+++ b/runtime/vm/regexp_assembler.cc
@@ -4,10 +4,23 @@
#include "vm/regexp_assembler.h"
+#include "vm/flags.h"
#include "vm/regexp.h"
namespace dart {
+BlockLabel::BlockLabel()
+ : block_(NULL),
+ is_bound_(false),
+ is_linked_(false),
+ pos_(-1) {
+ if (!FLAG_interpret_irregexp) {
+ // Only needed by the compiled IR backend.
+ block_ = new JoinEntryInstr(-1, -1);
+ }
+}
+
+
RegExpMacroAssembler::RegExpMacroAssembler(Zone* zone)
: slow_safe_compiler_(false),
global_mode_(NOT_GLOBAL),
diff --git a/runtime/vm/regexp_assembler.h b/runtime/vm/regexp_assembler.h
index 5d0ee47..efd53c5 100644
--- a/runtime/vm/regexp_assembler.h
+++ b/runtime/vm/regexp_assembler.h
@@ -19,11 +19,7 @@
class BlockLabel : public ValueObject {
// Used by the IR assembler.
public:
- BlockLabel()
- : block_(new JoinEntryInstr(-1, -1)),
- is_bound_(false),
- is_linked_(false),
- pos_(-1) { }
+ BlockLabel();
JoinEntryInstr* block() const { return block_; }
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index f75291d..b7ac721 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -12,6 +12,7 @@
#include "vm/coverage.h"
#include "vm/cpu.h"
#include "vm/dart_api_impl.h"
+#include "vm/dart_api_state.h"
#include "vm/dart_entry.h"
#include "vm/debugger.h"
#include "vm/isolate.h"
@@ -20,6 +21,7 @@
#include "vm/message_handler.h"
#include "vm/native_entry.h"
#include "vm/native_arguments.h"
+#include "vm/native_symbol.h"
#include "vm/object.h"
#include "vm/object_graph.h"
#include "vm/object_id_ring.h"
@@ -996,6 +998,10 @@
OS::PrintErr(" Connect to Observatory at %s to debug.\n",
ServiceIsolate::server_address());
}
+ const Error& err = Error::Handle(Thread::Current()->sticky_error());
+ if (!err.IsNull()) {
+ OS::PrintErr("%s\n", err.ToErrorCString());
+ }
}
@@ -3463,6 +3469,99 @@
}
+static const MethodParameter* get_persistent_handles_params[] = {
+ ISOLATE_PARAMETER,
+ NULL,
+};
+
+
+template<typename T>
+class PersistentHandleVisitor : public HandleVisitor {
+ public:
+ PersistentHandleVisitor(Thread* thread, JSONArray* handles)
+ : HandleVisitor(thread),
+ handles_(handles) {
+ ASSERT(handles_ != NULL);
+ }
+
+ void Append(PersistentHandle* persistent_handle) {
+ JSONObject obj(handles_);
+ obj.AddProperty("type", "_PersistentHandle");
+ const Object& object = Object::Handle(persistent_handle->raw());
+ obj.AddProperty("object", object);
+ }
+
+ void Append(FinalizablePersistentHandle* weak_persistent_handle) {
+ JSONObject obj(handles_);
+ obj.AddProperty("type", "_WeakPersistentHandle");
+ const Object& object =
+ Object::Handle(weak_persistent_handle->raw());
+ obj.AddProperty("object", object);
+ obj.AddPropertyF(
+ "peer",
+ "0x%" Px "",
+ reinterpret_cast<uintptr_t>(weak_persistent_handle->peer()));
+ obj.AddPropertyF(
+ "callbackAddress",
+ "0x%" Px "",
+ reinterpret_cast<uintptr_t>(weak_persistent_handle->callback()));
+ // Attempt to include a native symbol name.
+ char* name = NativeSymbolResolver::LookupSymbolName(
+ reinterpret_cast<uintptr_t>(weak_persistent_handle->callback()),
+ NULL);
+ obj.AddProperty("callbackSymbolName",
+ (name == NULL) ? "" : name);
+ if (name != NULL) {
+ NativeSymbolResolver::FreeSymbolName(name);
+ }
+ obj.AddPropertyF("externalSize",
+ "%" Pd "",
+ weak_persistent_handle->external_size());
+ }
+
+ protected:
+ virtual void VisitHandle(uword addr) {
+ T* handle = reinterpret_cast<T*>(addr);
+ Append(handle);
+ }
+
+ JSONArray* handles_;
+};
+
+
+static bool GetPersistentHandles(Thread* thread, JSONStream* js) {
+ Isolate* isolate = thread->isolate();
+ ASSERT(isolate != NULL);
+
+ ApiState* api_state = isolate->api_state();
+ ASSERT(api_state != NULL);
+
+ {
+ JSONObject obj(js);
+ obj.AddProperty("type", "_PersistentHandles");
+ // Persistent handles.
+ {
+ JSONArray persistent_handles(&obj, "persistentHandles");
+ PersistentHandles& handles = api_state->persistent_handles();
+ PersistentHandleVisitor<PersistentHandle> visitor(
+ thread, &persistent_handles);
+ handles.Visit(&visitor);
+ }
+ // Weak persistent handles.
+ {
+ JSONArray weak_persistent_handles(&obj, "weakPersistentHandles");
+ FinalizablePersistentHandles& handles =
+ api_state->weak_persistent_handles();
+ PersistentHandleVisitor<FinalizablePersistentHandle> visitor(
+ thread, &weak_persistent_handles);
+ handles.VisitHandles(&visitor);
+ }
+ }
+
+ return true;
+}
+
+
static const MethodParameter* get_ports_params[] = {
RUNNABLE_ISOLATE_PARAMETER,
NULL,
@@ -3934,6 +4033,8 @@
get_object_params },
{ "_getObjectByAddress", GetObjectByAddress,
get_object_by_address_params },
+ { "_getPersistentHandles", GetPersistentHandles,
+ get_persistent_handles_params, },
{ "_getPorts", GetPorts,
get_ports_params },
{ "_getReachableSize", GetReachableSize,
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index 3d6207a..86c8aab 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -320,9 +320,8 @@
return;
}
- Isolate::Flags default_flags;
Dart_IsolateFlags api_flags;
- default_flags.CopyTo(&api_flags);
+ Isolate::FlagsInitialize(&api_flags);
isolate =
reinterpret_cast<Isolate*>(create_callback(ServiceIsolate::kName,
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index de6cf73..b211fb7 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -440,6 +440,81 @@
}
+
+static void WeakHandleFinalizer(void* isolate_callback_data,
+ Dart_WeakPersistentHandle handle,
+ void* peer) {
+}
+
+
+TEST_CASE(Service_PersistentHandles) {
+ const char* kScript =
+ "var port;\n" // Set to our mock port by C++.
+ "\n"
+ "class A {\n"
+ " var a;\n"
+ "}\n"
+ "var global = new A();\n"
+ "main() {\n"
+ " return global;\n"
+ "}";
+
+ Isolate* isolate = thread->isolate();
+ isolate->set_is_runnable(true);
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& vmlib = Library::Handle();
+ vmlib ^= Api::UnwrapHandle(lib);
+ EXPECT(!vmlib.IsNull());
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+
+ // Create a persistent handle to global.
+ Dart_PersistentHandle persistent_handle = Dart_NewPersistentHandle(result);
+
+ // Create a weak persistent handle to global.
+ Dart_WeakPersistentHandle weak_persistent_handle =
+ Dart_NewWeakPersistentHandle(result,
+ reinterpret_cast<void*>(0xdeadbeef),
+ 128,
+ WeakHandleFinalizer);
+
+ // Build a mock message handler and wrap it in a dart port.
+ ServiceTestMessageHandler handler;
+ Dart_Port port_id = PortMap::CreatePort(&handler);
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
+ EXPECT_VALID(port);
+ EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
+
+ Array& service_msg = Array::Handle();
+
+ // Get persistent handles.
+ service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
+ Service::HandleIsolateMessage(isolate, service_msg);
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
+ // Look for a heart beat.
+ EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
+ EXPECT_SUBSTRING("\"peer\":\"0xdeadbeef\"", handler.msg());
+ EXPECT_SUBSTRING("\"name\":\"A\"", handler.msg());
+ EXPECT_SUBSTRING("\"externalSize\":\"128\"", handler.msg());
+
+ // Delete persistent handles.
+ Dart_DeletePersistentHandle(persistent_handle);
+ Dart_DeleteWeakPersistentHandle(Dart_CurrentIsolate(),
+ weak_persistent_handle);
+
+ // Get persistent handles (again).
+ service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
+ Service::HandleIsolateMessage(isolate, service_msg);
+ EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
+ EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
+ // Verify that old persistent handles are not present.
+ EXPECT_NOTSUBSTRING("\"peer\":\"0xdeadbeef\"", handler.msg());
+ EXPECT_NOTSUBSTRING("\"name\":\"A\"", handler.msg());
+ EXPECT_NOTSUBSTRING("\"externalSize\":\"128\"", handler.msg());
+}
+
+
TEST_CASE(Service_Address) {
const char* kScript =
"var port;\n" // Set to our mock port by C++.
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index bbfa73b..e5d06c8 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -269,7 +269,7 @@
bool is_optimized,
bool is_inlined) {
const Script& script = Script::Handle(function.script());
- const String& func_name = String::Handle(function.QualifiedUserVisibleName());
+ const String& func_name = String::Handle(function.QualifiedScrubbedName());
const String& url = String::Handle(script.url());
intptr_t line = -1;
intptr_t column = -1;
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 7916d18..a19311d 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -287,7 +287,7 @@
bool is_optimized,
bool is_inlined) {
const Script& script = Script::Handle(function.script());
- const String& func_name = String::Handle(function.QualifiedUserVisibleName());
+ const String& func_name = String::Handle(function.QualifiedScrubbedName());
const String& url = String::Handle(script.url());
intptr_t line = -1;
intptr_t column = -1;
@@ -1223,18 +1223,18 @@
}
-intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
+intptr_t Simulator::ReadExclusiveX(uword addr, Instr* instr) {
MutexLocker ml(exclusive_access_lock_);
SetExclusiveAccess(addr);
- return ReadW(addr, instr);
+ return ReadX(addr, instr);
}
-intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) {
+intptr_t Simulator::WriteExclusiveX(uword addr, intptr_t value, Instr* instr) {
MutexLocker ml(exclusive_access_lock_);
bool write_allowed = HasExclusiveAccessAndOpen(addr);
if (write_allowed) {
- WriteW(addr, value, instr);
+ WriteX(addr, value, instr);
return 0; // Success.
}
return 1; // Failure.
@@ -1749,6 +1749,12 @@
void Simulator::DecodeSystem(Instr* instr) {
+ if (instr->InstructionBits() == CLREX) {
+ // Format(instr, "clrex");
+ ClearExclusive();
+ return;
+ }
+
if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) &&
(instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) &&
(instr->Bit(21) == 0)) {
@@ -2164,6 +2170,36 @@
}
+void Simulator::DecodeLoadStoreExclusive(Instr* instr) {
+ if ((instr->Bit(23) != 0) ||
+ (instr->Bit(21) != 0) ||
+ (instr->Bit(15) != 0)) {
+ UNIMPLEMENTED();
+ }
+ const int32_t size = instr->Bits(30, 2);
+ if (size != 3) {
+ UNIMPLEMENTED();
+ }
+
+ const Register rs = instr->RsField();
+ const Register rn = instr->RnField();
+ const Register rt = instr->RtField();
+ const bool is_load = instr->Bit(22) == 1;
+ if (is_load) {
+ // Format(instr, "ldxr 'rt, 'rn");
+ const int64_t addr = get_register(rn, R31IsSP);
+ intptr_t value = ReadExclusiveX(addr, instr);
+ set_register(instr, rt, value, R31IsSP);
+ } else {
+ // Format(instr, "stxr 'rs, 'rt, 'rn");
+ uword value = get_register(rt, R31IsSP);
+ uword addr = get_register(rn, R31IsSP);
+ intptr_t status = WriteExclusiveX(addr, value, instr);
+ set_register(instr, rs, status, R31IsSP);
+ }
+}
+
+
void Simulator::DecodeLoadStore(Instr* instr) {
if (instr->IsLoadStoreRegOp()) {
DecodeLoadStoreReg(instr);
@@ -2171,6 +2207,8 @@
DecodeLoadStoreRegPair(instr);
} else if (instr->IsLoadRegLiteralOp()) {
DecodeLoadRegLiteral(instr);
+ } else if (instr->IsLoadStoreExclusiveOp()) {
+ DecodeLoadStoreExclusive(instr);
} else {
UnimplementedInstruction(instr);
}
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index d395f6b..bf3572c 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -208,8 +208,8 @@
// Synchronization primitives support.
void ClearExclusive();
- intptr_t ReadExclusiveW(uword addr, Instr* instr);
- intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr);
+ intptr_t ReadExclusiveX(uword addr, Instr* instr);
+ intptr_t WriteExclusiveX(uword addr, intptr_t value, Instr* instr);
// Set access to given address to 'exclusive state' for current thread.
static void SetExclusiveAccess(uword addr);
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 2b03da8..074fc8c 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -280,7 +280,7 @@
bool is_optimized,
bool is_inlined) {
const Script& script = Script::Handle(function.script());
- const String& func_name = String::Handle(function.QualifiedUserVisibleName());
+ const String& func_name = String::Handle(function.QualifiedScrubbedName());
const String& url = String::Handle(script.url());
intptr_t line = -1;
intptr_t column = -1;
@@ -1173,9 +1173,9 @@
bool write_allowed = HasExclusiveAccessAndOpen(addr);
if (write_allowed) {
WriteW(addr, value, instr);
- return 0; // Success.
+ return 1; // Success.
}
- return 1; // Failure.
+ return 0; // Failure.
}
@@ -2169,6 +2169,19 @@
set_register(instr->RtField(), instr->UImmField() << 16);
break;
}
+ case LL: {
+ // Format(instr, "ll 'rt, 'imms('rs)");
+ int32_t base_val = get_register(instr->RsField());
+ int32_t imm_val = instr->SImmField();
+ uword addr = base_val + imm_val;
+ if (Simulator::IsIllegalAddress(addr)) {
+ HandleIllegalAccess(addr, instr);
+ } else {
+ int32_t res = ReadExclusiveW(addr, instr);
+ set_register(instr->RtField(), res);
+ }
+ break;
+ }
case LW: {
// Format(instr, "lw 'rt, 'imms('rs)");
int32_t base_val = get_register(instr->RsField());
@@ -2214,6 +2227,20 @@
}
break;
}
+ case SC: {
+ // Format(instr, "sc 'rt, 'imms('rs)");
+ int32_t rt_val = get_register(instr->RtField());
+ int32_t base_val = get_register(instr->RsField());
+ int32_t imm_val = instr->SImmField();
+ uword addr = base_val + imm_val;
+ if (Simulator::IsIllegalAddress(addr)) {
+ HandleIllegalAccess(addr, instr);
+ } else {
+ intptr_t status = WriteExclusiveW(addr, rt_val, instr);
+ set_register(instr->RtField(), status);
+ }
+ break;
+ }
case SLTI: {
// Format(instr, "slti 'rt, 'rs, 'imms");
int32_t rs_val = get_register(instr->RsField());
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index bf02cba..294a90b 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -28,9 +28,6 @@
namespace dart {
-DECLARE_FLAG(bool, use_field_guards);
-
-
static const int kNumVmIsolateSnapshotReferences = 32 * KB;
static const int kNumInitialReferencesInFullSnapshot = 160 * KB;
static const int kNumInitialReferences = 64;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 35d3728..26dccc8 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -18,8 +18,6 @@
namespace dart {
-DECLARE_FLAG(bool, enable_type_checks);
-DECLARE_FLAG(bool, load_deferred_eagerly);
DECLARE_FLAG(bool, concurrent_sweep);
// Check if serialized and deserialized objects are equal.
@@ -1001,6 +999,7 @@
}
+#if !defined(PRODUCT) // Uses deferred loading.
UNIT_TEST_CASE(CanonicalizationInScriptSnapshots) {
const char* kScriptChars =
"\n"
@@ -1106,6 +1105,7 @@
free(script_snapshot);
free(full_snapshot);
}
+#endif
static void IterateScripts(const Library& lib) {
@@ -1469,9 +1469,6 @@
}
-#endif // !PRODUCT
-
-
UNIT_TEST_CASE(ScriptSnapshot1) {
const char* kScriptChars =
"class _SimpleNumEnumerable<T extends num> {"
@@ -1581,7 +1578,7 @@
// Force creation of snapshot in production mode.
bool saved_enable_type_checks_mode = FLAG_enable_type_checks;
- FLAG_enable_type_checks = false;
+ NOT_IN_PRODUCT(FLAG_enable_type_checks = false);
bool saved_load_deferred_eagerly_mode = FLAG_load_deferred_eagerly;
FLAG_load_deferred_eagerly = true;
bool saved_concurrent_sweep_mode = FLAG_concurrent_sweep;
@@ -1633,7 +1630,7 @@
}
// Continue in originally saved mode.
- FLAG_enable_type_checks = saved_enable_type_checks_mode;
+ NOT_IN_PRODUCT(FLAG_enable_type_checks = saved_enable_type_checks_mode);
FLAG_load_deferred_eagerly = saved_load_deferred_eagerly_mode;
{
@@ -1666,6 +1663,9 @@
}
+#endif // !PRODUCT
+
+
TEST_CASE(IntArrayMessage) {
StackZone zone(Thread::Current());
uint8_t* buffer = NULL;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 77b6685..6b8812e 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -26,7 +26,6 @@
DEFINE_FLAG(bool, use_slow_path, false,
"Set to true for debugging & verifying the slow paths.");
DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
// Input parameters:
// LR : return address.
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index c0648d4..61c3a4b 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -25,7 +25,6 @@
DEFINE_FLAG(bool, use_slow_path, false,
"Set to true for debugging & verifying the slow paths.");
DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
// Input parameters:
// LR : return address.
@@ -1040,8 +1039,17 @@
__ Push(R2);
__ Push(R3);
- __ orri(R2, TMP, Immediate(1 << RawObject::kRememberedBit));
- __ StoreFieldToOffset(R2, R0, Object::tags_offset());
+ // Atomically set the remembered bit of the object header.
+ ASSERT(Object::tags_offset() == 0);
+ __ sub(R3, R0, Operand(kHeapObjectTag));
+ // R3: Untagged address of header word (ldxr/stxr do not support offsets).
+ Label retry;
+ __ Bind(&retry);
+ __ ldxr(R2, R3);
+ __ orri(R2, R2, Immediate(1 << RawObject::kRememberedBit));
+ __ stxr(R1, R2, R3);
+ __ cmp(R1, Operand(1));
+ __ b(&retry, EQ);
// Load the StoreBuffer block out of the thread. Then load top_ out of the
// StoreBufferBlock and add the address to the pointers_.
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index e79efba..640f0ec 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -27,7 +27,6 @@
DEFINE_FLAG(bool, use_slow_path, false,
"Set to true for debugging & verifying the slow paths.");
DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
#define INT32_SIZEOF(x) static_cast<int32_t>(sizeof(x))
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 8d1b252..b4965c33 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -25,7 +25,6 @@
DEFINE_FLAG(bool, use_slow_path, false,
"Set to true for debugging & verifying the slow paths.");
DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
// Input parameters:
// RA : return address.
@@ -1066,8 +1065,14 @@
__ Ret();
__ Bind(&add_to_buffer);
+ // Atomically set the remembered bit of the object header.
+ Label retry;
+ __ Bind(&retry);
+ __ ll(T2, FieldAddress(T0, Object::tags_offset()));
__ ori(T2, T2, Immediate(1 << RawObject::kRememberedBit));
- __ sw(T2, FieldAddress(T0, Object::tags_offset()));
+ __ sc(T2, FieldAddress(T0, Object::tags_offset()));
+ // T2 = 1 on success, 0 on failure.
+ __ beq(T2, ZR, &retry);
// Load the StoreBuffer block out of the thread. Then load top_ out of the
// StoreBufferBlock and add the address to the pointers_.
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index ace6744..b33ee01 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -26,7 +26,6 @@
DEFINE_FLAG(bool, use_slow_path, false,
"Set to true for debugging & verifying the slow paths.");
DECLARE_FLAG(bool, trace_optimized_ic_calls);
-DECLARE_FLAG(int, optimization_counter_threshold);
// Input parameters:
// RSP : points to return address.
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 39d6b23..9390ee1 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -316,6 +316,9 @@
V(ColonSpace, ": ") \
V(RParenArrow, ") => ") \
V(SpaceExtendsSpace, " extends ") \
+ V(SpaceWhereNewLine, " where\n") \
+ V(SpaceIsFromSpace, " is from ") \
+ V(SpaceOfSpace, " of ") \
V(SwitchExpr, ":switch_expr") \
V(TwoNewlines, "\n\n") \
V(TwoSpaces, " ") \
@@ -401,6 +404,8 @@
V(ConstructorClosurePrefix, "new#") \
V(_runExtension, "_runExtension") \
V(_runPendingImmediateCallback, "_runPendingImmediateCallback") \
+ V(DartLibrary, "dart.library.") \
+ V(DartLibraryMirrors, "dart.library.mirrors") \
// Contains a list of frequently used strings in a canonicalized form. This
@@ -421,7 +426,7 @@
kKwTableStart, // First keyword at kKwTableStart + 1.
-#define DEFINE_KEYWORD_SYMBOL_INDEX(t, s, p, a) \
+#define DEFINE_KEYWORD_SYMBOL_INDEX(t, s, p, a) \
t##Id,
DART_KEYWORD_LIST(DEFINE_KEYWORD_SYMBOL_INDEX)
#undef DEFINE_KEYWORD_SYMBOL_INDEX
diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc
index 19c0a4d..b281d5c 100644
--- a/runtime/vm/thread_pool.cc
+++ b/runtime/vm/thread_pool.cc
@@ -383,11 +383,11 @@
task_ = NULL;
// Release monitor while handling the task.
- monitor_.Exit();
+ ml.Exit();
task->Run();
ASSERT(Isolate::Current() == NULL);
delete task;
- monitor_.Enter();
+ ml.Enter();
ASSERT(task_ == NULL);
if (IsDone()) {
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 95ea190..a20d7a4 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -45,6 +45,8 @@
Monitor* monitor = new Monitor();
monitor->Enter();
monitor->Exit();
+ EXPECT_EQ(true, monitor->TryEnter());
+ monitor->Exit();
const int kNumAttempts = 5;
int attempts = 0;
diff --git a/runtime/vm/token_position.h b/runtime/vm/token_position.h
index b36d58a..c964716 100644
--- a/runtime/vm/token_position.h
+++ b/runtime/vm/token_position.h
@@ -38,7 +38,11 @@
V(ControlFlow, -7) \
V(Context, -8) \
V(MethodExtractor, -9) \
- V(Last, -10) // Always keep this at the end.
+ V(DeferredSlowPath, -10) \
+ V(DeferredDeoptInfo, -11) \
+ V(DartCodePrologue, -12) \
+ V(DartCodeEpilogue, -13) \
+ V(Last, -14) // Always keep this at the end.
// A token position representing a debug safe source (real) position,
// non-debug safe source (synthetic) positions, or a classifying value used
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index f21951b..ee08b98 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -185,8 +185,6 @@
'flow_graph_compiler_x64.cc',
'flow_graph_inliner.cc',
'flow_graph_inliner.h',
- 'flow_graph_optimizer.cc',
- 'flow_graph_optimizer.h',
'flow_graph_range_analysis.cc',
'flow_graph_range_analysis.h',
'flow_graph_range_analysis_test.cc',
@@ -250,6 +248,8 @@
'isolate.cc',
'isolate.h',
'isolate_test.cc',
+ 'jit_optimizer.cc',
+ 'jit_optimizer.h',
'json_stream.h',
'json_stream.cc',
'json_test.cc',
diff --git a/runtime/vm/weak_code.cc b/runtime/vm/weak_code.cc
index 0c5cca2..eb04d1f 100644
--- a/runtime/vm/weak_code.cc
+++ b/runtime/vm/weak_code.cc
@@ -13,8 +13,6 @@
namespace dart {
-DECLARE_FLAG(bool, precompilation);
-
bool WeakCodeReferences::HasCodes() const {
return !array_.IsNull() && (array_.Length() > 0);
}
@@ -68,7 +66,7 @@
if (code_objects.IsNull()) {
return;
}
- ASSERT(!FLAG_precompilation);
+ ASSERT(!FLAG_precompiled_mode);
UpdateArrayTo(Object::null_array());
// Disable all code on stack.
Code& code = Code::Handle();
diff --git a/sdk/lib/html/html_common/conversions_dartium.dart b/sdk/lib/html/html_common/conversions_dartium.dart
index 3c35817..90fe55d 100644
--- a/sdk/lib/html/html_common/conversions_dartium.dart
+++ b/sdk/lib/html/html_common/conversions_dartium.dart
@@ -103,7 +103,7 @@
class _ReturnedDictionary {
Map _values;
- noSuchMethod(InvocationMirror invocation) {
+ noSuchMethod(Invocation invocation) {
var key = MirrorSystem.getName(invocation.memberName);
if (invocation.isGetter) {
return _values[key];
@@ -115,7 +115,7 @@
Map get toMap => _values;
- _ReturnedDictionary(Map value): _values = value;
+ _ReturnedDictionary(Map value): _values = value != null ? value : {};
}
// Helper function to wrapped a returned dictionary from blink to a Dart looking
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index cfdcc10..c63d28b 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -108,8 +108,8 @@
* var key =
* Platform.script.resolve('certificates/server_key.pem')
* .toFilePath();
- * context.useCertificateChainSync(chain);
- * context.usePrivateKeySync(key, password: 'dartdart');
+ * context.useCertificateChain(chain);
+ * context.usePrivateKey(key, password: 'dartdart');
*
* HttpServer
* .bindSecure(InternetAddress.ANY_IP_V6,
diff --git a/sdk/lib/io/security_context.dart b/sdk/lib/io/security_context.dart
index fc9defd..86dfc96 100644
--- a/sdk/lib/io/security_context.dart
+++ b/sdk/lib/io/security_context.dart
@@ -14,14 +14,6 @@
*
* Certificates and keys can be added to a SecurityContext from either PEM
* or PKCS12 containers.
- *
- * [usePrivateKey], [setTrustedCertificates], [useCertificateChain], and
- * [setClientAuthorities] are deprecated. They have been renamed
- * [usePrivateKeySync], [setTrustedCertificatesSync], [useCertificateChainSync],
- * and [setClientAuthoritiesSync] to reflect the fact that they do blocking
- * IO. Async-friendly versions have been added in [usePrivateKeyBytes],
- * [setTrustedCertificatesBytes], [useCertificateChainBytes], and
- * [setClientAuthoritiesBytes].
*/
abstract class SecurityContext {
external factory SecurityContext();
@@ -42,23 +34,21 @@
*
* A secure connection using this SecurityContext will use this key with
* the server or client certificate to sign and decrypt messages.
- * [keyFile] is the path to a PEM or PKCS12 file containing an encrypted
- * private key, encrypted with [password]. An unencrypted file can be
- * used, but this is not usual.
+ * [file] is the path to a PEM or PKCS12 file containing an encrypted
+ * private key, encrypted with [password]. Assuming it is well-formatted, all
+ * other contents of [file] are ignored. An unencrypted file can be used,
+ * but this is not usual.
+ *
+ * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+ * Prefer using [usePrivateKeyBytes].
*/
- void usePrivateKeySync(String keyFile, {String password});
-
- /**
- * [usePrivateKey] is deprecated. Use [usePrivateKeySync] or
- * [usePrivateKeyBytes].
- */
- @deprecated
- void usePrivateKey(String keyFile, {String password});
+ void usePrivateKey(String file, {String password});
/**
* Sets the private key for a server certificate or client certificate.
*
- * Like [usePrivateKeyBytesSync], but takes the contents of the file.
+ * Like [usePrivateKey], but takes the contents of the file as a list
+ * of bytes.
*/
void usePrivateKeyBytes(List<int> keyBytes, {String password});
@@ -69,24 +59,21 @@
* [file] is the path to a PEM or PKCS12 file containing X509 certificates,
* usually root certificates from certificate authorities. For PKCS12 files,
* [password] is the password for the file. For PEM files, [password] is
+ * ignored. Assuming it is well-formatted, all other contents of [file] are
* ignored.
+ *
+ * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+ * Prefer using [setTrustedCertificatesBytes].
*/
- void setTrustedCertificatesSync(String file, {String password});
-
- /**
- * [setTrustedCertificates] is deprecated. Use [setTrustedCertificatesSync]
- * or [setTrustedCertificatesBytes].
- */
- @deprecated
void setTrustedCertificates(String file, {String password});
/**
* Sets the set of trusted X509 certificates used by [SecureSocket]
* client connections, when connecting to a secure server.
*
- * Like [setTrustedCertificatesSync] but takes the contents of the file.
+ * Like [setTrustedCertificates] but takes the contents of the file.
*/
- void setTrustedCertificatesBytes(List<int> certBytes,{String password});
+ void setTrustedCertificatesBytes(List<int> certBytes, {String password});
/**
* Sets the chain of X509 certificates served by [SecureServer]
@@ -97,22 +84,19 @@
* chain to the server certificate, and ending with the server certificate.
* The private key for the server certificate is set by [usePrivateKey]. For
* PKCS12 files, [password] is the password for the file. For PEM files,
- * [password] is ignored.
+ * [password] is ignored. Assuming it is well-formatted, all
+ * other contents of [file] are ignored.
+ *
+ * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+ * Prefer using [useCertificateChainBytes].
*/
- void useCertificateChainSync(String file, {String password});
-
- /**
- * [useCertificateChain] is deprecated. Use [useCertificateChainSync]
- * or [useCertificateChainBytes].
- */
- @deprecated
- void useCertificateChain({String file, String directory, String password});
+ void useCertificateChain(String file, {String password});
/**
* Sets the chain of X509 certificates served by [SecureServer]
* when making secure connections, including the server certificate.
*
- * Like [useCertificateChainSync] but takes the contents of the file.
+ * Like [useCertificateChain] but takes the contents of the file.
*/
void useCertificateChainBytes(List<int> chainBytes, {String password});
@@ -124,15 +108,12 @@
* [file] is a PEM or PKCS12 file containing the accepted signing
* authority certificates - the authority names are extracted from the
* certificates. For PKCS12 files, [password] is the password for the file.
- * For PEM files, [password] is ignored.
+ * For PEM files, [password] is ignored. Assuming it is well-formatted, all
+ * other contents of [file] are ignored.
+ *
+ * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+ * Prefer using [setClientAuthoritiesBytes].
*/
- void setClientAuthoritiesSync(String file, {String password});
-
- /**
- * [setClientAuthorities] is deprecated. Use [setClientAuthoritiesSync]
- * or [setClientAuthoritiesBytes].
- */
- @deprecated
void setClientAuthorities(String file, {String password});
/**
@@ -140,7 +121,7 @@
* as accepted, when requesting a client certificate from a connecting
* client.
*
- * Like [setClientAuthoritySync] but takes the contents of the file.
+ * Like [setClientAuthority] but takes the contents of the file.
*/
void setClientAuthoritiesBytes(List<int> authCertBytes, {String password});
diff --git a/sdk/lib/rules.gni b/sdk/lib/rules.gni
index 93ade221..0aa80f8 100644
--- a/sdk/lib/rules.gni
+++ b/sdk/lib/rules.gni
@@ -9,10 +9,13 @@
# The name of a Dart SDK library.
#
# Optional arguments:
+# destination
+# Base path to copy sources. Default value is "$root_gen_dir/dart_sdk".
+#
# dart_root
# Path to the Dart SDK source root. Default value is "//dart".
#
-# The sources will be copied into $root_gen_dir/dart_sdk_libs/$sdk_lib_name/.
+# The sources will be copied into $root_gen_dir/dart_sdk/$sdk_lib_name/.
#
template("dart_sdk_lib_copy") {
assert(defined(invoker.sdk_lib_name))
@@ -21,6 +24,11 @@
} else {
dart_root = rebase_path("//dart")
}
+ if (defined(invoker.destination)) {
+ destination = invoker.destination
+ } else {
+ destination = "$root_gen_dir/dart_sdk"
+ }
dart_sdk_sdk_lib_path =
rebase_path("sdk/lib", "", dart_root)
dart_sdk_tools_gypi_to_gn_path =
@@ -39,6 +47,6 @@
[rebase_path(lib_sources_gypi, "", lib_path)])
copy(target_name) {
sources = rebase_path(sdk_lib_sources_gypi.sources, "", lib_path)
- outputs = [ "$root_gen_dir/dart_sdk_libs/$lib_name/{{source_file_part}}" ]
+ outputs = [ "$destination/$lib_name/{{source_file_part}}" ]
}
}
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index e8e6c56..eb9b059 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -18,6 +18,31 @@
[ $compiler == none && $runtime == dartium && $system != windows ]
LayoutTests/fast/css/font-face-unicode-range-monospace_t01: RuntimeError # co19-roll r761: Please triage this failure.
+[ $compiler == none && $runtime == dartium && ($system == windows || $system == linux) ]
+LayoutTests/fast/canvas/webgl/buffer-data-array-buffer_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/canvas-zero-size_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/compressed-tex-image_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/context-lost_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/draw-arrays-out-of-bounds_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/draw-elements-out-of-bounds_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-enum-tests_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-object-get-calls_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-uniformmatrix4fv_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-vertex-attrib-zero-issues_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/gl-vertex-attrib_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation-copies-indices_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation-crash-with-buffer-sub-data_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation-verifies-too-many-indices_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation-with-resized-buffer_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/index-validation_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/null-uniform-location_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/program-test_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/tex-image-and-uniform-binding-bugs_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/texImageTest_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+LayoutTests/fast/canvas/webgl/texture-transparent-pixels-initialized_t01: RuntimeError # 45 roll ArrayBuffer failure only on windows/linux.
+
[ $compiler == none && $runtime == dartium && $mode == debug ]
WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/TextTrack/mode_t01: Skip # Issue 19495.
WebPlatformTest/html/semantics/forms/the-datalist-element/datalistoptions_t01: Skip # Issue 20540.
@@ -197,7 +222,6 @@
LayoutTests/fast/canvas/canvas-getImageData-invalid_t01: RuntimeError # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/canvas-large-dimensions_t01: RuntimeError # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/canvas-large-fills_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/canvas-lineDash-input-sequence_t01: RuntimeError # Dartium 45 roll. Issue 25754
LayoutTests/fast/canvas/canvas-lose-restore-googol-size_t01: RuntimeError # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/canvas-lose-restore-max-int-size_t01: RuntimeError # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/draw-custom-focus-ring_t01: RuntimeError # co19-roll r761: Please triage this failure.
@@ -208,24 +232,18 @@
LayoutTests/fast/canvas/webgl/attrib-location-length-limits_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/bad-arguments-test_t01: Pass, RuntimeError # Issue 20, 22026
LayoutTests/fast/canvas/webgl/buffer-bind-test_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/buffer-data-array-buffer_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/canvas-2d-webgl-texture_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/canvas-resize-crash_t01: Skip # Causes following tests to fail. co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/webgl/canvas-test_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
LayoutTests/fast/canvas/webgl/canvas-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/canvas-zero-size_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/compressed-tex-image_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/webgl/context-destroyed-crash_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/context-lost-restored_t01: RuntimeError # Issue 25653
-LayoutTests/fast/canvas/webgl/context-lost_t01: RuntimeError # Issue 20, 22026
LayoutTests/fast/canvas/webgl/copy-tex-image-and-sub-image-2d_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/copy-tex-image-and-sub-image-2d_t01: RuntimeError # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/webgl/css-webkit-canvas-repaint_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/css-webkit-canvas_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/draw-arrays-out-of-bounds_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/draw-elements-out-of-bounds_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/draw-webgl-to-canvas-2d_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/drawingbuffer-test_t01: RuntimeError # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/webgl/error-reporting_t01: Pass, RuntimeError # Issue 22026
@@ -239,31 +257,18 @@
LayoutTests/fast/canvas/webgl/get-active-test_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/gl-bind-attrib-location-test_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/gl-enable-enum-test_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-enum-tests_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/gl-get-calls_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/gl-getshadersource_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/gl-getstring_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-object-get-calls_t01: RuntimeError # Pass, Issue 20, 22026
LayoutTests/fast/canvas/webgl/gl-pixelstorei_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/gl-teximage_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/gl-teximage_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/gl-uniformmatrix4fv_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-vertex-attrib-zero-issues_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-vertex-attrib_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/gl-vertexattribpointer_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/glsl-conformance_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/incorrect-context-object-behaviour_t01: Pass, RuntimeError # Issue 20, 22026
-LayoutTests/fast/canvas/webgl/index-validation-copies-indices_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/index-validation-crash-with-buffer-sub-data_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/index-validation-verifies-too-many-indices_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/index-validation-with-resized-buffer_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/index-validation_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/invalid-UTF-16_t01: Pass, RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # Issue 20, 22026
-LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/is-object_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/webgl/null-object-behaviour_t01: Pass, RuntimeError # Issue 20, 22026
-LayoutTests/fast/canvas/webgl/null-uniform-location_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/object-deletion-behaviour_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/object-deletion-behaviour_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/oes-element-index-uint_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
@@ -271,7 +276,6 @@
LayoutTests/fast/canvas/webgl/oes-vertex-array-object_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/point-size_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/premultiplyalpha-test_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/webgl/program-test_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/read-pixels-pack-alignment_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/read-pixels-test_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/renderbuffer-initialization_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
@@ -311,23 +315,18 @@
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba5551_t01: Skip # Issue 20540
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video_t01: Skip # Issue 20540
-LayoutTests/fast/canvas/webgl/tex-image-and-uniform-binding-bugs_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/tex-image-webgl_t01: RuntimeError # Issue 25653
-LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # Issue 20, 22026
-LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/tex-sub-image-2d-bad-args_t01: Pass, RuntimeError # Issue 20, 22026
LayoutTests/fast/canvas/webgl/tex-sub-image-2d_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/tex-sub-image-2d_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-sub-image-cube-maps_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/tex-sub-image-cube-maps_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/texImage2DImageDataTest_t01: RuntimeError # Issue 25653
-LayoutTests/fast/canvas/webgl/texImageTest_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/texture-active-bind_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/texture-bindings-uneffected-on-resize_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/texture-color-profile_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/texture-complete_t01: RuntimeError # Issue 25653
LayoutTests/fast/canvas/webgl/texture-npot_t01: RuntimeError # Issue 25653
-LayoutTests/fast/canvas/webgl/texture-transparent-pixels-initialized_t01: RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/triangle_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
LayoutTests/fast/canvas/webgl/uniform-location-length-limits_t01: Pass, RuntimeError # Issue 22026
LayoutTests/fast/canvas/webgl/uniform-location_t01: RuntimeError # Please triage this failure
@@ -629,8 +628,6 @@
LayoutTests/fast/files/blob-close-read_t01: RuntimeError # co19-roll r786: Please triage this failure.
LayoutTests/fast/files/blob-close-revoke_t01: RuntimeError # Experimental feature not exposed anywhere yet
LayoutTests/fast/files/blob-close_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/files/blob-constructor_t01: RuntimeError # Dartium 45 roll. Issue 25754
-LayoutTests/fast/files/file-reader-fffd_t01: RuntimeError # Dartium 45 roll. Issue 25754
LayoutTests/fast/files/xhr-response-blob_t01: RuntimeError # co19-roll r786: Please triage this failure.
LayoutTests/fast/filesystem/async-operations_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
LayoutTests/fast/filesystem/directory-entry-to-uri_t01: RuntimeError # co19-roll r786: Please triage this failure.
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 01a850a..0fc268d 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -143,7 +143,8 @@
Language/Errors_and_Warnings/static_warning_t05: RuntimeError # Please triage this failure
Language/Errors_and_Warnings/static_warning_t06: RuntimeError # Please triage this failure
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler ]
+Language/Metadata/*: SkipByDesign # Uses dart:mirrors
LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Timeout
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Pass, Timeout
LibTest/core/Map/Map_class_A01_t04: Pass, Timeout
@@ -152,13 +153,15 @@
Language/Mixins/Mixin_Application/error_t02: Pass
Language/Mixins/declaring_constructor_t01: Pass
Language/Expressions/Property_Extraction/Named_Constructor_Extraction/deferred_type_t01: Pass
-Language/Metadata/*: Skip # Uses dart:mirrors
[ $runtime == dart_precompiled ]
LibTest/isolate/Isolate/spawnUri*: RuntimeError # Isolate.spawnUri
+Language/Expressions/Constants/identifier_denotes_a_constant_t05: Crash # Issue 25892
+Language/Expressions/Constants/static_method_t01: Crash # Issue 25892
[ $runtime == dart_product ]
LibTest/isolate/Isolate/spawnUri*: Skip # Isolate.spawnUri
+Language/Metadata/*: SkipByDesign # Uses dart:mirrors
[ $runtime == vm && $mode == product ]
LibTest/typed_data/Float32List/runtimeType_A01_t01: Fail,OK # Expects exact type name.
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 3d4c849..52a0522 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -154,19 +154,19 @@
[ $system == windows && $arch == x64 ]
stopwatch_test: Skip # Flaky test due to expected performance behaviour.
-[ $runtime != d8 && $runtime != vm ]
+[ $runtime != d8 && $runtime != vm && $runtime != dart_precompiled ]
# The regexp tests are not verified to work on non d8/vm platforms yet.
regexp/*: Skip
[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
regexp/global_test: Skip # Timeout. Issue 21709 and 21708
-[ $runtime != vm && $compiler != dart2analyzer]
+[ $runtime != vm && $runtime != dart_precompiled && $compiler != dart2analyzer]
data_resource_test: RuntimeError # Issue 23825 (not implemented yet).
file_resource_test: Skip, OK # VM specific test, uses dart:io.
http_resource_test: Skip, OK # VM specific test, uses dart:io.
-[ $runtime != vm && $compiler != dart2analyzer && $cps_ir == false ]
+[ $runtime != vm && $runtime != dart_precompiled && $compiler != dart2analyzer && $cps_ir == false ]
package_resource_test: RuntimeError # Issue 23825 (not implemented yet).
[ $mode == debug ]
@@ -184,13 +184,19 @@
[ $compiler == dart2js && $cps_ir && $host_checked ]
regexp/pcre_test: Crash # Stack Overflow
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler ]
+# Stacktraces in precompilation omit inlined frames.
+stacktrace_current_test: Pass, RuntimeError
+error_stack_trace1_test: Pass, RuntimeError
+
+[ $noopt || $compiler == precompiler ]
apply3_test: CompileTimeError # Imports dart:mirrors
regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
big_integer_huge_mul_vm_test: Pass, Timeout # --no_intrinsify
big_integer_parsed_mul_div_vm_test: Pass, Timeout # --no_intrinsify
int_parse_radix_test: Pass, Timeout # --no_intrinsify
-[ ($runtime == dart_product) ]
+[ $runtime == dart_product ]
data_resource_test: Skip # Resolve URI not supported yet in product mode.
package_resource_test: Skip # Resolve URI not supported yet in product mode.
+apply3_test: SkipByDesign # Imports dart:mirrors
diff --git a/tests/html/html.status b/tests/html/html.status
index cf55429..1facc17 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -18,10 +18,6 @@
native_gc_test: Skip # Dartium JSInterop failure
transferables_test: RuntimeError # Dartium JSInterop failure
-blob_constructor_test: RuntimeError # Dartium 45 roll. Issue 25754
-crypto_test/functional: RuntimeError # Dartium 45 roll. Issue 25754
-url_test: RuntimeError # Dartium 45 roll. Issue 25754
-
[ $compiler == none && ($runtime == drt || $runtime == dartium ) ]
worker_api_test: Fail # Issue 10223
resource_http_test: Fail # Issue 24203
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 4149d7d..953be4d 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -139,27 +139,31 @@
spawn_uri_fail_test: SkipByDesign # Uses dart:io.
scenarios/*: SkipByDesign # Use automatic package resolution, spawnFunction and .dart URIs.
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler || $runtime == dart_product ]
# Imports dart:mirrors
-count_test: CompileTimeError
-cross_isolate_message_test: CompileTimeError
-illegal_msg_function_test: CompileTimeError
-illegal_msg_mirror_test: CompileTimeError
-isolate_complex_messages_test: CompileTimeError
-mandel_isolate_test: CompileTimeError
-message2_test: CompileTimeError
-message_test: CompileTimeError
-mint_maker_test: CompileTimeError
-nested_spawn2_test: CompileTimeError
-nested_spawn_test: CompileTimeError
-raw_port_test: CompileTimeError
-request_reply_test: CompileTimeError
-spawn_function_custom_class_test: CompileTimeError
-spawn_function_test: CompileTimeError
-stacktrace_message_test: CompileTimeError
-stacktrace_message_test: CompileTimeError
-static_function_test: CompileTimeError
-unresolved_ports_test: CompileTimeError
+count_test: SkipByDesign
+cross_isolate_message_test: SkipByDesign
+illegal_msg_function_test: SkipByDesign
+illegal_msg_mirror_test: SkipByDesign
+isolate_complex_messages_test: SkipByDesign
+mandel_isolate_test: SkipByDesign
+message2_test: SkipByDesign
+message_test: SkipByDesign
+mint_maker_test: SkipByDesign
+nested_spawn2_test: SkipByDesign
+nested_spawn_test: SkipByDesign
+raw_port_test: SkipByDesign
+request_reply_test: SkipByDesign
+spawn_function_custom_class_test: SkipByDesign
+spawn_function_test: SkipByDesign
+stacktrace_message_test: SkipByDesign
+stacktrace_message_test: SkipByDesign
+static_function_test: SkipByDesign
+unresolved_ports_test: SkipByDesign
+
+[ $compiler == precompiler ]
+function_send_test: RuntimeError # Issue 25892
+message3_test/fun: RuntimeError # Issue 25892
[ $runtime == dart_precompiled || $runtime == dart_product ]
deferred_in_isolate_test: Skip # Isolate.spawnUri
diff --git a/tests/language/language.status b/tests/language/language.status
index b2409a5..42bb58b 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -45,8 +45,6 @@
async_star_cancel_while_paused_test: RuntimeError
async_star_await_pauses_test: Skip # Times out. Issue 23996
-library_env_test: RuntimeError
-
accessor_conflict_export2_test: RuntimeError # Issue 25625
accessor_conflict_import2_test: RuntimeError # Issue 25625
accessor_conflict_import_prefixed2_test: RuntimeError # Issue 25625
@@ -106,6 +104,9 @@
stack_overflow_stacktrace_test: Skip # Crashes. Issue 17440.
large_class_declaration_test: SkipSlow # Times out. Issue 20352
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == arm64 ]
+large_class_declaration_test: SkipSlow # Uses too much memory.
+
[ $compiler == none && ($runtime == dartium || $runtime == drt) && $mode == debug ]
large_class_declaration_test: SkipSlow # Times out. Issue 20352
@@ -118,31 +119,38 @@
[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && (($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) || $runtime == drt || $runtime == dartium) && $arch == ia32 ]
vm/regress_24517_test: Pass, Fail # Issue 24517.
-[ ($noopt || $compiler == precompiler) ]
-# Imports dart:mirrors
-const_evaluation_test: CompileTimeError
-deferred_constraints_constants_test/none: CompileTimeError
-deferred_constraints_constants_test/reference_after_load: CompileTimeError
-enum_mirror_test: CompileTimeError
-field_increment_bailout_test: CompileTimeError
-instance_creation_in_function_annotation_test: CompileTimeError
-invocation_mirror2_test: CompileTimeError
-invocation_mirror_invoke_on2_test: CompileTimeError
-invocation_mirror_invoke_on_test: CompileTimeError
-issue21079_test: CompileTimeError
-many_overridden_no_such_method_test: CompileTimeError
-no_such_method_test: CompileTimeError
-null_test/none: CompileTimeError
-overridden_no_such_method_test: CompileTimeError
-redirecting_factory_reflection_test: CompileTimeError
-regress_13462_0_test: CompileTimeError
-regress_13462_1_test: CompileTimeError
-regress_18535_test: CompileTimeError
-super_call4_test: CompileTimeError
-super_getter_setter_test: CompileTimeError
-vm/reflect_core_vm_test: CompileTimeError
+[ $noopt || $compiler == precompiler ]
+# Stacktraces in precompilation omit inlined frames.
+full_stacktrace1_test: Pass, RuntimeError
+full_stacktrace2_test: Pass, RuntimeError
+full_stacktrace3_test: Pass, RuntimeError
+stack_trace_test: Pass, RuntimeError
+stacktrace_rethrow_error_test: Pass, RuntimeError
+stacktrace_rethrow_nonerror_test: Pass, RuntimeError
+stacktrace_test: Pass, RuntimeError
-deferred_global_test: RuntimeError # Issue 25845
+[ $noopt || $compiler == precompiler || $runtime == dart_product ]
+# Imports dart:mirrors
+const_evaluation_test: SkipByDesign
+deferred_constraints_constants_test: SkipByDesign
+enum_mirror_test: SkipByDesign
+field_increment_bailout_test: SkipByDesign
+instance_creation_in_function_annotation_test: SkipByDesign
+invocation_mirror2_test: SkipByDesign
+invocation_mirror_invoke_on2_test: SkipByDesign
+invocation_mirror_invoke_on_test: SkipByDesign
+issue21079_test: SkipByDesign
+many_overridden_no_such_method_test: SkipByDesign
+no_such_method_test: SkipByDesign
+null_test/none: SkipByDesign
+overridden_no_such_method_test: SkipByDesign
+redirecting_factory_reflection_test: SkipByDesign
+regress_13462_0_test: SkipByDesign
+regress_13462_1_test: SkipByDesign
+regress_18535_test: SkipByDesign
+super_call4_test: SkipByDesign
+super_getter_setter_test: SkipByDesign
+vm/reflect_core_vm_test: SkipByDesign
[ ($noopt || $compiler == precompiler || $compiler == dart2app) ]
# Deferred loading happens eagerly
@@ -150,6 +158,7 @@
deferred_inheritance_constraints_test: Skip
deferred_load_constants_test: Skip # multitest gets confused
tearoff_basic_test: RuntimeError, Crash # Conflicting flag.
+deferred_global_test: RuntimeError # Issue 25845
vm/type_vm_test: RuntimeError # Expects line and column numbers
vm/type_cast_vm_test: RuntimeError # Line number mismatch.
@@ -171,3 +180,21 @@
[ $runtime == vm && $mode == product ]
vm/type_vm_test: Fail,OK # Expects exact type name.
+
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $browser ]
+# The following tests are supposed to fail.
+library_env_test/has_io_support: RuntimeError, OK
+library_env_test/has_no_html_support: RuntimeError, OK
+
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $browser != true ]
+# The following tests are supposed to fail.
+library_env_test/has_html_support: RuntimeError, OK
+library_env_test/has_no_io_support: RuntimeError, OK
+
+[ $compiler == none && $noopt == false && $mode != product ]
+# The following tests are supposed to fail.
+library_env_test/has_no_mirror_support: RuntimeError, OK
+
+[ $noopt || $compiler == precompiler || $mode == product ]
+# The following tests are supposed to fail.
+library_env_test/has_mirror_support: RuntimeError, OK
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 90527a4..a3327e4 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -25,7 +25,7 @@
mixin_of_mixin_test: CompileTimeError # Issue 23773
# The following tests are supposed to fail.
-# When run for testing dart2js supports all dart:X libraries (because it
+# In testing-mode, dart2js supports all dart:X libraries (because it
# uses '--categories=all').
library_env_test/has_no_html_support: RuntimeError, OK
library_env_test/has_no_io_support: RuntimeError, OK
diff --git a/tests/language/library_env_test.dart b/tests/language/library_env_test.dart
index 7095d83..bbe3b84 100644
--- a/tests/language/library_env_test.dart
+++ b/tests/language/library_env_test.dart
@@ -5,7 +5,7 @@
import 'package:expect/expect.dart';
main() {
- const NOT_PRESENT = null;
+ const NOT_PRESENT = false;
Expect.isTrue(const bool.fromEnvironment("dart.library.async"));
Expect.isTrue(const bool.fromEnvironment("dart.library.collection"));
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 4a43727..a8623b4 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -233,7 +233,7 @@
mirrors/native_class_test: Fail, OK # This test is meant to run in a browser.
mirrors/deferred_type_test: CompileTimeError, OK # Don't have a multitest marker for dynamic compile time errors.
-[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) ]
+[ $compiler == none || $compiler == precompiler || $compiler == dart2app ]
async/timer_not_available_test: SkipByDesign # only meant to test when there is no way to implement timer (currently only in d8)
mirrors/symbol_validation_test: RuntimeError # Issue 13596
@@ -348,7 +348,7 @@
[ $noopt && $arch == simarm64 ]
async/slow_consumer2_test: Pass, RuntimeError # Issue 25726
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler ]
mirrors/*: SkipByDesign
convert/chunked_conversion_utf88_test: Pass, Timeout
convert/utf85_test: Pass, Timeout
diff --git a/tests/standalone/io/http_proxy_advanced_test.dart b/tests/standalone/io/http_proxy_advanced_test.dart
index 81a43c9..1d2e585 100644
--- a/tests/standalone/io/http_proxy_advanced_test.dart
+++ b/tests/standalone/io/http_proxy_advanced_test.dart
@@ -12,12 +12,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
class Server {
HttpServer server;
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index 042807c..e2505f3 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -12,13 +12,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(
- localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
class Server {
HttpServer server;
diff --git a/tests/standalone/io/https_bad_certificate_test.dart b/tests/standalone/io/https_bad_certificate_test.dart
index d90acd4..90c630f 100644
--- a/tests/standalone/io/https_bad_certificate_test.dart
+++ b/tests/standalone/io/https_bad_certificate_test.dart
@@ -14,9 +14,9 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
class CustomException {}
@@ -31,7 +31,7 @@
});
SecurityContext goodContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
SecurityContext badContext = new SecurityContext();
SecurityContext defaultContext = SecurityContext.defaultContext;
diff --git a/tests/standalone/io/https_client_certificate_test.dart b/tests/standalone/io/https_client_certificate_test.dart
index 27b97ed..dc11a45 100644
--- a/tests/standalone/io/https_client_certificate_test.dart
+++ b/tests/standalone/io/https_client_certificate_test.dart
@@ -13,17 +13,17 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
// TODO: Specify which client certificate roots to trust.
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'))
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'))
// TODO: Set a client certificate here.
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
void main() {
asyncStart();
diff --git a/tests/standalone/io/https_server_test.dart b/tests/standalone/io/https_server_test.dart
index c0bce81..3f9bc52 100644
--- a/tests/standalone/io/https_server_test.dart
+++ b/tests/standalone/io/https_server_test.dart
@@ -13,12 +13,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
void testListenOn() {
void test(void onDone()) {
diff --git a/tests/standalone/io/https_unauthorized_test.dart b/tests/standalone/io/https_unauthorized_test.dart
index cfa54c2..a556626 100644
--- a/tests/standalone/io/https_unauthorized_test.dart
+++ b/tests/standalone/io/https_unauthorized_test.dart
@@ -16,13 +16,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext untrustedServerContext = new SecurityContext()
- ..useCertificateChainSync(localFile(
- 'certificates/untrusted_server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/untrusted_server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/untrusted_server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/untrusted_server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
Future<SecureServerSocket> runServer() {
return HttpServer.bindSecure(
diff --git a/tests/standalone/io/raw_secure_server_closing_test.dart b/tests/standalone/io/raw_secure_server_closing_test.dart
index b63da9e..e6c084a 100644
--- a/tests/standalone/io/raw_secure_server_closing_test.dart
+++ b/tests/standalone/io/raw_secure_server_closing_test.dart
@@ -17,12 +17,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
void testCloseOneEnd(String toClose) {
asyncStart();
diff --git a/tests/standalone/io/raw_secure_server_socket_test.dart b/tests/standalone/io/raw_secure_server_socket_test.dart
index 0510ba6..ba34bed 100644
--- a/tests/standalone/io/raw_secure_server_socket_test.dart
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -17,12 +17,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
void testSimpleBind() {
asyncStart();
@@ -574,13 +574,13 @@
var chain =
Platform.script.resolve('certificates/untrusted_server_chain.pem')
.toFilePath();
- context.useCertificateChainSync(chain);
+ context.useCertificateChain(chain);
testSimpleConnectFail(context, false);
testSimpleConnectFail(context, true);
var key =
Platform.script.resolve('certificates/untrusted_server_key.pem')
.toFilePath();
- context.usePrivateKeySync(key, password: 'dartdart');
+ context.usePrivateKey(key, password: 'dartdart');
testSimpleConnectFail(context, false);
testSimpleConnectFail(context, true);
testServerListenAfterConnect();
diff --git a/tests/standalone/io/raw_secure_socket_pause_test.dart b/tests/standalone/io/raw_secure_socket_pause_test.dart
index 9ca848e..0073cda 100644
--- a/tests/standalone/io/raw_secure_socket_pause_test.dart
+++ b/tests/standalone/io/raw_secure_socket_pause_test.dart
@@ -16,12 +16,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
Future<HttpServer> startServer() {
return HttpServer.bindSecure(
diff --git a/tests/standalone/io/raw_secure_socket_test.dart b/tests/standalone/io/raw_secure_socket_test.dart
index 04d8417..df3994e 100644
--- a/tests/standalone/io/raw_secure_socket_test.dart
+++ b/tests/standalone/io/raw_secure_socket_test.dart
@@ -16,12 +16,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
main() async {
List<int> message = "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n".codeUnits;
diff --git a/tests/standalone/io/regress_21160_test.dart b/tests/standalone/io/regress_21160_test.dart
index 25d64e8..b3d39f1 100644
--- a/tests/standalone/io/regress_21160_test.dart
+++ b/tests/standalone/io/regress_21160_test.dart
@@ -13,12 +13,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
// 10 KiB of i%256 data.
Uint8List DATA = new Uint8List.fromList(
diff --git a/tests/standalone/io/secure_bad_certificate_test.dart b/tests/standalone/io/secure_bad_certificate_test.dart
index eeea66b..610bcdb 100644
--- a/tests/standalone/io/secure_bad_certificate_test.dart
+++ b/tests/standalone/io/secure_bad_certificate_test.dart
@@ -14,9 +14,9 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
class CustomException {}
@@ -30,7 +30,7 @@
}, onError: (e) { if (e is! HandshakeException) throw e; });
SecurityContext goodContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
SecurityContext badContext = new SecurityContext();
SecurityContext defaultContext = SecurityContext.defaultContext;
diff --git a/tests/standalone/io/secure_client_raw_server_test.dart b/tests/standalone/io/secure_client_raw_server_test.dart
index 00ea2dc..e8cb63d 100644
--- a/tests/standalone/io/secure_client_raw_server_test.dart
+++ b/tests/standalone/io/secure_client_raw_server_test.dart
@@ -16,12 +16,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
InternetAddress HOST;
Future<RawSecureServerSocket> startEchoServer() {
diff --git a/tests/standalone/io/secure_client_server_test.dart b/tests/standalone/io/secure_client_server_test.dart
index 360e9e4d..4d928ef 100644
--- a/tests/standalone/io/secure_client_server_test.dart
+++ b/tests/standalone/io/secure_client_server_test.dart
@@ -18,12 +18,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(
+ ..setTrustedCertificates(
localFile('certificates/trusted_certs.pem'));
diff --git a/tests/standalone/io/secure_multiple_client_server_test.dart b/tests/standalone/io/secure_multiple_client_server_test.dart
index 9515688..a0577df 100644
--- a/tests/standalone/io/secure_multiple_client_server_test.dart
+++ b/tests/standalone/io/secure_multiple_client_server_test.dart
@@ -19,12 +19,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
Future startServer() {
return SecureServerSocket.bind(HOST, 0, serverContext).then((server) {
diff --git a/tests/standalone/io/secure_server_client_certificate_test.dart b/tests/standalone/io/secure_server_client_certificate_test.dart
index e1cf015..6891037 100644
--- a/tests/standalone/io/secure_server_client_certificate_test.dart
+++ b/tests/standalone/io/secure_server_client_certificate_test.dart
@@ -14,27 +14,27 @@
SecurityContext serverContext(String certType, String password) =>
new SecurityContext()
- ..useCertificateChainSync(
- localFile('certificates/server_chain.$certType'), password: password)
- ..usePrivateKeySync(
- localFile('certificates/server_key.$certType'), password: password)
- ..setTrustedCertificatesSync(localFile(
+ ..useCertificateChain(localFile(
+ 'certificates/server_chain.$certType'), password: password)
+ ..usePrivateKey(localFile(
+ 'certificates/server_key.$certType'), password: password)
+ ..setTrustedCertificates(localFile(
'certificates/client_authority.$certType'), password: password)
- ..setClientAuthoritiesSync(localFile(
+ ..setClientAuthorities(localFile(
'certificates/client_authority.$certType'), password: password);
SecurityContext clientCertContext(String certType, String password) =>
new SecurityContext()
- ..setTrustedCertificatesSync(
- localFile('certificates/trusted_certs.$certType'), password: password)
- ..useCertificateChainSync(
- localFile('certificates/client1.$certType'), password: password)
- ..usePrivateKeySync(
- localFile('certificates/client1_key.$certType'), password: password);
+ ..setTrustedCertificates(localFile(
+ 'certificates/trusted_certs.$certType'), password: password)
+ ..useCertificateChain(localFile(
+ 'certificates/client1.$certType'), password: password)
+ ..usePrivateKey(localFile(
+ 'certificates/client1_key.$certType'), password: password);
SecurityContext clientNoCertContext(String certType, String password) =>
new SecurityContext()
- ..setTrustedCertificatesSync(localFile(
+ ..setTrustedCertificates(localFile(
'certificates/trusted_certs.$certType'), password: password);
Future testClientCertificate(
diff --git a/tests/standalone/io/secure_server_closing_test.dart b/tests/standalone/io/secure_server_closing_test.dart
index 1e2a2d7..159c6ae4 100644
--- a/tests/standalone/io/secure_server_closing_test.dart
+++ b/tests/standalone/io/secure_server_closing_test.dart
@@ -18,13 +18,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(
- localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
void testCloseOneEnd(String toClose) {
asyncStart();
diff --git a/tests/standalone/io/secure_server_socket_test.dart b/tests/standalone/io/secure_server_socket_test.dart
index 33cd57e..d3e2d1c 100644
--- a/tests/standalone/io/secure_server_socket_test.dart
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -18,12 +18,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
void testSimpleBind() {
asyncStart();
diff --git a/tests/standalone/io/secure_session_resume_test.dart b/tests/standalone/io/secure_session_resume_test.dart
index c4738f6..15f2b0b 100644
--- a/tests/standalone/io/secure_session_resume_test.dart
+++ b/tests/standalone/io/secure_session_resume_test.dart
@@ -28,12 +28,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
Future<SecureServerSocket> startServer() {
return SecureServerSocket.bind(HOST,
diff --git a/tests/standalone/io/secure_socket_alpn_test.dart b/tests/standalone/io/secure_socket_alpn_test.dart
index 4b717b2..8599991 100644
--- a/tests/standalone/io/secure_socket_alpn_test.dart
+++ b/tests/standalone/io/secure_socket_alpn_test.dart
@@ -17,12 +17,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext clientContext() => new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
SecurityContext serverContext() => new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
// Tests that client/server with same protocol can securely establish a
// connection, negotiate the protocol and can send data to each other.
diff --git a/tests/standalone/io/secure_socket_renegotiate_client.dart b/tests/standalone/io/secure_socket_renegotiate_client.dart
index 7886706..12f9245 100644
--- a/tests/standalone/io/secure_socket_renegotiate_client.dart
+++ b/tests/standalone/io/secure_socket_renegotiate_client.dart
@@ -15,7 +15,7 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
class ExpectException implements Exception {
ExpectException(this.message);
diff --git a/tests/standalone/io/secure_socket_renegotiate_test.dart b/tests/standalone/io/secure_socket_renegotiate_test.dart
index 7cc9346..457cee6 100644
--- a/tests/standalone/io/secure_socket_renegotiate_test.dart
+++ b/tests/standalone/io/secure_socket_renegotiate_test.dart
@@ -17,9 +17,9 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
Future<SecureServerSocket> runServer() {
return SecureServerSocket.bind(HOST_NAME, 0, serverContext)
diff --git a/tests/standalone/io/secure_socket_test.dart b/tests/standalone/io/secure_socket_test.dart
index c24fc5f..1566b5a 100644
--- a/tests/standalone/io/secure_socket_test.dart
+++ b/tests/standalone/io/secure_socket_test.dart
@@ -17,15 +17,15 @@
SecurityContext serverContext(String certType, String password) =>
new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.$certType'),
- password: password)
- ..usePrivateKeySync(localFile('certificates/server_key.$certType'),
- password: password);
+ ..useCertificateChain(localFile('certificates/server_chain.$certType'),
+ password: password)
+ ..usePrivateKey(localFile('certificates/server_key.$certType'),
+ password: password);
SecurityContext clientContext(String certType, String password) =>
new SecurityContext()
- ..setTrustedCertificatesSync(localFile(
- 'certificates/trusted_certs.$certType'), password: password);
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.$certType'),
+ password: password);
Future<HttpServer> startServer(String certType, String password) {
return HttpServer.bindSecure(
diff --git a/tests/standalone/io/secure_unauthorized_client.dart b/tests/standalone/io/secure_unauthorized_client.dart
index 9c764a7..10392f2 100644
--- a/tests/standalone/io/secure_unauthorized_client.dart
+++ b/tests/standalone/io/secure_unauthorized_client.dart
@@ -11,7 +11,7 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
class ExpectException implements Exception {
ExpectException(this.message);
diff --git a/tests/standalone/io/secure_unauthorized_test.dart b/tests/standalone/io/secure_unauthorized_test.dart
index 097a0d0..a600d74 100644
--- a/tests/standalone/io/secure_unauthorized_test.dart
+++ b/tests/standalone/io/secure_unauthorized_test.dart
@@ -14,10 +14,9 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile(
- 'certificates/untrusted_server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/untrusted_server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/untrusted_server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/untrusted_server_key.pem'),
+ password: 'dartdart');
Future<SecureServerSocket> runServer() {
return SecureServerSocket.bind(HOST_NAME, 0, serverContext)
diff --git a/tests/standalone/io/security_context_argument_test.dart b/tests/standalone/io/security_context_argument_test.dart
index 6d5e1e2..e5332ac 100644
--- a/tests/standalone/io/security_context_argument_test.dart
+++ b/tests/standalone/io/security_context_argument_test.dart
@@ -15,71 +15,71 @@
void testUsePrivateKeyArguments() {
var c = new SecurityContext();
- c.useCertificateChainSync(localFile('certificates/server_chain.pem'));
+ c.useCertificateChain(localFile('certificates/server_chain.pem'));
// Wrong password.
- Expect.throws(() => c.usePrivateKeySync(
+ Expect.throws(() => c.usePrivateKey(
localFile('certificates/server_key.pem')),
tlsException);
- Expect.throws(() => c.usePrivateKeySync(
- localFile('certificates/server_key.pem'), password: "iHackSites"),
+ Expect.throws(() => c.usePrivateKey(
+ localFile('certificates/server_key.pem'), password: "iHackSites"),
tlsException);
- Expect.throws(() => c.usePrivateKeySync(
+ Expect.throws(() => c.usePrivateKey(
localFile('certificates/server_key.p12')),
tlsException);
- Expect.throws(() => c.usePrivateKeySync(
- localFile('certificates/server_key.p12'), password: "iHackSites"),
+ Expect.throws(() => c.usePrivateKey(
+ localFile('certificates/server_key.p12'), password: "iHackSites"),
tlsException);
- Expect.throws(() => c.setTrustedCertificatesSync(
+ Expect.throws(() => c.setTrustedCertificates(
localFile('certificates/server_key.p12')),
tlsException);
- Expect.throws(() => c.setTrustedCertificatesSync(
- localFile('certificates/server_key.p12'), password: "iHackSites"),
+ Expect.throws(() => c.setTrustedCertificates(
+ localFile('certificates/server_key.p12'), password: "iHackSites"),
tlsException);
- Expect.throws(() => c.useCertificateChainSync(
+ Expect.throws(() => c.useCertificateChain(
localFile('certificates/server_key.p12')),
tlsException);
- Expect.throws(() => c.useCertificateChainSync(
- localFile('certificates/server_key.p12'), password: "iHackSites"),
+ Expect.throws(() => c.useCertificateChain(
+ localFile('certificates/server_key.p12'), password: "iHackSites"),
tlsException);
- Expect.throws(() => c.setClientAuthoritiesSync(
+ Expect.throws(() => c.setClientAuthorities(
localFile('certificates/server_key.p12')),
argumentError);
- Expect.throws(() => c.setClientAuthoritiesSync(
- localFile('certificates/server_key.p12'), password: "iHackSites"),
+ Expect.throws(() => c.setClientAuthorities(
+ localFile('certificates/server_key.p12'), password: "iHackSites"),
argumentError);
// File does not exist
- Expect.throws(() => c.usePrivateKeySync(
+ Expect.throws(() => c.usePrivateKey(
localFile('certificates/server_key_oops.pem'),
password: "dartdart"),
fileSystemException);
// Wrong type for file name or data
- Expect.throws(() => c.usePrivateKeySync(1), argumentOrTypeError);
- Expect.throws(() => c.usePrivateKeySync(null), argumentError);
+ Expect.throws(() => c.usePrivateKey(1), argumentOrTypeError);
+ Expect.throws(() => c.usePrivateKey(null), argumentError);
Expect.throws(() => c.usePrivateKeyBytes(1), argumentOrTypeError);
Expect.throws(() => c.usePrivateKeyBytes(null), argumentError);
// Too-long passwords.
- Expect.throws(() => c.usePrivateKeySync(
+ Expect.throws(() => c.usePrivateKey(
localFile('certificates/server_key.pem'), password: "dart" * 1000),
argumentError);
- Expect.throws(() => c.usePrivateKeySync(
+ Expect.throws(() => c.usePrivateKey(
localFile('certificates/server_key.p12'), password: "dart" * 1000),
argumentOrTypeError);
- Expect.throws(() => c.setTrustedCertificatesSync(
+ Expect.throws(() => c.setTrustedCertificates(
localFile('certificates/server_key.p12'), password: "dart" * 1000),
argumentOrTypeError);
- Expect.throws(() => c.useCertificateChainSync(
+ Expect.throws(() => c.useCertificateChain(
localFile('certificates/server_key.p12'), password: "dart" * 1000),
argumentOrTypeError);
- Expect.throws(() => c.setClientAuthoritiesSync(
+ Expect.throws(() => c.setClientAuthorities(
localFile('certificates/server_key.p12'), password: "dart" * 1000),
argumentOrTypeError);
// Bad password type.
- Expect.throws(() => c.usePrivateKeySync(
+ Expect.throws(() => c.usePrivateKey(
localFile('certificates/server_key.pem'), password: 3),
argumentOrTypeError);
Expect.throws(() => c.setTrustedCertificatesBytes(
@@ -100,24 +100,24 @@
Expect.throws(() => c.setClientAuthoritiesBytes([]), argumentError);
// Malformed PEM certs.
- Expect.throws(() => c.usePrivateKeySync(
+ Expect.throws(() => c.usePrivateKey(
localFile('certificates/client1_key_malformed.pem'),
password: "dartdart"),
tlsException);
- Expect.throws(() => c.setTrustedCertificatesSync(
+ Expect.throws(() => c.setTrustedCertificates(
localFile('certificates/trusted_certs_malformed.pem')),
tlsException);
- Expect.throws(() => c.useCertificateChainSync(
+ Expect.throws(() => c.useCertificateChain(
localFile('certificates/server_chain_malformed1.pem')),
tlsException);
- Expect.throws(() => c.useCertificateChainSync(
+ Expect.throws(() => c.useCertificateChain(
localFile('certificates/server_chain_malformed2.pem')),
tlsException);
- Expect.throws(() => c.setClientAuthoritiesSync(
+ Expect.throws(() => c.setClientAuthorities(
localFile('certificates/client_authority_malformed.pem')),
argumentError);
- c.usePrivateKeySync(
+ c.usePrivateKey(
localFile('certificates/server_key.pem'), password: "dartdart");
}
diff --git a/tests/standalone/io/socket_upgrade_to_secure_test.dart b/tests/standalone/io/socket_upgrade_to_secure_test.dart
index aa5eca0..b4c862b 100644
--- a/tests/standalone/io/socket_upgrade_to_secure_test.dart
+++ b/tests/standalone/io/socket_upgrade_to_secure_test.dart
@@ -18,12 +18,12 @@
List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
// This test creates a server and a client connects. After connecting
// and an optional initial handshake the connection is secured by
diff --git a/tests/standalone/io/web_socket_compression_test.dart b/tests/standalone/io/web_socket_compression_test.dart
index c2f87ec..e25bc1b 100644
--- a/tests/standalone/io/web_socket_compression_test.dart
+++ b/tests/standalone/io/web_socket_compression_test.dart
@@ -25,9 +25,9 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
class SecurityConfiguration {
final bool secure;
diff --git a/tests/standalone/io/web_socket_error_test.dart b/tests/standalone/io/web_socket_error_test.dart
index 31969a3..42b93d4 100644
--- a/tests/standalone/io/web_socket_error_test.dart
+++ b/tests/standalone/io/web_socket_error_test.dart
@@ -28,12 +28,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
/**
* A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
diff --git a/tests/standalone/io/web_socket_test.dart b/tests/standalone/io/web_socket_test.dart
index e8642f5..f7ff673 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -24,12 +24,12 @@
String localFile(path) => Platform.script.resolve(path).toFilePath();
SecurityContext serverContext = new SecurityContext()
- ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
- ..usePrivateKeySync(localFile('certificates/server_key.pem'),
- password: 'dartdart');
+ ..useCertificateChain(localFile('certificates/server_chain.pem'))
+ ..usePrivateKey(localFile('certificates/server_key.pem'),
+ password: 'dartdart');
SecurityContext clientContext = new SecurityContext()
- ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
+ ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
/**
* A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
diff --git a/tests/standalone/map_literal_oom_test.dart b/tests/standalone/map_literal_oom_test.dart
index fb23497..955a499 100644
--- a/tests/standalone/map_literal_oom_test.dart
+++ b/tests/standalone/map_literal_oom_test.dart
Binary files differ
diff --git a/tests/standalone/noopt_test.dart b/tests/standalone/noopt_test.dart
deleted file mode 100644
index 171f3a5..0000000
--- a/tests/standalone/noopt_test.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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.
-
-/// VMOptions=--noopt
-
-main() {
- print("Hello, --noopt World!");
-}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 6b9e9e9..41f4d09 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -68,7 +68,6 @@
verbose_gc_to_bmu_test: Skip
precompilation_test: Skip # Standalone only test.
precompilation_dart2js_test: Skip # Standalone only test.
-noopt_test: Skip # Standalone only test.
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
issue14236_test: Skip # Analyzer can't handle Script snapshots.
@@ -108,22 +107,17 @@
pair_location_remapping_test: Skip
precompilation_test: Skip # Standalone only test.
precompilation_dart2js_test: Skip # Standalone only test.
-noopt_test: Skip # Standalone only test.
regress_25335_test: Skip # Int64List not supported.
[ ($runtime == vm || $runtime == dart_product) && $mode == debug ]
precompilation_dart2js_test: Pass, Slow
[ ($runtime == vm || $runtime == dart_product) && $arch == ia32 ]
-precompilation_test: Skip # Not expected to pass on ia32.
-precompilation_dart2js_test: Skip # Not expected to pass on ia32.
-noopt_test: Skip # Not expected to pass on ia32.
+precompilation_test: SkipByDesign # Not expected to pass on ia32.
+precompilation_dart2js_test: SkipByDesign # Not expected to pass on ia32.
-[ ($runtime == vm || $runtime == dart_product) && $arch == arm ]
-precompilation_test: Skip # Issue 24427
-precompilation_dart2js_test: Skip # Issue 24427
-
-[ ($runtime == vm || $runtime == dart_product) && $arch == mips ]
+[ ($runtime == vm || $runtime == dart_product) && ($arch == mips || $arch == arm || $arch == arm64) ]
+precompilation_test: SkipSlow
precompilation_dart2js_test: SkipSlow
[ $compiler == dart2js && $jscl ]
@@ -217,10 +211,13 @@
no_allow_absolute_addresses_test: SkipByDesign # Not supported.
link_natives_lazily_test: SkipByDesign # Not supported.
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler ]
+# Stacktraces in precompilation omit inlined frames.
+assert_test: Pass, RuntimeError
+
+[ $noopt || $compiler == precompiler ]
map_literal_oom_test: Pass, Crash # Issue 24678
io/web_socket_test: Pass, RuntimeError # Issue 24674
-assert_test: RuntimeError # Expects line and column numbers
precompilation_test: Skip # Platform.executable
precompilation_dart2js_test: Skip # Platform.executable
io/test_extension_test: Skip # Platform.executable
@@ -237,7 +234,6 @@
[ $runtime == dart_precompiled || $runtime == dart_product ]
debugger/*: Skip
-noopt_test: Skip
precompilation_test: Skip # Platform.executable
precompilation_dart2js_test: Skip # Platform.executable
full_coverage_test: Skip # Platform.executable
@@ -275,7 +271,6 @@
io/test_extension_test: Skip # Platform.executable
io/regress_7679_test: Skip # Platform.executable
io/process_*: Skip # Most use Platform.executable
-assert_test: RuntimeError # Expects line and column numbers
# Code coverage is not supported in product mode.
[ $mode == product ]
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index 992eeb2..4ca122e 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -22,5 +22,5 @@
[ $compiler == dart2js && $mode == debug ]
dummy_compiler_test: Slow, Pass
-[ ($noopt || $compiler == precompiler || $compiler == dart2app) ]
+[ $noopt || $compiler == precompiler || $compiler == dart2app ]
source_mirrors_test: SkipByDesign # Imports dart:mirrors
diff --git a/tools/VERSION b/tools/VERSION
index 888fdb3..42b3a94 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 15
PATCH 0
-PRERELEASE 4
+PRERELEASE 5
PRERELEASE_PATCH 0
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index a510fd4..0105c11 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -9,7 +9,7 @@
vars.update({
"dartium_chromium_commit": "8df9de5a8f073d9c0feadf8d652408807e4a254e",
- "dartium_webkit_commit": "1d73225937ba77bba2d4279fe7b23bfb542d35d9",
+ "dartium_webkit_commit": "28b9a6c03797eaecf6c92677cba747eb9df0787c",
"chromium_base_revision": "338390",
# We use mirrors of all github repos to guarantee reproducibility and
diff --git a/tools/dom/idl/dart/dart.idl b/tools/dom/idl/dart/dart.idl
index f63ad18..bf857a8 100644
--- a/tools/dom/idl/dart/dart.idl
+++ b/tools/dom/idl/dart/dart.idl
@@ -142,47 +142,6 @@
optional DOMString statusMessageArg);
};
-[DartSupplemental]
-interface WebGLRenderingContext {
-
- //void compressedTexImage2D(unsigned long target, long level, unsigned long internalformat, unsigned long width, unsigned long height, long border, unsigned long imageSize, const void* data);
- //void compressedTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, unsigned long width, unsigned long height, unsigned long format, unsigned long imageSize, const void* data);
-
- [Custom] any getBufferParameter(unsigned long target, unsigned long pname);
- [DartSuppress, DartStrictTypeChecking, Custom] void getBufferParameter();
-
- [Custom] any getFramebufferAttachmentParameter(unsigned long target, unsigned long attachment, unsigned long pname);
- [DartSuppress, DartStrictTypeChecking, Custom] void getFramebufferAttachmentParameter();
-
- [Custom] any getParameter(unsigned long pname);
- [DartSuppress, DartStrictTypeChecking, Custom] void getParameter();
-
- [Custom] any getProgramParameter(WebGLProgram program, unsigned long pname);
- [DartSuppress, DartStrictTypeChecking, Custom] void getProgramParameter();
-
- [Custom] any getRenderbufferParameter(unsigned long target, unsigned long pname);
- [DartSuppress, DartStrictTypeChecking, Custom] void getRenderbufferParameter();
-
- [Custom] any getShaderParameter(WebGLShader shader, unsigned long pname);
- [DartSuppress, DartStrictTypeChecking, Custom] void getShaderParameter();
-
- // TBD
- // void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
-
- [Custom] any getExtension(DOMString name);
- [DartSuppress, DartStrictTypeChecking, Custom] void getExtension(DOMString name);
- [DartSuppress, DartStrictTypeChecking, Custom] void getSupportedExtensions();
-
- [Custom] any getTexParameter(unsigned long target, unsigned long pname);
- [DartSuppress, DartStrictTypeChecking, Custom] void getTexParameter();
-
- [Custom] any getUniform(WebGLProgram program, WebGLUniformLocation location);
- [DartSuppress, DartStrictTypeChecking, Custom] void getUniform();
-
- [Custom] any getVertexAttrib(unsigned long index, unsigned long pname);
- [DartSuppress, DartStrictTypeChecking, Custom] void getVertexAttrib();
-};
-
// TODO(vsm): Define new names for these (see b/4436830).
[DartSupplemental]
interface IDBCursor {
@@ -210,9 +169,6 @@
interface IDBObjectStore {
[CallWith=ScriptState, RaisesException] IDBRequest put(any value, [DartForceOptional] optional any key);
[CallWith=ScriptState, RaisesException] IDBRequest add(any value, [DartForceOptional] optional any key);
- // [CallWith=ExecutionContext, ImplementedAs=deleteFunction, RaisesException] IDBRequest delete(any key);
- [CallWith=ExecutionContext, RaisesException] IDBRequest openCursor([Default=Undefined] optional any range, [DartForceOptional] optional DOMString direction);
- [CallWith=ExecutionContext, RaisesException] IDBRequest count([Default=Undefined] any key);
};
interface EntrySync {
diff --git a/tools/dom/scripts/dartdomgenerator.py b/tools/dom/scripts/dartdomgenerator.py
index cacdd63..8194dfc 100755
--- a/tools/dom/scripts/dartdomgenerator.py
+++ b/tools/dom/scripts/dartdomgenerator.py
@@ -106,7 +106,7 @@
exclude_suppressed = ['WebKit', 'Dart'])
generator.FixEventTargets(webkit_database)
generator.AddMissingArguments(webkit_database)
- generator.HackCleanupTimers(webkit_database)
+ generator.CleanupOperationArguments(webkit_database)
emitters = multiemitter.MultiEmitter(logging_level)
metadata = DartMetadata(
diff --git a/tools/dom/scripts/dartgenerator.py b/tools/dom/scripts/dartgenerator.py
index 5adbe3a..e3e9625 100755
--- a/tools/dom/scripts/dartgenerator.py
+++ b/tools/dom/scripts/dartgenerator.py
@@ -12,6 +12,7 @@
import re
import shutil
from generator import *
+from idlnode import IDLType
_logger = logging.getLogger('dartgenerator')
@@ -245,10 +246,17 @@
if 'ScriptArguments' in call_with:
operation.arguments.append(ARG)
- # TODO(terry): Hack to remove 3rd arguments in setInterval/setTimeout.
- def HackCleanupTimers(self, database):
+ def CleanupOperationArguments(self, database):
for interface in database.GetInterfaces():
for operation in interface.operations:
+ # TODO(terry): Hack to remove 3rd arguments in setInterval/setTimeout.
if ((operation.id == 'setInterval' or operation.id == 'setTimeout') and \
operation.arguments[0].type.id == 'any'):
operation.arguments.pop(2)
+
+ # Massage any operation argument type that is IDLEnum to String.
+ for index, argument in enumerate(operation.arguments):
+ type_name = argument.type.id
+ if database.HasEnum(type_name):
+ operation.arguments[index].type = IDLType('DOMString')
+
diff --git a/tools/dom/scripts/database.py b/tools/dom/scripts/database.py
index 19ca222..7329b22 100755
--- a/tools/dom/scripts/database.py
+++ b/tools/dom/scripts/database.py
@@ -314,24 +314,30 @@
The list contains the interface objects for interfaces defined in the
database, and the name for undefined interfaces.
"""
- def walk(parents):
+ def walk(parents, walk_result):
for parent in parents:
parent_name = parent.type.id
if IsDartCollectionType(parent_name):
- result.append(parent_name)
+ if not(parent_name in walk_result):
+ walk_result.append(parent_name)
continue
if self.HasInterface(parent_name):
parent_interface = self.GetInterface(parent_name)
- result.append(parent_interface)
- walk(parent_interface.parents)
+ if not(parent_interface in walk_result):
+ # Interface has multi-inherited don't add interfaces more than once
+ # to our parent result list.
+ walk_result.append(parent_interface)
+ walk(parent_interface.parents, walk_result)
+ return walk_result
result = []
if interface.parents:
parent = interface.parents[0]
if (IsPureInterface(parent.type.id) or
(propagate_event_target and parent.type.id == 'EventTarget')):
- walk(interface.parents)
+ result = walk(interface.parents, [])
else:
- walk(interface.parents[1:])
+ result = walk(interface.parents[1:], [])
+
return result
diff --git a/tools/dom/scripts/generate_blink_file.py b/tools/dom/scripts/generate_blink_file.py
index a45b9ac..6f274da 100644
--- a/tools/dom/scripts/generate_blink_file.py
+++ b/tools/dom/scripts/generate_blink_file.py
@@ -158,6 +158,18 @@
ARGUMENT_NUM = "__arg_%s"
OPERATION_ARGS = ' %s_Callback_%s_(mthis, %s) => Blink_JsNative_DomException.callMethod(mthis, "%s", [%s]);\n\n'
+# get class property to make static call.
+CLASS_STATIC = 'Blink_JsNative_DomException.getProperty(js.context, "%s")'
+
+# name, classname_getproperty, name
+STATIC_ATTRIBUTE_GETTER = ' %s_Getter_() => Blink_JsNative_DomException.getProperty(%s, "%s");\n\n'
+
+# name, classname_getproperty, name
+STATIC_OPERATION_0 = ' %s_Callback_0_() => Blink_JsNative_DomException.callMethod(%s, "%s", []);\n\n'
+
+# name, argsCount, args, classname_getproperty, name, args
+STATIC_OPERATION_ARGS = ' %s_Callback_%s_(%s) => Blink_JsNative_DomException.callMethod(%s, "%s", [%s]);\n\n'
+
CLASS_DEFINITION_END = """}
"""
@@ -179,6 +191,7 @@
constructor_renames = {
'RTCPeerConnection': 'webkitRTCPeerConnection',
+ 'SpeechRecognition': 'webkitSpeechRecognition',
}
def rename_constructor(name):
@@ -215,12 +228,12 @@
# Zero parameter constructor.
blink_file.write(CONSTRUCTOR_0 % rename_constructor(name))
- _Process_Attributes(blink_file, interface.attributes)
+ _Process_Attributes(blink_file, interface, interface.attributes)
_Process_Operations(blink_file, interface, interface.operations)
secondary_parents = database.TransitiveSecondaryParents(interface, False)
for secondary in secondary_parents:
- _Process_Attributes(blink_file, secondary.attributes)
+ _Process_Attributes(blink_file, secondary, secondary.attributes)
_Process_Operations(blink_file, secondary, secondary.operations)
blink_file.write(CLASS_DEFINITION_END);
@@ -245,12 +258,16 @@
argument_list = ', '.join(arguments)
blink_file.write(CONSTRUCTOR_ARGS % (callback_index, argument_list, rename_constructor(name), argument_list))
-def _Process_Attributes(blink_file, attributes):
+def _Process_Attributes(blink_file, interface, attributes):
# Emit an interface's attributes and operations.
for attribute in sorted(attributes, ConstantOutputOrder):
name = attribute.id
if attribute.is_read_only:
- blink_file.write(ATTRIBUTE_GETTER % (name, name))
+ if attribute.is_static:
+ class_property = CLASS_STATIC % interface.id
+ blink_file.write(STATIC_ATTRIBUTE_GETTER % (name, class_property, name))
+ else:
+ blink_file.write(ATTRIBUTE_GETTER % (name, name))
else:
blink_file.write(ATTRIBUTE_GETTER % (name, name))
blink_file.write(ATTRIBUTE_SETTER % (name, name))
@@ -297,10 +314,18 @@
for callback_index in range(arg_min_count, arg_max_count):
if callback_index == 0:
- blink_file.write(OPERATION_0 % (name, name))
+ if operation.is_static:
+ class_property = CLASS_STATIC % interface.id
+ blink_file.write(STATIC_OPERATION_0 % (name, class_property, name))
+ else:
+ blink_file.write(OPERATION_0 % (name, name))
else:
arguments = []
for i in range(0, callback_index):
arguments.append(ARGUMENT_NUM % i)
argument_list = ', '.join(arguments)
- blink_file.write(OPERATION_ARGS % (name, callback_index, argument_list, name, argument_list))
+ if operation.is_static:
+ class_property = CLASS_STATIC % interface.id
+ blink_file.write(STATIC_OPERATION_ARGS % (name, callback_index, argument_list, class_property, name, argument_list))
+ else:
+ blink_file.write(OPERATION_ARGS % (name, callback_index, argument_list, name, argument_list))
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index a1ebfe2..a5488b2 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -141,7 +141,7 @@
'ApplicationCache,DOMApplicationCache,OfflineResourceList',
'Event':
- 'Event,InputEvent,ClipboardEvent',
+ 'Event,InputEvent',
'HTMLTableCellElement':
'HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement',
@@ -151,7 +151,7 @@
'IDBOpenDBRequest':
'IDBOpenDBRequest,IDBVersionChangeRequest',
- 'MouseEvent': 'MouseEvent,DragEvent,PointerEvent,MSPointerEvent',
+ 'MouseEvent': 'MouseEvent,DragEvent',
'MutationObserver': 'MutationObserver,WebKitMutationObserver',
@@ -1264,6 +1264,9 @@
# TODO(vsm): This won't actually work until we convert the Map to
# a native JS Map for JS DOM.
'Dictionary': TypeData(clazz='Primitive', dart_type='Map'),
+ # TODO(terry): It's a dictionary but a very complex dictionary is multiple lists.
+ # Need to investigate a 1-off solution probably.
+ 'MediaKeySystemConfiguration': TypeData(clazz='Primitive', dart_type='Map'),
'DOMTimeStamp': TypeData(clazz='Primitive', dart_type='int', native_type='unsigned long long'),
'object': TypeData(clazz='Primitive', dart_type='Object', native_type='ScriptValue'),
'ObjectArray': TypeData(clazz='Primitive', dart_type='List'),
@@ -1309,6 +1312,22 @@
suppress_interface=True),
'GLenum': TypeData(clazz='Primitive', dart_type='int',
native_type='unsigned'),
+ 'GLboolean': TypeData(clazz='Primitive', dart_type='bool',
+ native_type='bool'),
+ 'GLbitfield': TypeData(clazz='Primitive', dart_type='int',
+ native_type='unsigned'),
+ 'GLshort': TypeData(clazz='Primitive', dart_type='int', native_type='short'),
+ 'GLint': TypeData(clazz='Primitive', dart_type='int',
+ native_type='long'),
+ 'GLsizei': TypeData(clazz='Primitive', dart_type='int',
+ native_type='long'),
+ 'GLintptr': TypeData(clazz='Primitive', dart_type='int'),
+ 'GLsizeiptr': TypeData(clazz='Primitive', dart_type='int'),
+ 'GLushort': TypeData(clazz='Primitive', dart_type='int', native_type='int'),
+ 'GLuint': TypeData(clazz='Primitive', dart_type='int',
+ native_type='unsigned'),
+ 'GLfloat': TypeData(clazz='Primitive', dart_type='num', native_type='float'),
+ 'GLclampf': TypeData(clazz='Primitive', dart_type='num', native_type='float'),
'HTMLCollection': TypeData(clazz='Interface', item_type='Node',
dart_type='List<Node>'),
'NamedNodeMap': TypeData(clazz='Interface', item_type='Node'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index b05f9cc..addddd9 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -268,10 +268,6 @@
'Element.scrollTop',
'Element.scrollWidth',
'Element.scrollHeight',
- 'Element.clientLeft',
- 'Element.clientTop',
- 'Element.clientWidth',
- 'Element.clientHeight',
'Event.initEvent',
'EventTarget.addEventListener',
@@ -832,13 +828,6 @@
'NodeList.item',
'ParentNode.append',
'ParentNode.prepend',
- 'Performance.webkitClearMarks',
- 'Performance.webkitClearMeasures',
- 'Performance.webkitGetEntries',
- 'Performance.webkitGetEntriesByName',
- 'Performance.webkitGetEntriesByType',
- 'Performance.webkitMark',
- 'Performance.webkitMeasure',
'ShadowRoot.getElementsByTagNameNS',
'SVGElement.getPresentationAttribute',
'SVGElementInstance.on:wheel',
diff --git a/tools/dom/scripts/idlnode.py b/tools/dom/scripts/idlnode.py
index b5949a3..2d81988 100755
--- a/tools/dom/scripts/idlnode.py
+++ b/tools/dom/scripts/idlnode.py
@@ -12,6 +12,23 @@
new_asts = {}
+# Ugly but Chrome IDLs can reference typedefs in any IDL w/o an include. So we
+# need to remember any typedef seen then alias any reference to a typedef.
+typeDefsFixup = []
+
+def _resolveTypedef(type):
+ """ Given a type if it's a known typedef (only typedef's that aren't union)
+ are remembered for fixup. typedefs that are union type are mapped to
+ any so those we don't need to alias. typedefs referenced in the file
+ where the typedef was defined are automatically aliased to the real type.
+ This resolves typedef where the declaration is in another IDL file.
+ """
+ for typedef in typeDefsFixup:
+ if typedef.id == type.id:
+ return typedef.type
+
+ return type
+
_operation_suffix_map = {
'__getter__': "Getter",
@@ -406,6 +423,9 @@
elif typedef_type.idl_type.base_type == 'Dictionary':
dictionary = IDLDictionary(typedef_type, True)
self.dictionaries.append(dictionary)
+ else:
+ # All other typedefs we record
+ typeDefsFixup.append(IDLTypeDef(typedef_type))
self.enums = self._convert_all(ast, 'Enum', IDLEnum)
@@ -538,79 +558,80 @@
def __init__(self, ast):
IDLNode.__init__(self, ast)
- self.nullable = self._has(ast, 'Nullable')
- # Search for a 'ScopedName' or any label ending with 'Type'.
- if isinstance(ast, list):
- self.id = self._find_first(ast, 'ScopedName')
- if not self.id:
- # FIXME: use regexp search instead
- def findType(ast):
- for label, childAst in ast:
- if label.endswith('Type'):
- type = self._label_to_type(label, ast)
- if type != 'sequence':
- return type
- type_ast = self._find_first(childAst, 'Type')
- if not type_ast:
- return type
- return 'sequence<%s>' % findType(type_ast)
- raise Exception('No type declaration found in %s' % ast)
- self.id = findType(ast)
- # TODO(terry): Remove array_modifiers id has [] appended, keep for old
- # parsing.
- array_modifiers = self._find_first(ast, 'ArrayModifiers')
- if array_modifiers:
- self.id += array_modifiers
- elif isinstance(ast, tuple):
- (label, value) = ast
- if label == 'ScopedName':
- self.id = value
- else:
- self.id = self._label_to_type(label, ast)
- elif isinstance(ast, str):
- self.id = ast
- # New blink handling.
- elif ast.__module__ == "idl_types":
- if isinstance(ast, IdlType) or isinstance(ast, IdlArrayOrSequenceType) or \
- isinstance(ast, IdlNullableType):
- if isinstance(ast, IdlNullableType) and ast.inner_type.is_union_type:
- print 'WARNING type %s is union mapped to \'any\'' % self.id
+ if ast:
+ self.nullable = self._has(ast, 'Nullable')
+ # Search for a 'ScopedName' or any label ending with 'Type'.
+ if isinstance(ast, list):
+ self.id = self._find_first(ast, 'ScopedName')
+ if not self.id:
+ # FIXME: use regexp search instead
+ def findType(ast):
+ for label, childAst in ast:
+ if label.endswith('Type'):
+ type = self._label_to_type(label, ast)
+ if type != 'sequence':
+ return type
+ type_ast = self._find_first(childAst, 'Type')
+ if not type_ast:
+ return type
+ return 'sequence<%s>' % findType(type_ast)
+ raise Exception('No type declaration found in %s' % ast)
+ self.id = findType(ast)
+ # TODO(terry): Remove array_modifiers id has [] appended, keep for old
+ # parsing.
+ array_modifiers = self._find_first(ast, 'ArrayModifiers')
+ if array_modifiers:
+ self.id += array_modifiers
+ elif isinstance(ast, tuple):
+ (label, value) = ast
+ if label == 'ScopedName':
+ self.id = value
+ else:
+ self.id = self._label_to_type(label, ast)
+ elif isinstance(ast, str):
+ self.id = ast
+ # New blink handling.
+ elif ast.__module__ == "idl_types":
+ if isinstance(ast, IdlType) or isinstance(ast, IdlArrayOrSequenceType) or \
+ isinstance(ast, IdlNullableType):
+ if isinstance(ast, IdlNullableType) and ast.inner_type.is_union_type:
+ print 'WARNING type %s is union mapped to \'any\'' % self.id
+ # TODO(terry): For union types use any otherwise type is unionType is
+ # not found and is removed during merging.
+ self.id = 'any'
+ else:
+ type_name = str(ast)
+ # TODO(terry): For now don't handle unrestricted types see
+ # https://code.google.com/p/chromium/issues/detail?id=354298
+ type_name = type_name.replace('unrestricted ', '', 1);
+
+ # TODO(terry): Handled USVString as a DOMString.
+ type_name = type_name.replace('USVString', 'DOMString', 1)
+
+ # TODO(terry); WindowTimers setInterval/setTimeout overloads with a
+ # Function type - map to any until the IDL uses union.
+ type_name = type_name.replace('Function', 'any', 1)
+
+ self.id = type_name
+ else:
+ # IdlUnionType
+ if ast.is_union_type:
+ print 'WARNING type %s is union mapped to \'any\'' % self.id
# TODO(terry): For union types use any otherwise type is unionType is
# not found and is removed during merging.
- self.id = 'any'
- else:
- type_name = str(ast)
- # TODO(terry): For now don't handle unrestricted types see
- # https://code.google.com/p/chromium/issues/detail?id=354298
- type_name = type_name.replace('unrestricted ', '', 1);
-
- # TODO(terry): Handled USVString as a DOMString.
- type_name = type_name.replace('USVString', 'DOMString', 1)
-
- # TODO(terry); WindowTimers setInterval/setTimeout overloads with a
- # Function type - map to any until the IDL uses union.
- type_name = type_name.replace('Function', 'any', 1)
-
- self.id = type_name
- else:
- # IdlUnionType
- if ast.is_union_type:
- print 'WARNING type %s is union mapped to \'any\'' % self.id
- # TODO(terry): For union types use any otherwise type is unionType is
- # not found and is removed during merging.
- self.id = 'any'
- # TODO(terry): Any union type e.g. 'type1 or type2 or type2',
- # 'typedef (Type1 or Type2) UnionType'
- # Is a problem we need to extend IDLType and IDLTypeDef to handle more
- # than one type.
- #
- # Also for typedef's e.g.,
- # typedef (Type1 or Type2) UnionType
- # should consider synthesizing a new interface (e.g., UnionType) that's
- # both Type1 and Type2.
- if not self.id:
- print '>>>> __module__ %s' % ast.__module__
- raise SyntaxError('Could not parse type %s' % (ast))
+ self.id = 'any'
+ # TODO(terry): Any union type e.g. 'type1 or type2 or type2',
+ # 'typedef (Type1 or Type2) UnionType'
+ # Is a problem we need to extend IDLType and IDLTypeDef to handle more
+ # than one type.
+ #
+ # Also for typedef's e.g.,
+ # typedef (Type1 or Type2) UnionType
+ # should consider synthesizing a new interface (e.g., UnionType) that's
+ # both Type1 and Type2.
+ if not self.id:
+ print '>>>> __module__ %s' % ast.__module__
+ raise SyntaxError('Could not parse type %s' % (ast))
def _label_to_type(self, label, ast):
if label == 'LongLongType':
@@ -747,6 +768,8 @@
IDLNode.__init__(self, ast)
self.type = self._convert_first(ast, 'Type', IDLType)
+ self.type = _resolveTypedef(self.type)
+
self._convert_ext_attrs(ast)
self._convert_annotations(ast)
self.doc_js_interface_name = doc_js_interface_name
@@ -755,13 +778,13 @@
'DartSuppress' in self.ext_attrs
self.is_static = self._has(ast, 'Static')
-
class IDLOperation(IDLMember):
"""IDLNode specialization for 'type name(args)' declarations."""
def __init__(self, ast, doc_js_interface_name):
IDLMember.__init__(self, ast, doc_js_interface_name)
self.type = self._convert_first(ast, 'ReturnType', IDLType)
+ self.type = _resolveTypedef(self.type)
self.arguments = self._convert_all(ast, 'Argument', IDLArgument)
self.specials = self._find_all(ast, 'Special')
# Special case: there are getters of the form
@@ -839,6 +862,8 @@
self.default_value_is_null = False
self.type = self._convert_first(ast, 'Type', IDLType)
+ self.type = _resolveTypedef(self.type)
+
self.optional = self._has(ast, 'Optional')
self._convert_ext_attrs(ast)
# TODO(vsm): Recover this from the type instead.
diff --git a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
index 9173eff..cd5fa3c 100644
--- a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
@@ -11,6 +11,15 @@
$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS implements CanvasRenderingContext {
$!MEMBERS
+ @DomName('CanvasRenderingContext2D.createImageDataFromImageData')
+ @DocsEditable()
+ ImageData createImageDataFromImageData(ImageData imagedata) =>
+$if DART2JS
+ JS('ImageData', '#.createImageData(#, #)', this, imagedata);
+$else
+ this.createImageData(imagedata);
+$endif
+
/**
* Sets the color used inside shapes.
* [r], [g], [b] are 0-255, [a] is 0-1.
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index a4ddc94..4b8173b 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -1540,22 +1540,6 @@
@DocsEditable()
int get offsetWidth => JS('num', '#.offsetWidth', this).round();
- @DomName('Element.clientHeight')
- @DocsEditable()
- int get clientHeight => JS('num', '#.clientHeight', this).round();
-
- @DomName('Element.clientLeft')
- @DocsEditable()
- int get clientLeft => JS('num', '#.clientLeft', this).round();
-
- @DomName('Element.clientTop')
- @DocsEditable()
- int get clientTop => JS('num', '#.clientTop', this).round();
-
- @DomName('Element.clientWidth')
- @DocsEditable()
- int get clientWidth => JS('num', '#.clientWidth', this).round();
-
@DomName('Element.scrollHeight')
@DocsEditable()
int get scrollHeight => JS('num', '#.scrollHeight', this).round();
diff --git a/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate b/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
index 1b3280d..fec4341 100644
--- a/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
@@ -36,6 +36,22 @@
@DocsEditable()
dynamic get data => convertNativeToDart_SerializedScriptValue(
_blink.BlinkMessageEvent.instance.data_Getter_(unwrap_jso(this)));
+
+$else
+ // TODO(alanknight): This really should be generated by the
+ // _OutputConversion in the systemnative.py script, but that doesn't
+ // use those conversions right now, so do this as a one-off.
+ @DomName('MessageEvent.data')
+ @DocsEditable()
+ dynamic get data => convertNativeToDart_SerializedScriptValue(this._get_data);
+
+ @JSName('data')
+ @DomName('MessageEvent.data')
+ @DocsEditable()
+ @Creates('Null')
+ @Returns('Object|Null')
+ final dynamic _get_data;
+
$endif
$!MEMBERS
diff --git a/tools/precompilation/precompiler.dart b/tools/precompilation/precompiler.dart
deleted file mode 100755
index 419875a..0000000
--- a/tools/precompilation/precompiler.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.
-
-library precompiler;
-
-import 'dart:io';
-
-void run(String executable, String arguments, [String workingDirectory]) {
- print("+ $executable ${arguments.join(' ')}");
- var result = Process.runSync(executable, arguments,
- workingDirectory: workingDirectory);
- stdout.write(result.stdout);
- stderr.write(result.stderr);
- if (result.exitCode != 0) {
- exit(result.exitCode);
- }
-}
-
-void main(List<String> args) {
- var configuration = Platform.environment["DART_CONFIGURATION"];
-
- var cc, cc_flags, shared, libname;
- if (Platform.isLinux) {
- cc = 'gcc';
- shared = '-shared';
- libname = 'libprecompiled.so';
- } else if (Platform.isMacOS) {
- cc = 'clang';
- shared = '-dynamiclib';
- libname = 'libprecompiled.dylib';
- } else {
- print("Test only supports Linux and Mac");
- return;
- }
-
- if (configuration.endsWith("X64")) {
- cc_flags = "-m64";
- } else if (configuration.endsWith("SIMARM64")) {
- cc_flags = "-m64";
- } else if (configuration.endsWith("SIMARM")) {
- cc_flags = "-m32";
- } else if (configuration.endsWith("SIMMIPS")) {
- cc_flags = "-m32";
- } else if (configuration.endsWith("ARM")) {
- cc_flags = "";
- } else if (configuration.endsWith("MIPS")) {
- cc_flags = "-EL";
- } else {
- print("Architecture not supported: $configuration");
- return;
- }
-
- var tmpDir;
- for (var arg in args) {
- if (arg.startsWith("--gen-precompiled-snapshot")) {
- tmpDir = arg.substring("--gen-precompiled-snapshot".length + 1);
- }
- }
- print("Using directory $tmpDir");
-
- run(args[0], args.sublist(1));
- run(cc, [shared, cc_flags, "-o", libname, "precompiled.S"], tmpDir);
-}
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 931a53d..4794992 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -78,7 +78,8 @@
isDebug: isDebug, isChecked: isChecked);
case 'precompiler':
return new PrecompilerCompilerConfiguration(
- isDebug: isDebug, isChecked: isChecked);
+ isDebug: isDebug, isChecked: isChecked,
+ arch: configuration['arch']);
case 'none':
return new NoneCompilerConfiguration(
isDebug: isDebug, isChecked: isChecked,
@@ -302,10 +303,13 @@
class PrecompilerCompilerConfiguration extends CompilerConfiguration {
+ final String arch;
+
PrecompilerCompilerConfiguration({
bool isDebug,
- bool isChecked})
- : super._subclass(isDebug: isDebug, isChecked: isChecked);
+ bool isChecked,
+ String arch})
+ : super._subclass(isDebug: isDebug, isChecked: isChecked), arch = arch;
int computeTimeoutMultiplier() {
int multiplier = 2;
@@ -327,6 +331,18 @@
buildDir,
CommandBuilder.instance,
arguments,
+ environmentOverrides),
+ this.computeAssembleCommand(
+ tempDir,
+ buildDir,
+ CommandBuilder.instance,
+ arguments,
+ environmentOverrides),
+ this.computeRemoveAssemblyCommand(
+ tempDir,
+ buildDir,
+ CommandBuilder.instance,
+ arguments,
environmentOverrides)],
'$tempDir',
'application/dart-precompiled');
@@ -338,19 +354,91 @@
CommandBuilder commandBuilder,
List arguments,
Map<String, String> environmentOverrides) {
- var exec = "$buildDir/dart";
+ var exec = "$buildDir/dart_no_snapshot";
var args = new List();
- args.add("tools/precompilation/precompiler.dart");
- args.add("$buildDir/dart_no_snapshot");
args.add("--gen-precompiled-snapshot=$tempDir");
args.addAll(arguments);
return commandBuilder.getCompilationCommand(
- 'precompiler.dart', tempDir, !useSdk,
+ 'precompiler', tempDir, !useSdk,
bootstrapDependencies(buildDir),
exec, args, environmentOverrides);
}
+ CompilationCommand computeAssembleCommand(
+ String tempDir,
+ String buildDir,
+ CommandBuilder commandBuilder,
+ List arguments,
+ Map<String, String> environmentOverrides) {
+ var cc, cc_flags, shared, libname;
+ if (Platform.isLinux) {
+ cc = 'gcc';
+ shared = '-shared';
+ libname = 'libprecompiled.so';
+ } else if (Platform.isMacOS) {
+ cc = 'clang';
+ shared = '-dynamiclib';
+ libname = 'libprecompiled.dylib';
+ } else {
+ throw "Platform not supported: ${Platform.operatingSystem}";
+ }
+
+ if (arch == 'x64') {
+ cc_flags = "-m64";
+ } else if (arch == 'simarm64') {
+ cc_flags = "-m64";
+ } else if (arch == 'simarm') {
+ cc_flags = "-m32";
+ } else if (arch == 'simmips') {
+ cc_flags = "-m32";
+ } else if (arch == 'arm') {
+ cc_flags = "";
+ } else if (arch == 'mips') {
+ cc_flags = "-EL";
+ } else {
+ throw "Architecture not supported: $arch";
+ }
+
+ var exec = cc;
+ var args = [shared,
+ cc_flags,
+ '-o',
+ '$tempDir/$libname',
+ '$tempDir/precompiled.S'];
+
+ return commandBuilder.getCompilationCommand(
+ 'assemble', tempDir, !useSdk,
+ bootstrapDependencies(buildDir),
+ exec, args, environmentOverrides);
+ }
+
+ // This step reduces the amount of space needed to run the precompilation
+ // tests by 60%.
+ CompilationCommand computeRemoveAssemblyCommand(
+ String tempDir,
+ String buildDir,
+ CommandBuilder commandBuilder,
+ List arguments,
+ Map<String, String> environmentOverrides) {
+ var exec = 'rm';
+ var args = ['$tempDir/precompiled.S'];
+
+ return commandBuilder.getCompilationCommand(
+ 'remove_assembly', tempDir, !useSdk,
+ bootstrapDependencies(buildDir),
+ exec, args, environmentOverrides);
+ }
+
+ List<String> filterVmOptions(List<String> vmOptions) {
+ var filtered = new List.from(vmOptions);
+ filtered.removeWhere(
+ (option) => option.startsWith("--optimization-counter-threshold"));
+ filtered.removeWhere(
+ (option) => option.startsWith("--optimization_counter_threshold"));
+ return filtered;
+ }
+
List<String> computeCompilerArguments(vmOptions,
sharedOptions,
originalArguments) {
@@ -360,7 +448,7 @@
args.add('--enable_type_checks');
}
return args
- ..addAll(vmOptions)
+ ..addAll(filterVmOptions(vmOptions))
..addAll(sharedOptions)
..addAll(originalArguments);
}
@@ -405,35 +493,37 @@
CommandBuilder commandBuilder,
List arguments,
Map<String, String> environmentOverrides) {
+ String outputName = computeOutputName(tempDir);
return new CommandArtifact(
<Command>[
this.computeCompilationCommand(
- tempDir,
+ outputName,
buildDir,
CommandBuilder.instance,
arguments,
environmentOverrides)],
- computeOutputName(tempDir),
+ outputName,
'application/dart-snapshot');
}
String computeOutputName(String tempDir) {
- return '$tempDir/test.snapshot';
+ var randName = TestUtils.getRandomNumber().toString();
+ return '$tempDir/test.$randName';
}
CompilationCommand computeCompilationCommand(
- String tempDir,
+ String outputName,
String buildDir,
CommandBuilder commandBuilder,
List arguments,
Map<String, String> environmentOverrides) {
var exec = "$buildDir/dart_no_snapshot";
var args = new List();
- args.add("--full-snapshot-after-run=${computeOutputName(tempDir)}");
+ args.add("--full-snapshot-after-run=$outputName");
args.addAll(arguments);
return commandBuilder.getCompilationCommand(
- 'dart2snapshot', computeOutputName(tempDir), !useSdk,
+ 'dart2snapshot', outputName, !useSdk,
bootstrapDependencies(buildDir),
exec, args, environmentOverrides);
}
diff --git a/tools/testing/dart/test_configurations.dart b/tools/testing/dart/test_configurations.dart
index f4ea6d6..c7d4a09 100644
--- a/tools/testing/dart/test_configurations.dart
+++ b/tools/testing/dart/test_configurations.dart
@@ -160,7 +160,15 @@
} else if (conf['runtime'] == 'chrome' &&
Platform.operatingSystem == 'macos') {
// Chrome on mac results in random timeouts.
+ // Issue: https://github.com/dart-lang/sdk/issues/23891
+ // This change does not fix the problem.
maxBrowserProcesses = math.max(1, maxBrowserProcesses ~/ 2);
+ } else if (conf['runtime'] != 'drt') {
+ // Even on machines with more than 16 processors, don't open more
+ // than 15 browser instances, to avoid overloading the machine.
+ // This is especially important when running locally on powerful
+ // desktops.
+ maxBrowserProcesses = math.min(maxBrowserProcesses, 15);
}
// If we specifically pass in a suite only run that.
@@ -217,6 +225,7 @@
}
}
DebugLogger.close();
+ TestUtils.deleteTempSnapshotDirectory(configurations[0]);
}
var eventListener = [];
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 42dba81..a4abf47 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -1679,7 +1679,7 @@
return new VmCommandOutputImpl(
command, exitCode, timedOut, stdout, stderr, time, pid);
} else if (command is CompilationCommand) {
- if (command.displayName == 'precompiler.dart' ||
+ if (command.displayName == 'precompiler' ||
command.displayName == 'dart2snapshot') {
return new VmCommandOutputImpl(
command, exitCode, timedOut, stdout, stderr, time, pid);
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 21a99a8..fd06d20 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -16,6 +16,7 @@
import "dart:async";
import "dart:io";
+import "dart:math";
import "drt_updater.dart";
import "html_test.dart" as htmlTest;
import "path.dart";
@@ -1017,14 +1018,18 @@
List<List<String>> vmOptionsList = getVmOptions(info.optionsFromFile);
assert(!vmOptionsList.isEmpty);
- for (var vmOptions in vmOptionsList) {
+ for (var vmOptionsVarient = 0;
+ vmOptionsVarient < vmOptionsList.length;
+ vmOptionsVarient++) {
+ var vmOptions = vmOptionsList[vmOptionsVarient];
var allVmOptions = vmOptions;
if (!extraVmOptions.isEmpty) {
allVmOptions = new List.from(vmOptions)..addAll(extraVmOptions);
}
var commands = []..addAll(baseCommands);
- commands.addAll(makeCommands(info, allVmOptions, commonArguments));
+ commands.addAll(makeCommands(info, vmOptionsVarient,
+ allVmOptions, commonArguments));
enqueueNewTestCase(
new TestCase('$suiteName/$testName',
commands,
@@ -1049,7 +1054,10 @@
return negative;
}
- List<Command> makeCommands(TestInformation info, var vmOptions, var args) {
+ List<Command> makeCommands(TestInformation info,
+ int vmOptionsVarient,
+ var vmOptions,
+ var args) {
List<Command> commands = <Command>[];
CompilerConfiguration compilerConfiguration =
new CompilerConfiguration(configuration);
@@ -1063,7 +1071,12 @@
sharedOptions,
args);
// Avoid doing this for analyzer.
- tempDir = createCompilationOutputDirectory(info.filePath);
+ var path = info.filePath;
+ if (vmOptionsVarient != 0) {
+ // Ensure a unique directory for each test case.
+ path = path.join(new Path(vmOptionsVarient.toString()));
+ }
+ tempDir = createCompilationOutputDirectory(path);
}
CommandArtifact compilationArtifact =
@@ -2149,6 +2162,7 @@
dartDirUri = uri;
dartDir = new Path(uri.toFilePath());
}
+ static Random rand = new Random.secure();
static Uri dartDirUri;
static Path dartDir;
static LastModifiedCache lastModifiedCache = new LastModifiedCache();
@@ -2157,6 +2171,13 @@
new Path(Directory.current.path);
/**
+ * Generates a random number.
+ */
+ static int getRandomNumber() {
+ return rand.nextInt(0xffffffff);
+ }
+
+ /**
* Creates a directory using a [relativePath] to an existing
* [base] directory if that [relativePath] does not already exist.
*/
@@ -2232,6 +2253,22 @@
}
}
+ static deleteTempSnapshotDirectory(Map configuration) {
+ if (configuration['compiler'] == 'dart2app') {
+ var checked = configuration['checked'] ? '-checked' : '';
+ var minified = configuration['minified'] ? '-minified' : '';
+ var csp = configuration['csp'] ? '-csp' : '';
+ var sdk = configuration['use_sdk'] ? '-sdk' : '';
+ var packages = configuration['use_public_packages']
+ ? '-public_packages' : '';
+ var dirName = "${configuration['compiler']}"
+ "$checked$minified$csp$packages$sdk";
+ String generatedPath = "${TestUtils.buildDir(configuration)}"
+ "/generated_compilations/$dirName";
+ TestUtils.deleteDirectory(generatedPath);
+ }
+ }
+
static Path debugLogfile() {
return new Path(".debug.log");
}
diff --git a/utils/dartanalyzer/dartanalyzer.gyp b/utils/dartanalyzer/dartanalyzer.gyp
index 74dbf43..6aec554 100644
--- a/utils/dartanalyzer/dartanalyzer.gyp
+++ b/utils/dartanalyzer/dartanalyzer.gyp
@@ -34,8 +34,8 @@
'action_name': 'generate_summaries',
'inputs': [
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
- '../../sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart',
'<(SHARED_INTERMEDIATE_DIR)/packages.stamp',
+ '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../sdk/lib"])',
'<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../pkg/analyzer"])',
],
'outputs': [